diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-03-11 20:17:10 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2021-03-26 12:21:56 +0100 |
commit | 8806bb4bc7fa15d6ca46e81b8d535730209a3b66 (patch) | |
tree | 95412964dee1dca33817f5fa6bb2150436338bf2 | |
parent | f6ab6199a2e8cbda64fe2574af572b8800da48bd (diff) | |
download | systemd-8806bb4bc7fa15d6ca46e81b8d535730209a3b66.tar.gz |
ask-password: when querying for a password, try to read from credential store first
This adds generic support for the SetCredential=/LoadCredential= logic
to our password querying infrastructure: if a password is requested by a
program that has a credential store configured via
$CREDENTIALS_DIRECTORY we'll look in it for a password.
The "systemd-ask-password" tool is updated with an option to specify the
credential to look for.
-rw-r--r-- | man/systemd-ask-password.xml | 11 | ||||
-rw-r--r-- | src/ask-password/ask-password.c | 29 | ||||
-rw-r--r-- | src/cryptenroll/cryptenroll-password.c | 4 | ||||
-rw-r--r-- | src/cryptenroll/cryptenroll.c | 2 | ||||
-rw-r--r-- | src/cryptsetup/cryptsetup-fido2.c | 2 | ||||
-rw-r--r-- | src/cryptsetup/cryptsetup-pkcs11.c | 1 | ||||
-rw-r--r-- | src/cryptsetup/cryptsetup.c | 4 | ||||
-rw-r--r-- | src/home/homectl.c | 8 | ||||
-rw-r--r-- | src/shared/ask-password-api.c | 41 | ||||
-rw-r--r-- | src/shared/ask-password-api.h | 15 | ||||
-rw-r--r-- | src/shared/dissect-image.c | 2 | ||||
-rw-r--r-- | src/shared/libfido2-util.c | 2 | ||||
-rw-r--r-- | src/shared/pkcs11-util.c | 7 | ||||
-rw-r--r-- | src/shared/pkcs11-util.h | 2 |
14 files changed, 93 insertions, 37 deletions
diff --git a/man/systemd-ask-password.xml b/man/systemd-ask-password.xml index 433260475d..f241064d8b 100644 --- a/man/systemd-ask-password.xml +++ b/man/systemd-ask-password.xml @@ -139,6 +139,17 @@ </varlistentry> <varlistentry> + <term><option>--credential=</option></term> + <listitem><para>Configure a credential to read the password from – if it exists. This may be used in + conjunction with the <varname>LoadCredential=</varname> and <varname>SetCredential=</varname> + settings in unit files. See + <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for + details. If not specified, defaults to <literal>password</literal>. This option has no effect if no + credentials directory is passed to the program (i.e. <varname>$CREDENTIALS_DIRECTORY</varname> is not + set) or if the no credential of the specified name exists.</para></listitem> + </varlistentry> + + <varlistentry> <term><option>--timeout=</option></term> <listitem><para>Specify the query timeout in seconds. Defaults diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index 6b89f57e1b..09bcefbe66 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -12,10 +12,12 @@ #include "main-func.h" #include "pretty-print.h" #include "strv.h" +#include "terminal-util.h" static const char *arg_icon = NULL; -static const char *arg_id = NULL; -static const char *arg_keyname = NULL; +static const char *arg_id = NULL; /* identifier for 'ask-password' protocol */ +static const char *arg_key_name = NULL; /* name in kernel keyring */ +static const char *arg_credential_name = NULL; /* name in $CREDENTIALS_DIRECTORY directory */ static char *arg_message = NULL; static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC; static bool arg_multiple = false; @@ -32,21 +34,26 @@ static int help(void) { if (r < 0) return log_oom(); - printf("%s [OPTIONS...] MESSAGE\n\n" - "Query the user for a system passphrase, via the TTY or an UI agent.\n\n" + printf("%1$s [OPTIONS...] MESSAGE\n\n" + "%3$sQuery the user for a system passphrase, via the TTY or an UI agent.%4$s\n\n" " -h --help Show this help\n" " --icon=NAME Icon name\n" " --id=ID Query identifier (e.g. \"cryptsetup:/dev/sda5\")\n" " --keyname=NAME Kernel key name for caching passwords (e.g. \"cryptsetup\")\n" + " --credential=NAME\n" + " Credential name for LoadCredential=/SetCredential=\n" + " credentials\n" " --timeout=SEC Timeout in seconds\n" " --echo Do not mask input (useful for usernames)\n" " --no-tty Ask question via agent even on TTY\n" " --accept-cached Accept cached passwords\n" " --multiple List multiple passwords if available\n" " --no-output Do not print password to standard output\n" - "\nSee the %s for details.\n", + "\nSee the %2$s for details.\n", program_invocation_short_name, - link); + link, + ansi_highlight(), + ansi_normal()); return 0; } @@ -64,6 +71,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_KEYNAME, ARG_NO_OUTPUT, ARG_VERSION, + ARG_CREDENTIAL, }; static const struct option options[] = { @@ -78,6 +86,7 @@ static int parse_argv(int argc, char *argv[]) { { "id", required_argument, NULL, ARG_ID }, { "keyname", required_argument, NULL, ARG_KEYNAME }, { "no-output", no_argument, NULL, ARG_NO_OUTPUT }, + { "credential", required_argument, NULL, ARG_CREDENTIAL }, {} }; @@ -128,13 +137,17 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_KEYNAME: - arg_keyname = optarg; + arg_key_name = optarg; break; case ARG_NO_OUTPUT: arg_no_output = true; break; + case ARG_CREDENTIAL: + arg_credential_name = optarg; + break; + case '?': return -EINVAL; @@ -170,7 +183,7 @@ static int run(int argc, char *argv[]) { else timeout = 0; - r = ask_password_auto(arg_message, arg_icon, arg_id, arg_keyname, timeout, arg_flags, &l); + r = ask_password_auto(arg_message, arg_icon, arg_id, arg_key_name, arg_credential_name ?: "password", 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 e08f564d3f..0314831174 100644 --- a/src/cryptenroll/cryptenroll-password.c +++ b/src/cryptenroll/cryptenroll-password.c @@ -57,7 +57,7 @@ int enroll_password( if (!question) return log_oom(); - r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY, 0, &passwords); + r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords); if (r < 0) return log_error_errno(r, "Failed to query password: %m"); @@ -68,7 +68,7 @@ int enroll_password( if (!question) return log_oom(); - r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY, 0, &passwords2); + r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords2); if (r < 0) return log_error_errno(r, "Failed to query password: %m"); diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c index a137a41c9d..7d12c427b3 100644 --- a/src/cryptenroll/cryptenroll.c +++ b/src/cryptenroll/cryptenroll.c @@ -417,7 +417,7 @@ static int prepare_luks( "Too many attempts, giving up:"); r = ask_password_auto( - question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY, + question, "drive-harddisk", id, "cryptenroll", "cryptenroll.passphrase", USEC_INFINITY, ask_password_flags, &passwords); if (r < 0) diff --git a/src/cryptsetup/cryptsetup-fido2.c b/src/cryptsetup/cryptsetup-fido2.c index dfdb964360..82b83ee477 100644 --- a/src/cryptsetup/cryptsetup-fido2.c +++ b/src/cryptsetup/cryptsetup-fido2.c @@ -88,7 +88,7 @@ int acquire_fido2_key( pins = strv_free_erase(pins); - r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", until, flags, &pins); + r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins); if (r < 0) return log_error_errno(r, "Failed to ask for user password: %m"); diff --git a/src/cryptsetup/cryptsetup-pkcs11.c b/src/cryptsetup/cryptsetup-pkcs11.c index 8d7d74fb75..6d7b01176c 100644 --- a/src/cryptsetup/cryptsetup-pkcs11.c +++ b/src/cryptsetup/cryptsetup-pkcs11.c @@ -70,6 +70,7 @@ static int pkcs11_callback( data->friendly_name, "drive-harddisk", "pkcs11-pin", + "cryptsetup.pkcs11-pin", data->until, NULL); if (r < 0) diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index dba26a54a3..5c55dcd197 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -545,7 +545,7 @@ static int get_password( id = strjoina("cryptsetup:", disk_path); - r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, + r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", "cryptsetup.passphrase", until, ASK_PASSWORD_PUSH_CACHE | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED), &passwords); if (r < 0) @@ -561,7 +561,7 @@ static int get_password( id = strjoina("cryptsetup-verification:", disk_path); - r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE, &passwords2); + r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", "cryptsetup.passphrase", until, ASK_PASSWORD_PUSH_CACHE, &passwords2); if (r < 0) return log_error_errno(r, "Failed to query verification password: %m"); diff --git a/src/home/homectl.c b/src/home/homectl.c index 9d12b9abae..cf1a2d9f9b 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -221,7 +221,7 @@ static int acquire_existing_password(const char *user_name, UserRecord *hr, bool user_name) < 0) return log_oom(); - r = ask_password_auto(question, "user-home", NULL, "home-password", USEC_INFINITY, ASK_PASSWORD_ACCEPT_CACHED|ASK_PASSWORD_PUSH_CACHE, &password); + r = ask_password_auto(question, "user-home", NULL, "home-password", "home.password", USEC_INFINITY, ASK_PASSWORD_ACCEPT_CACHED|ASK_PASSWORD_PUSH_CACHE, &password); if (r < 0) return log_error_errno(r, "Failed to acquire password: %m"); @@ -257,7 +257,7 @@ static int acquire_token_pin(const char *user_name, UserRecord *hr) { return log_oom(); /* We never cache or use cached PINs, since usually there are only very few attempts allowed before the PIN is blocked */ - r = ask_password_auto(question, "user-home", NULL, "token-pin", USEC_INFINITY, 0, &pin); + r = ask_password_auto(question, "user-home", NULL, "token-pin", "home.token-pin", USEC_INFINITY, 0, &pin); if (r < 0) return log_error_errno(r, "Failed to acquire security token PIN: %m"); @@ -1010,7 +1010,7 @@ static int acquire_new_password( if (asprintf(&question, "Please enter new password for user %s:", user_name) < 0) return log_oom(); - r = ask_password_auto(question, "user-home", NULL, "home-password", USEC_INFINITY, 0, &first); + r = ask_password_auto(question, "user-home", NULL, "home-password", "home.new-password", USEC_INFINITY, 0, &first); if (r < 0) return log_error_errno(r, "Failed to acquire password: %m"); @@ -1018,7 +1018,7 @@ static int acquire_new_password( if (asprintf(&question, "Please enter new password for user %s (repeat):", user_name) < 0) return log_oom(); - r = ask_password_auto(question, "user-home", NULL, "home-password", USEC_INFINITY, 0, &second); + r = ask_password_auto(question, "user-home", NULL, "home-password", "home.new-password", USEC_INFINITY, 0, &second); if (r < 0) return log_error_errno(r, "Failed to acquire password: %m"); diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 729aa1fb00..04c6b5287e 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -20,6 +20,7 @@ #include "alloc-util.h" #include "ask-password-api.h" +#include "creds-util.h" #include "def.h" #include "fd-util.h" #include "fileio.h" @@ -971,11 +972,33 @@ finish: return r; } +static int ask_password_credential(const char *credential_name, AskPasswordFlags flags, char ***ret) { + _cleanup_(erase_and_freep) char *buffer = NULL; + size_t size; + char **l; + int r; + + assert(credential_name); + assert(ret); + + r = read_credential(credential_name, (void**) &buffer, &size); + if (IN_SET(r, -ENXIO, -ENOENT)) /* No credentials passed or this credential not defined? */ + return -ENOKEY; + + l = strv_parse_nulstr(buffer, size); + if (!l) + return -ENOMEM; + + *ret = l; + return 0; +} + int ask_password_auto( const char *message, const char *icon, - const char *id, - const char *keyname, + 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 */ usec_t until, AskPasswordFlags flags, char ***ret) { @@ -984,20 +1007,26 @@ int ask_password_auto( assert(ret); + if (!(flags & ASK_PASSWORD_NO_CREDENTIAL) && credential_name) { + r = ask_password_credential(credential_name, flags, ret); + if (r != -ENOKEY) + return r; + } + if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && - keyname && + key_name && ((flags & ASK_PASSWORD_NO_TTY) || !isatty(STDIN_FILENO)) && (flags & ASK_PASSWORD_NO_AGENT)) { - r = ask_password_keyring(keyname, flags, ret); + r = ask_password_keyring(key_name, flags, ret); if (r != -ENOKEY) return r; } if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) - return ask_password_tty(-1, message, keyname, until, flags, NULL, ret); + return ask_password_tty(-1, message, key_name, until, flags, NULL, ret); if (!(flags & ASK_PASSWORD_NO_AGENT)) - return ask_password_agent(message, icon, id, keyname, until, flags, ret); + return ask_password_agent(message, icon, id, key_name, until, flags, ret); return -EUNATCH; } diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h index 7aac5e5976..bb507b2e8d 100644 --- a/src/shared/ask-password-api.h +++ b/src/shared/ask-password-api.h @@ -6,16 +6,17 @@ #include "time-util.h" typedef enum AskPasswordFlags { - ASK_PASSWORD_ACCEPT_CACHED = 1 << 0, - ASK_PASSWORD_PUSH_CACHE = 1 << 1, + ASK_PASSWORD_ACCEPT_CACHED = 1 << 0, /* read from kernel keyring */ + ASK_PASSWORD_PUSH_CACHE = 1 << 1, /* write to kernel keyring after getting password from elsewhere */ ASK_PASSWORD_ECHO = 1 << 2, /* show the password literally while reading, instead of "*" */ ASK_PASSWORD_SILENT = 1 << 3, /* do no show any password at all while reading */ - ASK_PASSWORD_NO_TTY = 1 << 4, - ASK_PASSWORD_NO_AGENT = 1 << 5, + ASK_PASSWORD_NO_TTY = 1 << 4, /* never ask for password on tty */ + ASK_PASSWORD_NO_AGENT = 1 << 5, /* never ask for password via agent */ 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 */ } AskPasswordFlags; -int ask_password_tty(int tty_fd, const char *message, const char *keyname, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret); +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 *keyname, usec_t until, AskPasswordFlags flag, char ***ret); -int ask_password_auto(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, 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); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index cca92e7fb4..6eb23db312 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -1993,7 +1993,7 @@ int dissected_image_decrypt_interactively( z = strv_free(z); - r = ask_password_auto("Please enter image passphrase:", NULL, "dissect", "dissect", USEC_INFINITY, 0, &z); + r = ask_password_auto("Please enter image passphrase:", NULL, "dissect", "dissect", "dissect.passphrase", USEC_INFINITY, 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 22b8aba07e..951ed09899 100644 --- a/src/shared/libfido2-util.c +++ b/src/shared/libfido2-util.c @@ -566,7 +566,7 @@ int fido2_generate_hmac_hash( if (!has_client_pin) log_warning("Weird, device asked for client PIN, but does not advertise it as feature. Ignoring."); - r = ask_password_auto("Please enter security token PIN:", askpw_icon_name, NULL, "fido2-pin", USEC_INFINITY, 0, &pin); + r = ask_password_auto("Please enter security token PIN:", askpw_icon_name, NULL, "fido2-pin", "fido2-pin", USEC_INFINITY, 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 27c209cdf8..4fa1effb2d 100644 --- a/src/shared/pkcs11-util.c +++ b/src/shared/pkcs11-util.c @@ -181,7 +181,8 @@ int pkcs11_token_login( const CK_TOKEN_INFO *token_info, const char *friendly_name, const char *icon_name, - const char *keyname, + const char *key_name, + const char *credential_name, usec_t until, char **ret_used_pin) { @@ -269,7 +270,7 @@ int pkcs11_token_login( return log_oom(); /* 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, keyname, until, 0, &passwords); + r = ask_password_auto(text, icon_name, id, key_name, credential_name, until, 0, &passwords); if (r < 0) return log_error_errno(r, "Failed to query PIN for security token '%s': %m", token_label); } @@ -959,7 +960,7 @@ static int pkcs11_acquire_certificate_callback( /* Called for every token matching our URI */ - r = pkcs11_token_login(m, session, slot_id, token_info, data->askpw_friendly_name, data->askpw_icon_name, "pkcs11-pin", UINT64_MAX, &pin_used); + r = pkcs11_token_login(m, session, slot_id, token_info, data->askpw_friendly_name, data->askpw_icon_name, "pkcs11-pin", "pkcs11-pin", UINT64_MAX, &pin_used); if (r < 0) return r; diff --git a/src/shared/pkcs11-util.h b/src/shared/pkcs11-util.h index f32ab30429..c2c852f0eb 100644 --- a/src/shared/pkcs11-util.h +++ b/src/shared/pkcs11-util.h @@ -30,7 +30,7 @@ char *pkcs11_token_label(const CK_TOKEN_INFO *token_info); 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(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 *keyname, usec_t until, 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, char **ret_used_pin); int pkcs11_token_find_x509_certificate(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, P11KitUri *search_uri, CK_OBJECT_HANDLE *ret_object); #if HAVE_OPENSSL |