]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
homework: move all DM detachment/freeing into HomeSetup
authorLennart Poettering <lennart@poettering.net>
Mon, 25 Oct 2021 19:33:08 +0000 (21:33 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 28 Oct 2021 06:17:46 +0000 (08:17 +0200)
We actually already detach/free the LUKS DM devices for most operations
via HomeSetup, let's move the creation logic to also do this, in order
to unify behaviour between operations.

src/home/homework-luks.c
src/home/homework.c
src/home/homework.h

index c1c67f7ca75ce859b1f24625b789f80f1332339f..fd9baf84a7973632c5f4b4bc25bad9e5f88f266d 100644 (file)
@@ -509,23 +509,23 @@ static int fs_validate(
         return 0;
 }
 
-static int make_dm_names(const char *user_name, char **ret_dm_name, char **ret_dm_node) {
-        _cleanup_free_ char *name = NULL, *node = NULL;
-
-        assert(user_name);
-        assert(ret_dm_name);
-        assert(ret_dm_node);
+static int make_dm_names(UserRecord *h, HomeSetup *setup) {
+        assert(h);
+        assert(h->user_name);
+        assert(setup);
 
-        name = strjoin("home-", user_name);
-        if (!name)
-                return log_oom();
+        if (!setup->dm_name) {
+                setup->dm_name = strjoin("home-", h->user_name);
+                if (!setup->dm_name)
+                        return log_oom();
+        }
 
-        node = path_join("/dev/mapper/", name);
-        if (!node)
-                return log_oom();
+        if (!setup->dm_node) {
+                setup->dm_node = path_join("/dev/mapper/", setup->dm_name);
+                if (!setup->dm_node)
+                        return log_oom();
+        }
 
-        *ret_dm_name = TAKE_PTR(name);
-        *ret_dm_node = TAKE_PTR(node);
         return 0;
 }
 
@@ -1148,10 +1148,8 @@ int home_setup_luks(
         sd_id128_t found_partition_uuid, found_luks_uuid, found_fs_uuid;
         _cleanup_(user_record_unrefp) UserRecord *luks_home = NULL;
         _cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
-        _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
         _cleanup_(erase_and_freep) void *volume_key = NULL;
         _cleanup_close_ int opened_image_fd = -1, root_fd = -1;
-        bool dm_activated = false;
         size_t volume_key_size = 0;
         bool marked_dirty = false;
         uint64_t offset, size;
@@ -1161,6 +1159,7 @@ int home_setup_luks(
         assert(setup);
         assert(setup->dm_name);
         assert(setup->dm_node);
+        assert(!setup->crypt_device);
 
         assert(user_record_storage(h) == USER_LUKS);
 
@@ -1175,18 +1174,18 @@ int home_setup_luks(
                 r = luks_open(setup->dm_name,
                               h->password,
                               cache,
-                              &cd,
+                              &setup->crypt_device,
                               &found_luks_uuid,
                               &volume_key,
                               &volume_key_size);
                 if (r < 0)
                         return r;
 
-                r = luks_validate_home_record(cd, h, volume_key, cache, &luks_home);
+                r = luks_validate_home_record(setup->crypt_device, h, volume_key, cache, &luks_home);
                 if (r < 0)
                         return r;
 
-                n = sym_crypt_get_device_name(cd);
+                n = sym_crypt_get_device_name(setup->crypt_device);
                 if (!n)
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine backing device for DM %s.", setup->dm_name);
 
@@ -1307,16 +1306,16 @@ int home_setup_luks(
                                h->password,
                                cache,
                                user_record_luks_discard(h) || user_record_luks_offline_discard(h),
-                               &cd,
+                               &setup->crypt_device,
                                &found_luks_uuid,
                                &volume_key,
                                &volume_key_size);
                 if (r < 0)
                         return r;
 
-                dm_activated = true;
+                setup->undo_dm = true;
 
-                r = luks_validate_home_record(cd, h, volume_key, cache, &luks_home);
+                r = luks_validate_home_record(setup->crypt_device, h, volume_key, cache, &luks_home);
                 if (r < 0)
                         goto fail;
 
@@ -1354,7 +1353,6 @@ int home_setup_luks(
         }
 
         setup->loop = TAKE_PTR(loop);
-        setup->crypt_device = TAKE_PTR(cd);
         setup->root_fd = TAKE_FD(root_fd);
         setup->found_partition_uuid = found_partition_uuid;
         setup->found_luks_uuid = found_luks_uuid;
@@ -1364,8 +1362,6 @@ int home_setup_luks(
         setup->volume_key = TAKE_PTR(volume_key);
         setup->volume_key_size = volume_key_size;
 
-        setup->undo_dm = dm_activated;
-
         if (ret_luks_home)
                 *ret_luks_home = TAKE_PTR(luks_home);
 
@@ -1373,9 +1369,7 @@ int home_setup_luks(
 
 fail:
         home_setup_undo_mount(setup, LOG_ERR);
-
-        if (dm_activated)
-                (void) sym_crypt_deactivate_by_name(cd, setup->dm_name, 0);
+        home_setup_undo_dm(setup, LOG_ERR);
 
         if (image_fd >= 0 && marked_dirty)
                 (void) run_mark_dirty(image_fd, false);
@@ -1484,8 +1478,6 @@ int home_activate_luks(
 }
 
 int home_deactivate_luks(UserRecord *h, HomeSetup *setup) {
-        _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
-        _cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
         bool we_detached;
         int r;
 
@@ -1503,27 +1495,27 @@ int home_deactivate_luks(UserRecord *h, HomeSetup *setup) {
         if (r < 0)
                 return r;
 
-        r = make_dm_names(h->user_name, &dm_name, &dm_node);
+        r = make_dm_names(h, setup);
         if (r < 0)
                 return r;
 
-        r = sym_crypt_init_by_name(&cd, dm_name);
+        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.", dm_name);
+                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", dm_name);
+                return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", setup->dm_name);
         else {
-                log_info("Discovered used LUKS device %s.", dm_node);
+                log_info("Discovered used LUKS device %s.", setup->dm_node);
 
-                cryptsetup_enable_logging(cd);
+                cryptsetup_enable_logging(setup->crypt_device);
 
-                r = sym_crypt_deactivate_by_name(cd, dm_name, 0);
+                r = sym_crypt_deactivate_by_name(setup->crypt_device, setup->dm_name, 0);
                 if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) {
-                        log_debug_errno(r, "LUKS device %s is already detached.", dm_node);
+                        log_debug_errno(r, "LUKS device %s is already detached.", setup->dm_node);
                         we_detached = false;
                 } else if (r < 0)
-                        return log_info_errno(r, "LUKS device %s couldn't be deactivated: %m", dm_node);
+                        return log_info_errno(r, "LUKS device %s couldn't be deactivated: %m", setup->dm_node);
                 else {
                         log_info("LUKS device detaching completed.");
                         we_detached = true;
@@ -1999,15 +1991,14 @@ int home_create_luks(
                 char **effective_passwords,
                 UserRecord **ret_home) {
 
-        _cleanup_free_ char *dm_name = NULL, *dm_node = NULL, *subdir = NULL, *disk_uuid_path = NULL, *temporary_image_path = NULL;
+        _cleanup_free_ char *subdir = NULL, *disk_uuid_path = NULL, *temporary_image_path = NULL;
         uint64_t encrypted_size,
                 host_size = 0, partition_offset = 0, partition_size = 0; /* Unnecessary initialization to appease gcc */
-        bool image_created = false, dm_activated = false;
         _cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
         sd_id128_t partition_uuid, fs_uuid, luks_uuid, disk_uuid;
         _cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
-        _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
         _cleanup_close_ int image_fd = -1;
+        bool image_created = false;
         const char *fstype, *ip;
         struct statfs sfs;
         int r;
@@ -2065,16 +2056,16 @@ int home_create_luks(
         } else
                 fs_uuid = h->file_system_uuid;
 
-        r = make_dm_names(h->user_name, &dm_name, &dm_node);
+        r = make_dm_names(h, setup);
         if (r < 0)
                 return r;
 
-        r = access(dm_node, F_OK);
+        r = access(setup->dm_node, F_OK);
         if (r < 0) {
                 if (errno != ENOENT)
-                        return log_error_errno(errno, "Failed to determine whether %s exists: %m", dm_node);
+                        return log_error_errno(errno, "Failed to determine whether %s exists: %m", setup->dm_node);
         } else
-                return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "Device mapper device %s already exists, refusing.", dm_node);
+                return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "Device mapper device %s already exists, refusing.", setup->dm_node);
 
         if (path_startswith(ip, "/dev/")) {
                 _cleanup_free_ char *sysfs = NULL;
@@ -2214,34 +2205,34 @@ int home_create_luks(
         log_info("Setting up loopback device %s completed.", loop->node ?: ip);
 
         r = luks_format(loop->node,
-                        dm_name,
+                        setup->dm_name,
                         luks_uuid,
                         user_record_user_name_and_realm(h),
                         cache,
                         effective_passwords,
                         user_record_luks_discard(h) || user_record_luks_offline_discard(h),
                         h,
-                        &cd);
+                        &setup->crypt_device);
         if (r < 0)
                 goto fail;
 
-        dm_activated = true;
+        setup->undo_dm = true;
 
-        r = block_get_size_by_path(dm_node, &encrypted_size);
+        r = block_get_size_by_path(setup->dm_node, &encrypted_size);
         if (r < 0) {
                 log_error_errno(r, "Failed to get encrypted block device size: %m");
                 goto fail;
         }
 
-        log_info("Setting up LUKS device %s completed.", dm_node);
+        log_info("Setting up LUKS device %s completed.", setup->dm_node);
 
-        r = make_filesystem(dm_node, fstype, user_record_user_name_and_realm(h), fs_uuid, user_record_luks_discard(h));
+        r = make_filesystem(setup->dm_node, fstype, user_record_user_name_and_realm(h), fs_uuid, user_record_luks_discard(h));
         if (r < 0)
                 goto fail;
 
         log_info("Formatting file system completed.");
 
-        r = home_unshare_and_mount(dm_node, fstype, user_record_luks_discard(h), user_record_mount_flags(h));
+        r = home_unshare_and_mount(setup->dm_node, fstype, user_record_luks_discard(h), user_record_mount_flags(h));
         if (r < 0)
                 goto fail;
 
@@ -2287,9 +2278,9 @@ int home_create_luks(
                         partition_uuid,
                         luks_uuid,
                         fs_uuid,
-                        sym_crypt_get_cipher(cd),
-                        sym_crypt_get_cipher_mode(cd),
-                        luks_volume_key_size_convert(cd),
+                        sym_crypt_get_cipher(setup->crypt_device),
+                        sym_crypt_get_cipher_mode(setup->crypt_device),
+                        luks_volume_key_size_convert(setup->crypt_device),
                         fstype,
                         NULL,
                         h->uid,
@@ -2311,16 +2302,9 @@ int home_create_luks(
         if (r < 0)
                 goto fail;
 
-        r = sym_crypt_deactivate_by_name(cd, dm_name, 0);
-        if (r < 0) {
-                log_error_errno(r, "Failed to deactivate LUKS device: %m");
+        r = home_setup_undo_dm(setup, LOG_ERR);
+        if (r < 0)
                 goto fail;
-        }
-
-        sym_crypt_free(cd);
-        cd = NULL;
-
-        dm_activated = false;
 
         loop = loop_device_unref(loop);
 
@@ -2374,9 +2358,7 @@ fail:
         /* Let's close all files before we unmount the file system, to avoid EBUSY */
         setup->root_fd = safe_close(setup->root_fd);
         (void) home_setup_undo_mount(setup, LOG_WARNING);
-
-        if (dm_activated)
-                (void) sym_crypt_deactivate_by_name(cd, dm_name, 0);
+        (void) home_setup_undo_dm(setup, LOG_WARNING);
 
         loop = loop_device_unref(loop);
 
@@ -2387,22 +2369,18 @@ fail:
 }
 
 int home_get_state_luks(UserRecord *h, HomeSetup *setup) {
-        _cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
         int r;
 
         assert(h);
         assert(setup);
 
-        r = make_dm_names(h->user_name, &dm_name, &dm_node);
+        r = make_dm_names(h, setup);
         if (r < 0)
                 return r;
 
-        r = access(dm_node, F_OK);
+        r = access(setup->dm_node, F_OK);
         if (r < 0 && errno != ENOENT)
-                return log_error_errno(errno, "Failed to determine whether %s exists: %m", dm_node);
-
-        free_and_replace(setup->dm_name, dm_name);
-        free_and_replace(setup->dm_node, dm_node);
+                return log_error_errno(errno, "Failed to determine whether %s exists: %m", setup->dm_node);
 
         return r >= 0;
 }
@@ -3152,21 +3130,20 @@ int home_passwd_luks(
 }
 
 int home_lock_luks(UserRecord *h, HomeSetup *setup) {
-        _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
-        _cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
         const char *p;
         int r;
 
         assert(h);
         assert(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->user_name, &dm_name, &dm_node);
+        r = make_dm_names(h, setup);
         if (r < 0)
                 return r;
 
@@ -3174,12 +3151,12 @@ int home_lock_luks(UserRecord *h, HomeSetup *setup) {
         if (r < 0)
                 return r;
 
-        r = sym_crypt_init_by_name(&cd, dm_name);
+        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", dm_name);
+                return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", setup->dm_name);
 
-        log_info("Discovered used LUKS device %s.", dm_node);
-        cryptsetup_enable_logging(cd);
+        log_info("Discovered used LUKS device %s.", setup->dm_node);
+        cryptsetup_enable_logging(setup->crypt_device);
 
         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);
@@ -3190,9 +3167,9 @@ int home_lock_luks(UserRecord *h, HomeSetup *setup) {
 
         /* Note that we don't invoke FIFREEZE here, it appears libcryptsetup/device-mapper already does that on its own for us */
 
-        r = sym_crypt_suspend(cd, dm_name);
+        r = sym_crypt_suspend(setup->crypt_device, setup->dm_name);
         if (r < 0)
-                return log_error_errno(r, "Failed to suspend cryptsetup device: %s: %m", dm_node);
+                return log_error_errno(r, "Failed to suspend cryptsetup device: %s: %m", setup->dm_node);
 
         log_info("LUKS device suspended.");
         return 0;
@@ -3228,15 +3205,14 @@ static int luks_try_resume(
 }
 
 int home_unlock_luks(UserRecord *h, HomeSetup *setup, const PasswordCache *cache) {
-        _cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
-        _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
         char **list;
         int r;
 
         assert(h);
         assert(setup);
+        assert(!setup->crypt_device);
 
-        r = make_dm_names(h->user_name, &dm_name, &dm_node);
+        r = make_dm_names(h, setup);
         if (r < 0)
                 return r;
 
@@ -3244,19 +3220,19 @@ int home_unlock_luks(UserRecord *h, HomeSetup *setup, const PasswordCache *cache
         if (r < 0)
                 return r;
 
-        r = sym_crypt_init_by_name(&cd, dm_name);
+        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", dm_name);
+                return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", setup->dm_name);
 
-        log_info("Discovered used LUKS device %s.", dm_node);
-        cryptsetup_enable_logging(cd);
+        log_info("Discovered used LUKS device %s.", setup->dm_node);
+        cryptsetup_enable_logging(setup->crypt_device);
 
         r = -ENOKEY;
         FOREACH_POINTER(list,
                         cache ? cache->pkcs11_passwords : NULL,
                         cache ? cache->fido2_passwords : NULL,
                         h->password) {
-                r = luks_try_resume(cd, dm_name, list);
+                r = luks_try_resume(setup->crypt_device, setup->dm_name, list);
                 if (r != -ENOKEY)
                         break;
         }
index 318ee801dddc16432af661280e4ecfb843869c66..8634a9323047e9e3045580fb0b732706830a9400 100644 (file)
@@ -314,6 +314,32 @@ int home_setup_undo_mount(HomeSetup *setup, int level) {
         return 1;
 }
 
+int home_setup_undo_dm(HomeSetup *setup, int level) {
+        int r, ret;
+
+        assert(setup);
+
+        if (setup->undo_dm) {
+                assert(setup->crypt_device);
+                assert(setup->dm_name);
+
+                r = sym_crypt_deactivate_by_name(setup->crypt_device, setup->dm_name, 0);
+                if (r < 0)
+                        return log_full_errno(level, r, "Failed to deactivate LUKS device: %m");
+
+                setup->undo_dm = false;
+                ret = 1;
+        } else
+                ret = 0;
+
+        if (setup->crypt_device) {
+                sym_crypt_free(setup->crypt_device);
+                setup->crypt_device = NULL;
+        }
+
+        return ret;
+}
+
 int home_setup_done(HomeSetup *setup) {
         int r = 0, q;
 
@@ -336,11 +362,9 @@ int home_setup_done(HomeSetup *setup) {
         if (q < 0)
                 r = q;
 
-        if (setup->undo_dm && setup->crypt_device && setup->dm_name) {
-                q = sym_crypt_deactivate_by_name(setup->crypt_device, setup->dm_name, 0);
-                if (q < 0)
-                        r = q;
-        }
+        q = home_setup_undo_dm(setup, LOG_DEBUG);
+        if (q < 0)
+                r = q;
 
         if (setup->image_fd >= 0) {
                 if (setup->do_offline_fallocate) {
@@ -368,10 +392,6 @@ int home_setup_done(HomeSetup *setup) {
         setup->dm_node = mfree(setup->dm_node);
 
         setup->loop = loop_device_unref(setup->loop);
-        if (setup->crypt_device) {
-                sym_crypt_free(setup->crypt_device);
-                setup->crypt_device = NULL;
-        }
 
         setup->volume_key = erase_and_free(setup->volume_key);
         setup->volume_key_size = 0;
index 1b56fbbd8f1e91912d8a9dfdd853c738d2c3d892..fe8cbb46358d2934abcc01c9a2bfcb35ce333de2 100644 (file)
@@ -76,6 +76,7 @@ typedef enum HomeSetupFlags {
 int home_setup_done(HomeSetup *setup);
 
 int home_setup_undo_mount(HomeSetup *setup, int level);
+int home_setup_undo_dm(HomeSetup *setup, int level);
 
 int home_setup(UserRecord *h, HomeSetupFlags flags, PasswordCache *cache, HomeSetup *setup, UserRecord **ret_header_home);