]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/tty-ask-password-agent/tty-ask-password-agent.c
strv: Add _cleanup_strv_free_erase_ and _cleanup_string_free_erase_
[thirdparty/systemd.git] / src / tty-ask-password-agent / tty-ask-password-agent.c
index e1e2945c06d9bbc1c9fa32b499520cf2c2f9d6b4..8423364046693164f02d0bc27fae78cc9065a282 100644 (file)
@@ -58,9 +58,9 @@ static bool arg_console = false;
 static int ask_password_plymouth(
                 const char *message,
                 usec_t until,
+                AskPasswordFlags flags,
                 const char *flag_file,
-                bool accept_cached,
-                char ***_passphrases) {
+                char ***ret) {
 
         _cleanup_close_ int fd = -1, notify = -1;
         union sockaddr_union sa = PLYMOUTH_SOCKET;
@@ -75,7 +75,7 @@ static int ask_password_plymouth(
                 POLL_INOTIFY
         };
 
-        assert(_passphrases);
+        assert(ret);
 
         if (flag_file) {
                 notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
@@ -95,12 +95,11 @@ static int ask_password_plymouth(
         if (r < 0)
                 return -errno;
 
-        if (accept_cached) {
+        if (flags & ASK_PASSWORD_ACCEPT_CACHED) {
                 packet = strdup("c");
                 n = 1;
         } else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
                 packet = NULL;
-
         if (!packet)
                 return -ENOMEM;
 
@@ -121,33 +120,48 @@ static int ask_password_plymouth(
 
                         y = now(CLOCK_MONOTONIC);
 
-                        if (y > until)
-                                return -ETIME;
+                        if (y > until) {
+                                r = -ETIME;
+                                goto finish;
+                        }
 
                         sleep_for = (int) ((until - y) / USEC_PER_MSEC);
                 }
 
-                if (flag_file && access(flag_file, F_OK) < 0)
-                        return -errno;
+                if (flag_file && access(flag_file, F_OK) < 0) {
+                        r = -errno;
+                        goto finish;
+                }
 
-                j = poll(pollfd, notify > 0 ? 2 : 1, sleep_for);
+                j = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
                 if (j < 0) {
                         if (errno == EINTR)
                                 continue;
 
-                        return -errno;
-                } else if (j == 0)
-                        return -ETIME;
+                        r = -errno;
+                        goto finish;
+                } else if (j == 0) {
+                        r = -ETIME;
+                        goto finish;
+                }
 
-                if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0)
+                if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
                         flush_fd(notify);
 
                 if (pollfd[POLL_SOCKET].revents == 0)
                         continue;
 
                 k = read(fd, buffer + p, sizeof(buffer) - p);
-                if (k <= 0)
-                        return r = k < 0 ? -errno : -EIO;
+                if (k < 0) {
+                        if (errno == EINTR || errno == EAGAIN)
+                                continue;
+
+                        r = -errno;
+                        goto finish;
+                } else if (k == 0) {
+                        r = -EIO;
+                        goto finish;
+                }
 
                 p += k;
 
@@ -156,26 +170,29 @@ static int ask_password_plymouth(
 
                 if (buffer[0] == 5) {
 
-                        if (accept_cached) {
+                        if (flags & ASK_PASSWORD_ACCEPT_CACHED) {
                                 /* Hmm, first try with cached
                                  * passwords failed, so let's retry
                                  * with a normal password request */
                                 packet = mfree(packet);
 
-                                if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
-                                        return -ENOMEM;
+                                if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
 
                                 r = loop_write(fd, packet, n+1, true);
                                 if (r < 0)
-                                        return r;
+                                        goto finish;
 
-                                accept_cached = false;
+                                flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
                                 p = 0;
                                 continue;
                         }
 
                         /* No password, because UI not shown */
-                        return -ENOENT;
+                        r = -ENOENT;
+                        goto finish;
 
                 } else if (buffer[0] == 2 || buffer[0] == 9) {
                         uint32_t size;
@@ -187,32 +204,43 @@ static int ask_password_plymouth(
 
                         memcpy(&size, buffer+1, sizeof(size));
                         size = le32toh(size);
-                        if (size + 5 > sizeof(buffer))
-                                return -EIO;
+                        if (size + 5 > sizeof(buffer)) {
+                                r = -EIO;
+                                goto finish;
+                        }
 
                         if (p-5 < size)
                                 continue;
 
                         l = strv_parse_nulstr(buffer + 5, size);
-                        if (!l)
-                                return -ENOMEM;
+                        if (!l) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
 
-                        *_passphrases = l;
+                        *ret = l;
                         break;
 
-                } else
+                } else {
                         /* Unknown packet */
-                        return -EIO;
+                        r = -EIO;
+                        goto finish;
+                }
         }
 
-        return 0;
+        r = 0;
+
+finish:
+        memory_erase(buffer, sizeof(buffer));
+        return r;
 }
 
 static int parse_password(const char *filename, char **wall) {
         _cleanup_free_ char *socket_name = NULL, *message = NULL, *packet = NULL;
+        bool accept_cached = false, echo = false;
+        size_t packet_length = 0;
         uint64_t not_after = 0;
         unsigned pid = 0;
-        bool accept_cached = false, echo = false;
 
         const ConfigTableItem items[] = {
                 { "Ask", "Socket",       config_parse_string,   0, &socket_name   },
@@ -266,7 +294,6 @@ static int parse_password(const char *filename, char **wall) {
 
         } else {
                 union sockaddr_union sa = {};
-                size_t packet_length = 0;
                 _cleanup_close_ int socket_fd = -1;
 
                 assert(arg_action == ACTION_QUERY ||
@@ -280,9 +307,9 @@ static int parse_password(const char *filename, char **wall) {
                 }
 
                 if (arg_plymouth) {
-                        _cleanup_strv_free_ char **passwords = NULL;
+                        _cleanup_strv_free_erase_ char **passwords = NULL;
 
-                        r = ask_password_plymouth(message, not_after, filename, accept_cached, &passwords);
+                        r = ask_password_plymouth(message, not_after, accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0, filename, &passwords);
                         if (r >= 0) {
                                 char **p;
 
@@ -304,16 +331,20 @@ static int parse_password(const char *filename, char **wall) {
                         }
 
                 } else {
-                        _cleanup_free_ char *password = NULL;
+                        _cleanup_string_free_erase_ char *password = NULL;
                         int tty_fd = -1;
 
                         if (arg_console) {
                                 tty_fd = acquire_terminal("/dev/console", false, false, false, USEC_INFINITY);
                                 if (tty_fd < 0)
                                         return log_error_errno(tty_fd, "Failed to acquire /dev/console: %m");
+
+                                r = reset_terminal_fd(tty_fd, true);
+                                if (r < 0)
+                                        log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
                         }
 
-                        r = ask_password_tty(message, not_after, echo, filename, &password);
+                        r = ask_password_tty(message, NULL, not_after, echo ? ASK_PASSWORD_ECHO : 0, filename, &password);
 
                         if (arg_console) {
                                 tty_fd = safe_close(tty_fd);
@@ -332,26 +363,36 @@ static int parse_password(const char *filename, char **wall) {
                         }
                 }
 
-                if (IN_SET(r, -ETIME, -ENOENT))
+                if (IN_SET(r, -ETIME, -ENOENT)) {
                         /* If the query went away, that's OK */
-                        return 0;
-
-                if (r < 0)
-                        return log_error_errno(r, "Failed to query password: %m");
+                        r = 0;
+                        goto finish;
+                }
+                if (r < 0) {
+                        log_error_errno(r, "Failed to query password: %m");
+                        goto finish;
+                }
 
                 socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
-                if (socket_fd < 0)
-                        return log_error_errno(errno, "socket(): %m");
+                if (socket_fd < 0) {
+                        r = log_error_errno(errno, "socket(): %m");
+                        goto finish;
+                }
 
                 sa.un.sun_family = AF_UNIX;
                 strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
 
                 r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name));
+                memory_erase(packet, packet_length);
                 if (r < 0)
                         return log_error_errno(errno, "Failed to send: %m");
         }
 
         return 0;
+
+finish:
+        memory_erase(packet, packet_length);
+        return r;
 }
 
 static int wall_tty_block(void) {
@@ -360,6 +401,8 @@ static int wall_tty_block(void) {
         int fd, r;
 
         r = get_ctty_devnr(0, &devnr);
+        if (r == -ENXIO) /* We have no controlling tty */
+                return -ENOTTY;
         if (r < 0)
                 return log_error_errno(r, "Failed to get controlling TTY: %m");
 
@@ -371,7 +414,7 @@ static int wall_tty_block(void) {
 
         fd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
         if (fd < 0)
-                return log_error_errno(errno, "Failed to open %s: %m", p);
+                return log_debug_errno(errno, "Failed to open %s: %m", p);
 
         return fd;
 }