Hi list, Following this thread: http://lists.freedesktop.org/archives/systemd-devel/2012-July/005835.html, I understand you don't want to support a "keyscript" option as implemented in that patch.
So I wrote these few lines to support a new "keyhandler" option (so that you don't necessary need it to be a script, it can be whatever you want) and implemented a new crypt-keyhandler-agent. The keyhandler takes the third field of the crypttab record as argument (the key_file) Actually, I just enhanced the existing tty-ask-password-agent. The goal is to have a fallback with the "manual" ask-password method. For instance, I want my keyhandler to read the keyfile out of a usb key. If my usb key is not present I can fallback to the password method. Would a patch as below be acceptable? I didn't tested it yet. I just want to know if it is the right way to do it or if I misunderstood the discussion. Thanks -- Benjamin SANS diff --git a/src/crypt-keyhandler-agent/Makefile b/src/crypt-keyhandler-agent/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/crypt-keyhandler-agent/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/crypt-keyhandler-agent/crypt-keyhandler-agent.c b/src/crypt-keyhandler-agent/crypt-keyhandler-agent.c new file mode 100644 index 0000000..1036347 --- /dev/null +++ b/src/crypt-keyhandler-agent/crypt-keyhandler-agent.c @@ -0,0 +1,808 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 <stdbool.h> +#include <errno.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stddef.h> +#include <sys/poll.h> +#include <sys/inotify.h> +#include <unistd.h> +#include <getopt.h> +#include <sys/signalfd.h> +#include <fcntl.h> + +#include "util.h" +#include "mkdir.h" +#include "path-util.h" +#include "conf-parser.h" +#include "utmp-wtmp.h" +#include "socket-util.h" +#include "ask-password-api.h" +#include "strv.h" +#include "build.h" + +static enum { + ACTION_LIST, + ACTION_QUERY, + ACTION_WATCH, + ACTION_WALL +} arg_action = ACTION_QUERY; + +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, + bool accept_cached, + char ***_passphrases) { + + int fd = -1, notify = -1; + union sockaddr_union sa = {}; + char *packet = NULL; + ssize_t k; + int r, n; + struct pollfd pollfd[2] = {}; + char buffer[LINE_MAX]; + size_t p = 0; + enum { + POLL_SOCKET, + POLL_INOTIFY + }; + + assert(_passphrases); + + if (flag_file) { + if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) { + r = -errno; + goto finish; + } + + if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) { + r = -errno; + goto finish; + } + } + + if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { + r = -errno; + goto finish; + } + + sa.sa.sa_family = AF_UNIX; + strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1); + if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { + log_error("Failed to connect to Plymouth: %m"); + r = -errno; + goto finish; + } + + 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; + } + + if ((k = loop_write(fd, packet, n+1, true)) != n+1) { + r = k < 0 ? (int) k : -EIO; + goto finish; + } + + pollfd[POLL_SOCKET].fd = fd; + pollfd[POLL_SOCKET].events = POLLIN; + pollfd[POLL_INOTIFY].fd = notify; + pollfd[POLL_INOTIFY].events = POLLIN; + + for (;;) { + int sleep_for = -1, j; + + if (until > 0) { + usec_t y; + + y = now(CLOCK_MONOTONIC); + + if (y > until) { + r = -ETIME; + goto finish; + } + + sleep_for = (int) ((until - y) / USEC_PER_MSEC); + } + + if (flag_file) + if (access(flag_file, F_OK) < 0) { + r = -errno; + goto finish; + } + + if ((j = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) { + + if (errno == EINTR) + continue; + + r = -errno; + goto finish; + } else if (j == 0) { + r = -ETIME; + goto finish; + } + + if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0) + flush_fd(notify); + + if (pollfd[POLL_SOCKET].revents == 0) + continue; + + if ((k = read(fd, buffer + p, sizeof(buffer) - p)) <= 0) { + r = k < 0 ? -errno : -EIO; + goto finish; + } + + p += k; + + if (p < 1) + 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 || buffer[0] == 9) { + uint32_t size; + char **l; + + /* One ore more answers */ + if (p < 5) + continue; + + memcpy(&size, buffer+1, sizeof(size)); + size = le32toh(size); + if (size+5 > sizeof(buffer)) { + r = -EIO; + goto finish; + } + + if (p-5 < size) + continue; + + if (!(l = strv_parse_nulstr(buffer + 5, size))) { + r = -ENOMEM; + goto finish; + } + + *_passphrases = l; + break; + + } else { + /* Unknown packet */ + r = -EIO; + goto finish; + } + } + + r = 0; + +finish: + if (notify >= 0) + close_nointr_nofail(notify); + + if (fd >= 0) + close_nointr_nofail(fd); + + free(packet); + + return r; +} + +static int parse_password(const char *filename, char **wall) { + char *socket_name = NULL, *message = NULL, *packet = NULL, keyhandler = NULL, keyopts = NULL; + uint64_t not_after = 0; + unsigned pid = 0; + int socket_fd = -1; + bool accept_cached = false; + + const ConfigTableItem items[] = { + { "Ask", "Socket", config_parse_string, 0, &socket_name }, + { "Ask", "NotAfter", config_parse_uint64, 0, ¬_after }, + { "Ask", "Message", config_parse_string, 0, &message }, + { "Ask", "PID", config_parse_unsigned, 0, &pid }, + { "Ask", "AcceptCached", config_parse_bool, 0, &accept_cached }, + { "Ask", "KeyHandler", config_parse_string, 0, &keyhandler }, + { "Ask", "KeyOpts", config_parse_string, 0, &keyopts }, + { NULL, NULL, NULL, 0, NULL } + }; + + FILE *f; + int r; + + assert(filename); + + f = fopen(filename, "re"); + if (!f) { + if (errno == ENOENT) + return 0; + + log_error("open(%s): %m", filename); + return -errno; + } + + r = config_parse(NULL, filename, f, NULL, config_item_table_lookup, (void*) items, true, false, NULL); + if (r < 0) { + log_error("Failed to parse password file %s: %s", filename, strerror(-r)); + goto finish; + } + + if (!socket_name) { + log_error("Invalid password file %s", filename); + r = -EBADMSG; + goto finish; + } + + if (not_after > 0) { + if (now(CLOCK_MONOTONIC) > not_after) { + r = 0; + goto finish; + } + } + + if (pid > 0 && !pid_is_alive(pid)) { + r = 0; + goto finish; + } + + if (arg_action == ACTION_LIST) + printf("'%s' (PID %u)\n", message, pid); + else if (arg_action == ACTION_WALL) { + char *_wall; + + if (asprintf(&_wall, + "%s%sPassword entry required for \'%s\' (PID %u).\r\n" + "Please enter password with the systemd-tty-ask-password-agent tool!", + *wall ? *wall : "", + *wall ? "\r\n\r\n" : "", + message, + pid) < 0) { + r = log_oom(); + goto finish; + } + + free(*wall); + *wall = _wall; + } else { + union { + struct sockaddr sa; + struct sockaddr_un un; + } sa = {}; + size_t packet_length = 0; + + assert(arg_action == ACTION_QUERY || + arg_action == ACTION_WATCH); + + if (access(socket_name, W_OK) < 0) { + + if (arg_action == ACTION_QUERY) + log_info("Not querying '%s' (PID %u), lacking privileges.", message, pid); + + r = 0; + goto finish; + } + + if (keyhandler) { + char temp[] = "/run/systemd/ask-password/tmp.XXXXXX"; + int fd = -1; + pid_t pid; + + mkdir_p_label("/run/systemd/ask-password", 0755); + + fd = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC); + if (fd < 0) { + log_error("Failed to create password file: %m"); + r = -errno; + goto finish; + } + + fchmod(fd, 0644); + + pid = fork(); + + if (pid < 0) { + log_error("Failed to fork: %m"); + r = -errno; + goto finish; + } else if (pid > 0) { + waitpid(pid, NULL, 0); + + /* send back the temporary filename that now contains our key */ + packet_length = 2 + strlen(temp); + + if (!(packet = new(char, packet_length))) + r = -ENOMEM; + else { + char *d; + packet[0] = '+'; + d = packet+1; + d = stpcpy(d, temp) + 1; + } + } else if (pid == 0) { + /* launch the keyhandler programm and redirect its output to our temporary file */ + const char *args[3]; + + if (dup2(fd, STDOUT_FILENO) < 0) + _exit(EXIT_FAILURE); + + args[0] = keyhandler; + args[1] = keyopts; + args[2] = NULL; + + execv(args[0], (char **)args); + _exit(EXIT_FAILURE); + } + } else if (arg_plymouth) { + _cleanup_strv_free_ char **passwords = NULL; + + 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 = NULL; + + if (arg_console) + if ((tty_fd = acquire_terminal("/dev/console", false, false, false, (usec_t) -1)) < 0) { + r = tty_fd; + goto finish; + } + + r = ask_password_tty(message, not_after, filename, &password); + + if (arg_console) { + close_nointr_nofail(tty_fd); + release_terminal(); + } + + if (r >= 0) { + packet_length = 1+strlen(password)+1; + if (!(packet = new(char, packet_length))) + r = -ENOMEM; + else { + packet[0] = '+'; + strcpy(packet+1, password); + } + + free(password); + } + } + + if (r == -ETIME || r == -ENOENT) { + /* If the query went away, that's OK */ + r = 0; + goto finish; + } + + if (r < 0) { + log_error("Failed to query password: %s", strerror(-r)); + goto finish; + } + + if ((socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { + log_error("socket(): %m"); + r = -errno; + goto finish; + } + + sa.un.sun_family = AF_UNIX; + strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); + + 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; + } + } + +finish: + fclose(f); + + if (socket_fd >= 0) + close_nointr_nofail(socket_fd); + + free(packet); + free(socket_name); + free(message); + + return r; +} + +static int wall_tty_block(void) { + char *p; + int fd, r; + dev_t devnr; + + r = get_ctty_devnr(0, &devnr); + if (r < 0) + return -r; + + if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(devnr), minor(devnr)) < 0) + return -ENOMEM; + + mkdir_parents_label(p, 0700); + mkfifo(p, 0600); + + fd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); + free(p); + + if (fd < 0) + return -errno; + + return fd; +} + +static bool wall_tty_match(const char *path) { + int fd, k; + char *p; + struct stat st; + + if (path_is_absolute(path)) + k = lstat(path, &st); + else { + if (asprintf(&p, "/dev/%s", path) < 0) + return true; + + k = lstat(p, &st); + free(p); + } + + if (k < 0) + return true; + + if (!S_ISCHR(st.st_mode)) + return true; + + /* We use named pipes to ensure that wall messages suggesting + * password entry are not printed over password prompts + * already shown. We use the fact here that opening a pipe in + * non-blocking mode for write-only will succeed only if + * there's some writer behind it. Using pipes has the + * advantage that the block will automatically go away if the + * process dies. */ + + if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) + return true; + + fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); + free(p); + + if (fd < 0) + return true; + + /* What, we managed to open the pipe? Then this tty is filtered. */ + close_nointr_nofail(fd); + return false; +} + +static int show_passwords(void) { + DIR *d; + struct dirent *de; + int r = 0; + + if (!(d = opendir("/run/systemd/ask-password"))) { + if (errno == ENOENT) + return 0; + + log_error("opendir(): %m"); + return -errno; + } + + while ((de = readdir(d))) { + char *p; + int q; + char *wall; + + /* We only support /dev on tmpfs, hence we can rely on + * d_type to be reliable */ + + if (de->d_type != DT_REG) + continue; + + if (ignore_file(de->d_name)) + continue; + + if (!startswith(de->d_name, "ask.")) + continue; + + if (!(p = strappend("/run/systemd/ask-password/", de->d_name))) { + r = log_oom(); + goto finish; + } + + wall = NULL; + if ((q = parse_password(p, &wall)) < 0) + r = q; + + free(p); + + if (wall) { + utmp_wall(wall, wall_tty_match); + free(wall); + } + } + +finish: + if (d) + closedir(d); + + return r; +} + +static int watch_passwords(void) { + enum { + FD_INOTIFY, + FD_SIGNAL, + _FD_MAX + }; + + int notify = -1, signal_fd = -1, tty_block_fd = -1; + struct pollfd pollfd[_FD_MAX] = {}; + sigset_t mask; + int r; + + tty_block_fd = wall_tty_block(); + + mkdir_p_label("/run/systemd/ask-password", 0755); + + if ((notify = inotify_init1(IN_CLOEXEC)) < 0) { + r = -errno; + goto finish; + } + + if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0) { + r = -errno; + goto finish; + } + + assert_se(sigemptyset(&mask) == 0); + sigset_add_many(&mask, SIGINT, SIGTERM, -1); + assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); + + if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { + log_error("signalfd(): %m"); + r = -errno; + goto finish; + } + + pollfd[FD_INOTIFY].fd = notify; + pollfd[FD_INOTIFY].events = POLLIN; + pollfd[FD_SIGNAL].fd = signal_fd; + pollfd[FD_SIGNAL].events = POLLIN; + + for (;;) { + if ((r = show_passwords()) < 0) + log_error("Failed to show password: %s", strerror(-r)); + + if (poll(pollfd, _FD_MAX, -1) < 0) { + + if (errno == EINTR) + continue; + + r = -errno; + goto finish; + } + + if (pollfd[FD_INOTIFY].revents != 0) + flush_fd(notify); + + if (pollfd[FD_SIGNAL].revents != 0) + break; + } + + r = 0; + +finish: + if (notify >= 0) + close_nointr_nofail(notify); + + if (signal_fd >= 0) + close_nointr_nofail(signal_fd); + + if (tty_block_fd >= 0) + close_nointr_nofail(tty_block_fd); + + return r; +} + +static int help(void) { + + printf("%s [OPTIONS...]\n\n" + "Process system password requests.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --list Show pending password requests\n" + " --query Process pending password requests\n" + " --watch Continuously process password requests\n" + " --wall Continuously forward password requests to wall\n" + " --plymouth Ask question with Plymouth instead of on TTY\n" + " --console Ask question on /dev/console instead of current TTY\n" + " --script=<path> Script to run before falling back to another ask mode\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_LIST = 0x100, + ARG_QUERY, + ARG_WATCH, + ARG_WALL, + ARG_PLYMOUTH, + ARG_CONSOLE, + ARG_VERSION, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "list", no_argument, NULL, ARG_LIST }, + { "query", no_argument, NULL, ARG_QUERY }, + { "watch", no_argument, NULL, ARG_WATCH }, + { "wall", no_argument, NULL, ARG_WALL }, + { "plymouth", no_argument, NULL, ARG_PLYMOUTH }, + { "console", no_argument, NULL, ARG_CONSOLE }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_LIST: + arg_action = ACTION_LIST; + break; + + case ARG_QUERY: + arg_action = ACTION_QUERY; + break; + + case ARG_WATCH: + arg_action = ACTION_WATCH; + break; + + case ARG_WALL: + arg_action = ACTION_WALL; + break; + + case ARG_PLYMOUTH: + arg_plymouth = true; + break; + + case ARG_CONSOLE: + arg_console = true; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind != argc) { + help(); + return -EINVAL; + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + if ((r = parse_argv(argc, argv)) <= 0) + goto finish; + + if (arg_console) { + setsid(); + release_terminal(); + } + + if (arg_action == ACTION_WATCH || + arg_action == ACTION_WALL) + r = watch_passwords(); + else + r = show_passwords(); + + if (r < 0) + log_error("Error: %s", strerror(-r)); + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 4dc2b08..110f11d 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -43,6 +43,7 @@ static int arg_key_slot = CRYPT_ANY_SLOT; static unsigned arg_keyfile_size = 0; static unsigned arg_keyfile_offset = 0; static char *arg_hash = NULL; +static char *opt_keyhandler = NULL; static unsigned arg_tries = 3; static bool arg_readonly = false; static bool arg_verify = false; @@ -129,6 +130,23 @@ static int parse_one_option(const char *option) { free(arg_hash); arg_hash = t; + } else if (startswith(option, "keyhandler=")) { + char *t; + + if (!option[11] || !path_is_absolute(option+11)) { + log_error("keyhandler= path is invalid, ignoring."); + free(opt_keyhandler); + opt_keyhandler = NULL; + return 0; + } + + t = strdup(option+11); + if (!t) + return log_oom(); + + free(opt_keyhandler); + opt_keyhandler = t; + } else if (startswith(option, "tries=")) { if (safe_atou(option+6, &arg_tries) < 0) { @@ -363,7 +381,8 @@ static int attach_luks_or_plain(struct crypt_device *cd, const char *name, const char *key_file, char **passwords, - uint32_t flags) { + uint32_t flagsi, + int tries) { int r = 0; bool pass_volume_key = false; @@ -430,10 +449,20 @@ static int attach_luks_or_plain(struct crypt_device *cd, crypt_get_volume_key_size(cd)*8, crypt_get_device_name(cd)); + if (opt_keyhandler && tries == 0) + key_file = passwords[0]; + if (key_file) { - r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, - key_file, arg_keyfile_size, - arg_keyfile_offset, flags); + r = crypt_activate_by_keyfile_offset(cd, name, opt_key_slot, + key_file, opt_keyfile_size, + opt_keyfile_offset, flags); + + /* Remove the temporary file created by our agent as it contains our key! */ + if (opt_keyhandler && tries == 0) { + unlink(key_file); + key_file = NULL; + } + if (r < 0) { log_error("Failed to activate with key file '%s': %s", key_file, strerror(-r)); return -EAGAIN; @@ -502,6 +531,7 @@ int main(int argc, char *argv[]) { goto finish; } + /* if (argc >= 5 && argv[4][0] && !streq(argv[4], "-") && @@ -512,12 +542,26 @@ int main(int argc, char *argv[]) { else key_file = argv[4]; } + */ if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) { if (parse_options(argv[5]) < 0) goto finish; } + if (argc >= 5) { + if (opt_keyhandler) + key_file = argv[4]; /* used as arg to keyscript */ + else if (argv[4][0] && + !streq(argv[4], "-") && + !streq(argv[4], "none")) + /* do nothing */; + else if (!path_is_absolute(argv[4])) + log_error("Password file path %s is not absolute. Ignoring.", argv[4]); + else + key_file = argv[4]; + } + /* A delicious drop of snake oil */ mlockall(MCL_FUTURE); @@ -581,6 +625,13 @@ int main(int argc, char *argv[]) { for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) { _cleanup_strv_free_ char **passwords = NULL; + /* We only launch the handler once */ + if (opt_keyhandler && tries == 0) { + passwords = strv_new(opt_keyhandler, key_file, NULL); + /* We unset the key_file as it is only an argument to our handler and it has been copied above */ + key_file = NULL; + } + if (!key_file) { k = get_password(name, until, tries == 0 && !arg_verify, &passwords); if (k == -EAGAIN) @@ -592,7 +643,7 @@ int main(int argc, char *argv[]) { if (streq_ptr(arg_type, CRYPT_TCRYPT)) k = attach_tcrypt(cd, argv[2], key_file, passwords, flags); else - k = attach_luks_or_plain(cd, argv[2], key_file, passwords, flags); + k = attach_luks_or_plain(cd, argv[2], key_file, passwords, flags, tries); if (k >= 0) break; else if (k == -EAGAIN) { diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index a328f14..cb24c00 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -370,6 +370,17 @@ int ask_password_agent( if (icon) fprintf(f, "Icon=%s\n", icon); + /* We assume the keyhandler path and options are provided */ + if (strv_length(*_passphrases) == 2) { + char **p = *_passphrases; + fprintf(f, "KeyHandler=%s\n" + "KeyOpts=%s\n" + p[0], + p[1]); + strv_free(*_passphrases); + *_passphrases = NULL; + } + fflush(f); if (ferror(f)) {
signature.asc
Description: Digital signature
_______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel