diff --git a/TODO b/TODO index 776c90f12e..f670370a8e 100644 --- a/TODO +++ b/TODO @@ -226,9 +226,6 @@ Features: * introduce a new group to own TPM devices -* cryptenroll: politely refuse enrolling new keys to homed volumes, since we - we cannot update identity info - * cryptsetup: if only recovery keys are registered and no regular passphrases, ask user for "recovery key", not "passphrase" diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c index cf99aab96d..c9bc9a2489 100644 --- a/src/cryptenroll/cryptenroll.c +++ b/src/cryptenroll/cryptenroll.c @@ -381,6 +381,28 @@ static int parse_argv(int argc, char *argv[]) { return 1; } +static int check_for_homed(struct crypt_device *cd) { + int r; + + assert_se(cd); + + /* Politely refuse operating on homed volumes. The enrolled tokens for the user record and the LUKS2 + * volume should not get out of sync. */ + + for (int token = 0; token < crypt_token_max(CRYPT_LUKS2); token ++) { + r = cryptsetup_get_token_as_json(cd, token, "systemd-homed", NULL); + if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE)) + continue; + if (r < 0) + return log_error_errno(r, "Failed to read JSON token data off disk: %m"); + + return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN), + "LUKS2 volume is managed by systemd-homed, please use homectl to enroll tokens."); + } + + return 0; +} + static int prepare_luks( struct crypt_device **ret_cd, void **ret_volume_key, @@ -405,6 +427,10 @@ static int prepare_luks( if (r < 0) return log_error_errno(r, "Failed to load LUKS2 superblock: %m"); + r = check_for_homed(cd); + if (r < 0) + return r; + if (!ret_volume_key) { *ret_cd = TAKE_PTR(cd); return 0; diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index 8af9223d57..c9c2476ed6 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -698,7 +698,7 @@ static int luks_validate_home_record( assert(cd); assert(h); - for (int token = 0;; token++) { + for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token++) { _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *rr = NULL; _cleanup_(EVP_CIPHER_CTX_freep) EVP_CIPHER_CTX *context = NULL; _cleanup_(user_record_unrefp) UserRecord *lhr = NULL; @@ -894,7 +894,7 @@ int home_store_header_identity_luks( _cleanup_(user_record_unrefp) UserRecord *header_home = NULL; _cleanup_free_ char *text = NULL; - int token = 0, r; + int r; assert(h); @@ -924,7 +924,7 @@ int home_store_header_identity_luks( if (r < 0) return r; - for (;; token++) { + for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token++) { crypt_token_info state; const char *type; @@ -946,7 +946,6 @@ int home_store_header_identity_luks( /* Now, let's free the text so that for all further matching tokens we all crypt_json_token_set() * with a NULL text in order to invalidate the tokens. */ text = mfree(text); - token++; } if (text) diff --git a/src/shared/cryptsetup-util.h b/src/shared/cryptsetup-util.h index 1bf9830a7d..ff44af8441 100644 --- a/src/shared/cryptsetup-util.h +++ b/src/shared/cryptsetup-util.h @@ -54,11 +54,12 @@ extern int (*sym_crypt_token_json_set)(struct crypt_device *cd, int token, const extern int (*sym_crypt_token_max)(const char *type); #else /* As a fallback, use the same hard-coded value libcryptsetup uses internally. */ -static inline int sym_crypt_token_max(_unused_ const char *type) { +static inline int crypt_token_max(_unused_ const char *type) { assert(streq(type, CRYPT_LUKS2)); return 32; } +#define sym_crypt_token_max(type) crypt_token_max(type) #endif extern crypt_token_info (*sym_crypt_token_status)(struct crypt_device *cd, int token, const char **type); extern int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);