summaryrefslogtreecommitdiffstats
path: root/src/cryptsetup/cryptsetup.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:40 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:40 +0000
commitfc53809803cd2bc2434e312b19a18fa36776da12 (patch)
treeb4b43bd6538f51965ce32856e9c053d0f90919c8 /src/cryptsetup/cryptsetup.c
parentAdding upstream version 255.5. (diff)
downloadsystemd-fc53809803cd2bc2434e312b19a18fa36776da12.tar.xz
systemd-fc53809803cd2bc2434e312b19a18fa36776da12.zip
Adding upstream version 256.upstream/256
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cryptsetup/cryptsetup.c')
-rw-r--r--src/cryptsetup/cryptsetup.c288
1 files changed, 205 insertions, 83 deletions
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 1822beb..85897ae 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -101,10 +101,12 @@ 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;
+static char *arg_link_keyring = NULL;
+static char *arg_link_key_type = NULL;
+static char *arg_link_key_description = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep);
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
@@ -118,6 +120,9 @@ STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_signature, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_measure_banks, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_pcrlock, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_link_keyring, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_link_key_type, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_link_key_description, freep);
static const char* const passphrase_type_table[_PASSPHRASE_TYPE_MAX] = {
[PASSPHRASE_REGULAR] = "passphrase",
@@ -338,7 +343,7 @@ static int parse_one_option(const char *option) {
arg_pkcs11_uri_auto = true;
} else {
if (!pkcs11_uri_valid(val))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "pkcs11-uri= parameter expects a PKCS#11 URI, refusing");
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "pkcs11-uri= parameter expects a PKCS#11 URI, refusing.");
r = free_and_strdup(&arg_pkcs11_uri, val);
if (r < 0)
@@ -368,7 +373,7 @@ static int parse_one_option(const char *option) {
_cleanup_free_ void *cid = NULL;
size_t cid_size;
- r = unbase64mem(val, SIZE_MAX, &cid, &cid_size);
+ r = unbase64mem(val, &cid, &cid_size);
if (r < 0)
return log_error_errno(r, "Failed to decode FIDO2 CID data: %m");
@@ -498,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="))) {
@@ -508,6 +513,56 @@ static int parse_one_option(const char *option) {
if (r < 0)
log_warning_errno(r, "Failed to parse %s, ignoring: %m", option);
+ } else if ((val = startswith(option, "link-volume-key="))) {
+#ifdef HAVE_CRYPT_SET_KEYRING_TO_LINK
+ const char *sep, *c;
+ _cleanup_free_ char *keyring = NULL, *key_type = NULL, *key_description = NULL;
+
+ /* Stick with cryptsetup --link-vk-to-keyring format
+ * <keyring_description>::%<key_type>:<key_description>,
+ * where %<key_type> is optional and defaults to 'user'.
+ */
+ if (!(sep = strstr(val, "::")))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse link-volume-key= option value: %s", val);
+
+ /* cryptsetup (cli) supports <keyring_description> passed in various formats:
+ * - well-known keyrings prefixed with '@' (@u user, @s session, etc)
+ * - text descriptions prefixed with "%:" or "%keyring:".
+ * - text description with no prefix.
+ * - numeric keyring id (ignored in current patch set). */
+ if (IN_SET(*val, '@', '%'))
+ keyring = strndup(val, sep - val);
+ else
+ /* add type prefix if missing (crypt_set_keyring_to_link() expects it) */
+ keyring = strnappend("%:", val, sep - val);
+ if (!keyring)
+ return log_oom();
+
+ sep += 2;
+
+ /* %<key_type> is optional (and defaults to 'user') */
+ if (*sep == '%') {
+ /* must be separated by colon */
+ if (!(c = strchr(sep, ':')))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse link-volume-key= option value: %s", val);
+
+ key_type = strndup(sep + 1, c - sep - 1);
+ if (!key_type)
+ return log_oom();
+
+ sep = c + 1;
+ }
+
+ key_description = strdup(sep);
+ if (!key_description)
+ return log_oom();
+
+ free_and_replace(arg_link_keyring, keyring);
+ free_and_replace(arg_link_key_type, key_type);
+ free_and_replace(arg_link_key_description, key_description);
+#else
+ log_error("Build lacks libcryptsetup support for linking volume keys in user specified kernel keyrings upon device activation, ignoring: %s", option);
+#endif
} else if (!streq(option, "x-initrd.attach"))
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
@@ -742,17 +797,16 @@ 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);
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);
@@ -766,11 +820,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();
+
+ AskPasswordRequest req = {
+ .message = text,
+ .icon = "drive-harddisk",
+ .id = id,
+ .keyring = "cryptsetup",
+ .credential = "cryptsetup.passphrase",
+ };
- r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", "cryptsetup.passphrase", until,
- flags | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED),
- &passwords);
+ 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");
@@ -779,12 +845,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");
@@ -1192,12 +1265,11 @@ 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,
- 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;
@@ -1222,12 +1294,20 @@ 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 (;;) {
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;
@@ -1251,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) {
@@ -1260,7 +1339,6 @@ static int attach_luks2_by_fido2_via_plugin(
name,
"systemd-fido2",
until,
- headless,
userdata,
activation_flags,
"Please enter security token PIN:",
@@ -1315,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.");
@@ -1331,10 +1409,11 @@ 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,
- &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,
@@ -1342,9 +1421,10 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
friendly,
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;
}
@@ -1405,7 +1485,7 @@ 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) {
#if HAVE_LIBCRYPTSETUP_PLUGINS
@@ -1417,7 +1497,7 @@ 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,
};
@@ -1481,7 +1561,13 @@ 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,
+ "cryptsetup.pkcs11-pin",
+ flags);
else {
r = decrypt_pkcs11_key(
name,
@@ -1490,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;
@@ -1615,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
@@ -1635,7 +1720,6 @@ static int attach_luks2_by_tpm2_via_plugin(
name,
"systemd-tpm2",
until,
- headless,
&params,
flags,
"Please enter TPM2 PIN:",
@@ -1650,18 +1734,16 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
struct crypt_device *cd,
const char *name,
const char *key_file,
- const void *key_data,
- size_t key_data_size,
+ const struct iovec *key_data,
usec_t until,
uint32_t flags,
bool pass_volume_key) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
- _cleanup_(erase_and_freep) void *decrypted_key = NULL;
+ _cleanup_(iovec_done_erase) struct iovec decrypted_key = {};
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_free_ char *friendly = NULL;
int keyslot = arg_key_slot, r;
- size_t decrypted_key_size;
assert(cd);
assert(name);
@@ -1672,7 +1754,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
return log_oom();
for (;;) {
- if (key_file || key_data) {
+ if (key_file || iovec_is_set(key_data)) {
/* If key data is specified, use that */
r = acquire_tpm2_key(
@@ -1680,21 +1762,22 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
arg_tpm2_device,
arg_tpm2_pcr_mask == UINT32_MAX ? TPM2_PCR_MASK_DEFAULT : arg_tpm2_pcr_mask,
UINT16_MAX,
- /* pubkey= */ NULL, /* pubkey_size= */ 0,
+ /* pubkey= */ NULL,
/* pubkey_pcr_mask= */ 0,
/* signature_path= */ NULL,
/* pcrlock_path= */ NULL,
/* primary_alg= */ 0,
key_file, arg_keyfile_size, arg_keyfile_offset,
- key_data, key_data_size,
- /* policy_hash= */ NULL, /* policy_hash_size= */ 0, /* we don't know the policy hash */
- /* salt= */ NULL, /* salt_size= */ 0,
- /* srk_buf= */ NULL, /* srk_buf_size= */ 0,
+ key_data,
+ /* policy_hash= */ NULL, /* we don't know the policy hash */
+ /* salt= */ NULL,
+ /* srk= */ NULL,
+ /* pcrlock_nv= */ NULL,
arg_tpm2_pin ? TPM2_FLAGS_USE_PIN : 0,
until,
- arg_headless,
+ "cryptsetup.tpm2-pin",
arg_ask_password_flags,
- &decrypted_key, &decrypted_key_size);
+ &decrypted_key);
if (r >= 0)
break;
if (IN_SET(r, -EACCES, -ENOLCK))
@@ -1707,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
@@ -1725,8 +1808,6 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
}
if (r == -EOPNOTSUPP) { /* Plugin not available, let's process TPM2 stuff right here instead */
- _cleanup_free_ void *blob = NULL, *policy_hash = NULL;
- size_t blob_size, policy_hash_size;
bool found_some = false;
int token = 0; /* first token to look at */
@@ -1735,8 +1816,8 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
* works. */
for (;;) {
- _cleanup_free_ void *pubkey = NULL, *salt = NULL, *srk_buf = NULL;
- size_t pubkey_size = 0, salt_size = 0, srk_buf_size = 0;
+ _cleanup_(iovec_done) struct iovec pubkey = {}, salt = {}, srk = {}, pcrlock_nv = {};
+ _cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {};
uint32_t hash_pcr_mask, pubkey_pcr_mask;
uint16_t pcr_bank, primary_alg;
TPM2Flags tpm2_flags;
@@ -1747,13 +1828,14 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
token, /* search for the token with this index, or any later index than this */
&hash_pcr_mask,
&pcr_bank,
- &pubkey, &pubkey_size,
+ &pubkey,
&pubkey_pcr_mask,
&primary_alg,
- &blob, &blob_size,
- &policy_hash, &policy_hash_size,
- &salt, &salt_size,
- &srk_buf, &srk_buf_size,
+ &blob,
+ &policy_hash,
+ &salt,
+ &srk,
+ &pcrlock_nv,
&tpm2_flags,
&keyslot,
&token);
@@ -1778,21 +1860,22 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
arg_tpm2_device,
hash_pcr_mask,
pcr_bank,
- pubkey, pubkey_size,
+ &pubkey,
pubkey_pcr_mask,
arg_tpm2_signature,
arg_tpm2_pcrlock,
primary_alg,
/* key_file= */ NULL, /* key_file_size= */ 0, /* key_file_offset= */ 0, /* no key file */
- blob, blob_size,
- policy_hash, policy_hash_size,
- salt, salt_size,
- srk_buf, srk_buf_size,
+ &blob,
+ &policy_hash,
+ &salt,
+ &srk,
+ &pcrlock_nv,
tpm2_flags,
until,
- arg_headless,
+ "cryptsetup.tpm2-pin",
arg_ask_password_flags,
- &decrypted_key, &decrypted_key_size);
+ &decrypted_key);
if (IN_SET(r, -EACCES, -ENOLCK))
return log_notice_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 PIN unlock failed, falling back to traditional unlocking.");
if (r != -EPERM)
@@ -1837,17 +1920,16 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
log_debug("Got one or more potentially relevant udev events, rescanning for TPM2...");
}
- assert(decrypted_key);
if (pass_volume_key)
- r = measured_crypt_activate_by_volume_key(cd, name, decrypted_key, decrypted_key_size, flags);
+ r = measured_crypt_activate_by_volume_key(cd, name, decrypted_key.iov_base, decrypted_key.iov_len, flags);
else {
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
ssize_t base64_encoded_size;
/* Before using this key as passphrase we base64 encode it, for compat with homed */
- base64_encoded_size = base64mem(decrypted_key, decrypted_key_size, &base64_encoded);
+ base64_encoded_size = base64mem(decrypted_key.iov_base, decrypted_key.iov_len, &base64_encoded);
if (base64_encoded_size < 0)
return log_oom();
@@ -2045,7 +2127,7 @@ static int attach_luks_or_plain_or_bitlk(
crypt_get_device_name(cd));
if (arg_tpm2_device || arg_tpm2_device_auto)
- return attach_luks_or_plain_or_bitlk_by_tpm2(cd, name, key_file, key_data, key_data_size, until, flags, pass_volume_key);
+ return attach_luks_or_plain_or_bitlk_by_tpm2(cd, name, key_file, &IOVEC_MAKE(key_data, key_data_size), until, flags, pass_volume_key);
if (arg_fido2_device || arg_fido2_device_auto)
return attach_luks_or_plain_or_bitlk_by_fido2(cd, name, key_file, key_data, key_data_size, until, flags, pass_volume_key);
if (arg_pkcs11_uri || arg_pkcs11_uri_auto)
@@ -2289,6 +2371,15 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd));
+/* since cryptsetup 2.7.0 (Jan 2024) */
+#if HAVE_CRYPT_SET_KEYRING_TO_LINK
+ if (arg_link_key_description) {
+ r = crypt_set_keyring_to_link(cd, arg_link_key_description, NULL, arg_link_key_type, arg_link_keyring);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set keyring or key description to link volume key in, ignoring: %m");
+ }
+#endif
+
if (arg_header) {
r = crypt_set_data_device(cd, source);
if (r < 0)
@@ -2302,7 +2393,6 @@ static int run(int argc, char *argv[]) {
volume,
/* type= */ NULL,
until,
- arg_headless,
/* userdata= */ NULL,
flags,
"Please enter LUKS2 token PIN:",
@@ -2326,8 +2416,10 @@ static int run(int argc, char *argv[]) {
}
#endif
+ bool use_cached_passphrase = true;
+ _cleanup_strv_free_erase_ char **passwords = NULL;
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
- _cleanup_strv_free_erase_ char **passwords = NULL;
+ log_debug("Beginning attempt %u to unlock.", tries);
/* When we were able to acquire multiple keys, let's always process them in this order:
*
@@ -2338,7 +2430,9 @@ static int run(int argc, char *argv[]) {
* 5. We enquire the user for a password
*/
- if (!key_file && !key_data && !arg_pkcs11_uri && !arg_pkcs11_uri_auto && !arg_fido2_device && !arg_fido2_device_auto && !arg_tpm2_device && !arg_tpm2_device_auto) {
+ if (!passwords && !key_file && !key_data && !arg_pkcs11_uri && !arg_pkcs11_uri_auto && !arg_fido2_device && !arg_fido2_device_auto && !arg_tpm2_device && !arg_tpm2_device_auto) {
+
+ /* If we have nothing to try anymore, then acquire a new password */
if (arg_try_empty_password) {
/* Hmm, let's try an empty password now, but only once */
@@ -2358,7 +2452,8 @@ static int run(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No passphrase or recovery key registered.");
}
- r = get_password(volume, source, until, tries == 0 && !arg_verify, passphrase_type, &passwords);
+ r = get_password(volume, source, until, use_cached_passphrase && !arg_verify, passphrase_type, &passwords);
+ use_cached_passphrase = false;
if (r == -EAGAIN)
continue;
if (r < 0)
@@ -2375,17 +2470,44 @@ static int run(int argc, char *argv[]) {
if (r != -EAGAIN)
return r;
- /* Key not correct? Let's try again! */
+ /* Key not correct? Let's try again, but let's invalidate one of the passed fields,
+ * so that we fallback to the next best thing. */
- key_file = NULL;
- key_data = erase_and_free(key_data);
- key_data_size = 0;
- arg_pkcs11_uri = mfree(arg_pkcs11_uri);
- arg_pkcs11_uri_auto = false;
- arg_fido2_device = mfree(arg_fido2_device);
- arg_fido2_device_auto = false;
- arg_tpm2_device = mfree(arg_tpm2_device);
- arg_tpm2_device_auto = false;
+ if (arg_tpm2_device || arg_tpm2_device_auto) {
+ arg_tpm2_device = mfree(arg_tpm2_device);
+ arg_tpm2_device_auto = false;
+ continue;
+ }
+
+ if (arg_fido2_device || arg_fido2_device_auto) {
+ arg_fido2_device = mfree(arg_fido2_device);
+ arg_fido2_device_auto = false;
+ continue;
+ }
+
+ if (arg_pkcs11_uri || arg_pkcs11_uri_auto) {
+ arg_pkcs11_uri = mfree(arg_pkcs11_uri);
+ arg_pkcs11_uri_auto = false;
+ continue;
+ }
+
+ if (key_data) {
+ key_data = erase_and_free(key_data);
+ key_data_size = 0;
+ continue;
+ }
+
+ if (key_file) {
+ key_file = NULL;
+ continue;
+ }
+
+ if (passwords) {
+ passwords = strv_free_erase(passwords);
+ continue;
+ }
+
+ log_debug("Prepared for next attempt to unlock.");
}
if (arg_tries != 0 && tries >= arg_tries)
@@ -2395,7 +2517,7 @@ static int run(int argc, char *argv[]) {
const char *volume = ASSERT_PTR(argv[optind + 1]);
if (argc - optind >= 3)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach does not accept more than one argument.");
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "detach does not accept more than one argument.");
if (!filename_is_valid(volume))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);