From cd5f57bda71dc9485d7eddf6cfcbfba843f5126c Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Fri, 9 Apr 2021 20:43:10 +0100 Subject: [PATCH] cryptsetup: add 'headless' parameter to skip password/pin query On headless setups, in case other methods fail, asking for a password/pin is not useful as there are no users on the terminal, and generates unwanted noise. Add a parameter to /etc/crypttab to skip it. --- man/crypttab.xml | 7 +++++++ man/systemd-cryptsetup@.service.xml | 3 ++- src/cryptsetup/cryptsetup-fido2.c | 4 ++++ src/cryptsetup/cryptsetup-fido2.h | 2 ++ src/cryptsetup/cryptsetup-pkcs11.c | 4 ++++ src/cryptsetup/cryptsetup-pkcs11.h | 2 ++ src/cryptsetup/cryptsetup.c | 17 +++++++++++++++++ src/shared/pkcs11-util.c | 7 +++++-- src/shared/pkcs11-util.h | 2 +- 9 files changed, 44 insertions(+), 4 deletions(-) diff --git a/man/crypttab.xml b/man/crypttab.xml index 72fe2e692da..d3aa3b8fc1f 100644 --- a/man/crypttab.xml +++ b/man/crypttab.xml @@ -514,6 +514,13 @@ user is queried for a password indefinitely. + + + + Takes a boolean argument, defaults to false. If true, never query interactively + for the password/PIN. Useful for headless systems. + + diff --git a/man/systemd-cryptsetup@.service.xml b/man/systemd-cryptsetup@.service.xml index 668208a01d3..1697ccc0f3c 100644 --- a/man/systemd-cryptsetup@.service.xml +++ b/man/systemd-cryptsetup@.service.xml @@ -73,7 +73,8 @@ The kernel keyring is then checked for a suitable cached password from previous attempts. - Finally, the user is queried for a password, possibly multiple times. + Finally, the user is queried for a password, possibly multiple times, unless + the headless option is set. If no suitable key may be acquired via any of the mechanisms describes above, volume activation fails. diff --git a/src/cryptsetup/cryptsetup-fido2.c b/src/cryptsetup/cryptsetup-fido2.c index 82b83ee4770..8238e823cdf 100644 --- a/src/cryptsetup/cryptsetup-fido2.c +++ b/src/cryptsetup/cryptsetup-fido2.c @@ -23,6 +23,7 @@ int acquire_fido2_key( const void *key_data, size_t key_data_size, usec_t until, + bool headless, void **ret_decrypted_key, size_t *ret_decrypted_key_size) { @@ -88,6 +89,9 @@ int acquire_fido2_key( pins = strv_free_erase(pins); + if (headless) + return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable."); + 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-fido2.h b/src/cryptsetup/cryptsetup-fido2.h index 92093ba38bb..d5c5ce59268 100644 --- a/src/cryptsetup/cryptsetup-fido2.h +++ b/src/cryptsetup/cryptsetup-fido2.h @@ -22,6 +22,7 @@ int acquire_fido2_key( const void *key_data, size_t key_data_size, usec_t until, + bool headless, void **ret_decrypted_key, size_t *ret_decrypted_key_size); @@ -49,6 +50,7 @@ static inline int acquire_fido2_key( const void *key_data, size_t key_data_size, usec_t until, + bool headless, void **ret_decrypted_key, size_t *ret_decrypted_key_size) { diff --git a/src/cryptsetup/cryptsetup-pkcs11.c b/src/cryptsetup/cryptsetup-pkcs11.c index 6d7b01176cb..67adf923cc0 100644 --- a/src/cryptsetup/cryptsetup-pkcs11.c +++ b/src/cryptsetup/cryptsetup-pkcs11.c @@ -32,6 +32,7 @@ struct pkcs11_callback_data { void *decrypted_key; size_t decrypted_key_size; bool free_encrypted_key; + bool headless; }; static void pkcs11_callback_data_release(struct pkcs11_callback_data *data) { @@ -72,6 +73,7 @@ static int pkcs11_callback( "pkcs11-pin", "cryptsetup.pkcs11-pin", data->until, + data->headless, NULL); if (r < 0) return r; @@ -109,12 +111,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, void **ret_decrypted_key, size_t *ret_decrypted_key_size) { _cleanup_(pkcs11_callback_data_release) struct pkcs11_callback_data data = { .friendly_name = friendly_name, .until = until, + .headless = headless, }; int r; diff --git a/src/cryptsetup/cryptsetup-pkcs11.h b/src/cryptsetup/cryptsetup-pkcs11.h index 4cd82e0215f..256c09a9b68 100644 --- a/src/cryptsetup/cryptsetup-pkcs11.h +++ b/src/cryptsetup/cryptsetup-pkcs11.h @@ -19,6 +19,7 @@ int decrypt_pkcs11_key( const void *key_data, size_t key_data_size, usec_t until, + bool headless, void **ret_decrypted_key, size_t *ret_decrypted_key_size); @@ -41,6 +42,7 @@ static inline int decrypt_pkcs11_key( const void *key_data, size_t key_data_size, usec_t until, + bool headless, void **ret_decrypted_key, size_t *ret_decrypted_key_size) { diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index c9cebb46378..7902377a25a 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -79,6 +79,7 @@ static char *arg_fido2_rp_id = NULL; static char *arg_tpm2_device = NULL; static bool arg_tpm2_device_auto = false; static uint32_t arg_tpm2_pcr_mask = UINT32_MAX; +static bool arg_headless = false; STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep); STATIC_DESTRUCTOR_REGISTER(arg_hash, freep); @@ -381,6 +382,17 @@ static int parse_one_option(const char *option) { } else if (streq(option, "try-empty-password")) arg_try_empty_password = true; + else if ((val = startswith(option, "headless="))) { + + r = parse_boolean(val); + if (r < 0) { + log_error_errno(r, "Failed to parse %s, ignoring: %m", option); + return 0; + } + + arg_headless = r; + } else if (streq(option, "headless")) + arg_headless = true; else if (!streq(option, "x-initrd.attach")) log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option); @@ -532,6 +544,9 @@ static int get_password( assert(src); assert(ret); + if (arg_headless) + return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "Password querying disabled via 'headless' option."); + friendly = friendly_disk_name(src, vol); if (!friendly) return log_oom(); @@ -775,6 +790,7 @@ 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, &decrypted_key, &decrypted_key_size); if (r >= 0) break; @@ -895,6 +911,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, &decrypted_key, &decrypted_key_size); if (r >= 0) break; diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c index aff45ed868c..9fc577ca3cf 100644 --- a/src/shared/pkcs11-util.c +++ b/src/shared/pkcs11-util.c @@ -184,6 +184,7 @@ int pkcs11_token_login( const char *key_name, const char *credential_name, usec_t until, + bool headless, char **ret_used_pin) { _cleanup_free_ char *token_uri_string = NULL, *token_uri_escaped = NULL, *id = NULL, *token_label = NULL; @@ -247,7 +248,9 @@ int pkcs11_token_login( string_erase(e); if (unsetenv("PIN") < 0) return log_error_errno(errno, "Failed to unset $PIN: %m"); - } else { + } else if (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; if (FLAGS_SET(token_info->flags, CKF_USER_PIN_FINAL_TRY)) @@ -960,7 +963,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", "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, false, &pin_used); if (r < 0) return r; diff --git a/src/shared/pkcs11-util.h b/src/shared/pkcs11-util.h index c2c852f0ebe..f7f32d34d71 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 *key_name, const char *credential_name, 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, bool headless, 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