[systemd-devel] [PATCH] [RFC] Add binary password agent protocol

David Härdeman david at hardeman.nu
Thu Jun 26 16:54:17 PDT 2014


Add binary string handling functions and extend the password agent
protocol to support binary strings (using "=" as a string prefix
instead of "+").
---
 Makefile.am                                        |    9 +
 src/ask-password/ask-password.c                    |   33 +--
 src/cryptsetup/cryptsetup.c                        |   60 +++---
 src/shared/ask-password-api.c                      |   58 +++---
 src/shared/ask-password-api.h                      |    7 -
 src/shared/bstrv.c                                 |  194 ++++++++++++++++++++
 src/shared/bstrv.h                                 |   50 +++++
 src/test/test-bstrv.c                              |  122 +++++++++++++
 .../tty-ask-password-agent.c                       |   11 +
 9 files changed, 451 insertions(+), 93 deletions(-)
 create mode 100644 src/shared/bstrv.c
 create mode 100644 src/shared/bstrv.h
 create mode 100644 src/test/test-bstrv.c

diff --git a/Makefile.am b/Makefile.am
index e02dede..08705a4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -736,6 +736,8 @@ libsystemd_shared_la_SOURCES = \
 	src/shared/sleep-config.h \
 	src/shared/strv.c \
 	src/shared/strv.h \
+	src/shared/bstrv.c \
+	src/shared/bstrv.h \
 	src/shared/env-util.c \
 	src/shared/env-util.h \
 	src/shared/strbuf.c \
@@ -1219,6 +1221,7 @@ tests += \
 	test-env-replace \
 	test-strbuf \
 	test-strv \
+	test-bstrv \
 	test-path-util \
 	test-strxcpyx \
 	test-unit-name \
@@ -1584,6 +1587,12 @@ test_strv_LDADD = \
 	libsystemd-internal.la \
 	libsystemd-shared.la
 
+test_bstrv_SOURCES = \
+        src/test/test-bstrv.c
+
+test_bstrv_LDADD = \
+        libsystemd-shared.la
+
 test_path_util_SOURCES = \
 	src/test/test-path-util.c
 
diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c
index 4d5690c..6a00ea8 100644
--- a/src/ask-password/ask-password.c
+++ b/src/ask-password/ask-password.c
@@ -39,6 +39,7 @@
 #include "macro.h"
 #include "util.h"
 #include "strv.h"
+#include "bstrv.h"
 #include "ask-password-api.h"
 #include "def.h"
 
@@ -147,6 +148,7 @@ static int parse_argv(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
         int r;
         usec_t timeout;
+        _cleanup_bstrv_free_ bstr **passwords = NULL;
 
         log_parse_environment();
         log_open();
@@ -159,28 +161,19 @@ int main(int argc, char *argv[]) {
         else
                 timeout = 0;
 
-        if (arg_use_tty && isatty(STDIN_FILENO)) {
-                char *password = NULL;
-
-                if ((r = ask_password_tty(arg_message, timeout, NULL, &password)) >= 0) {
-                        puts(password);
-                        free(password);
-                }
-
-        } else {
-                char **l;
-
-                if ((r = ask_password_agent(arg_message, arg_icon, arg_id, timeout, arg_accept_cached, &l)) >= 0) {
-                        char **p;
-
-                        STRV_FOREACH(p, l) {
-                                puts(*p);
+        if (arg_use_tty && isatty(STDIN_FILENO))
+                r = ask_password_tty(arg_message, timeout, NULL, &passwords);
+        else
+                r = ask_password_agent(arg_message, arg_icon, arg_id, timeout, arg_accept_cached, &passwords);
 
-                                if (!arg_multiple)
-                                        break;
-                        }
+        if (r >= 0) {
+                bstr **p;
 
-                        strv_free(l);
+                BSTRV_FOREACH(p, passwords) {
+                        fwrite(bstr_data(*p), bstr_length(*p), 1, stdout);
+                        putchar('\n');
+                        if (!arg_multiple)
+                                break;
                 }
         }
 
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index a67d85e..a0209e4 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -31,6 +31,7 @@
 #include "util.h"
 #include "path-util.h"
 #include "strv.h"
+#include "bstrv.h"
 #include "ask-password-api.h"
 #include "def.h"
 #include "libudev.h"
@@ -260,9 +261,8 @@ static char *disk_mount_point(const char *label) {
         return NULL;
 }
 
-static int get_password(const char *name, usec_t until, bool accept_cached, char ***passwords) {
+static int get_password(const char *name, usec_t until, bool accept_cached, bstr ***passwords) {
         int r;
-        char **p;
         _cleanup_free_ char *text = NULL;
         _cleanup_free_ char *escaped_name = NULL;
         char *id;
@@ -286,9 +286,9 @@ static int get_password(const char *name, usec_t until, bool accept_cached, char
         }
 
         if (arg_verify) {
-                _cleanup_strv_free_ char **passwords2 = NULL;
+                _cleanup_bstrv_free_ bstr **passwords2 = NULL;
 
-                assert(strv_length(*passwords) == 1);
+                assert(bstrv_length(*passwords) == 1);
 
                 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
                         return log_oom();
@@ -301,30 +301,15 @@ static int get_password(const char *name, usec_t until, bool accept_cached, char
                         return r;
                 }
 
-                assert(strv_length(passwords2) == 1);
+                assert(bstrv_length(passwords2) == 1);
 
-                if (!streq(*passwords[0], passwords2[0])) {
+                if (!bstreq(*passwords[0], passwords2[0])) {
                         log_warning("Passwords did not match, retrying.");
                         return -EAGAIN;
                 }
         }
 
-        strv_uniq(*passwords);
-
-        STRV_FOREACH(p, *passwords) {
-                char *c;
-
-                if (strlen(*p)+1 >= arg_key_size)
-                        continue;
-
-                /* Pad password if necessary */
-                if (!(c = new(char, arg_key_size)))
-                        return log_oom();
-
-                strncpy(c, *p, arg_key_size);
-                free(*p);
-                *p = c;
-        }
+        bstrv_uniq(*passwords);
 
         return 0;
 }
@@ -332,7 +317,7 @@ static int get_password(const char *name, usec_t until, bool accept_cached, char
 static int attach_tcrypt(struct crypt_device *cd,
                                 const char *name,
                                 const char *key_file,
-                                char **passwords,
+                                bstr **passwords,
                                 uint32_t flags) {
         int r = 0;
         _cleanup_free_ char *passphrase = NULL;
@@ -360,9 +345,11 @@ static int attach_tcrypt(struct crypt_device *cd,
                 }
 
                 params.passphrase = passphrase;
-        } else
-                params.passphrase = passwords[0];
-        params.passphrase_size = strlen(params.passphrase);
+        	params.passphrase_size = strlen(passphrase);
+        } else {
+                params.passphrase = bstr_cdata(passwords[0]);
+                params.passphrase_size = bstr_length(passwords[0]);
+        }
 
         r = crypt_load(cd, CRYPT_TCRYPT, &params);
         if (r < 0) {
@@ -379,7 +366,7 @@ static int attach_tcrypt(struct crypt_device *cd,
 static int attach_luks_or_plain(struct crypt_device *cd,
                                 const char *name,
                                 const char *key_file,
-                                char **passwords,
+                                bstr **passwords,
                                 uint32_t flags) {
         int r = 0;
         bool pass_volume_key = false;
@@ -456,13 +443,18 @@ static int attach_luks_or_plain(struct crypt_device *cd,
                         return -EAGAIN;
                 }
         } else {
-                char **p;
+                bstr **p;
 
-                STRV_FOREACH(p, passwords) {
-                        if (pass_volume_key)
-                                r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
-                        else
-                                r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
+                BSTRV_FOREACH(p, passwords) {
+                        if (pass_volume_key) {
+                                uint8_t key[arg_key_size];
+                                unsigned l = MIN(bstr_length(*p), arg_key_size);
+
+                                memcpy(key, bstr_data(*p), l);
+                                memzero(key + l, arg_key_size - l);
+                                r = crypt_activate_by_volume_key(cd, name, bstr_cdata(*p), sizeof(key), flags);
+                        } else
+                                r = crypt_activate_by_passphrase(cd, name, arg_key_slot, bstr_cdata(*p), bstr_length(*p), flags);
 
                         if (r >= 0)
                                 break;
@@ -596,7 +588,7 @@ int main(int argc, char *argv[]) {
                 }
 
                 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
-                        _cleanup_strv_free_ char **passwords = NULL;
+                        _cleanup_bstrv_free_ bstr **passwords = NULL;
 
                         if (!key_file) {
                                 k = get_password(name, until, tries == 0 && !arg_verify, &passwords);
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index 5997a03..76d0310 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -34,6 +34,7 @@
 #include "util.h"
 #include "mkdir.h"
 #include "strv.h"
+#include "bstrv.h"
 
 #include "ask-password-api.h"
 
@@ -53,10 +54,10 @@ int ask_password_tty(
                 const char *message,
                 usec_t until,
                 const char *flag_file,
-                char **_passphrase) {
+                bstr ***_passphrases) {
 
         struct termios old_termios, new_termios;
-        char passphrase[LINE_MAX], *x;
+        uint8_t passphrase[LINE_MAX];
         size_t p = 0;
         int r;
         _cleanup_close_ int ttyfd = -1, notify = -1;
@@ -69,8 +70,8 @@ int ask_password_tty(
                 POLL_INOTIFY
         };
 
+        assert(_passphrases);
         assert(message);
-        assert(_passphrase);
 
         if (flag_file) {
                 notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
@@ -224,13 +225,11 @@ int ask_password_tty(
                 }
         }
 
-        x = strndup(passphrase, p);
-        if (!x) {
+        if (bstrv_push(_passphrases, passphrase, p) < 0) {
                 r = -ENOMEM;
                 goto finish;
         }
 
-        *_passphrase = x;
         r = 0;
 
 finish:
@@ -301,7 +300,7 @@ int ask_password_agent(
                 const char *id,
                 usec_t until,
                 bool accept_cached,
-                char ***_passphrases) {
+                bstr ***_passphrases) {
 
         enum {
                 FD_SOCKET,
@@ -404,7 +403,7 @@ int ask_password_agent(
         pollfd[FD_SIGNAL].events = POLLIN;
 
         for (;;) {
-                char passphrase[LINE_MAX+1];
+                uint8_t passphrase[LINE_MAX+1];
                 struct msghdr msghdr;
                 struct iovec iovec;
                 struct ucred *ucred;
@@ -493,27 +492,38 @@ int ask_password_agent(
                 }
 
                 if (passphrase[0] == '+') {
-                        char **l;
+                        bstr **l;
 
                         if (n == 1)
-                                l = strv_new("", NULL);
-                        else
-                                l = strv_parse_nulstr(passphrase+1, n-1);
                                 /* An empty message refers to the empty password */
+                                l = bstrv_new((uint8_t *)"", 0);
+                        else
+                                l = bstrv_parse_nulstr(passphrase+1, n-1);
 
                         if (!l) {
                                 r = -ENOMEM;
                                 goto finish;
                         }
 
-                        if (strv_length(l) <= 0) {
-                                strv_free(l);
+                        if (bstrv_length(l) <= 0) {
+                                bstrv_free(l);
                                 log_error("Invalid packet");
                                 continue;
                         }
 
                         *_passphrases = l;
 
+                } else if (passphrase[0] == '=') {
+                        bstr **l;
+
+                        l = bstrv_new(passphrase + 1, n - 1);
+                        if (!l) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+
+                        *_passphrases = l;
+
                 } else if (passphrase[0] == '-') {
                         r = -ECANCELED;
                         goto finish;
@@ -542,24 +552,12 @@ finish:
 }
 
 int ask_password_auto(const char *message, const char *icon, const char *id,
-                      usec_t until, bool accept_cached, char ***_passphrases) {
+                      usec_t until, bool accept_cached, bstr ***_passphrases) {
         assert(message);
         assert(_passphrases);
 
-        if (isatty(STDIN_FILENO)) {
-                int r;
-                char *s = NULL, **l = NULL;
-
-                r = ask_password_tty(message, until, NULL, &s);
-                if (r < 0)
-                        return r;
-
-                r = strv_consume(&l, s);
-                if (r < 0)
-                        return r;
-
-                *_passphrases = l;
-                return r;
-        } else
+        if (isatty(STDIN_FILENO))
+                return ask_password_tty(message, until, NULL, _passphrases);
+        else
                 return ask_password_agent(message, icon, id, until, accept_cached, _passphrases);
 }
diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h
index 3839a2d..b69a8c8 100644
--- a/src/shared/ask-password-api.h
+++ b/src/shared/ask-password-api.h
@@ -21,12 +21,13 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "bstrv.h"
 #include "util.h"
 
-int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase);
+int ask_password_tty(const char *message, usec_t until, const char *flag_file, bstr ***_passphrases);
 
 int ask_password_agent(const char *message, const char *icon, const char *id,
-                       usec_t until, bool accept_cached, char ***_passphrases);
+                       usec_t until, bool accept_cached, bstr ***_passphrases);
 
 int ask_password_auto(const char *message, const char *icon, const char *id,
-                      usec_t until, bool accept_cached, char ***_passphrases);
+                      usec_t until, bool accept_cached, bstr ***_passphrases);
diff --git a/src/shared/bstrv.c b/src/shared/bstrv.c
new file mode 100644
index 0000000..118e0aa
--- /dev/null
+++ b/src/shared/bstrv.c
@@ -0,0 +1,194 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 David Härdeman <david at hardeman.nu>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+#include "util.h"
+#include "strv.h"
+#include "bstrv.h"
+
+struct bstr {
+        size_t len;
+        uint8_t data[];
+};
+
+static void bstr_free(bstr *l) {
+        if (l) {
+                /* FIXME: This should be something like explicit_bzero() */
+                memzero(l->data, l->len);
+                free(l);
+        }
+}
+
+void bstrv_free(bstr **l) {
+        bstr **k;
+
+        if (!l)
+                return;
+
+        for (k = l; *k; k++)
+                bstr_free(*k);
+
+        free(l);
+}
+
+bstr **bstrv_new(const uint8_t *data, size_t len) {
+        bstr **a;
+
+        if (len > 0)
+                assert(data);
+
+        a = new0(bstr *, 2);
+        if (!a)
+                return NULL;
+
+        a[0] = malloc(sizeof(bstr) + len);
+        if (!a[0]) {
+                free(a);
+                return NULL;
+        }
+        a[0]->len = len;
+        memcpy(a[0]->data, data, len);
+
+        return a;
+}
+
+bstr **bstrv_remove(bstr **l, const uint8_t *data, size_t len) {
+        bstr **f, **t;
+
+        if (!l)
+                return NULL;
+
+        if (len > 0)
+                assert(data);
+
+        for (f = t = l; *f; f++) {
+                if ((*f)->len == len &&
+                    memcmp((*f)->data, data, len) == 0)
+                        bstr_free(*f);
+                else
+                        *(t++) = *f;
+        }
+
+        *t = NULL;
+        return l;
+}
+
+bstr **bstrv_uniq(bstr **l) {
+        bstr **i;
+
+        /* Drops duplicate entries. The first identical binary string will be
+         * kept, the others dropped */
+
+        BSTRV_FOREACH(i, l)
+                bstrv_remove(i + 1, (*i)->data, (*i)->len);
+
+        return l;
+}
+
+int bstrv_push(bstr ***l, const uint8_t *data, size_t len) {
+        bstr **c;
+        bstr *k;
+        size_t n;
+
+        if (len > 0)
+                assert(data);
+
+        k = malloc(sizeof(*k) + len);
+        if (!k)
+                return -ENOMEM;
+
+        n = bstrv_length(*l);
+        c = realloc(*l, sizeof(bstr *) * (n + 2));
+        if (!c) {
+                free(k);
+                return -ENOMEM;
+        }
+
+        k->len = len;
+        memcpy(k->data, data, len);
+
+        c[n] = k;
+        c[n + 1] = NULL;
+
+        *l = c;
+        return 0;
+}
+
+bstr **bstrv_parse_nulstr(const uint8_t *s, size_t l) {
+        _cleanup_strv_free_ char **v = NULL;
+        char **k;
+        bstr **b = NULL;
+
+        v = strv_parse_nulstr((const char *)s, l);
+        if (!v)
+                return NULL;
+
+        STRV_FOREACH(k, v) {
+                if (bstrv_push(&b, (const uint8_t *)*k, strlen(*k)) < 0) {
+                        bstrv_free(b);
+                        return NULL;
+                }
+        }
+
+        return b;
+}
+
+unsigned bstrv_length(bstr * const *l) {
+        unsigned n = 0;
+
+        if (!l)
+                return 0;
+
+        for (; *l; l++)
+                n++;
+
+        return n;
+}
+
+unsigned bstr_length(const bstr *l) {
+        if (l)
+                return l->len;
+        return 0;
+}
+
+uint8_t *bstr_data(bstr *l) {
+        if (l)
+                return l->data;
+        return NULL;
+}
+
+char *bstr_cdata(bstr *l) {
+        return (char *)bstr_data(l);
+}
+
+bool bstreq(const bstr *a, const bstr *b) {
+        if (!a || !b)
+                return false;
+        if (a->len != b->len)
+                return false;
+        return memcmp(a->data, b->data, a->len) == 0;
+}
+
diff --git a/src/shared/bstrv.h b/src/shared/bstrv.h
new file mode 100644
index 0000000..e08c215
--- /dev/null
+++ b/src/shared/bstrv.h
@@ -0,0 +1,50 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 David Härdeman
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include "util.h"
+
+typedef struct bstr bstr;
+
+void bstrv_free(bstr **l);
+DEFINE_TRIVIAL_CLEANUP_FUNC(bstr **, bstrv_free);
+#define _cleanup_bstrv_free_ _cleanup_(bstrv_freep)
+
+bstr **bstrv_new(const uint8_t *data, size_t len);
+bstr **bstrv_remove(bstr **l, const uint8_t *data, size_t len);
+bstr **bstrv_uniq(bstr **l);
+int bstrv_push(bstr ***l, const uint8_t *data, size_t len);
+bstr **bstrv_parse_nulstr(const uint8_t *s, size_t l);
+
+unsigned bstrv_length(bstr * const *l) _pure_;
+
+unsigned bstr_length(const bstr *l) _pure_;
+uint8_t *bstr_data(bstr *l);
+char *bstr_cdata(bstr *l);
+bool bstreq(const bstr *a, const bstr *b) _pure_;
+
+#define BSTRV_FOREACH(s, l)                      \
+        for ((s) = (l); (s) && *(s); (s)++)
+
diff --git a/src/test/test-bstrv.c b/src/test/test-bstrv.c
new file mode 100644
index 0000000..3c511b7
--- /dev/null
+++ b/src/test/test-bstrv.c
@@ -0,0 +1,122 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 David Härdeman
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+
+#include "util.h"
+#include "bstrv.h"
+
+int main(int argc, char *argv[]) {
+        bstr **v = NULL;
+        bstr **c = NULL;
+        uint8_t one[]   = { 'o','n','e',0,'o','n','e',0 };
+        uint8_t two[]   = { 't','w','o',0,'t','w','o',0 };
+        uint8_t three[] = { 't','h','r','e','e',0,'t','h','r','e','e',0 };
+
+        assert_se(bstrv_length(v) == 0);
+        assert_se(bstrv_push(&v, one, sizeof(one)) == 0);
+        assert_se(bstrv_push(&v, two, sizeof(two)) == 0);
+        assert_se(bstrv_push(&v, three, sizeof(three)) == 0);
+        assert_se(bstrv_length(v) == 3); 
+
+        assert_se(bstr_length(v[0]) == sizeof(one));
+        assert_se(bstr_length(v[1]) == sizeof(two));
+        assert_se(bstr_length(v[2]) == sizeof(three));
+
+        assert_se(bstrv_push(&v, one, sizeof(one)) == 0);
+        assert_se(bstrv_push(&v, two, sizeof(two)) == 0);
+        assert_se(bstrv_push(&v, three, sizeof(three)) == 0);
+
+        assert_se(bstrv_length(v) == 6); 
+        assert_se(bstrv_uniq(v));
+        assert_se(bstrv_length(v) == 3); 
+
+        assert_se(bstrv_length(c) == 0);
+        assert_se(bstrv_push(&c, one, sizeof(one)) == 0);
+        assert_se(bstrv_push(&c, two, sizeof(two)) == 0);
+        assert_se(bstrv_push(&c, three, sizeof(three)) == 0);
+        assert_se(bstrv_length(c) == 3); 
+
+        assert_se(bstreq(v[0], c[0]));
+        assert_se(bstreq(v[1], c[1]));
+        assert_se(bstreq(v[2], c[2]));
+        assert_se(!bstreq(v[0], c[1]));
+        assert_se(!bstreq(v[1], c[2]));
+        assert_se(!bstreq(v[2], c[0]));
+ 
+        assert_se(bstrv_remove(v, two, sizeof(two)));
+        assert_se(bstrv_length(v) == 2); 
+        assert_se(bstrv_remove(c, two, sizeof(two)));
+        assert_se(bstrv_length(c) == 2); 
+        assert_se(bstreq(v[0], c[0]));
+        assert_se(bstreq(v[1], c[1]));
+        assert_se(!bstreq(v[0], c[1]));
+        assert_se(!bstreq(v[1], c[0]));
+
+        assert_se(bstrv_remove(v, one, sizeof(one)));
+        assert_se(bstrv_length(v) == 1); 
+        assert_se(bstrv_remove(v, three, sizeof(three)));
+        assert_se(bstrv_length(v) == 0); 
+
+        bstrv_free(v);
+        v = NULL;
+        bstrv_free(c);
+        c = NULL;
+
+        v = bstrv_parse_nulstr(one, sizeof(one));
+        assert_se(bstrv_length(v) == 2);
+        assert_se(bstreq(v[0], v[1]));
+        assert_se(bstrv_uniq(v));
+        assert_se(bstrv_length(v) == 1);
+
+        assert_se(bstrv_push(&v, bstr_data(v[0]), bstr_length(v[0])) == 0);
+        assert_se(bstrv_length(v) == 2);
+        assert_se(bstreq(v[0], v[1]));
+
+        assert_se(bstrv_push(&c, one, 3) == 0);
+        assert_se(bstrv_length(c) == 1);
+        assert_se(bstreq(v[0], c[0]));
+
+        assert_se(bstrv_push(&c, two, 3) == 0);
+        assert_se(bstrv_length(c) == 2);
+        assert_se(!bstreq(v[0], c[1]));
+
+        assert_se(bstrv_remove(v, bstr_data(c[0]), bstr_length(c[0])));
+        assert_se(bstrv_length(v) == 0);
+
+        bstrv_free(v);
+        v = bstrv_new(one, 3);
+        assert_se(v);
+        assert_se(bstrv_length(v) == 1);
+        assert_se(bstreq(v[0], c[0]));
+        assert_se(!bstreq(v[0], c[1]));
+        assert_se(bstrv_remove(v, bstr_data(c[1]), bstr_length(c[1])));
+        assert_se(bstrv_length(v) == 1);
+
+        bstrv_free(v);
+        v = bstrv_new(one, sizeof(one));
+        assert_se(v);
+        assert_se(bstrv_length(v) == 1);
+        assert_se(streq(bstr_cdata(v[0]), (char *)one));
+
+        return 0;
+}
+
diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c
index 55a2215..3f74bc8 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -40,6 +40,7 @@
 #include "socket-util.h"
 #include "ask-password-api.h"
 #include "strv.h"
+#include "bstrv.h"
 #include "build.h"
 
 static enum {
@@ -358,7 +359,7 @@ static int parse_password(const char *filename, char **wall) {
 
                 } else {
                         int tty_fd = -1;
-                        char *password = NULL;
+                        _cleanup_bstrv_free_ bstr **passwords = NULL;
 
                         if (arg_console)
                                 if ((tty_fd = acquire_terminal("/dev/console", false, false, false, (usec_t) -1)) < 0) {
@@ -366,7 +367,7 @@ static int parse_password(const char *filename, char **wall) {
                                         goto finish;
                                 }
 
-                        r = ask_password_tty(message, not_after, filename, &password);
+                        r = ask_password_tty(message, not_after, filename, &passwords);
 
                         if (arg_console) {
                                 safe_close(tty_fd);
@@ -374,15 +375,13 @@ static int parse_password(const char *filename, char **wall) {
                         }
 
                         if (r >= 0) {
-                                packet_length = 1+strlen(password)+1;
+                                packet_length = 1+bstr_length(passwords[0])+1;
                                 if (!(packet = new(char, packet_length)))
                                         r = -ENOMEM;
                                 else {
                                         packet[0] = '+';
-                                        strcpy(packet+1, password);
+                                        memcpy(packet+1, bstr_data(passwords[0]), bstr_length(passwords[0]));
                                 }
-
-                                free(password);
                         }
                 }
 



More information about the systemd-devel mailing list