From d08fd4c314f93e955586337e56ece4ce21c9c329 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 16:35:12 +0100 Subject: [PATCH 01/13] ask-password: rework how we pass request meta info when asking passwords Rather than adding more and more parameters to ask_password_auto(), let's pass a structure of the fields that often are constant anyway. This way, callers can fill in what they need, and we take the filled structure which we can pass around internally as one. This is in particular preparation for adding one more field in one of the next commits. --- src/ask-password/ask-password.c | 10 +- src/cryptenroll/cryptenroll-password.c | 42 +++++--- src/cryptenroll/cryptenroll-tpm2.c | 27 ++--- src/cryptsetup/cryptsetup.c | 50 +++++++--- src/firstboot/firstboot.c | 10 +- src/home/homectl.c | 74 +++++++------- src/pcrlock/pcrlock.c | 12 ++- src/shared/ask-password-api.c | 99 +++++++++---------- src/shared/ask-password-api.h | 17 +++- src/shared/cryptsetup-fido2.c | 9 +- src/shared/cryptsetup-tpm2.c | 13 ++- src/shared/dissect-image.c | 9 +- src/shared/libfido2-util.c | 8 +- src/shared/pkcs11-util.c | 10 +- src/test/test-ask-password-api.c | 9 +- .../tty-ask-password-agent.c | 16 ++- 16 files changed, 262 insertions(+), 153 deletions(-) diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index bf4c93e2dc..371d316332 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -239,7 +239,15 @@ static int run(int argc, char *argv[]) { else timeout = 0; - r = ask_password_auto(arg_message, arg_icon, arg_id, arg_key_name, arg_credential_name ?: "password", timeout, arg_flags, &l); + AskPasswordRequest req = { + .message = arg_message, + .icon = arg_icon, + .id = arg_id, + .keyring = arg_key_name, + .credential = arg_credential_name ?: "password", + }; + + r = ask_password_auto(&req, timeout, arg_flags, &l); if (r < 0) return log_error_errno(r, "Failed to query password: %m"); diff --git a/src/cryptenroll/cryptenroll-password.c b/src/cryptenroll/cryptenroll-password.c index c35b6092c8..a9f52bceeb 100644 --- a/src/cryptenroll/cryptenroll-password.c +++ b/src/cryptenroll/cryptenroll-password.c @@ -38,9 +38,8 @@ int load_volume_key_password( return log_error_errno(r, "Password from environment variable $PASSWORD did not work: %m"); } else { AskPasswordFlags ask_password_flags = ASK_PASSWORD_PUSH_CACHE|ASK_PASSWORD_ACCEPT_CACHED; - _cleanup_free_ char *question = NULL, *disk_path = NULL; + _cleanup_free_ char *question = NULL, *id = NULL, *disk_path = NULL; unsigned i = 5; - const char *id; question = strjoin("Please enter current passphrase for disk ", cd_node, ":"); if (!question) @@ -50,7 +49,17 @@ int load_volume_key_password( if (!disk_path) return log_oom(); - id = strjoina("cryptsetup:", disk_path); + id = strjoin("cryptsetup:", disk_path); + if (!id) + return log_oom(); + + AskPasswordRequest req = { + .message = question, + .icon = "drive-harddisk", + .id = id, + .keyring = "cryptenroll", + .credential = "cryptenroll.passphrase", + }; for (;;) { _cleanup_strv_free_erase_ char **passwords = NULL; @@ -59,10 +68,7 @@ int load_volume_key_password( return log_error_errno(SYNTHETIC_ERRNO(ENOKEY), "Too many attempts, giving up."); - r = ask_password_auto( - question, "drive-harddisk", id, "cryptenroll", "cryptenroll.passphrase", USEC_INFINITY, - ask_password_flags, - &passwords); + r = ask_password_auto(&req, USEC_INFINITY, ask_password_flags, &passwords); if (r < 0) return log_error_errno(r, "Failed to query password: %m"); @@ -105,9 +111,8 @@ int enroll_password( if (r < 0) return log_error_errno(r, "Failed to acquire password from environment: %m"); if (r == 0) { - _cleanup_free_ char *disk_path = NULL; + _cleanup_free_ char *disk_path = NULL, *id = NULL; unsigned i = 5; - const char *id; assert_se(node = crypt_get_device_name(cd)); @@ -117,7 +122,16 @@ int enroll_password( if (!disk_path) return log_oom(); - id = strjoina("cryptsetup:", disk_path); + id = strjoin("cryptsetup:", disk_path); + if (!id) + return log_oom(); + + AskPasswordRequest req = { + .icon = "drive-harddisk", + .id = id, + .keyring = "cryptenroll", + .credential = "cryptenroll.new-passphrase", + }; for (;;) { _cleanup_strv_free_erase_ char **passwords = NULL, **passwords2 = NULL; @@ -131,7 +145,9 @@ int enroll_password( if (!question) return log_oom(); - r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords); + req.message = question; + + r = ask_password_auto(&req, USEC_INFINITY, /* flags= */ 0, &passwords); if (r < 0) return log_error_errno(r, "Failed to query password: %m"); @@ -142,7 +158,9 @@ int enroll_password( if (!question) return log_oom(); - r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords2); + req.message = question; + + r = ask_password_auto(&req, USEC_INFINITY, /* flags= */ 0, &passwords2); if (r < 0) return log_error_errno(r, "Failed to query password: %m"); diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c index fb862a3329..def3acda69 100644 --- a/src/cryptenroll/cryptenroll-tpm2.c +++ b/src/cryptenroll/cryptenroll-tpm2.c @@ -87,28 +87,29 @@ static int get_pin(char **ret_pin_str, TPM2Flags *ret_flags) { return log_error_errno( SYNTHETIC_ERRNO(ENOKEY), "Too many attempts, giving up."); + AskPasswordRequest req = { + .message = "Please enter TPM2 PIN:", + .icon = "drive-harddisk", + .keyring = "tpm2-pin", + .credential = "cryptenroll.tpm2-pin", + }; + pin = strv_free_erase(pin); r = ask_password_auto( - "Please enter TPM2 PIN:", - "drive-harddisk", - NULL, - "tpm2-pin", - "cryptenroll.tpm2-pin", - USEC_INFINITY, - 0, + &req, + /* until= */ USEC_INFINITY, + /* flags= */ 0, &pin); if (r < 0) return log_error_errno(r, "Failed to ask for user pin: %m"); assert(strv_length(pin) == 1); + req.message = "Please enter TPM2 PIN (repeat):"; + r = ask_password_auto( - "Please enter TPM2 PIN (repeat):", - "drive-harddisk", - NULL, - "tpm2-pin", - "cryptenroll.tpm2-pin", + &req, USEC_INFINITY, - 0, + /* flags= */ 0, &pin2); if (r < 0) return log_error_errno(r, "Failed to ask for user pin: %m"); diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 1caaa514d5..06fc32ea27 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -798,11 +798,10 @@ static int get_password( PassphraseType passphrase_type, char ***ret) { - _cleanup_free_ char *friendly = NULL, *text = NULL, *disk_path = NULL; + _cleanup_free_ char *friendly = NULL, *text = NULL, *disk_path = NULL, *id = NULL; _cleanup_strv_free_erase_ char **passwords = NULL; - char *id; - int r = 0; AskPasswordFlags flags = arg_ask_password_flags | ASK_PASSWORD_PUSH_CACHE; + int r; assert(vol); assert(src); @@ -822,11 +821,23 @@ static int get_password( if (!disk_path) return log_oom(); - id = strjoina("cryptsetup:", disk_path); + id = strjoin("cryptsetup:", disk_path); + if (!id) + return log_oom(); - r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", "cryptsetup.passphrase", until, - flags | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED), - &passwords); + AskPasswordRequest req = { + .message = text, + .icon = "drive-harddisk", + .id = id, + .keyring = "cryptsetup", + .credential = "cryptsetup.passphrase", + }; + + r = ask_password_auto( + &req, + until, + flags | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED), + &passwords); if (r < 0) return log_error_errno(r, "Failed to query password: %m"); @@ -835,12 +846,19 @@ static int get_password( assert(strv_length(passwords) == 1); + text = mfree(text); if (asprintf(&text, "Please enter %s for disk %s (verification):", passphrase_type_to_string(passphrase_type), friendly) < 0) return log_oom(); - id = strjoina("cryptsetup-verification:", disk_path); + free(id); + id = strjoin("cryptsetup-verification:", disk_path); + if (!id) + return log_oom(); - r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", "cryptsetup.passphrase", until, flags, &passwords2); + req.message = text; + req.id = id; + + r = ask_password_auto(&req, until, flags, &passwords2); if (r < 0) return log_error_errno(r, "Failed to query verification password: %m"); @@ -1252,8 +1270,8 @@ static int crypt_activate_by_token_pin_ask_password( void *userdata, uint32_t activation_flags, const char *message, - const char *key_name, - const char *credential_name) { + const char *keyring, + const char *credential) { #if HAVE_LIBCRYPTSETUP_PLUGINS AskPasswordFlags flags = arg_ask_password_flags | ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED; @@ -1283,7 +1301,15 @@ static int crypt_activate_by_token_pin_ask_password( for (;;) { pins = strv_free_erase(pins); - r = ask_password_auto(message, "drive-harddisk", /* id= */ NULL, key_name, credential_name, until, flags, &pins); + + AskPasswordRequest req = { + .message = message, + .icon = "drive-harddisk", + .keyring = keyring, + .credential = credential, + }; + + r = ask_password_auto(&req, until, flags, &pins); if (r < 0) return r; diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 76af4e4ed5..d9d2e28251 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -797,7 +797,11 @@ static int prompt_root_password(int rfd) { _cleanup_strv_free_erase_ char **a = NULL, **b = NULL; _cleanup_free_ char *error = NULL; - r = ask_password_tty(-1, msg1, NULL, 0, 0, NULL, &a); + AskPasswordRequest req = { + .message = msg1, + }; + + r = ask_password_tty(-EBADF, &req, /* until= */ 0, /* flags= */ 0, /* flag_file= */ NULL, &a); if (r < 0) return log_error_errno(r, "Failed to query root password: %m"); if (strv_length(a) != 1) @@ -817,7 +821,9 @@ static int prompt_root_password(int rfd) { else if (r == 0) log_warning("Password is weak, accepting anyway: %s", error); - r = ask_password_tty(-1, msg2, NULL, 0, 0, NULL, &b); + req.message = msg2; + + r = ask_password_tty(-EBADF, &req, /* until= */ 0, /* flags= */ 0, /* flag_file= */ NULL, &b); if (r < 0) return log_error_errno(r, "Failed to query root password: %m"); if (strv_length(b) != 1) diff --git a/src/home/homectl.c b/src/home/homectl.c index 5357e791a5..3a839c73ea 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -261,14 +261,14 @@ static int acquire_existing_password( user_name) < 0) return log_oom(); - r = ask_password_auto(question, - /* icon= */ "user-home", - NULL, - /* key_name= */ "home-password", - /* credential_name= */ "home.password", - USEC_INFINITY, - flags, - &password); + AskPasswordRequest req = { + .message = question, + .icon = "user-home", + .keyring = "home-password", + .credential = "home.password", + }; + + r = ask_password_auto(&req, USEC_INFINITY, flags, &password); if (r == -EUNATCH) { /* EUNATCH is returned if no password was found and asking interactively was * disabled via the flags. Not an error for us. */ log_debug_errno(r, "No passwords acquired."); @@ -319,14 +319,14 @@ static int acquire_recovery_key( if (asprintf(&question, "Please enter recovery key for user %s:", user_name) < 0) return log_oom(); - r = ask_password_auto(question, - /* icon= */ "user-home", - NULL, - /* key_name= */ "home-recovery-key", - /* credential_name= */ "home.recovery-key", - USEC_INFINITY, - flags, - &recovery_key); + AskPasswordRequest req = { + .message = question, + .icon = "user-home", + .keyring = "home-recovery-key", + .credential = "home.recovery-key", + }; + + r = ask_password_auto(&req, USEC_INFINITY, flags, &recovery_key); if (r == -EUNATCH) { /* EUNATCH is returned if no recovery key was found and asking interactively was * disabled via the flags. Not an error for us. */ log_debug_errno(r, "No recovery keys acquired."); @@ -373,15 +373,14 @@ static int acquire_token_pin( if (asprintf(&question, "Please enter security token PIN for user %s:", user_name) < 0) return log_oom(); - r = ask_password_auto( - question, - /* icon= */ "user-home", - NULL, - /* key_name= */ "token-pin", - /* credential_name= */ "home.token-pin", - USEC_INFINITY, - flags, - &pin); + AskPasswordRequest req = { + .message = question, + .icon = "user-home", + .keyring = "token-pin", + .credential = "home.token-pin", + }; + + r = ask_password_auto(&req, USEC_INFINITY, flags, &pin); if (r == -EUNATCH) { /* EUNATCH is returned if no PIN was found and asking interactively was disabled * via the flags. Not an error for us. */ log_debug_errno(r, "No security token PINs acquired."); @@ -1228,14 +1227,17 @@ static int acquire_new_password( if (asprintf(&question, "Please enter new password for user %s:", user_name) < 0) return log_oom(); + AskPasswordRequest req = { + .message = question, + .icon = "user-home", + .keyring = "home-password", + .credential = "home.new-password", + }; + r = ask_password_auto( - question, - /* icon= */ "user-home", - NULL, - /* key_name= */ "home-password", - /* credential_name= */ "home.new-password", + &req, USEC_INFINITY, - 0, /* no caching, we want to collect a new password here after all */ + /* flags= */ 0, /* no caching, we want to collect a new password here after all */ &first); if (r < 0) return log_error_errno(r, "Failed to acquire password: %m"); @@ -1244,14 +1246,12 @@ static int acquire_new_password( if (asprintf(&question, "Please enter new password for user %s (repeat):", user_name) < 0) return log_oom(); + req.message = question; + r = ask_password_auto( - question, - /* icon= */ "user-home", - NULL, - /* key_name= */ "home-password", - /* credential_name= */ "home.new-password", + &req, USEC_INFINITY, - 0, /* no caching */ + /* flags= */ 0, /* no caching */ &second); if (r < 0) return log_error_errno(r, "Failed to acquire password: %m"); diff --git a/src/pcrlock/pcrlock.c b/src/pcrlock/pcrlock.c index 1dd3d86a73..e1f25b62d9 100644 --- a/src/pcrlock/pcrlock.c +++ b/src/pcrlock/pcrlock.c @@ -4444,12 +4444,14 @@ static int make_policy(bool force, bool recovery_pin) { if (r == 0) { _cleanup_(strv_free_erasep) char **l = NULL; + AskPasswordRequest req = { + .message = "Recovery PIN", + .id = "pcrlock-recovery-pin", + .credential = "systemd-pcrlock.recovery-pin", + }; + r = ask_password_auto( - "Recovery PIN", - /* icon= */ NULL, - /* id= */ "pcrlock-recovery-pin", - /* key_name= */ NULL, - /* credential_name= */ "systemd-pcrlock.recovery-pin", + &req, /* until= */ 0, /* flags= */ 0, &l); diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 6d71245549..a9d9cde97b 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -147,18 +147,17 @@ static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, c return 0; } -static int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) { - +static int ask_password_keyring(const AskPasswordRequest *req, AskPasswordFlags flags, char ***ret) { key_serial_t serial; int r; - assert(keyname); + assert(req); assert(ret); if (!FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED)) return -EUNATCH; - r = lookup_key(keyname, &serial); + r = lookup_key(req->keyring, &serial); if (ERRNO_IS_NEG_NOT_SUPPORTED(r) || r == -EPERM) /* When retrieving, the distinction between "kernel or container manager don't support or * allow this" and "no matching key known" doesn't matter. Note that we propagate EACCESS @@ -205,7 +204,7 @@ static int backspace_string(int ttyfd, const char *str) { } int ask_password_plymouth( - const char *message, + const AskPasswordRequest *req, usec_t until, AskPasswordFlags flags, const char *flag_file, @@ -225,8 +224,7 @@ int ask_password_plymouth( assert(ret); - if (!message) - message = "Password:"; + const char *message = req && req->message ? req->message : "Password:"; if (flag_file) { notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK); @@ -357,8 +355,7 @@ int ask_password_plymouth( int ask_password_tty( int ttyfd, - const char *message, - const char *keyname, + const AskPasswordRequest *req, usec_t until, AskPasswordFlags flags, const char *flag_file, @@ -384,13 +381,13 @@ int ask_password_tty( if (FLAGS_SET(flags, ASK_PASSWORD_NO_TTY)) return -EUNATCH; - if (!message) - message = "Password:"; + const char *message = req && req->message ? req->message : "Password:"; + const char *keyring = req ? req->keyring : NULL; if (!FLAGS_SET(flags, ASK_PASSWORD_HIDE_EMOJI) && emoji_enabled()) message = strjoina(special_glyph(SPECIAL_GLYPH_LOCK_AND_KEY), " ", message); - if (flag_file || (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && keyname)) { + if (flag_file || (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && keyring)) { notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK); if (notify < 0) return -errno; @@ -399,8 +396,8 @@ int ask_password_tty( if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) return -errno; } - if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && keyname) { - r = ask_password_keyring(keyname, flags, ret); + if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && req && keyring) { + r = ask_password_keyring(req, flags, ret); if (r >= 0) return 0; else if (r != -ENOKEY) @@ -487,10 +484,10 @@ int ask_password_tty( goto finish; } - if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyname) { + if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyring) { (void) flush_fd(notify); - r = ask_password_keyring(keyname, flags, ret); + r = ask_password_keyring(req, flags, ret); if (r >= 0) { r = 0; goto finish; @@ -629,8 +626,8 @@ skipped: if (strv_isempty(l)) r = log_debug_errno(SYNTHETIC_ERRNO(ECANCELED), "Password query was cancelled."); else { - if (keyname) - (void) add_to_keyring_and_log(keyname, flags, l); + if (keyring) + (void) add_to_keyring_and_log(keyring, flags, l); *ret = TAKE_PTR(l); r = 0; @@ -679,10 +676,7 @@ static int create_socket(char **ret) { } int ask_password_agent( - const char *message, - const char *icon, - const char *id, - const char *keyname, + const AskPasswordRequest *req, usec_t until, AskPasswordFlags flags, char ***ret) { @@ -715,8 +709,8 @@ int ask_password_agent( (void) mkdir_p_label("/run/systemd/ask-password", 0755); - if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && keyname) { - r = ask_password_keyring(keyname, flags, ret); + if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && req && req->keyring) { + r = ask_password_keyring(req, flags, ret); if (r >= 0) { r = 0; goto finish; @@ -775,14 +769,16 @@ int ask_password_agent( until, FLAGS_SET(flags, ASK_PASSWORD_SILENT)); - if (message) - fprintf(f, "Message=%s\n", message); + if (req) { + if (req->message) + fprintf(f, "Message=%s\n", req->message); - if (icon) - fprintf(f, "Icon=%s\n", icon); + if (req->icon) + fprintf(f, "Icon=%s\n", req->icon); - if (id) - fprintf(f, "Id=%s\n", id); + if (req->id) + fprintf(f, "Id=%s\n", req->id); + } r = fflush_and_check(f); if (r < 0) @@ -837,12 +833,14 @@ int ask_password_agent( if (notify >= 0 && pollfd[FD_INOTIFY].revents != 0) { (void) flush_fd(notify); - r = ask_password_keyring(keyname, flags, ret); - if (r >= 0) { - r = 0; - goto finish; - } else if (r != -ENOKEY) - goto finish; + if (req && req->keyring) { + r = ask_password_keyring(req, flags, ret); + if (r >= 0) { + r = 0; + goto finish; + } else if (r != -ENOKEY) + goto finish; + } } if (pollfd[FD_SOCKET].revents == 0) @@ -921,8 +919,8 @@ int ask_password_agent( log_debug("Invalid packet"); } - if (keyname) - (void) add_to_keyring_and_log(keyname, flags, l); + if (req && req->keyring) + (void) add_to_keyring_and_log(req->keyring, flags, l); *ret = TAKE_PTR(l); r = 0; @@ -940,16 +938,17 @@ finish: return r; } -static int ask_password_credential(const char *credential_name, AskPasswordFlags flags, char ***ret) { +static int ask_password_credential(const AskPasswordRequest *req, AskPasswordFlags flags, char ***ret) { _cleanup_(erase_and_freep) char *buffer = NULL; size_t size; char **l; int r; - assert(credential_name); + assert(req); + assert(req->credential); assert(ret); - r = read_credential(credential_name, (void**) &buffer, &size); + r = read_credential(req->credential, (void**) &buffer, &size); if (IN_SET(r, -ENXIO, -ENOENT)) /* No credentials passed or this credential not defined? */ return -ENOKEY; @@ -962,11 +961,7 @@ static int ask_password_credential(const char *credential_name, AskPasswordFlags } int ask_password_auto( - const char *message, - const char *icon, - const char *id, /* id in "ask-password" protocol */ - const char *key_name, /* name in kernel keyring */ - const char *credential_name, /* name in $CREDENTIALS_DIRECTORY directory */ + const AskPasswordRequest *req, usec_t until, AskPasswordFlags flags, char ***ret) { @@ -975,26 +970,26 @@ int ask_password_auto( assert(ret); - if (!FLAGS_SET(flags, ASK_PASSWORD_NO_CREDENTIAL) && credential_name) { - r = ask_password_credential(credential_name, flags, ret); + if (!FLAGS_SET(flags, ASK_PASSWORD_NO_CREDENTIAL) && req && req->credential) { + r = ask_password_credential(req, flags, ret); if (r != -ENOKEY) return r; } if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && - key_name && + req && req->keyring && (FLAGS_SET(flags, ASK_PASSWORD_NO_TTY) || !isatty(STDIN_FILENO)) && FLAGS_SET(flags, ASK_PASSWORD_NO_AGENT)) { - r = ask_password_keyring(key_name, flags, ret); + r = ask_password_keyring(req, flags, ret); if (r != -ENOKEY) return r; } if (!FLAGS_SET(flags, ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) - return ask_password_tty(-1, message, key_name, until, flags, NULL, ret); + return ask_password_tty(-EBADF, req, until, flags, NULL, ret); if (!FLAGS_SET(flags, ASK_PASSWORD_NO_AGENT)) - return ask_password_agent(message, icon, id, key_name, until, flags, ret); + return ask_password_agent(req, until, flags, ret); return -EUNATCH; } diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h index 7464e7f6de..fced27798f 100644 --- a/src/shared/ask-password-api.h +++ b/src/shared/ask-password-api.h @@ -17,7 +17,16 @@ typedef enum AskPasswordFlags { ASK_PASSWORD_HIDE_EMOJI = 1 << 8, /* hide the lock and key emoji */ } AskPasswordFlags; -int ask_password_tty(int tty_fd, const char *message, const char *key_name, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret); -int ask_password_plymouth(const char *message, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret); -int ask_password_agent(const char *message, const char *icon, const char *id, const char *key_name, usec_t until, AskPasswordFlags flag, char ***ret); -int ask_password_auto(const char *message, const char *icon, const char *id, const char *key_name, const char *credential_name, usec_t until, AskPasswordFlags flag, char ***ret); +/* Encapsulates the mostly static fields of a password query */ +typedef struct AskPasswordRequest { + const char *message; /* The human readable password prompt when asking interactively */ + const char *keyring; /* kernel keyring key name (key of "user" type) */ + const char *icon; /* freedesktop icon spec name */ + const char *id; /* some identifier used for this prompt for the "ask-password" protocol */ + const char *credential; /* $CREDENTIALS_DIRECTORY credential name */ +} AskPasswordRequest; + +int ask_password_tty(int tty_fd, const AskPasswordRequest *req, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret); +int ask_password_plymouth(const AskPasswordRequest *req, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret); +int ask_password_agent(const AskPasswordRequest *req, usec_t until, AskPasswordFlags flag, char ***ret); +int ask_password_auto(const AskPasswordRequest *req, usec_t until, AskPasswordFlags flag, char ***ret); diff --git a/src/shared/cryptsetup-fido2.c b/src/shared/cryptsetup-fido2.c index 2d59a630a6..9771726da4 100644 --- a/src/shared/cryptsetup-fido2.c +++ b/src/shared/cryptsetup-fido2.c @@ -118,8 +118,15 @@ int acquire_fido2_key( if (headless) return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable."); + static const AskPasswordRequest req = { + .message = "Please enter security token PIN:", + .icon = "drive-harddisk", + .keyring = "fido2-pin", + .credential = "cryptsetup.fido2-pin", + }; + pins = strv_free_erase(pins); - r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, ask_password_flags, &pins); + r = ask_password_auto(&req, until, ask_password_flags, &pins); if (r < 0) return log_error_errno(r, "Failed to ask for user password: %m"); diff --git a/src/shared/cryptsetup-tpm2.c b/src/shared/cryptsetup-tpm2.c index 297ef6fe4a..d120e4e1fb 100644 --- a/src/shared/cryptsetup-tpm2.c +++ b/src/shared/cryptsetup-tpm2.c @@ -29,13 +29,16 @@ static int get_pin(usec_t until, AskPasswordFlags ask_password_flags, bool headl "PIN querying disabled via 'headless' option. " "Use the '$PIN' environment variable."); + static const AskPasswordRequest req = { + .message = "Please enter TPM2 PIN:", + .icon = "drive-harddisk", + .keyring = "tpm2-pin", + .credential = "cryptsetup.tpm2-pin", + }; + pin = strv_free_erase(pin); r = ask_password_auto( - "Please enter TPM2 PIN:", - "drive-harddisk", - NULL, - "tpm2-pin", - "cryptsetup.tpm2-pin", + &req, until, ask_password_flags, &pin); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index d7c705184a..179ee46e43 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -2991,7 +2991,14 @@ int dissected_image_decrypt_interactively( z = strv_free(z); - r = ask_password_auto("Please enter image passphrase:", NULL, "dissect", "dissect", "dissect.passphrase", USEC_INFINITY, 0, &z); + static const AskPasswordRequest req = { + .message = "Please enter image passphrase:", + .id = "dissect", + .keyring = "dissect", + .credential = "dissect.passphrase", + }; + + r = ask_password_auto(&req, USEC_INFINITY, /* flags= */ 0, &z); if (r < 0) return log_error_errno(r, "Failed to query for passphrase: %m"); diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c index 43efa3529a..18ad00097a 100644 --- a/src/shared/libfido2-util.c +++ b/src/shared/libfido2-util.c @@ -838,8 +838,14 @@ int fido2_generate_hmac_hash( for (;;) { _cleanup_strv_free_erase_ char **pin = NULL; + AskPasswordRequest req = { + .message = "Please enter security token PIN:", + .icon = askpw_icon_name, + .keyring = "fido2-pin", + .credential = "fido2-pin", + }; - r = ask_password_auto("Please enter security token PIN:", askpw_icon_name, NULL, "fido2-pin", "fido2-pin", USEC_INFINITY, 0, &pin); + r = ask_password_auto(&req, USEC_INFINITY, /* flags= */ 0, &pin); if (r < 0) return log_error_errno(r, "Failed to acquire user PIN: %m"); diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c index 832d8af7e4..6d7568d69b 100644 --- a/src/shared/pkcs11-util.c +++ b/src/shared/pkcs11-util.c @@ -375,8 +375,16 @@ int pkcs11_token_login( if (r < 0) return log_oom(); + AskPasswordRequest req = { + .message = text, + .icon = icon_name, + .id = id, + .keyring = key_name, + .credential = credential_name, + }; + /* We never cache PINs, simply because it's fatal if we use wrong PINs, since usually there are only 3 tries */ - r = ask_password_auto(text, icon_name, id, key_name, credential_name, until, ask_password_flags, &passwords); + r = ask_password_auto(&req, until, ask_password_flags, &passwords); if (r < 0) return log_error_errno(r, "Failed to query PIN for security token '%s': %m", token_label); } diff --git a/src/test/test-ask-password-api.c b/src/test/test-ask-password-api.c index b24159e2aa..8fee07330d 100644 --- a/src/test/test-ask-password-api.c +++ b/src/test/test-ask-password-api.c @@ -5,10 +5,15 @@ #include "tests.h" TEST(ask_password) { - int r; _cleanup_strv_free_ char **ret = NULL; + int r; - r = ask_password_tty(-1, "hello?", "da key", 0, ASK_PASSWORD_CONSOLE_COLOR, NULL, &ret); + static const AskPasswordRequest req = { + .message = "hello?", + .keyring = "da key", + }; + + r = ask_password_tty(-EBADF, &req, /* until= */ 0, /* flags= */ ASK_PASSWORD_CONSOLE_COLOR, /* flag_file= */ NULL, &ret); if (r == -ECANCELED) assert_se(ret == NULL); else { 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 3a30bfe042..df979be5cd 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -157,7 +157,11 @@ static int agent_ask_password_tty( log_info("Starting password query on %s.", con); } - r = ask_password_tty(tty_fd, message, NULL, until, flags, flag_file, ret); + AskPasswordRequest req = { + .message = message, + }; + + r = ask_password_tty(tty_fd, &req, until, flags, flag_file, ret); if (arg_console) { tty_fd = safe_close(tty_fd); @@ -245,9 +249,13 @@ static int process_one_password_file(const char *filename) { SET_FLAG(flags, ASK_PASSWORD_ECHO, echo); SET_FLAG(flags, ASK_PASSWORD_SILENT, silent); - if (arg_plymouth) - r = ask_password_plymouth(message, not_after, flags, filename, &passwords); - else + if (arg_plymouth) { + AskPasswordRequest req = { + .message = message, + }; + + r = ask_password_plymouth(&req, not_after, flags, filename, &passwords); + } else r = agent_ask_password_tty(message, not_after, flags, filename, &passwords); if (r < 0) { /* If the query went away, that's OK */ From 05569104bd579228d4c48faf78c231bb654f2ede Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 16:37:36 +0100 Subject: [PATCH 02/13] cryptenroll: fix type confusion on acquire_tpm2_key() parameter --- src/cryptenroll/cryptenroll-tpm2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c index def3acda69..e5e0cd6529 100644 --- a/src/cryptenroll/cryptenroll-tpm2.c +++ b/src/cryptenroll/cryptenroll-tpm2.c @@ -211,7 +211,7 @@ int load_volume_key_tpm2( tpm2_flags, /* until= */ 0, /* headless= */ false, - /* ask_password_flags */ false, + /* ask_password_flags= */ 0, &decrypted_key); if (IN_SET(r, -EACCES, -ENOLCK)) return log_notice_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 PIN unlock failed"); From 6b3a907764824d32b10cb0f95b338c1aed6fc55a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 16:38:01 +0100 Subject: [PATCH 03/13] dissect-image: use strv_free_erase() at one more place --- src/shared/dissect-image.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 179ee46e43..216c036a31 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -2989,7 +2989,7 @@ int dissected_image_decrypt_interactively( return log_error_errno(SYNTHETIC_ERRNO(EKEYREJECTED), "Too many retries."); - z = strv_free(z); + z = strv_free_erase(z); static const AskPasswordRequest req = { .message = "Please enter image passphrase:", From 6278a8655fc3ad9993cfc3e9d2acfe3a688788a9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 17:01:01 +0100 Subject: [PATCH 04/13] cryptenroll: use correct askpw id for pw request The "id" is used in the askpw protocol to recognize password prompts, in case a service is replying to them and needs some id. Previously we set an incorrect id, the one of cryptsetup. Fix that. (I guess the id is not used much, it comes from a time where we had no credentials, and thus some people wanted to supply passphrases programmatically rather interactively. The usecase is probably gone, but we should still set some valid id I guess.) --- src/cryptenroll/cryptenroll-password.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cryptenroll/cryptenroll-password.c b/src/cryptenroll/cryptenroll-password.c index a9f52bceeb..a9bd8a1dd0 100644 --- a/src/cryptenroll/cryptenroll-password.c +++ b/src/cryptenroll/cryptenroll-password.c @@ -49,7 +49,7 @@ int load_volume_key_password( if (!disk_path) return log_oom(); - id = strjoin("cryptsetup:", disk_path); + id = strjoin("cryptenroll:", disk_path); if (!id) return log_oom(); @@ -122,7 +122,7 @@ int enroll_password( if (!disk_path) return log_oom(); - id = strjoin("cryptsetup:", disk_path); + id = strjoin("cryptenroll-new:", disk_path); if (!id) return log_oom(); From 09eed3bf8ceab1e5f3f062e53f2ce9f5d7d61db6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 17:03:49 +0100 Subject: [PATCH 05/13] pcrlock: normalize credential name for TPM2 PIN Let's drop the "systemd-" prefix from the credential name. We do not prefix credentials that way so far. Don't do so here either. The name is not really API, it's not documented, hence change it now where we still can. --- src/pcrlock/pcrlock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pcrlock/pcrlock.c b/src/pcrlock/pcrlock.c index e1f25b62d9..e70c44c675 100644 --- a/src/pcrlock/pcrlock.c +++ b/src/pcrlock/pcrlock.c @@ -4447,7 +4447,7 @@ static int make_policy(bool force, bool recovery_pin) { AskPasswordRequest req = { .message = "Recovery PIN", .id = "pcrlock-recovery-pin", - .credential = "systemd-pcrlock.recovery-pin", + .credential = "pcrlock.recovery-pin", }; r = ask_password_auto( From 251c71b62bb2f43dd6815c9a99e2d059a0ce2aef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 17:30:56 +0100 Subject: [PATCH 06/13] libfido2: tweak credential to read fido2 PIN from Querying a fido2 PIN via askpw for enrolling is currently used in two places: cryptenroll and homectl. So far we sloppily used the same fixed credential name "fido2-pin" in both cases. Let's tweak that and make the credential name match the other credentials cryptenroll or home query, i.e. using the cryptenroll.* and home.* namespaces. This is particular done in light of #31370, which wants to make the credential name public. We really should get the name in order before making it public. --- src/cryptenroll/cryptenroll-fido2.c | 1 + src/home/homectl-fido2.c | 1 + src/shared/libfido2-util.c | 7 ++++--- src/shared/libfido2-util.h | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/cryptenroll/cryptenroll-fido2.c b/src/cryptenroll/cryptenroll-fido2.c index 2baeb92e07..7e35dca9c5 100644 --- a/src/cryptenroll/cryptenroll-fido2.c +++ b/src/cryptenroll/cryptenroll-fido2.c @@ -97,6 +97,7 @@ int enroll_fido2( /* user_display_name= */ node, /* user_icon_name= */ NULL, /* askpw_icon_name= */ "drive-harddisk", + /* askpw_credential= */ "cryptenroll.fido2-pin", lock_with, cred_alg, &cid, &cid_size, diff --git a/src/home/homectl-fido2.c b/src/home/homectl-fido2.c index 3cbdf912aa..384461a1ca 100644 --- a/src/home/homectl-fido2.c +++ b/src/home/homectl-fido2.c @@ -167,6 +167,7 @@ int identity_add_fido2_parameters( /* user_display_name= */ rn ? json_variant_string(rn) : NULL, /* user_icon_name= */ NULL, /* askpw_icon_name= */ "user-home", + /* askpw_credential= */ "home.token-pin", lock_with, cred_alg, &cid, &cid_size, diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c index 18ad00097a..f5df579369 100644 --- a/src/shared/libfido2-util.c +++ b/src/shared/libfido2-util.c @@ -686,7 +686,8 @@ int fido2_generate_hmac_hash( const char *user_name, const char *user_display_name, const char *user_icon, - const char *askpw_icon_name, + const char *askpw_icon, + const char *askpw_credential, Fido2EnrollFlags lock_with, int cred_alg, void **ret_cid, size_t *ret_cid_size, @@ -840,9 +841,9 @@ int fido2_generate_hmac_hash( _cleanup_strv_free_erase_ char **pin = NULL; AskPasswordRequest req = { .message = "Please enter security token PIN:", - .icon = askpw_icon_name, + .icon = askpw_icon, .keyring = "fido2-pin", - .credential = "fido2-pin", + .credential = askpw_credential, }; r = ask_password_auto(&req, USEC_INFINITY, /* flags= */ 0, &pin); diff --git a/src/shared/libfido2-util.h b/src/shared/libfido2-util.h index 4cfc95f712..3520ab4ec3 100644 --- a/src/shared/libfido2-util.h +++ b/src/shared/libfido2-util.h @@ -109,7 +109,8 @@ int fido2_generate_hmac_hash( const char *user_name, const char *user_display_name, const char *user_icon, - const char *askpw_icon_name, + const char *askpw_icon, + const char *askpw_credential, Fido2EnrollFlags lock_with, int cred_alg, void **ret_cid, size_t *ret_cid_size, From 7252be60833c67077f8a27177ccc62888a91c539 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 17:34:20 +0100 Subject: [PATCH 07/13] cryptenroll: use a different credential for new new PIN The TPM2 enrollment is the only of the three token enrollments where the user picks a PIN at enrollment time (the others have a PIN set for the token, not for the enrollment). Let's make sure it uses a different credential for retrieving this PIN, in order to make sure people can programmatically change PINs via credentials (in which case they need to supply both). --- src/cryptenroll/cryptenroll-tpm2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c index e5e0cd6529..d7497c756b 100644 --- a/src/cryptenroll/cryptenroll-tpm2.c +++ b/src/cryptenroll/cryptenroll-tpm2.c @@ -91,7 +91,7 @@ static int get_pin(char **ret_pin_str, TPM2Flags *ret_flags) { .message = "Please enter TPM2 PIN:", .icon = "drive-harddisk", .keyring = "tpm2-pin", - .credential = "cryptenroll.tpm2-pin", + .credential = "cryptenroll.new-tpm2-pin", }; pin = strv_free_erase(pin); From a96c284f10dd28ebad99d52bd72e00f3cb93bfaa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 17:44:01 +0100 Subject: [PATCH 08/13] pkcs11-util: clean up credential handling for PKCS11 PIN similar as the previous commit, let's clean up the credential name we use. Use home.token-pin in case of homectl, and cryptenroll.pkcs11-pin in case of cryptenroll. --- src/cryptenroll/cryptenroll-pkcs11.c | 2 +- src/home/homectl-pkcs11.c | 2 +- src/shared/pkcs11-util.c | 26 ++++++++++++++------------ src/shared/pkcs11-util.h | 3 ++- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/cryptenroll/cryptenroll-pkcs11.c b/src/cryptenroll/cryptenroll-pkcs11.c index 6b70a147c3..9cdb840763 100644 --- a/src/cryptenroll/cryptenroll-pkcs11.c +++ b/src/cryptenroll/cryptenroll-pkcs11.c @@ -55,7 +55,7 @@ int enroll_pkcs11( assert_se(node = crypt_get_device_name(cd)); - r = pkcs11_acquire_public_key(uri, "volume enrollment operation", "drive-harddisk", &pkey, NULL); + r = pkcs11_acquire_public_key(uri, "volume enrollment operation", "drive-harddisk", "cryptenroll.pkcs11-pin", &pkey, NULL); if (r < 0) return r; diff --git a/src/home/homectl-pkcs11.c b/src/home/homectl-pkcs11.c index 5c54ec016e..b9ee8acc4c 100644 --- a/src/home/homectl-pkcs11.c +++ b/src/home/homectl-pkcs11.c @@ -153,7 +153,7 @@ int identity_add_pkcs11_key_data(JsonVariant **v, const char *uri) { assert(v); - r = pkcs11_acquire_public_key(uri, "home directory operation", "user-home", &pkey, &pin); + r = pkcs11_acquire_public_key(uri, "home directory operation", "user-home", "home.token-pin", &pkey, &pin); if (r < 0) return r; diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c index 6d7568d69b..bfaca79bc8 100644 --- a/src/shared/pkcs11-util.c +++ b/src/shared/pkcs11-util.c @@ -291,9 +291,9 @@ int pkcs11_token_login( CK_SLOT_ID slotid, const CK_TOKEN_INFO *token_info, const char *friendly_name, - const char *icon_name, - const char *key_name, - const char *credential_name, + const char *askpw_icon, + const char *askpw_keyring, + const char *askpw_credential, usec_t until, AskPasswordFlags ask_password_flags, bool headless, @@ -377,10 +377,10 @@ int pkcs11_token_login( AskPasswordRequest req = { .message = text, - .icon = icon_name, + .icon = askpw_icon, .id = id, - .keyring = key_name, - .credential = credential_name, + .keyring = askpw_keyring, + .credential = askpw_credential, }; /* We never cache PINs, simply because it's fatal if we use wrong PINs, since usually there are only 3 tries */ @@ -1651,7 +1651,7 @@ int pkcs11_find_token( struct pkcs11_acquire_public_key_callback_data { char *pin_used; EVP_PKEY *pkey; - const char *askpw_friendly_name, *askpw_icon_name; + const char *askpw_friendly_name, *askpw_icon, *askpw_credential; AskPasswordFlags askpw_flags; bool headless; }; @@ -1698,9 +1698,9 @@ static int pkcs11_acquire_public_key_callback( slot_id, token_info, data->askpw_friendly_name, - data->askpw_icon_name, - "pkcs11-pin", + data->askpw_icon, "pkcs11-pin", + data->askpw_credential, UINT64_MAX, data->askpw_flags, data->headless, @@ -1829,13 +1829,15 @@ success: int pkcs11_acquire_public_key( const char *uri, const char *askpw_friendly_name, - const char *askpw_icon_name, + const char *askpw_icon, + const char *askpw_credential, EVP_PKEY **ret_pkey, char **ret_pin_used) { _cleanup_(pkcs11_acquire_public_key_callback_data_release) struct pkcs11_acquire_public_key_callback_data data = { .askpw_friendly_name = askpw_friendly_name, - .askpw_icon_name = askpw_icon_name, + .askpw_icon = askpw_icon, + .askpw_credential = askpw_credential, }; int r; @@ -2040,7 +2042,7 @@ int pkcs11_crypt_device_callback( data->friendly_name, "drive-harddisk", "pkcs11-pin", - "cryptsetup.pkcs11-pin", + data->askpw_credential, data->until, data->askpw_flags, data->headless, diff --git a/src/shared/pkcs11-util.h b/src/shared/pkcs11-util.h index 838f90b6c1..9b4336dc05 100644 --- a/src/shared/pkcs11-util.h +++ b/src/shared/pkcs11-util.h @@ -71,7 +71,7 @@ typedef int (*pkcs11_find_token_callback_t)(CK_FUNCTION_LIST *m, CK_SESSION_HAND int pkcs11_find_token(const char *pkcs11_uri, pkcs11_find_token_callback_t callback, void *userdata); #if HAVE_OPENSSL -int pkcs11_acquire_public_key(const char *uri, const char *askpw_friendly_name, const char *askpw_icon_name, EVP_PKEY **ret_pkey, char **ret_pin_used); +int pkcs11_acquire_public_key(const char *uri, const char *askpw_friendly_name, const char *askpw_icon, const char *askpw_credential, EVP_PKEY **ret_pkey, char **ret_pin_used); #endif typedef struct { @@ -83,6 +83,7 @@ typedef struct { size_t decrypted_key_size; bool free_encrypted_key; bool headless; + const char *askpw_credential; AskPasswordFlags askpw_flags; } pkcs11_crypt_device_callback_data; From b3a635841aaf5a6d3f5985dfd2082f7a22ca74d1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 18:06:34 +0100 Subject: [PATCH 09/13] cryptenroll,cryptsetup: clean up unlock credential for TPM2 + FIDO2 Let's make sure that when cryptenroll asks for the TPM2 or FIDO2 token PIN it uses cryptenroll.* credential namespace, and cryptsetup uses cryptsetup.*. --- src/cryptenroll/cryptenroll-fido2.c | 5 +++-- src/cryptenroll/cryptenroll-tpm2.c | 3 ++- src/cryptsetup/cryptsetup.c | 14 ++++++++++---- src/shared/cryptsetup-fido2.c | 22 +++++++++++++--------- src/shared/cryptsetup-fido2.h | 20 ++++++++++++-------- src/shared/cryptsetup-tpm2.c | 18 ++++++++++++------ src/shared/cryptsetup-tpm2.h | 6 ++++-- 7 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/cryptenroll/cryptenroll-fido2.c b/src/cryptenroll/cryptenroll-fido2.c index 7e35dca9c5..194771d54e 100644 --- a/src/cryptenroll/cryptenroll-fido2.c +++ b/src/cryptenroll/cryptenroll-fido2.c @@ -34,9 +34,10 @@ int load_volume_key_fido2( device, /* until= */ 0, /* headless= */ false, + "cryptenroll.fido2-pin", + ASK_PASSWORD_PUSH_CACHE|ASK_PASSWORD_ACCEPT_CACHED, &decrypted_key, - &decrypted_key_size, - ASK_PASSWORD_PUSH_CACHE|ASK_PASSWORD_ACCEPT_CACHED); + &decrypted_key_size); if (r == -EAGAIN) return log_error_errno(r, "FIDO2 token does not exist, or UV is blocked. Please try again."); if (r < 0) diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c index d7497c756b..5359c9f8d5 100644 --- a/src/cryptenroll/cryptenroll-tpm2.c +++ b/src/cryptenroll/cryptenroll-tpm2.c @@ -211,7 +211,8 @@ int load_volume_key_tpm2( tpm2_flags, /* until= */ 0, /* headless= */ false, - /* ask_password_flags= */ 0, + "cryptenroll.tpm2-pin", + /* askpw_flags= */ 0, &decrypted_key); if (IN_SET(r, -EACCES, -ENOLCK)) return log_notice_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 PIN unlock failed"); diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 06fc32ea27..e96686cff3 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -1415,8 +1415,10 @@ static int attach_luks_or_plain_or_bitlk_by_fido2( until, arg_headless, required, - &decrypted_key, &decrypted_key_size, - arg_ask_password_flags); + "cryptsetup.fido2-pin", + arg_ask_password_flags, + &decrypted_key, + &decrypted_key_size); else r = acquire_fido2_key_auto( cd, @@ -1425,8 +1427,10 @@ static int attach_luks_or_plain_or_bitlk_by_fido2( arg_fido2_device, until, arg_headless, - &decrypted_key, &decrypted_key_size, - arg_ask_password_flags); + "cryptsetup.fido2-pin", + arg_ask_password_flags, + &decrypted_key, + &decrypted_key_size); if (r >= 0) break; } @@ -1774,6 +1778,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( arg_tpm2_pin ? TPM2_FLAGS_USE_PIN : 0, until, arg_headless, + "cryptsetup.tpm2-pin", arg_ask_password_flags, &decrypted_key); if (r >= 0) @@ -1872,6 +1877,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( tpm2_flags, until, arg_headless, + "cryptsetup.tpm2-pin", arg_ask_password_flags, &decrypted_key); if (IN_SET(r, -EACCES, -ENOLCK)) diff --git a/src/shared/cryptsetup-fido2.c b/src/shared/cryptsetup-fido2.c index 9771726da4..d22c1059e6 100644 --- a/src/shared/cryptsetup-fido2.c +++ b/src/shared/cryptsetup-fido2.c @@ -26,9 +26,10 @@ int acquire_fido2_key( usec_t until, bool headless, Fido2EnrollFlags required, + const char *askpw_credential, + AskPasswordFlags askpw_flags, void **ret_decrypted_key, - size_t *ret_decrypted_key_size, - AskPasswordFlags ask_password_flags) { + size_t *ret_decrypted_key_size) { _cleanup_(erase_and_freep) char *envpw = NULL; _cleanup_strv_free_erase_ char **pins = NULL; @@ -42,7 +43,7 @@ int acquire_fido2_key( return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "Local verification is required to unlock this volume, but the 'headless' parameter was set."); - ask_password_flags |= ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED; + askpw_flags |= ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED; assert(cid); assert(key_file || key_data); @@ -126,11 +127,11 @@ int acquire_fido2_key( }; pins = strv_free_erase(pins); - r = ask_password_auto(&req, until, ask_password_flags, &pins); + r = ask_password_auto(&req, until, askpw_flags, &pins); if (r < 0) return log_error_errno(r, "Failed to ask for user password: %m"); - ask_password_flags &= ~ASK_PASSWORD_ACCEPT_CACHED; + askpw_flags &= ~ASK_PASSWORD_ACCEPT_CACHED; } } @@ -141,9 +142,10 @@ int acquire_fido2_key_auto( const char *fido2_device, usec_t until, bool headless, + const char *askpw_credential, + AskPasswordFlags askpw_flags, void **ret_decrypted_key, - size_t *ret_decrypted_key_size, - AskPasswordFlags ask_password_flags) { + size_t *ret_decrypted_key_size) { _cleanup_free_ void *cid = NULL; size_t cid_size = 0; @@ -263,8 +265,10 @@ int acquire_fido2_key_auto( until, headless, required, - ret_decrypted_key, ret_decrypted_key_size, - ask_password_flags); + "cryptsetup.fido2-pin", + askpw_flags, + ret_decrypted_key, + ret_decrypted_key_size); if (ret == 0) break; } diff --git a/src/shared/cryptsetup-fido2.h b/src/shared/cryptsetup-fido2.h index d96bb403ff..d99ad05725 100644 --- a/src/shared/cryptsetup-fido2.h +++ b/src/shared/cryptsetup-fido2.h @@ -25,9 +25,10 @@ int acquire_fido2_key( usec_t until, bool headless, Fido2EnrollFlags required, + const char *askpw_credential, + AskPasswordFlags askpw_flags, void **ret_decrypted_key, - size_t *ret_decrypted_key_size, - AskPasswordFlags ask_password_flags); + size_t *ret_decrypted_key_size); int acquire_fido2_key_auto( struct crypt_device *cd, @@ -36,9 +37,10 @@ int acquire_fido2_key_auto( const char *fido2_device, usec_t until, bool headless, + const char *askpw_credential, + AskPasswordFlags askpw_flags, void **ret_decrypted_key, - size_t *ret_decrypted_key_size, - AskPasswordFlags ask_password_flags); + size_t *ret_decrypted_key_size); #else @@ -57,9 +59,10 @@ static inline int acquire_fido2_key( usec_t until, bool headless, Fido2EnrollFlags required, + const char *askpw_credential, + AskPasswordFlags askpw_flags, void **ret_decrypted_key, - size_t *ret_decrypted_key_size, - AskPasswordFlags ask_password_flags) { + size_t *ret_decrypted_key_size) { return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "FIDO2 token support not available."); @@ -72,9 +75,10 @@ static inline int acquire_fido2_key_auto( const char *fido2_device, usec_t until, bool headless, + const char *askpw_credential, + AskPasswordFlags askpw_flags, void **ret_decrypted_key, - size_t *ret_decrypted_key_size, - AskPasswordFlags ask_password_flags) { + size_t *ret_decrypted_key_size) { return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "FIDO2 token support not available."); diff --git a/src/shared/cryptsetup-tpm2.c b/src/shared/cryptsetup-tpm2.c index d120e4e1fb..85bc42aef0 100644 --- a/src/shared/cryptsetup-tpm2.c +++ b/src/shared/cryptsetup-tpm2.c @@ -12,7 +12,12 @@ #include "sha256.h" #include "tpm2-util.h" -static int get_pin(usec_t until, AskPasswordFlags ask_password_flags, bool headless, char **ret_pin_str) { +static int get_pin( + usec_t until, + bool headless, + const char *askpw_credential, + AskPasswordFlags askpw_flags, + char **ret_pin_str) { _cleanup_(erase_and_freep) char *pin_str = NULL; _cleanup_strv_free_erase_ char **pin = NULL; int r; @@ -29,18 +34,18 @@ static int get_pin(usec_t until, AskPasswordFlags ask_password_flags, bool headl "PIN querying disabled via 'headless' option. " "Use the '$PIN' environment variable."); - static const AskPasswordRequest req = { + AskPasswordRequest req = { .message = "Please enter TPM2 PIN:", .icon = "drive-harddisk", .keyring = "tpm2-pin", - .credential = "cryptsetup.tpm2-pin", + .credential = askpw_credential, }; pin = strv_free_erase(pin); r = ask_password_auto( &req, until, - ask_password_flags, + askpw_flags, &pin); if (r < 0) return log_error_errno(r, "Failed to ask for user pin: %m"); @@ -77,7 +82,8 @@ int acquire_tpm2_key( TPM2Flags flags, usec_t until, bool headless, - AskPasswordFlags ask_password_flags, + const char *askpw_credential, + AskPasswordFlags askpw_flags, struct iovec *ret_decrypted_key) { _cleanup_(json_variant_unrefp) JsonVariant *signature_json = NULL; @@ -173,7 +179,7 @@ int acquire_tpm2_key( if (i <= 0) return -EACCES; - r = get_pin(until, ask_password_flags, headless, &pin_str); + r = get_pin(until, headless, askpw_credential, askpw_flags, &pin_str); if (r < 0) return r; diff --git a/src/shared/cryptsetup-tpm2.h b/src/shared/cryptsetup-tpm2.h index 0eaf9280ef..5809655c15 100644 --- a/src/shared/cryptsetup-tpm2.h +++ b/src/shared/cryptsetup-tpm2.h @@ -32,7 +32,8 @@ int acquire_tpm2_key( TPM2Flags flags, usec_t until, bool headless, - AskPasswordFlags ask_password_flags, + const char *askpw_credential, + AskPasswordFlags askpw_flags, struct iovec *ret_decrypted_key); int find_tpm2_auto_data( @@ -76,7 +77,8 @@ static inline int acquire_tpm2_key( TPM2Flags flags, usec_t until, bool headless, - AskPasswordFlags ask_password_flags, + const char *askpw_credential, + AskPasswordFlags askpw_flags, struct iovec *ret_decrypted_key) { return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), From 1c12daa46f90a8b74b83a14c0b657d71a535ac6f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 18:16:47 +0100 Subject: [PATCH 10/13] cryptsetup-pkcs11: also plug credential name to use to credential plugin --- src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c | 1 + src/cryptsetup/cryptsetup.c | 11 ++++++++++- src/shared/pkcs11-util.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c b/src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c index 512a4cf18a..0203e72645 100644 --- a/src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c +++ b/src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c @@ -158,6 +158,7 @@ static int acquire_luks2_key_systemd( data.friendly_name = params->friendly_name; data.headless = params->headless; + data.askpw_credential = params->askpw_credential; data.askpw_flags = params->askpw_flags; data.until = params->until; diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index e96686cff3..63f8cdb81f 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -1492,6 +1492,7 @@ static int attach_luks2_by_pkcs11_via_plugin( const char *friendly_name, usec_t until, bool headless, + const char *askpw_credential, uint32_t flags) { #if HAVE_LIBCRYPTSETUP_PLUGINS @@ -1504,6 +1505,7 @@ static int attach_luks2_by_pkcs11_via_plugin( .friendly_name = friendly_name, .until = until, .headless = headless, + .askpw_credential = askpw_credential, .askpw_flags = arg_ask_password_flags, }; @@ -1567,7 +1569,14 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11( for (;;) { if (use_libcryptsetup_plugin && arg_pkcs11_uri_auto) - r = attach_luks2_by_pkcs11_via_plugin(cd, name, friendly, until, arg_headless, flags); + r = attach_luks2_by_pkcs11_via_plugin( + cd, + name, + friendly, + until, + arg_headless, + "cryptsetup.pkcs11-pin", + flags); else { r = decrypt_pkcs11_key( name, diff --git a/src/shared/pkcs11-util.h b/src/shared/pkcs11-util.h index 9b4336dc05..dbd88ede67 100644 --- a/src/shared/pkcs11-util.h +++ b/src/shared/pkcs11-util.h @@ -112,6 +112,7 @@ typedef struct { const char *friendly_name; usec_t until; bool headless; + const char *askpw_credential; AskPasswordFlags askpw_flags; } systemd_pkcs11_plugin_params; From 0fceb5539d59e5d8bc0b8a387a686059483de174 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 18:22:49 +0100 Subject: [PATCH 11/13] man: now that the crdentials used by systemd-cryptenroll are in order, document them Replaces: #31370 --- man/systemd-cryptenroll.xml | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/man/systemd-cryptenroll.xml b/man/systemd-cryptenroll.xml index dfc6d31cf4..c687ac31bb 100644 --- a/man/systemd-cryptenroll.xml +++ b/man/systemd-cryptenroll.xml @@ -650,6 +650,51 @@ + + Credentials + + systemd-cryptenroll supports the service credentials logic as implemented by + ImportCredential=/LoadCredential=/SetCredential= + (see systemd.exec5 for + details). The following credentials are used when passed in: + + + + cryptenroll.passphrase + cryptenroll.new-passphrase + + May contain the passphrase to unlock the volume with/to newly enroll. + + + + + + cryptenroll.tpm2-pin + cryptenroll.new-tpm2-pin + + May contain the TPM2 PIN to unlock the volume with/to newly enroll. + + + + + + cryptenroll.fido2-pin + + If a FIDO2 token is enrolled this may contain the PIN of the token. + + + + + + cryptenroll.pkcs11-pin + + If a PKCS#11 token is enrolled this may contain the PIN of the token. + + + + + + Exit status From 732285eb8c2c597c7289d612fc99ad467eff85a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 18:21:31 +0100 Subject: [PATCH 12/13] man: tweak cryptsetup credentials docs a bit Let's bring the credentials into a better order, in order of relevance. Also, let's clarify what the generic LUKS PIN is about. Finally, list the credentials in system-credentials(7) too, after all people might want to unlock a disk with this via SMBIOS Type 11 or so. --- man/systemd-cryptsetup.xml | 22 +++++++++++----------- man/systemd.system-credentials.xml | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/man/systemd-cryptsetup.xml b/man/systemd-cryptsetup.xml index 5f12dc4748..72dc56390f 100644 --- a/man/systemd-cryptsetup.xml +++ b/man/systemd-cryptsetup.xml @@ -105,7 +105,7 @@ - System Credentials + Credentials systemd-cryptsetup supports the service credentials logic as implemented by ImportCredential=/LoadCredential=/SetCredential= @@ -122,14 +122,6 @@ - - cryptsetup.fido2-pin - - This credential specifies the FIDO2 token pin. - - - - cryptsetup.tpm2-pin @@ -139,9 +131,9 @@ - cryptsetup.luks2-pin + cryptsetup.fido2-pin - This credential specifies the LUKS2 token pin. + This credential specifies the FIDO2 token pin. @@ -153,6 +145,14 @@ + + + cryptsetup.luks2-pin + + This credential specifies the PIN requested by generic LUKS2 token modules. + + + diff --git a/man/systemd.system-credentials.xml b/man/systemd.system-credentials.xml index 749d3bfb15..2a345c47b4 100644 --- a/man/systemd.system-credentials.xml +++ b/man/systemd.system-credentials.xml @@ -353,6 +353,20 @@ + + + cryptsetup.passphrase + cryptsetup.tpm2-pin + cryptsetup.fido2-pin + cryptsetup.pkcs11-pin + cryptsetup.luks2-pin + + Specifies the passphrase/PINs to use for unlock encrypted storage volumes. For details see + systemd-cryptsetup8. + + + + From b2ac9280889ce5915e9b8437ee2aff134142ace9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2024 18:45:49 +0100 Subject: [PATCH 13/13] cryptsetup: drop "headless" bool, make it a flag in AskPasswordFlags instead This bool controls whether we should interactively ask for a password, which is pretty much what the ask_password-api.c APIs are about. Hence, just make the bool a flag in AskPasswordFlags enum, and use it everywhere. This still catches the flag early in upper levels of the codebase, exactly as before, but if the flag is still present in the lower layers it's also handled there and results in ENOEXEC if seen. This is mostly an excercise in simplifying our ridiculously long function call parameter lists a bit. --- src/cryptenroll/cryptenroll-fido2.c | 1 - src/cryptenroll/cryptenroll-pkcs11.c | 9 +++++- src/cryptenroll/cryptenroll-tpm2.c | 1 - src/cryptsetup/cryptsetup-pkcs11.c | 4 +-- src/cryptsetup/cryptsetup-pkcs11.h | 4 +-- .../cryptsetup-tokens/luks2-pkcs11.c | 1 - src/cryptsetup/cryptsetup.c | 28 +++++-------------- src/home/homectl-pkcs11.c | 9 +++++- src/shared/ask-password-api.c | 9 ++++++ src/shared/ask-password-api.h | 1 + src/shared/cryptsetup-fido2.c | 7 ++--- src/shared/cryptsetup-fido2.h | 4 --- src/shared/cryptsetup-tpm2.c | 12 ++------ src/shared/cryptsetup-tpm2.h | 2 -- src/shared/pkcs11-util.c | 12 ++++---- src/shared/pkcs11-util.h | 6 ++-- 16 files changed, 49 insertions(+), 61 deletions(-) diff --git a/src/cryptenroll/cryptenroll-fido2.c b/src/cryptenroll/cryptenroll-fido2.c index 194771d54e..baa630a6b3 100644 --- a/src/cryptenroll/cryptenroll-fido2.c +++ b/src/cryptenroll/cryptenroll-fido2.c @@ -33,7 +33,6 @@ int load_volume_key_fido2( cd_node, device, /* until= */ 0, - /* headless= */ false, "cryptenroll.fido2-pin", ASK_PASSWORD_PUSH_CACHE|ASK_PASSWORD_ACCEPT_CACHED, &decrypted_key, diff --git a/src/cryptenroll/cryptenroll-pkcs11.c b/src/cryptenroll/cryptenroll-pkcs11.c index 9cdb840763..09875c1598 100644 --- a/src/cryptenroll/cryptenroll-pkcs11.c +++ b/src/cryptenroll/cryptenroll-pkcs11.c @@ -55,7 +55,14 @@ int enroll_pkcs11( assert_se(node = crypt_get_device_name(cd)); - r = pkcs11_acquire_public_key(uri, "volume enrollment operation", "drive-harddisk", "cryptenroll.pkcs11-pin", &pkey, NULL); + r = pkcs11_acquire_public_key( + uri, + "volume enrollment operation", + "drive-harddisk", + "cryptenroll.pkcs11-pin", + /* askpw_flags= */ 0, + &pkey, + /* ret_pin_used= */ NULL); if (r < 0) return r; diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c index 5359c9f8d5..3ded815fb0 100644 --- a/src/cryptenroll/cryptenroll-tpm2.c +++ b/src/cryptenroll/cryptenroll-tpm2.c @@ -210,7 +210,6 @@ int load_volume_key_tpm2( &pcrlock_nv, tpm2_flags, /* until= */ 0, - /* headless= */ false, "cryptenroll.tpm2-pin", /* askpw_flags= */ 0, &decrypted_key); diff --git a/src/cryptsetup/cryptsetup-pkcs11.c b/src/cryptsetup/cryptsetup-pkcs11.c index 4ef249509d..4b2b5bbf00 100644 --- a/src/cryptsetup/cryptsetup-pkcs11.c +++ b/src/cryptsetup/cryptsetup-pkcs11.c @@ -34,14 +34,14 @@ int decrypt_pkcs11_key( const void *key_data, /* … or key_data and key_data_size (for literal keys) */ size_t key_data_size, usec_t until, - bool headless, + AskPasswordFlags askpw_flags, void **ret_decrypted_key, size_t *ret_decrypted_key_size) { _cleanup_(pkcs11_crypt_device_callback_data_release) pkcs11_crypt_device_callback_data data = { .friendly_name = friendly_name, + .askpw_flags = askpw_flags, .until = until, - .headless = headless, }; int r; diff --git a/src/cryptsetup/cryptsetup-pkcs11.h b/src/cryptsetup/cryptsetup-pkcs11.h index 256c09a9b6..22e6992582 100644 --- a/src/cryptsetup/cryptsetup-pkcs11.h +++ b/src/cryptsetup/cryptsetup-pkcs11.h @@ -19,7 +19,7 @@ int decrypt_pkcs11_key( const void *key_data, size_t key_data_size, usec_t until, - bool headless, + AskPasswordFlags askpw_flags, void **ret_decrypted_key, size_t *ret_decrypted_key_size); @@ -42,7 +42,7 @@ static inline int decrypt_pkcs11_key( const void *key_data, size_t key_data_size, usec_t until, - bool headless, + AskPasswordFlags askpw_flags, void **ret_decrypted_key, size_t *ret_decrypted_key_size) { diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c b/src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c index 0203e72645..ac5100f688 100644 --- a/src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c +++ b/src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c @@ -157,7 +157,6 @@ static int acquire_luks2_key_systemd( assert(params); data.friendly_name = params->friendly_name; - data.headless = params->headless; data.askpw_credential = params->askpw_credential; data.askpw_flags = params->askpw_flags; data.until = params->until; diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 63f8cdb81f..7099f68f88 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -101,7 +101,6 @@ static uint32_t arg_tpm2_pcr_mask = UINT32_MAX; static char *arg_tpm2_signature = NULL; static bool arg_tpm2_pin = false; static char *arg_tpm2_pcrlock = NULL; -static bool arg_headless = false; static usec_t arg_token_timeout_usec = 30*USEC_PER_SEC; static unsigned arg_tpm2_measure_pcr = UINT_MAX; /* This and the following field is about measuring the unlocked volume key to the local TPM */ static char **arg_tpm2_measure_banks = NULL; @@ -504,9 +503,9 @@ static int parse_one_option(const char *option) { return 0; } - arg_headless = r; + SET_FLAG(arg_ask_password_flags, ASK_PASSWORD_HEADLESS, r); } else if (streq(option, "headless")) - arg_headless = true; + arg_ask_password_flags |= ASK_PASSWORD_HEADLESS; else if ((val = startswith(option, "token-timeout="))) { @@ -807,7 +806,7 @@ static int get_password( assert(src); assert(ret); - if (arg_headless) + if (FLAGS_SET(arg_ask_password_flags, ASK_PASSWORD_HEADLESS)) return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "Password querying disabled via 'headless' option."); friendly = friendly_disk_name(src, vol); @@ -1266,7 +1265,6 @@ static int crypt_activate_by_token_pin_ask_password( const char *name, const char *type, usec_t until, - bool headless, void *userdata, uint32_t activation_flags, const char *message, @@ -1296,7 +1294,7 @@ static int crypt_activate_by_token_pin_ask_password( return r; } - if (headless) + if (FLAGS_SET(arg_ask_password_flags, ASK_PASSWORD_HEADLESS)) return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable."); for (;;) { @@ -1333,7 +1331,6 @@ static int attach_luks2_by_fido2_via_plugin( struct crypt_device *cd, const char *name, usec_t until, - bool headless, void *userdata, uint32_t activation_flags) { @@ -1342,7 +1339,6 @@ static int attach_luks2_by_fido2_via_plugin( name, "systemd-fido2", until, - headless, userdata, activation_flags, "Please enter security token PIN:", @@ -1397,7 +1393,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2( for (;;) { if (use_libcryptsetup_plugin && !arg_fido2_cid) { - r = attach_luks2_by_fido2_via_plugin(cd, name, until, arg_headless, arg_fido2_device, flags); + r = attach_luks2_by_fido2_via_plugin(cd, name, until, arg_fido2_device, flags); if (IN_SET(r, -ENOTUNIQ, -ENXIO, -ENOENT)) return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), "Automatic FIDO2 metadata discovery was not possible because missing or not unique, falling back to traditional unlocking."); @@ -1413,7 +1409,6 @@ static int attach_luks_or_plain_or_bitlk_by_fido2( key_file, arg_keyfile_size, arg_keyfile_offset, key_data, key_data_size, until, - arg_headless, required, "cryptsetup.fido2-pin", arg_ask_password_flags, @@ -1426,7 +1421,6 @@ static int attach_luks_or_plain_or_bitlk_by_fido2( friendly, arg_fido2_device, until, - arg_headless, "cryptsetup.fido2-pin", arg_ask_password_flags, &decrypted_key, @@ -1491,7 +1485,6 @@ static int attach_luks2_by_pkcs11_via_plugin( const char *name, const char *friendly_name, usec_t until, - bool headless, const char *askpw_credential, uint32_t flags) { @@ -1504,7 +1497,6 @@ static int attach_luks2_by_pkcs11_via_plugin( systemd_pkcs11_plugin_params params = { .friendly_name = friendly_name, .until = until, - .headless = headless, .askpw_credential = askpw_credential, .askpw_flags = arg_ask_password_flags, }; @@ -1574,7 +1566,6 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11( name, friendly, until, - arg_headless, "cryptsetup.pkcs11-pin", flags); else { @@ -1585,7 +1576,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11( key_file, arg_keyfile_size, arg_keyfile_offset, key_data, key_data_size, until, - arg_headless, + arg_ask_password_flags, &decrypted_key, &decrypted_key_size); if (r >= 0) break; @@ -1710,7 +1701,6 @@ static int attach_luks2_by_tpm2_via_plugin( struct crypt_device *cd, const char *name, usec_t until, - bool headless, uint32_t flags) { #if HAVE_LIBCRYPTSETUP_PLUGINS @@ -1730,7 +1720,6 @@ static int attach_luks2_by_tpm2_via_plugin( name, "systemd-tpm2", until, - headless, ¶ms, flags, "Please enter TPM2 PIN:", @@ -1786,7 +1775,6 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( /* pcrlock_nv= */ NULL, arg_tpm2_pin ? TPM2_FLAGS_USE_PIN : 0, until, - arg_headless, "cryptsetup.tpm2-pin", arg_ask_password_flags, &decrypted_key); @@ -1802,7 +1790,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( return -EAGAIN; /* Mangle error code: let's make any form of TPM2 failure non-fatal. */ } } else { - r = attach_luks2_by_tpm2_via_plugin(cd, name, until, arg_headless, flags); + r = attach_luks2_by_tpm2_via_plugin(cd, name, until, flags); if (r >= 0) return 0; /* EAGAIN means: no tpm2 chip found @@ -1885,7 +1873,6 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( &pcrlock_nv, tpm2_flags, until, - arg_headless, "cryptsetup.tpm2-pin", arg_ask_password_flags, &decrypted_key); @@ -2406,7 +2393,6 @@ static int run(int argc, char *argv[]) { volume, /* type= */ NULL, until, - arg_headless, /* userdata= */ NULL, flags, "Please enter LUKS2 token PIN:", diff --git a/src/home/homectl-pkcs11.c b/src/home/homectl-pkcs11.c index b9ee8acc4c..bb582d7d47 100644 --- a/src/home/homectl-pkcs11.c +++ b/src/home/homectl-pkcs11.c @@ -153,7 +153,14 @@ int identity_add_pkcs11_key_data(JsonVariant **v, const char *uri) { assert(v); - r = pkcs11_acquire_public_key(uri, "home directory operation", "user-home", "home.token-pin", &pkey, &pin); + r = pkcs11_acquire_public_key( + uri, + "home directory operation", + "user-home", + "home.token-pin", + /* askpw_flags= */ 0, + &pkey, + &pin); if (r < 0) return r; diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index a9d9cde97b..462b3d2e00 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -224,6 +224,9 @@ int ask_password_plymouth( assert(ret); + if (FLAGS_SET(flags, ASK_PASSWORD_HEADLESS)) + return -ENOEXEC; + const char *message = req && req->message ? req->message : "Password:"; if (flag_file) { @@ -378,6 +381,9 @@ int ask_password_tty( assert(ret); + if (FLAGS_SET(flags, ASK_PASSWORD_HEADLESS)) + return -ENOEXEC; + if (FLAGS_SET(flags, ASK_PASSWORD_NO_TTY)) return -EUNATCH; @@ -700,6 +706,9 @@ int ask_password_agent( assert(ret); + if (FLAGS_SET(flags, ASK_PASSWORD_HEADLESS)) + return -ENOEXEC; + if (FLAGS_SET(flags, ASK_PASSWORD_NO_AGENT)) return -EUNATCH; diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h index fced27798f..e851d6d087 100644 --- a/src/shared/ask-password-api.h +++ b/src/shared/ask-password-api.h @@ -15,6 +15,7 @@ typedef enum AskPasswordFlags { ASK_PASSWORD_CONSOLE_COLOR = 1 << 6, /* Use color if /dev/console points to a console that supports color */ ASK_PASSWORD_NO_CREDENTIAL = 1 << 7, /* never use $CREDENTIALS_DIRECTORY data */ ASK_PASSWORD_HIDE_EMOJI = 1 << 8, /* hide the lock and key emoji */ + ASK_PASSWORD_HEADLESS = 1 << 9, /* headless mode: never query interactively */ } AskPasswordFlags; /* Encapsulates the mostly static fields of a password query */ diff --git a/src/shared/cryptsetup-fido2.c b/src/shared/cryptsetup-fido2.c index d22c1059e6..5ab5cefe8f 100644 --- a/src/shared/cryptsetup-fido2.c +++ b/src/shared/cryptsetup-fido2.c @@ -24,7 +24,6 @@ int acquire_fido2_key( const void *key_data, size_t key_data_size, usec_t until, - bool headless, Fido2EnrollFlags required, const char *askpw_credential, AskPasswordFlags askpw_flags, @@ -39,7 +38,7 @@ int acquire_fido2_key( size_t salt_size; int r; - if ((required & (FIDO2ENROLL_PIN | FIDO2ENROLL_UP | FIDO2ENROLL_UV)) && headless) + if ((required & (FIDO2ENROLL_PIN | FIDO2ENROLL_UP | FIDO2ENROLL_UV)) && FLAGS_SET(askpw_flags, ASK_PASSWORD_HEADLESS)) return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "Local verification is required to unlock this volume, but the 'headless' parameter was set."); @@ -116,7 +115,7 @@ int acquire_fido2_key( device_exists = true; /* that a PIN is needed/wasn't correct means that we managed to * talk to a device */ - if (headless) + if (FLAGS_SET(askpw_flags, ASK_PASSWORD_HEADLESS)) return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable."); static const AskPasswordRequest req = { @@ -141,7 +140,6 @@ int acquire_fido2_key_auto( const char *friendly_name, const char *fido2_device, usec_t until, - bool headless, const char *askpw_credential, AskPasswordFlags askpw_flags, void **ret_decrypted_key, @@ -263,7 +261,6 @@ int acquire_fido2_key_auto( /* key_file_offset= */ 0, salt, salt_size, until, - headless, required, "cryptsetup.fido2-pin", askpw_flags, diff --git a/src/shared/cryptsetup-fido2.h b/src/shared/cryptsetup-fido2.h index d99ad05725..bd25566806 100644 --- a/src/shared/cryptsetup-fido2.h +++ b/src/shared/cryptsetup-fido2.h @@ -23,7 +23,6 @@ int acquire_fido2_key( const void *key_data, size_t key_data_size, usec_t until, - bool headless, Fido2EnrollFlags required, const char *askpw_credential, AskPasswordFlags askpw_flags, @@ -36,7 +35,6 @@ int acquire_fido2_key_auto( const char *friendly_name, const char *fido2_device, usec_t until, - bool headless, const char *askpw_credential, AskPasswordFlags askpw_flags, void **ret_decrypted_key, @@ -57,7 +55,6 @@ static inline int acquire_fido2_key( const void *key_data, size_t key_data_size, usec_t until, - bool headless, Fido2EnrollFlags required, const char *askpw_credential, AskPasswordFlags askpw_flags, @@ -74,7 +71,6 @@ static inline int acquire_fido2_key_auto( const char *friendly_name, const char *fido2_device, usec_t until, - bool headless, const char *askpw_credential, AskPasswordFlags askpw_flags, void **ret_decrypted_key, diff --git a/src/shared/cryptsetup-tpm2.c b/src/shared/cryptsetup-tpm2.c index 85bc42aef0..ee664a95a1 100644 --- a/src/shared/cryptsetup-tpm2.c +++ b/src/shared/cryptsetup-tpm2.c @@ -14,7 +14,6 @@ static int get_pin( usec_t until, - bool headless, const char *askpw_credential, AskPasswordFlags askpw_flags, char **ret_pin_str) { @@ -28,7 +27,7 @@ static int get_pin( if (r < 0) return log_error_errno(r, "Failed to acquire PIN from environment: %m"); if (!r) { - if (headless) + if (FLAGS_SET(askpw_flags, ASK_PASSWORD_HEADLESS)) return log_error_errno( SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. " @@ -42,11 +41,7 @@ static int get_pin( }; pin = strv_free_erase(pin); - r = ask_password_auto( - &req, - until, - askpw_flags, - &pin); + r = ask_password_auto(&req, until, askpw_flags, &pin); if (r < 0) return log_error_errno(r, "Failed to ask for user pin: %m"); assert(strv_length(pin) == 1); @@ -81,7 +76,6 @@ int acquire_tpm2_key( const struct iovec *pcrlock_nv, TPM2Flags flags, usec_t until, - bool headless, const char *askpw_credential, AskPasswordFlags askpw_flags, struct iovec *ret_decrypted_key) { @@ -179,7 +173,7 @@ int acquire_tpm2_key( if (i <= 0) return -EACCES; - r = get_pin(until, headless, askpw_credential, askpw_flags, &pin_str); + r = get_pin(until, askpw_credential, askpw_flags, &pin_str); if (r < 0) return r; diff --git a/src/shared/cryptsetup-tpm2.h b/src/shared/cryptsetup-tpm2.h index 5809655c15..b9905f4f4b 100644 --- a/src/shared/cryptsetup-tpm2.h +++ b/src/shared/cryptsetup-tpm2.h @@ -31,7 +31,6 @@ int acquire_tpm2_key( const struct iovec *pcrlock_nv, TPM2Flags flags, usec_t until, - bool headless, const char *askpw_credential, AskPasswordFlags askpw_flags, struct iovec *ret_decrypted_key); @@ -76,7 +75,6 @@ static inline int acquire_tpm2_key( const struct iovec *pcrlock_nv, TPM2Flags flags, usec_t until, - bool headless, const char *askpw_credential, AskPasswordFlags askpw_flags, struct iovec *ret_decrypted_key) { diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c index bfaca79bc8..c330d9b6e0 100644 --- a/src/shared/pkcs11-util.c +++ b/src/shared/pkcs11-util.c @@ -295,8 +295,7 @@ int pkcs11_token_login( const char *askpw_keyring, const char *askpw_credential, usec_t until, - AskPasswordFlags ask_password_flags, - bool headless, + AskPasswordFlags askpw_flags, char **ret_used_pin) { _cleanup_free_ char *token_uri_string = NULL, *token_uri_escaped = NULL, *id = NULL, *token_label = NULL; @@ -351,7 +350,7 @@ int pkcs11_token_login( if (!passwords) return log_oom(); - } else if (headless) + } else if (FLAGS_SET(askpw_flags, ASK_PASSWORD_HEADLESS)) return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the 'PIN' environment variable."); else { _cleanup_free_ char *text = NULL; @@ -384,7 +383,7 @@ int pkcs11_token_login( }; /* We never cache PINs, simply because it's fatal if we use wrong PINs, since usually there are only 3 tries */ - r = ask_password_auto(&req, until, ask_password_flags, &passwords); + r = ask_password_auto(&req, until, askpw_flags, &passwords); if (r < 0) return log_error_errno(r, "Failed to query PIN for security token '%s': %m", token_label); } @@ -1653,7 +1652,6 @@ struct pkcs11_acquire_public_key_callback_data { EVP_PKEY *pkey; const char *askpw_friendly_name, *askpw_icon, *askpw_credential; AskPasswordFlags askpw_flags; - bool headless; }; static void pkcs11_acquire_public_key_callback_data_release(struct pkcs11_acquire_public_key_callback_data *data) { @@ -1703,7 +1701,6 @@ static int pkcs11_acquire_public_key_callback( data->askpw_credential, UINT64_MAX, data->askpw_flags, - data->headless, &pin_used); if (r < 0) return r; @@ -1831,6 +1828,7 @@ int pkcs11_acquire_public_key( const char *askpw_friendly_name, const char *askpw_icon, const char *askpw_credential, + AskPasswordFlags askpw_flags, EVP_PKEY **ret_pkey, char **ret_pin_used) { @@ -1838,6 +1836,7 @@ int pkcs11_acquire_public_key( .askpw_friendly_name = askpw_friendly_name, .askpw_icon = askpw_icon, .askpw_credential = askpw_credential, + .askpw_flags = askpw_flags, }; int r; @@ -2045,7 +2044,6 @@ int pkcs11_crypt_device_callback( data->askpw_credential, data->until, data->askpw_flags, - data->headless, NULL); if (r < 0) return r; diff --git a/src/shared/pkcs11-util.h b/src/shared/pkcs11-util.h index dbd88ede67..6927a37113 100644 --- a/src/shared/pkcs11-util.h +++ b/src/shared/pkcs11-util.h @@ -53,7 +53,7 @@ char *pkcs11_token_manufacturer_id(const CK_TOKEN_INFO *token_info); char *pkcs11_token_model(const CK_TOKEN_INFO *token_info); int pkcs11_token_login_by_pin(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, const CK_TOKEN_INFO *token_info, const char *token_label, const void *pin, size_t pin_size); -int pkcs11_token_login(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, CK_SLOT_ID slotid, const CK_TOKEN_INFO *token_info, const char *friendly_name, const char *icon_name, const char *key_name, const char *credential_name, usec_t until, AskPasswordFlags ask_password_flags, bool headless, char **ret_used_pin); +int pkcs11_token_login(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, CK_SLOT_ID slotid, const CK_TOKEN_INFO *token_info, const char *friendly_name, const char *icon_name, const char *key_name, const char *credential_name, usec_t until, AskPasswordFlags ask_password_flags, char **ret_used_pin); int pkcs11_token_find_related_object(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE prototype, CK_OBJECT_CLASS class, CK_OBJECT_HANDLE *ret_object); int pkcs11_token_find_x509_certificate(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, P11KitUri *search_uri, CK_OBJECT_HANDLE *ret_object); @@ -71,7 +71,7 @@ typedef int (*pkcs11_find_token_callback_t)(CK_FUNCTION_LIST *m, CK_SESSION_HAND int pkcs11_find_token(const char *pkcs11_uri, pkcs11_find_token_callback_t callback, void *userdata); #if HAVE_OPENSSL -int pkcs11_acquire_public_key(const char *uri, const char *askpw_friendly_name, const char *askpw_icon, const char *askpw_credential, EVP_PKEY **ret_pkey, char **ret_pin_used); +int pkcs11_acquire_public_key(const char *uri, const char *askpw_friendly_name, const char *askpw_icon, const char *askpw_credential, AskPasswordFlags askpw_flags, EVP_PKEY **ret_pkey, char **ret_pin_used); #endif typedef struct { @@ -82,7 +82,6 @@ typedef struct { void *decrypted_key; size_t decrypted_key_size; bool free_encrypted_key; - bool headless; const char *askpw_credential; AskPasswordFlags askpw_flags; } pkcs11_crypt_device_callback_data; @@ -111,7 +110,6 @@ static inline int dlopen_p11kit(void) { typedef struct { const char *friendly_name; usec_t until; - bool headless; const char *askpw_credential; AskPasswordFlags askpw_flags; } systemd_pkcs11_plugin_params;