chiark / gitweb /
ask-password: supported plymouth cached passwords
authorLennart Poettering <lennart@poettering.net>
Wed, 23 Feb 2011 00:12:07 +0000 (01:12 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 23 Feb 2011 00:12:07 +0000 (01:12 +0100)
README
TODO
src/ask-password-api.c
src/ask-password-api.h
src/ask-password.c
src/cryptsetup.c
src/strv.c
src/strv.h
src/test-env-replace.c
src/tty-ask-password-agent.c

diff --git a/README b/README
index b2a6dc3ecf4e90b49d70fa05acd4eb6ead5156d8..a183cb364f7eb3958eede5d4cca09e28438ef0e7 100644 (file)
--- a/README
+++ b/README
@@ -27,7 +27,7 @@ AUTHOR:
         Lennart Poettering with major support from Kay Sievers
 
 REQUIREMENTS:
-        Linux kernel >= 2.6.30 (with autofs4, devtmpfs, cgroups, ipv6)
+        Linux kernel >= 2.6.30 (with devtmpfs, cgroups; optional but strongly recommended: autofs4, ipv6)
         libudev >= 163
         dbus >= 1.4.0
         libcap
@@ -47,10 +47,27 @@ REQUIREMENTS:
         automake
         autoconf
         libtool
+        make, gcc, and similar tools
 
         During runtime you need the following dependencies:
 
         util-linux > v2.18 (requires fsck -l, agetty -s)
-        sulogin (from sysvinit-tools)
+        sulogin (from sysvinit-tools, optional but recommended)
         plymouth (optional)
         dracut (optional)
+
+WARNINGS:
+        systemd will warn you during boot if /etc/mtab is not a
+        symlink to /proc/mounts. Please ensure that /etc/mtab is a
+        proper symlink.
+
+        systemd will warn you during boot if /usr is on a different
+        file system than /. While in systemd itself very little will
+        break if /usr is on a seperate partition many of its
+        dependencies very likely will break sooner or later in one
+        form or another. For example udev rules tend to refer to
+        binaries in /usr, binaries that link to libraries in /usr or
+        binaries that refer to data files in /usr. Since these
+        breakages are not always directly visible systemd will warn
+        about this, since this kind of file system setup is not really
+        supported anymore by the basic set of Linux OS components.
diff --git a/TODO b/TODO
index 415eb762246fdc29a38be034802f3edcb5099ddb..64f7ad7d3cfae456ab1d35aa3dfa407c7d3569ce 100644 (file)
--- a/TODO
+++ b/TODO
@@ -4,17 +4,11 @@ F15:
 
 * isolate multi-user.target doesn't start a getty@tty1 if we run it from graphical.target
 
-* when plymouth is disabled the console password entry stuff seems to be borked
-  https://bugzilla.redhat.com/show_bug.cgi?id=655538
-
 * increase password timeout
   https://bugzilla.redhat.com/show_bug.cgi?id=677962
 
 * finish syslog socket stuff
 
-* support caching password questions in plymouth and on the console
-  https://bugzilla.redhat.com/show_bug.cgi?id=677438
-
 * load EnvironmentFile= when starting services, not when reloading configuration
   https://bugzilla.redhat.com/show_bug.cgi?id=661282
 
index 9f7023e32847ae14fb40e37f4ca949623738dd5b..cd663ae09ccc5712c7b019d0fafaa7f8676d5cd6 100644 (file)
@@ -32,6 +32,7 @@
 #include <sys/signalfd.h>
 
 #include "util.h"
+#include "strv.h"
 
 #include "ask-password-api.h"
 
@@ -251,12 +252,12 @@ fail:
         return r;
 }
 
-
 int ask_password_agent(
                 const char *message,
                 const char *icon,
                 usec_t until,
-                char **_passphrase) {
+                bool accept_cached,
+                char ***_passphrases) {
 
         enum {
                 FD_SOCKET,
@@ -273,6 +274,8 @@ int ask_password_agent(
         sigset_t mask;
         struct pollfd pollfd[_FD_MAX];
 
+        assert(_passphrases);
+
         mkdir_p("/dev/.systemd/ask-password", 0755);
 
         if ((fd = mkostemp(temp, O_CLOEXEC|O_CREAT|O_WRONLY)) < 0) {
@@ -310,9 +313,11 @@ int ask_password_agent(
                 "[Ask]\n"
                 "PID=%lu\n"
                 "Socket=%s\n"
+                "AcceptCached=%i\n"
                 "NotAfter=%llu\n",
                 (unsigned long) getpid(),
                 socket_name,
+                accept_cached ? 1 : 0,
                 (unsigned long long) until);
 
         if (message)
@@ -384,8 +389,10 @@ int ask_password_agent(
                         goto finish;
                 }
 
-                if (pollfd[FD_SIGNAL].revents & POLLIN)
-                        break;
+                if (pollfd[FD_SIGNAL].revents & POLLIN) {
+                        r = -EINTR;
+                        goto finish;
+                }
 
                 if (pollfd[FD_SOCKET].revents != POLLIN) {
                         log_error("Unexpected poll() event.");
@@ -395,7 +402,7 @@ int ask_password_agent(
 
                 zero(iovec);
                 iovec.iov_base = passphrase;
-                iovec.iov_len = sizeof(passphrase)-1;
+                iovec.iov_len = sizeof(passphrase);
 
                 zero(control);
                 zero(msghdr);
@@ -435,13 +442,21 @@ int ask_password_agent(
                 }
 
                 if (passphrase[0] == '+') {
-                        passphrase[n] = 0;
+                        char **l;
 
-                        if (!(*_passphrase = strdup(passphrase+1))) {
+                        if (!(l = strv_parse_nulstr(passphrase+1, n-1))) {
                                 r = -ENOMEM;
                                 goto finish;
                         }
 
+                        if (strv_length(l) <= 0) {
+                                strv_free(l);
+                                log_error("Invalid packet");
+                                continue;
+                        }
+
+                        *_passphrases = l;
+
                 } else if (passphrase[0] == '-') {
                         r = -ECANCELED;
                         goto finish;
@@ -481,12 +496,26 @@ finish:
         return r;
 }
 
-int ask_password_auto(const char *message, const char *icon, usec_t until, char **_passphrase) {
+int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases) {
         assert(message);
-        assert(_passphrase);
+        assert(_passphrases);
+
+        if (isatty(STDIN_FILENO)) {
+                int r;
+                char *s = NULL, **l = NULL;
+
+                if ((r = ask_password_tty(message, until, NULL, &s)) < 0)
+                        return r;
+
+                l = strv_new(s, NULL);
+                free(s);
+
+                if (!l)
+                        return -ENOMEM;
+
+                *_passphrases = l;
+                return r;
 
-        if (isatty(STDIN_FILENO))
-                return ask_password_tty(message, until, NULL, _passphrase);
-        else
-                return ask_password_agent(message, icon, until, _passphrase);
+        } else
+                return ask_password_agent(message, icon, until, accept_cached, _passphrases);
 }
index ec858bac7851d2813a7b1ead0116f7878b50da83..fec8625a0f0feeaf57ea8918d196681453b33c3f 100644 (file)
@@ -26,8 +26,8 @@
 
 int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase);
 
-int ask_password_agent(const char *message, const char *icon, usec_t until, char **_passphrase);
+int ask_password_agent(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases);
 
-int ask_password_auto(const char *message, const char *icon, usec_t until, char **_passphrase);
+int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases);
 
 #endif
index 596c8e08f07a767b9907250a2cfa9148a6a65a23..c77376482e4a511ed8cbb80270197118a1bc6d47 100644 (file)
 #include "log.h"
 #include "macro.h"
 #include "util.h"
+#include "strv.h"
 #include "ask-password-api.h"
 
 static const char *arg_icon = NULL;
 static const char *arg_message = NULL;
 static bool arg_use_tty = true;
 static usec_t arg_timeout = 60 * USEC_PER_SEC;
+static bool arg_accept_cached = false;
+static bool arg_multiple = false;
 
 static int help(void) {
 
         printf("%s [OPTIONS...] MESSAGE\n\n"
                "Query the user for a system passphrase, via the TTY or an UI agent.\n\n"
-               "  -h --help         Show this help\n"
-               "     --icon=NAME    Icon name\n"
-               "     --timeout=SEC Timeout in sec\n"
-               "     --no-tty       Ask question via agent even on TTY\n",
+               "  -h --help          Show this help\n"
+               "     --icon=NAME     Icon name\n"
+               "     --timeout=SEC   Timeout in sec\n"
+               "     --no-tty        Ask question via agent even on TTY\n"
+               "     --accept-cached Accept cached passwords\n"
+               "     --multiple      List multiple passwords if available\n",
                program_invocation_short_name);
 
         return 0;
@@ -63,15 +68,19 @@ static int parse_argv(int argc, char *argv[]) {
         enum {
                 ARG_ICON = 0x100,
                 ARG_TIMEOUT,
-                ARG_NO_TTY
+                ARG_NO_TTY,
+                ARG_ACCEPT_CACHED,
+                ARG_MULTIPLE
         };
 
         static const struct option options[] = {
-                { "help",      no_argument,       NULL, 'h'         },
-                { "icon",      required_argument, NULL, ARG_ICON    },
-                { "timeout",   required_argument, NULL, ARG_TIMEOUT },
-                { "no-tty",    no_argument,       NULL, ARG_NO_TTY  },
-                { NULL,        0,                 NULL, 0           }
+                { "help",          no_argument,       NULL, 'h'               },
+                { "icon",          required_argument, NULL, ARG_ICON          },
+                { "timeout",       required_argument, NULL, ARG_TIMEOUT       },
+                { "no-tty",        no_argument,       NULL, ARG_NO_TTY        },
+                { "accept-cached", no_argument,       NULL, ARG_ACCEPT_CACHED },
+                { "multiple",      no_argument,       NULL, ARG_MULTIPLE      },
+                { NULL,            0,                 NULL, 0                 }
         };
 
         int c;
@@ -102,6 +111,14 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_use_tty = false;
                         break;
 
+                case ARG_ACCEPT_CACHED:
+                        arg_accept_cached = true;
+                        break;
+
+                case ARG_MULTIPLE:
+                        arg_multiple = true;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -122,7 +139,6 @@ static int parse_argv(int argc, char *argv[]) {
 
 int main(int argc, char *argv[]) {
         int r;
-        char *password = NULL;
 
         log_parse_environment();
         log_open();
@@ -130,18 +146,32 @@ int main(int argc, char *argv[]) {
         if ((r = parse_argv(argc, argv)) <= 0)
                 goto finish;
 
-        if (arg_use_tty && isatty(STDIN_FILENO))
-                r = ask_password_tty(arg_message, now(CLOCK_MONOTONIC) + arg_timeout, NULL, &password);
-        else
-                r = ask_password_agent(arg_message, arg_icon, now(CLOCK_MONOTONIC) + arg_timeout, &password);
+        if (arg_use_tty && isatty(STDIN_FILENO)) {
+                char *password = NULL;
+
+                if ((r = ask_password_tty(arg_message, now(CLOCK_MONOTONIC) + arg_timeout, NULL, &password)) >= 0) {
+                        puts(password);
+                        free(password);
+                }
+
+        } else {
+                char **l;
+
+                if ((r = ask_password_agent(arg_message, arg_icon, now(CLOCK_MONOTONIC) + arg_timeout, arg_accept_cached, &l)) >= 0) {
+                        char **p;
+
+                        STRV_FOREACH(p, l) {
+                                puts(*p);
 
-        if (r >= 0) {
-                fputs(password, stdout);
-                fflush(stdout);
+                                if (!arg_multiple)
+                                        break;
+                        }
+
+                        strv_free(l);
+                }
         }
 
 finish:
-        free(password);
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index c80572aed9672f26c0255cbac561182b21a017dc..f72a14abf617baa199401a3921b1131ee671eae8 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "log.h"
 #include "util.h"
+#include "strv.h"
 #include "ask-password-api.h"
 
 static const char *opt_type = NULL; /* LUKS1 or PLAIN */
@@ -179,7 +180,7 @@ finish:
 int main(int argc, char *argv[]) {
         int r = EXIT_FAILURE;
         struct crypt_device *cd = NULL;
-        char *password = NULL, *truncated_cipher = NULL;
+        char **passwords = NULL, *truncated_cipher = NULL;
         const char *cipher = NULL, *cipher_mode = NULL, *hash = NULL, *name = NULL;
         char *description = NULL;
 
@@ -268,18 +269,19 @@ int main(int argc, char *argv[]) {
                 for (try = 0; try < opt_tries; try++) {
                         bool pass_volume_key = false;
 
-                        free(password);
-                        password = NULL;
+                        strv_free(passwords);
+                        passwords = NULL;
 
                         if (!key_file) {
                                 char *text;
+                                char **p;
 
                                 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) {
                                         log_error("Out of memory");
                                         goto finish;
                                 }
 
-                                k = ask_password_auto(text, "drive-harddisk", until, &password);
+                                k = ask_password_auto(text, "drive-harddisk", until, try == 0 && !opt_verify, &passwords);
                                 free(text);
 
                                 if (k < 0) {
@@ -288,14 +290,16 @@ int main(int argc, char *argv[]) {
                                 }
 
                                 if (opt_verify) {
-                                        char *password2 = NULL;
+                                        char **passwords2 = NULL;
+
+                                        assert(strv_length(passwords) == 1);
 
                                         if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) {
                                                 log_error("Out of memory");
                                                 goto finish;
                                         }
 
-                                        k = ask_password_auto(text, "drive-harddisk", until, &password2);
+                                        k = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
                                         free(text);
 
                                         if (k < 0) {
@@ -303,28 +307,32 @@ int main(int argc, char *argv[]) {
                                                 goto finish;
                                         }
 
-                                        if (!streq(password, password2)) {
+                                        assert(strv_length(passwords2) == 1);
+
+                                        if (!streq(passwords[0], passwords2[0])) {
                                                 log_warning("Passwords did not match, retrying.");
-                                                free(password2);
+                                                strv_free(passwords2);
                                                 continue;
                                         }
 
-                                        free(password2);
+                                        strv_free(passwords2);
                                 }
 
-                                if (strlen(password)+1 < opt_key_size) {
+                                STRV_FOREACH(p, passwords) {
                                         char *c;
 
-                                        /* Pad password if necessary */
+                                        if (strlen(*p)+1 >= opt_key_size)
+                                                continue;
 
+                                        /* Pad password if necessary */
                                         if (!(c = new(char, opt_key_size))) {
                                                 log_error("Out of memory.");
                                                 goto finish;
                                         }
 
-                                        strncpy(c, password, opt_key_size);
-                                        free(password);
-                                        password = c;
+                                        strncpy(c, *p, opt_key_size);
+                                        free(*p);
+                                        *p = c;
                                 }
                         }
 
@@ -367,10 +375,20 @@ int main(int argc, char *argv[]) {
 
                         if (key_file)
                                 k = crypt_activate_by_keyfile(cd, argv[2], CRYPT_ANY_SLOT, key_file, opt_key_size, flags);
-                        else if (pass_volume_key)
-                                k = crypt_activate_by_volume_key(cd, argv[2], password, opt_key_size, flags);
-                        else
-                                k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, password, strlen(password), flags);
+                        else {
+                                char **p;
+
+                                STRV_FOREACH(p, passwords) {
+
+                                        if (pass_volume_key)
+                                                k = crypt_activate_by_volume_key(cd, argv[2], *p, opt_key_size, flags);
+                                        else
+                                                k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, *p, strlen(*p), flags);
+
+                                        if (k >= 0)
+                                                break;
+                                }
+                        }
 
                         if (k >= 0)
                                 break;
@@ -421,7 +439,7 @@ finish:
 
         free(truncated_cipher);
 
-        free(password);
+        strv_free(passwords);
 
         free(description);
 
index d1c7b2c32d89c31b121fc6ef1c0c719a9167c81c..b1643b357fbddf9f69eb09d4ae2c8cde67b7dd5d 100644 (file)
@@ -577,3 +577,45 @@ char **strv_env_clean(char **l) {
 
         return ret;
 }
+
+char **strv_parse_nulstr(const char *s, size_t l) {
+        const char *p;
+        unsigned c = 0, i = 0;
+        char **v;
+
+        assert(s || l <= 0);
+
+        if (l <= 0)
+                return strv_new(NULL, NULL);
+
+        for (p = s; p < s + l; p++)
+                if (*p == 0)
+                        c++;
+
+        if (s[l-1] != 0)
+                c++;
+
+        if (!(v = new0(char*, c+1)))
+                return NULL;
+
+        p = s;
+        while (p < s + l) {
+                const char *e;
+
+                e = memchr(p, 0, s + l - p);
+
+                if (!(v[i++] = strndup(p, e ? e - p : s + l - p))) {
+                        strv_free(v);
+                        return NULL;
+                }
+
+                if (!e)
+                        break;
+
+                p = e + 1;
+        }
+
+        assert(i == c);
+
+        return v;
+}
index 5af84ee41fdb263e31955643364ab0074007aee6..064576ce1ea6f6ed890822d5468e585261d5f65d 100644 (file)
@@ -65,6 +65,8 @@ char *strv_env_get(char **x, const char *n);
 
 char **strv_env_clean(char **l);
 
+char **strv_parse_nulstr(const char *s, size_t l);
+
 #define STRV_FOREACH(s, l)                      \
         for ((s) = (l); (s) && *(s); (s)++)
 
index 4188c67ddedee088557305f13d4ec9c05e678c5f..05dbacd7df49b8030a6f6a50eaf9ec0677cae5d9 100644 (file)
@@ -48,6 +48,14 @@ int main(int argc, char *argv[]) {
         };
 
         char **i, **r, *t, **a, **b;
+        const char nulstr[] = "fuck\0fuck2\0fuck3\0\0fuck5\0\0xxx";
+
+        a = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
+
+        STRV_FOREACH(i, a)
+                printf("nulstr--%s\n", *i);
+
+        strv_free(a);
 
         r = replace_env_argv((char**) line, (char**) env);
 
index 655bfb9ff5b4667af2cd5cf37aaaafafa86c0cf0..14b01486bd4636a942347df45c7df77880f5838e 100644 (file)
@@ -37,6 +37,7 @@
 #include "utmp-wtmp.h"
 #include "socket-util.h"
 #include "ask-password-api.h"
+#include "strv.h"
 
 static enum {
         ACTION_LIST,
@@ -48,7 +49,13 @@ static enum {
 static bool arg_plymouth = false;
 static bool arg_console = false;
 
-static int ask_password_plymouth(const char *message, usec_t until, const char *flag_file, char **_passphrase) {
+static int ask_password_plymouth(
+                const char *message,
+                usec_t until,
+                const char *flag_file,
+                bool accept_cached,
+                char ***_passphrases) {
+
         int fd = -1, notify = -1;
         union sockaddr_union sa;
         char *packet = NULL;
@@ -62,6 +69,8 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
                 POLL_INOTIFY
         };
 
+        assert(_passphrases);
+
         if (flag_file) {
                 if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) {
                         r = -errno;
@@ -88,7 +97,13 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
                 goto finish;
         }
 
-        if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
+        if (accept_cached) {
+                packet = strdup("c");
+                n = 1;
+        } else
+                asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n);
+
+        if (!packet) {
                 r = -ENOMEM;
                 goto finish;
         }
@@ -155,15 +170,38 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
                         continue;
 
                 if (buffer[0] == 5) {
+
+                        if (accept_cached) {
+                                /* Hmm, first try with cached
+                                 * passwords failed, so let's retry
+                                 * with a normal password request */
+                                free(packet);
+                                packet = NULL;
+
+                                if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                                if ((k = loop_write(fd, packet, n+1, true)) != n+1) {
+                                        r = k < 0 ? (int) k : -EIO;
+                                        goto finish;
+                                }
+
+                                accept_cached = false;
+                                p = 0;
+                                continue;
+                        }
+
                         /* No password, because UI not shown */
                         r = -ENOENT;
                         goto finish;
 
-                } else if (buffer[0] == 2) {
+                } else if (buffer[0] == 2 || buffer[0] == 9) {
                         uint32_t size;
-                        char *s;
+                        char **l;
 
-                        /* One answer */
+                        /* One ore more answers */
                         if (p < 5)
                                 continue;
 
@@ -176,13 +214,14 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
                         if (p-5 < size)
                                 continue;
 
-                        if (!(s = strndup(buffer + 5, size))) {
+                        if (!(l = strv_parse_nulstr(buffer + 5, size))) {
                                 r = -ENOMEM;
                                 goto finish;
                         }
 
-                        *_passphrase = s;
+                        *_passphrases = l;
                         break;
+
                 } else {
                         /* Unknown packet */
                         r = -EIO;
@@ -209,12 +248,14 @@ static int parse_password(const char *filename, char **wall) {
         uint64_t not_after = 0;
         unsigned pid = 0;
         int socket_fd = -1;
+        bool accept_cached = false;
 
         const ConfigItem items[] = {
-                { "Socket",   config_parse_string,   &socket_name, "Ask" },
-                { "NotAfter", config_parse_uint64,   &not_after,   "Ask" },
-                { "Message",  config_parse_string,   &message,     "Ask" },
-                { "PID",      config_parse_unsigned, &pid,         "Ask" },
+                { "Socket",       config_parse_string,   &socket_name,   "Ask" },
+                { "NotAfter",     config_parse_uint64,   &not_after,     "Ask" },
+                { "Message",      config_parse_string,   &message,       "Ask" },
+                { "PID",          config_parse_unsigned, &pid,           "Ask" },
+                { "AcceptCached", config_parse_bool,     &accept_cached, "Ask" },
                 { NULL, NULL, NULL, NULL }
         };
 
@@ -274,7 +315,7 @@ static int parse_password(const char *filename, char **wall) {
                         struct sockaddr sa;
                         struct sockaddr_un un;
                 } sa;
-                char *password;
+                size_t packet_length;
 
                 assert(arg_action == ACTION_QUERY ||
                        arg_action == ACTION_WATCH);
@@ -288,10 +329,32 @@ static int parse_password(const char *filename, char **wall) {
                         goto finish;
                 }
 
-                if (arg_plymouth)
-                        r = ask_password_plymouth(message, not_after, filename, &password);
-                else {
+                if (arg_plymouth) {
+                        char **passwords;
+
+                        if ((r = ask_password_plymouth(message, not_after, filename, accept_cached, &passwords)) >= 0) {
+                                char **p;
+
+                                packet_length = 1;
+                                STRV_FOREACH(p, passwords)
+                                        packet_length += strlen(*p) + 1;
+
+                                if (!(packet = new(char, packet_length)))
+                                        r = -ENOMEM;
+                                else {
+                                        char *d;
+
+                                        packet[0] = '+';
+                                        d = packet+1;
+
+                                        STRV_FOREACH(p, passwords)
+                                                d = stpcpy(d, *p) + 1;
+                                }
+                        }
+
+                } else {
                         int tty_fd = -1;
+                        char *password;
 
                         if (arg_console)
                                 if ((tty_fd = acquire_terminal("/dev/console", false, false, false)) < 0) {
@@ -305,6 +368,11 @@ static int parse_password(const char *filename, char **wall) {
                                 close_nointr_nofail(tty_fd);
                                 release_terminal();
                         }
+
+                        asprintf(&packet, "+%s", password);
+                        free(password);
+
+                        packet_length = strlen(packet);
                 }
 
                 if (r < 0) {
@@ -312,9 +380,6 @@ static int parse_password(const char *filename, char **wall) {
                         goto finish;
                 }
 
-                asprintf(&packet, "+%s", password);
-                free(password);
-
                 if (!packet) {
                         log_error("Out of memory");
                         r = -ENOMEM;
@@ -331,7 +396,7 @@ static int parse_password(const char *filename, char **wall) {
                 sa.un.sun_family = AF_UNIX;
                 strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
 
-                if (sendto(socket_fd, packet, strlen(packet), MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) {
+                if (sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) {
                         log_error("Failed to send: %m");
                         r = -errno;
                         goto finish;