diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-10-26 11:07:04 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2021-10-28 08:17:46 +0200 |
commit | a23cf7f4c767cd2825ea2384f3d9faea85e2b316 (patch) | |
tree | db0b1f4c6c847ffca8659a47a0c78b0989be8f78 /src/home/homework-luks.c | |
parent | homework: move all LoopDevice handling into HomeSetup too (diff) | |
download | systemd-a23cf7f4c767cd2825ea2384f3d9faea85e2b316.tar.xz systemd-a23cf7f4c767cd2825ea2384f3d9faea85e2b316.zip |
homework: unify similar code for opening existing LUKS DM devices
Let's introduce a new helper acquire_open_luks_device() that combines a
few steps we keep doing at three places into one.
Diffstat (limited to '')
-rw-r--r-- | src/home/homework-luks.c | 159 |
1 files changed, 80 insertions, 79 deletions
diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index 8e0ddd7739..f30acb0c1c 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -384,39 +384,88 @@ static int luks_setup( return 0; } +static int make_dm_names(UserRecord *h, HomeSetup *setup) { + assert(h); + assert(h->user_name); + assert(setup); + + if (!setup->dm_name) { + setup->dm_name = strjoin("home-", h->user_name); + if (!setup->dm_name) + return log_oom(); + } + + if (!setup->dm_node) { + setup->dm_node = path_join("/dev/mapper/", setup->dm_name); + if (!setup->dm_node) + return log_oom(); + } + + return 0; +} + +static int acquire_open_luks_device( + UserRecord *h, + HomeSetup *setup, + bool graceful) { + + _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL; + int r; + + assert(h); + assert(setup); + assert(!setup->crypt_device); + + r = dlopen_cryptsetup(); + if (r < 0) + return r; + + r = make_dm_names(h, setup); + if (r < 0) + return r; + + r = sym_crypt_init_by_name(&cd, setup->dm_name); + if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT) && graceful) + return 0; + if (r < 0) + return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", setup->dm_name); + + cryptsetup_enable_logging(cd); + + setup->crypt_device = TAKE_PTR(cd); + return 1; +} + static int luks_open( - const char *dm_name, - char **passwords, + UserRecord *h, + HomeSetup *setup, const PasswordCache *cache, - struct crypt_device **ret, sd_id128_t *ret_found_uuid, void **ret_volume_key, size_t *ret_volume_key_size) { - _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL; _cleanup_(erase_and_freep) void *vk = NULL; sd_id128_t p; char **list; size_t vks; int r; - assert(dm_name); - assert(ret); + assert(h); + assert(setup); + assert(!setup->crypt_device); /* Opens a LUKS device that is already set up. Re-validates the password while doing so (which also * provides us with the volume key, which we want). */ - r = sym_crypt_init_by_name(&cd, dm_name); + r = acquire_open_luks_device(h, setup, /* graceful= */ false); if (r < 0) - return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name); - - cryptsetup_enable_logging(cd); + return r; - r = sym_crypt_load(cd, CRYPT_LUKS2, NULL); + r = sym_crypt_load(setup->crypt_device, CRYPT_LUKS2, NULL); if (r < 0) return log_error_errno(r, "Failed to load LUKS superblock: %m"); - r = sym_crypt_get_volume_key_size(cd); + r = sym_crypt_get_volume_key_size(setup->crypt_device); if (r <= 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size"); vks = (size_t) r; @@ -424,7 +473,7 @@ static int luks_open( if (ret_found_uuid) { const char *s; - s = sym_crypt_get_uuid(cd); + s = sym_crypt_get_uuid(setup->crypt_device); if (!s) return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock has no UUID."); @@ -441,8 +490,8 @@ static int luks_open( FOREACH_POINTER(list, cache ? cache->pkcs11_passwords : NULL, cache ? cache->fido2_passwords : NULL, - passwords) { - r = luks_try_passwords(cd, list, vk, &vks); + h->password) { + r = luks_try_passwords(setup->crypt_device, list, vk, &vks); if (r != -ENOKEY) break; } @@ -451,18 +500,16 @@ static int luks_open( if (r < 0) return log_error_errno(r, "Failed to unlocks LUKS superblock: %m"); - log_info("Discovered used LUKS device /dev/mapper/%s, and validated password.", dm_name); + log_info("Discovered used LUKS device /dev/mapper/%s, and validated password.", setup->dm_name); /* This is needed so that crypt_resize() can operate correctly for pre-existing LUKS devices. We need * to tell libcryptsetup the volume key explicitly, so that it is in the kernel keyring. */ - r = sym_crypt_activate_by_volume_key(cd, NULL, vk, vks, CRYPT_ACTIVATE_KEYRING_KEY); + r = sym_crypt_activate_by_volume_key(setup->crypt_device, NULL, vk, vks, CRYPT_ACTIVATE_KEYRING_KEY); if (r < 0) return log_error_errno(r, "Failed to upload volume key again: %m"); log_info("Successfully re-activated LUKS device."); - *ret = TAKE_PTR(cd); - if (ret_found_uuid) *ret_found_uuid = p; if (ret_volume_key) @@ -509,26 +556,6 @@ static int fs_validate( return 0; } -static int make_dm_names(UserRecord *h, HomeSetup *setup) { - assert(h); - assert(h->user_name); - assert(setup); - - if (!setup->dm_name) { - setup->dm_name = strjoin("home-", h->user_name); - if (!setup->dm_name) - return log_oom(); - } - - if (!setup->dm_node) { - setup->dm_node = path_join("/dev/mapper/", setup->dm_name); - if (!setup->dm_node) - return log_oom(); - } - - return 0; -} - static int luks_validate( int fd, const char *label, @@ -1171,10 +1198,9 @@ int home_setup_luks( struct loop_info64 info; const char *n; - r = luks_open(setup->dm_name, - h->password, + r = luks_open(h, + setup, cache, - &setup->crypt_device, &found_luks_uuid, &volume_key, &volume_key_size); @@ -1490,21 +1516,13 @@ int home_deactivate_luks(UserRecord *h, HomeSetup *setup) { * don't bother about the loopback device because unlike the DM device it doesn't have a fixed * name. */ - r = dlopen_cryptsetup(); - if (r < 0) - return r; - - r = make_dm_names(h, setup); + r = acquire_open_luks_device(h, setup, /* graceful= */ true); if (r < 0) - return r; - - r = sym_crypt_init_by_name(&setup->crypt_device, setup->dm_name); - if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) { - log_debug_errno(r, "LUKS device %s has already been detached.", setup->dm_name); - we_detached = false; - } else if (r < 0) return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", setup->dm_name); - else { + if (r == 0) { + log_debug("LUKS device %s has already been detached.", setup->dm_name); + we_detached = false; + } else { log_info("Discovered used LUKS device %s.", setup->dm_node); cryptsetup_enable_logging(setup->crypt_device); @@ -3136,25 +3154,17 @@ int home_lock_luks(UserRecord *h, HomeSetup *setup) { assert(setup->root_fd < 0); assert(!setup->crypt_device); - assert_se(p = user_record_home_directory(h)); - setup->root_fd = open(p, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW); - if (setup->root_fd < 0) - return log_error_errno(errno, "Failed to open home directory: %m"); - - r = make_dm_names(h, setup); + r = acquire_open_luks_device(h, setup, /* graceful= */ false); if (r < 0) return r; - r = dlopen_cryptsetup(); - if (r < 0) - return r; + log_info("Discovered used LUKS device %s.", setup->dm_node); - r = sym_crypt_init_by_name(&setup->crypt_device, setup->dm_name); - if (r < 0) - return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", setup->dm_name); + assert_se(p = user_record_home_directory(h)); - log_info("Discovered used LUKS device %s.", setup->dm_node); - cryptsetup_enable_logging(setup->crypt_device); + setup->root_fd = open(p, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW); + if (setup->root_fd < 0) + return log_error_errno(errno, "Failed to open home directory: %m"); if (syncfs(setup->root_fd) < 0) /* Snake oil, but let's better be safe than sorry */ return log_error_errno(errno, "Failed to synchronize file system %s: %m", p); @@ -3210,20 +3220,11 @@ int home_unlock_luks(UserRecord *h, HomeSetup *setup, const PasswordCache *cache assert(setup); assert(!setup->crypt_device); - r = make_dm_names(h, setup); + r = acquire_open_luks_device(h, setup, /* graceful= */ false); if (r < 0) return r; - r = dlopen_cryptsetup(); - if (r < 0) - return r; - - r = sym_crypt_init_by_name(&setup->crypt_device, setup->dm_name); - if (r < 0) - return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", setup->dm_name); - log_info("Discovered used LUKS device %s.", setup->dm_node); - cryptsetup_enable_logging(setup->crypt_device); r = -ENOKEY; FOREACH_POINTER(list, |