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, ¶ms); 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 <da...@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); } } _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel