diff options
Diffstat (limited to 'src/home/homework-fscrypt.c')
-rw-r--r-- | src/home/homework-fscrypt.c | 137 |
1 files changed, 108 insertions, 29 deletions
diff --git a/src/home/homework-fscrypt.c b/src/home/homework-fscrypt.c index 6aae1d2..92ce5c3 100644 --- a/src/home/homework-fscrypt.c +++ b/src/home/homework-fscrypt.c @@ -12,6 +12,7 @@ #include "homework-fscrypt.h" #include "homework-mount.h" #include "homework-quota.h" +#include "keyring-util.h" #include "memory-util.h" #include "missing_keyctl.h" #include "missing_syscall.h" @@ -29,6 +30,98 @@ #include "user-util.h" #include "xattr-util.h" +static int fscrypt_unlink_key(UserRecord *h) { + _cleanup_free_ void *keyring = NULL; + size_t keyring_size = 0, n_keys = 0; + int r; + + assert(h); + assert(user_record_storage(h) == USER_FSCRYPT); + + r = fully_set_uid_gid( + h->uid, + user_record_gid(h), + /* supplementary_gids= */ NULL, + /* n_supplementary_gids= */ 0); + if (r < 0) + return log_error_errno(r, "Failed to change UID/GID to " UID_FMT "/" GID_FMT ": %m", + h->uid, user_record_gid(h)); + + r = keyring_read(KEY_SPEC_USER_KEYRING, &keyring, &keyring_size); + if (r < 0) + return log_error_errno(r, "Failed to read the keyring of user " UID_FMT ": %m", h->uid); + + n_keys = keyring_size / sizeof(key_serial_t); + assert(keyring_size % sizeof(key_serial_t) == 0); + + /* Find any key with a description starting with 'fscrypt:' and unlink it. We need to iterate as we + * store the key with a description that uses the hash of the secret key, that we do not have when + * we are deactivating. */ + FOREACH_ARRAY(key, ((key_serial_t *) keyring), n_keys) { + _cleanup_free_ char *description = NULL; + char *d; + + r = keyring_describe(*key, &description); + if (r < 0) { + if (r == -ENOKEY) /* Something else deleted it already, that's ok. */ + continue; + + return log_error_errno(r, "Failed to describe key id %d: %m", *key); + } + + /* The description is the final element as per manpage. */ + d = strrchr(description, ';'); + if (!d) + return log_error_errno( + SYNTHETIC_ERRNO(EINVAL), + "Failed to parse description of key id %d: %s", + *key, + description); + + if (!startswith(d + 1, "fscrypt:")) + continue; + + r = keyctl(KEYCTL_UNLINK, *key, KEY_SPEC_USER_KEYRING, 0, 0); + if (r < 0) { + if (errno == ENOKEY) /* Something else deleted it already, that's ok. */ + continue; + + return log_error_errno( + errno, + "Failed to delete encryption key with id '%d' from the keyring of user " UID_FMT ": %m", + *key, + h->uid); + } + + log_debug("Deleted encryption key with id '%d' from the keyring of user " UID_FMT ".", *key, h->uid); + } + + return 0; +} + +int home_flush_keyring_fscrypt(UserRecord *h) { + int r; + + assert(h); + assert(user_record_storage(h) == USER_FSCRYPT); + + if (!uid_is_valid(h->uid)) + return 0; + + r = safe_fork("(sd-delkey)", + FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_WAIT|FORK_REOPEN_LOG, + NULL); + if (r < 0) + return r; + if (r == 0) { + if (fscrypt_unlink_key(h) < 0) + _exit(EXIT_FAILURE); + _exit(EXIT_SUCCESS); + } + + return 0; +} + static int fscrypt_upload_volume_key( const uint8_t key_descriptor[static FS_KEY_DESCRIPTOR_SIZE], const void *volume_key, @@ -131,7 +224,7 @@ static int fscrypt_slot_try_one( salt, salt_size, 0xFFFF, EVP_sha512(), sizeof(derived), derived) != 1) - return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "PBKDF2 failed"); + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "PBKDF2 failed."); context = EVP_CIPHER_CTX_new(); if (!context) @@ -212,14 +305,13 @@ static int fscrypt_setup( r = flistxattr_malloc(setup->root_fd, &xattr_buf); if (r < 0) - return log_error_errno(errno, "Failed to retrieve xattr list: %m"); + return log_error_errno(r, "Failed to retrieve xattr list: %m"); NULSTR_FOREACH(xa, xattr_buf) { _cleanup_free_ void *salt = NULL, *encrypted = NULL; _cleanup_free_ char *value = NULL; size_t salt_size, encrypted_size; const char *nr, *e; - char **list; int n; /* Check if this xattr has the format 'trusted.fscrypt_slot<nr>' where '<nr>' is a 32-bit unsigned integer */ @@ -237,31 +329,30 @@ static int fscrypt_setup( e = memchr(value, ':', n); if (!e) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "xattr %s lacks ':' separator: %m", xa); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "xattr %s lacks ':' separator.", xa); - r = unbase64mem(value, e - value, &salt, &salt_size); + r = unbase64mem_full(value, e - value, /* secure = */ false, &salt, &salt_size); if (r < 0) return log_error_errno(r, "Failed to decode salt of %s: %m", xa); - r = unbase64mem(e+1, n - (e - value) - 1, &encrypted, &encrypted_size); + + r = unbase64mem_full(e + 1, n - (e - value) - 1, /* secure = */ false, &encrypted, &encrypted_size); if (r < 0) return log_error_errno(r, "Failed to decode encrypted key of %s: %m", xa); r = -ENOANO; - FOREACH_POINTER(list, cache->pkcs11_passwords, cache->fido2_passwords, password) { + char **list; + FOREACH_ARGUMENT(list, cache->pkcs11_passwords, cache->fido2_passwords, password) { r = fscrypt_slot_try_many( list, salt, salt_size, encrypted, encrypted_size, setup->fscrypt_key_descriptor, ret_volume_key, ret_volume_key_size); - if (r != -ENOANO) - break; - } - if (r < 0) { + if (r >= 0) + return 0; if (r != -ENOANO) return r; - } else - return 0; + } } return log_error_errno(SYNTHETIC_ERRNO(ENOKEY), "Failed to set up home directory with provided passwords."); @@ -319,23 +410,11 @@ int home_setup_fscrypt( if (r < 0) return log_error_errno(r, "Failed install encryption key in user's keyring: %m"); if (r == 0) { - gid_t gid; - /* Child */ - gid = user_record_gid(h); - if (setresgid(gid, gid, gid) < 0) { - log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid); - _exit(EXIT_FAILURE); - } - - if (setgroups(0, NULL) < 0) { - log_error_errno(errno, "Failed to reset auxiliary groups list: %m"); - _exit(EXIT_FAILURE); - } - - if (setresuid(h->uid, h->uid, h->uid) < 0) { - log_error_errno(errno, "Failed to change UID to " UID_FMT ": %m", h->uid); + r = fully_set_uid_gid(h->uid, user_record_gid(h), /* supplementary_gids= */ NULL, /* n_supplementary_gids= */ 0); + if (r < 0) { + log_error_errno(r, "Failed to change UID/GID to " UID_FMT "/" GID_FMT ": %m", h->uid, user_record_gid(h)); _exit(EXIT_FAILURE); } @@ -649,7 +728,7 @@ int home_passwd_fscrypt( r = flistxattr_malloc(setup->root_fd, &xattr_buf); if (r < 0) - return log_error_errno(errno, "Failed to retrieve xattr list: %m"); + return log_error_errno(r, "Failed to retrieve xattr list: %m"); NULSTR_FOREACH(xa, xattr_buf) { const char *nr; |