From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 May 2020 14:57:14 +0000 (+0200) Subject: Merge pull request #15703 from poettering/homed-tweak-default-storage X-Git-Tag: v246-rc1~406 X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fsystemd.git;a=commitdiff_plain;h=f2a8372e37a1e07d5e52a73065b26d96b0e3999e;hp=0328d672f3ad72a4f07fcb23859678b99e352898 Merge pull request #15703 from poettering/homed-tweak-default-storage homed: avoid double encryption --- diff --git a/TODO b/TODO index fda2e67764e..b59ba01208b 100644 --- a/TODO +++ b/TODO @@ -51,11 +51,11 @@ Features: * homed: add a way to "adopt" a home directory, i.e. strip foreign signatures and insert a local signature instead. +* Maybe expose path_is_encrypted() as a new ConditionPathIsEncrypted=? + * busctl: maybe expose a verb "ping" for pinging a dbus service to see if it exists and responds. -* homed: add homed.conf setting DefaultStorage= or so - * homed: maybe pre-create ~/.cache as subvol so that it can have separate quota easily? diff --git a/man/directives-template.xml b/man/directives-template.xml index 5ab0beb4cfa..50380614673 100644 --- a/man/directives-template.xml +++ b/man/directives-template.xml @@ -51,6 +51,15 @@ + + Home Area/User Account directives + + Directives for configuring home areas and user accounts via + systemd-homed.service8. + + + + UDEV directives diff --git a/man/homectl.xml b/man/homectl.xml index 632c8b95bbf..14877a0cde0 100644 --- a/man/homectl.xml +++ b/man/homectl.xml @@ -504,9 +504,9 @@ Selects the storage mechanism to use for this home directory. Takes one of luks, fscrypt, directory, subvolume, cifs. For details about these mechanisms, see - above. If a new home directory is created and the storage type is not specifically specified defaults - to luks if supported, subvolume as first fallback if supported, - and directory if not. + above. If a new home directory is created and the storage type is not specifically specified, + homed.conf5 + defines which default storage to use. @@ -525,9 +525,10 @@ When LUKS2 storage is used configures the file system type to use inside the home directory LUKS2 container. One of ext4, xfs, - btrfs. If not specified defaults to ext4. Note that - xfs is not recommended as its support for file system resizing is too - limited. + btrfs. If not specified + homed.conf5 + defines which default file system type to use. Note that xfs is not recommended as + its support for file system resizing is too limited. @@ -837,6 +838,7 @@ homectl update lafcadio --pkcs11-token-uri=… systemd1, systemd-homed.service8, + homed.conf5, userdbctl1, useradd8, cryptsetup8 diff --git a/man/homed.conf.xml b/man/homed.conf.xml new file mode 100644 index 00000000000..03590feeaa6 --- /dev/null +++ b/man/homed.conf.xml @@ -0,0 +1,84 @@ + + + + + + + homed.conf + systemd + + + + homed.conf + 5 + + + + homed.conf + homed.conf.d + Home area/user account manager configuration files + + + + /etc/systemd/homed.conf + /etc/systemd/homed.conf.d/*.conf + /run/systemd/homed.conf.d/*.conf + /usr/lib/systemd/homed.conf.d/*.conf + + + + Description + + These configuration files control default parameters for home areas/user accounts created and + managed by + systemd-homed.service8. + + + + + + + Options + + The following options are available in the [Home] section: + + + + + DefaultStorage= + The default storage to use for home areas. Takes one of luks, + fscrypt, directory, subvolume, + cifs. For details about these options, see + homectl1. If not + configured or assigned the empty string, the default storage is automatically determined: if not + running in a container enviroment and /home/ is not itself encrypted, defaults + to luks. Otherwise defaults to subvolume if + /home/ is on a btrfs file system, and directory + otherwise. Note that the storage selected on the homectl command line always takes + precedence. + + + + DefaultFileSystemType= + When using luks as storage (see above), selects the default file + system to use inside the user's LUKS volume. Takes one of ext4, + xfs or btrfs. If not specified defaults to + ext4. This setting has no effect if a different storage mechanism is used. The + file system type selected on the homectl command line always takes + precedence. + + + + + + + See Also + + systemd1, + systemd-homed.service8 + + + + diff --git a/man/rules/meson.build b/man/rules/meson.build index 5bbee35e9f8..941e248d72a 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -18,6 +18,7 @@ manpages = [ ['file-hierarchy', '7', [], ''], ['halt', '8', ['poweroff', 'reboot'], ''], ['homectl', '1', [], 'ENABLE_HOMED'], + ['homed.conf', '5', ['homed.conf.d'], 'ENABLE_RESOLVE'], ['hostname', '5', [], ''], ['hostnamectl', '1', [], 'ENABLE_HOSTNAMED'], ['hwdb', '7', [], 'ENABLE_HWDB'], diff --git a/man/systemd-homed.service.xml b/man/systemd-homed.service.xml index a51bd36d410..049b7e9097c 100644 --- a/man/systemd-homed.service.xml +++ b/man/systemd-homed.service.xml @@ -100,6 +100,7 @@ See Also systemd1, + homed.conf5, homectl1, pam_systemd_home8, userdbctl1 diff --git a/meson.build b/meson.build index 97ee0856a04..4c997ab6f7e 100644 --- a/meson.build +++ b/meson.build @@ -1492,6 +1492,7 @@ meson_apply_m4 = find_program('tools/meson-apply-m4.sh') includes = include_directories('src/basic', 'src/boot', + 'src/home', 'src/shared', 'src/systemd', 'src/journal', diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index e16bfef3c3b..e568c706842 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -8,8 +8,10 @@ #include #include "alloc-util.h" +#include "blockdev-util.h" #include "dirent-util.h" #include "fd-util.h" +#include "fileio.h" #include "fs-util.h" #include "locale-util.h" #include "log.h" @@ -1488,3 +1490,26 @@ int open_parent(const char *path, int flags, mode_t mode) { return fd; } + +int path_is_encrypted(const char *path) { + _cleanup_free_ char *uuids = NULL; + char p[SYS_BLOCK_PATH_MAX("/dm/uuid")]; + dev_t devt; + int r; + + r = get_block_device(path, &devt); + if (r < 0) + return r; + if (r == 0) /* doesn't have a block device */ + return false; + + xsprintf_sys_block_path(p, "/dm/uuid", devt); + r = read_one_line_file(p, &uuids); + if (r == -ENOENT) + return false; + if (r < 0) + return r; + + /* The DM device's uuid attribute is prefixed with "CRYPT-" if this is a dm-crypt device. */ + return !!startswith(uuids, "CRYPT-"); +} diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index c2c39c4315d..08892398291 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -122,3 +122,5 @@ int fsync_path_at(int at_fd, const char *path); int syncfs_path(int atfd, const char *path); int open_parent(const char *path, int flags, mode_t mode); + +int path_is_encrypted(const char *path); diff --git a/src/home/home-util.c b/src/home/home-util.c index 51406fd2345..3fd57639f84 100644 --- a/src/home/home-util.c +++ b/src/home/home-util.c @@ -64,6 +64,12 @@ int suitable_image_path(const char *path) { path_is_absolute(path); } +bool supported_fstype(const char *fstype) { + /* Limit the set of supported file systems a bit, as protection against little tested kernel file + * systems. Also, we only support the resize ioctls for these file systems. */ + return STR_IN_SET(fstype, "ext4", "btrfs", "xfs"); +} + int split_user_name_realm(const char *t, char **ret_user_name, char **ret_realm) { _cleanup_free_ char *user_name = NULL, *realm = NULL; const char *c; diff --git a/src/home/home-util.h b/src/home/home-util.h index df20c0af71e..78d6e7b4176 100644 --- a/src/home/home-util.h +++ b/src/home/home-util.h @@ -12,6 +12,8 @@ bool suitable_user_name(const char *name); int suitable_realm(const char *realm); int suitable_image_path(const char *path); +bool supported_fstype(const char *fstype); + int split_user_name_realm(const char *t, char **ret_user_name, char **ret_realm); int bus_message_append_secret(sd_bus_message *m, UserRecord *secret); diff --git a/src/home/homed-conf.c b/src/home/homed-conf.c new file mode 100644 index 00000000000..14ec8b336d4 --- /dev/null +++ b/src/home/homed-conf.c @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "conf-parser.h" +#include "def.h" +#include "home-util.h" +#include "homed-conf.h" + +int manager_parse_config_file(Manager *m) { + int r; + + assert(m); + + r = config_parse_many_nulstr(PKGSYSCONFDIR "/homed.conf", + CONF_PATHS_NULSTR("systemd/homed.conf.d"), + "Home\0", + config_item_perf_lookup, homed_gperf_lookup, + CONFIG_PARSE_WARN, m); + if (r < 0) + return r; + + return 0; + +} + +DEFINE_CONFIG_PARSE_ENUM(config_parse_default_storage, user_storage, UserStorage, "Failed to parse default storage setting"); + +int config_parse_default_file_system_type( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char **s = data; + + assert(rvalue); + assert(s); + + if (!isempty(rvalue) && !supported_fstype(rvalue)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Unsupported file system, ignoring: %s", rvalue); + return 0; + } + + return free_and_strdup_warn(s, empty_to_null(rvalue)); + +} diff --git a/src/home/homed-conf.h b/src/home/homed-conf.h new file mode 100644 index 00000000000..00eb3fdb684 --- /dev/null +++ b/src/home/homed-conf.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "conf-parser.h" +#include "homed-manager.h" + +int manager_parse_config_file(Manager *m); + +const struct ConfigPerfItem* homed_gperf_lookup(const char *key, GPERF_LEN_TYPE length); + +CONFIG_PARSER_PROTOTYPE(config_parse_default_storage); +CONFIG_PARSER_PROTOTYPE(config_parse_default_file_system_type); diff --git a/src/home/homed-gperf.gperf b/src/home/homed-gperf.gperf new file mode 100644 index 00000000000..970da5f7902 --- /dev/null +++ b/src/home/homed-gperf.gperf @@ -0,0 +1,21 @@ +%{ +#if __GNUC__ >= 7 +_Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") +#endif +#include +#include "conf-parser.h" +#include "homed-conf.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name homed_gperf_hash +%define lookup-function-name homed_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +Home.DefaultStorage, config_parse_default_storage, 0, offsetof(Manager, default_storage) +Home.DefaultFileSystemType, config_parse_default_file_system_type, 0, offsetof(Manager, default_file_system_type) diff --git a/src/home/homed-home.c b/src/home/homed-home.c index 07356e60c4f..65e363c23c1 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -1011,6 +1011,18 @@ static int home_start_work(Home *h, const char *verb, UserRecord *hr, UserRecord _exit(EXIT_FAILURE); } + if (h->manager->default_storage >= 0) + if (setenv("SYSTEMD_HOME_DEFAULT_STORAGE", user_storage_to_string(h->manager->default_storage), 1) < 0) { + log_error_errno(errno, "Failed to set $SYSTEMD_HOME_DEFAULT_STORAGE: %m"); + _exit(EXIT_FAILURE); + } + + if (h->manager->default_file_system_type) + if (setenv("SYSTEMD_HOME_DEFAULT_FILE_SYSTEM_TYPE", h->manager->default_file_system_type, 1) < 0) { + log_error_errno(errno, "Failed to set $SYSTEMD_HOME_DEFAULT_FILE_SYSTEM_TYPE: %m"); + _exit(EXIT_FAILURE); + } + r = rearrange_stdio(stdin_fd, stdout_fd, STDERR_FILENO); if (r < 0) { log_error_errno(r, "Failed to rearrange stdin/stdout/stderr: %m"); diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index 70673fc84d6..df0ed2f4f36 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -24,6 +24,7 @@ #include "fs-util.h" #include "gpt.h" #include "home-util.h" +#include "homed-conf.h" #include "homed-home-bus.h" #include "homed-home.h" #include "homed-manager-bus.h" @@ -184,10 +185,18 @@ int manager_new(Manager **ret) { assert(ret); - m = new0(Manager, 1); + m = new(Manager, 1); if (!m) return -ENOMEM; + *m = (Manager) { + .default_storage = _USER_STORAGE_INVALID, + }; + + r = manager_parse_config_file(m); + if (r < 0) + return r; + r = sd_event_default(&m->event); if (r < 0) return r; @@ -251,6 +260,8 @@ Manager* manager_free(Manager *m) { varlink_server_unref(m->varlink_server); + free(m->default_file_system_type); + return mfree(m); } diff --git a/src/home/homed-manager.h b/src/home/homed-manager.h index 6deffb0d26b..83a71446279 100644 --- a/src/home/homed-manager.h +++ b/src/home/homed-manager.h @@ -28,6 +28,8 @@ struct Manager { Hashmap *homes_by_sysfs; bool scan_slash_home; + UserStorage default_storage; + char *default_file_system_type; sd_event_source *inotify_event_source; diff --git a/src/home/homed.conf b/src/home/homed.conf new file mode 100644 index 00000000000..a8a48fe5939 --- /dev/null +++ b/src/home/homed.conf @@ -0,0 +1,16 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# Entries in this file show the compile time defaults. +# You can change settings by editing this file. +# Defaults can be restored by simply deleting this file. +# +# See homed.conf(5) for details + +[Resolve] +#DefaultStorage= +#DefaultFileSystemType=ext4 diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index 694f215b30d..caa4168265a 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -16,6 +16,7 @@ #include "fileio.h" #include "fs-util.h" #include "fsck-util.h" +#include "home-util.h" #include "homework-luks.h" #include "homework-mount.h" #include "id128-util.h" @@ -39,12 +40,6 @@ * strictly round disk sizes down to the next 1K boundary.*/ #define DISK_SIZE_ROUND_DOWN(x) ((x) & ~UINT64_C(1023)) -static bool supported_fstype(const char *fstype) { - /* Limit the set of supported file systems a bit, as protection against little tested kernel file - * systems. Also, we only support the resize ioctls for these file systems. */ - return STR_IN_SET(fstype, "ext4", "btrfs", "xfs"); -} - static int probe_file_system_by_fd( int fd, char **ret_fstype, diff --git a/src/home/homework.c b/src/home/homework.c index 77afc402d38..71e7cfdb499 100644 --- a/src/home/homework.c +++ b/src/home/homework.c @@ -7,6 +7,7 @@ #include "copy.h" #include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "home-util.h" #include "homework-cifs.h" #include "homework-directory.h" @@ -862,9 +863,68 @@ static int user_record_compile_effective_passwords( return 0; } +static int determine_default_storage(UserStorage *ret) { + UserStorage storage = _USER_STORAGE_INVALID; + const char *e; + int r; + + assert(ret); + + /* homed tells us via an environment variable which default storage to use */ + e = getenv("SYSTEMD_HOME_DEFAULT_STORAGE"); + if (e) { + storage = user_storage_from_string(e); + if (storage < 0) + log_warning("$SYSTEMD_HOME_DEFAULT_STORAGE set to invalid storage type, ignoring: %s", e); + else { + log_info("Using configured default storage '%s'.", user_storage_to_string(storage)); + *ret = storage; + return 0; + } + } + + /* When neither user nor admin specified the storage type to use, fix it to be LUKS — unless we run + * in a container where loopback devices and LUKS/DM are not available. Also, if /home is encrypted + * anyway, let's avoid duplicate encryption. Note that we typically default to the assumption of + * "classic" storage for most operations. However, if we create a new home, then let's user LUKS if + * nothing is specified. */ + + r = detect_container(); + if (r < 0) + return log_error_errno(r, "Failed to determine whether we are in a container: %m"); + if (r == 0) { + r = path_is_encrypted("/home"); + if (r < 0) + log_warning_errno(r, "Failed to determine if /home is encrypted, ignoring: %m"); + if (r <= 0) { + log_info("Using automatic default storage of '%s'.", user_storage_to_string(USER_LUKS)); + *ret = USER_LUKS; + return 0; + } + + log_info("/home is encrypted, not using '%s' storage, in order to avoid double encryption.", user_storage_to_string(USER_LUKS)); + } else + log_info("Running in container, not using '%s' storage.", user_storage_to_string(USER_LUKS)); + + r = path_is_fs_type("/home", BTRFS_SUPER_MAGIC); + if (r < 0) + log_warning_errno(r, "Failed to determine file system of /home, ignoring: %m"); + if (r > 0) { + log_info("/home is on btrfs, using '%s' as storage.", user_storage_to_string(USER_SUBVOLUME)); + *ret = USER_SUBVOLUME; + } else { + log_info("/home is on simple file system, using '%s' as storage.", user_storage_to_string(USER_DIRECTORY)); + *ret = USER_DIRECTORY; + } + + return 0; +} + static int home_create(UserRecord *h, UserRecord **ret_home) { _cleanup_(strv_free_erasep) char **effective_passwords = NULL, **pkcs11_decrypted_passwords = NULL; _cleanup_(user_record_unrefp) UserRecord *new_home = NULL; + UserStorage new_storage = _USER_STORAGE_INVALID; + const char *new_fs = NULL; int r; assert(h); @@ -884,27 +944,18 @@ static int home_create(UserRecord *h, UserRecord **ret_home) { if (r != USER_TEST_ABSENT) return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "Home directory %s already exists, refusing.", user_record_home_directory(h)); - /* When the user didn't specify the storage type to use, fix it to be LUKS -- unless we run in a - * container where loopback devices and LUKS/DM are not available. Note that we typically default to - * the assumption of "classic" storage for most operations. However, if we create a new home, then - * let's user LUKS if nothing is specified. */ if (h->storage < 0) { - UserStorage new_storage; - - r = detect_container(); + r = determine_default_storage(&new_storage); if (r < 0) - return log_error_errno(r, "Failed to determine whether we are in a container: %m"); - if (r > 0) { - new_storage = USER_DIRECTORY; - - r = path_is_fs_type("/home", BTRFS_SUPER_MAGIC); - if (r < 0) - log_debug_errno(r, "Failed to determine file system of /home, ignoring: %m"); + return r; + } - new_storage = r > 0 ? USER_SUBVOLUME : USER_DIRECTORY; - } else - new_storage = USER_LUKS; + if ((h->storage == USER_LUKS || + (h->storage < 0 && new_storage == USER_LUKS)) && + !h->file_system_type) + new_fs = getenv("SYSTEMD_HOME_DEFAULT_FILE_SYSTEM_TYPE"); + if (new_storage >= 0 || new_fs) { r = user_record_add_binding( h, new_storage, @@ -915,18 +966,12 @@ static int home_create(UserRecord *h, UserRecord **ret_home) { NULL, NULL, UINT64_MAX, - NULL, + new_fs, NULL, UID_INVALID, GID_INVALID); if (r < 0) return log_error_errno(r, "Failed to change storage type to LUKS: %m"); - - if (!h->image_path_auto) { - h->image_path_auto = strjoin("/home/", user_record_user_name_and_realm(h), new_storage == USER_LUKS ? ".home" : ".homedir"); - if (!h->image_path_auto) - return log_oom(); - } } r = user_record_test_image_path_and_warn(h); diff --git a/src/home/meson.build b/src/home/meson.build index eb6da0b6969..2c5664aae1d 100644 --- a/src/home/meson.build +++ b/src/home/meson.build @@ -31,6 +31,8 @@ systemd_homed_sources = files(''' home-util.h homed-bus.c homed-bus.h + homed-conf.c + homed-conf.h homed-home-bus.c homed-home-bus.h homed-home.c @@ -52,6 +54,14 @@ systemd_homed_sources = files(''' user-record-util.h '''.split()) +homed_gperf_c = custom_target( + 'homed_gperf.c', + input : 'homed-gperf.gperf', + output : 'homed-gperf.c', + command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) + +systemd_homed_sources += [homed_gperf_c] + homectl_sources = files(''' home-util.c home-util.h @@ -78,4 +88,7 @@ if conf.get('ENABLE_HOMED') == 1 install_dir : dbussystemservicedir) install_data('org.freedesktop.home1.policy', install_dir : polkitpolicydir) + + install_data('homed.conf', + install_dir : pkgsysconfdir) endif diff --git a/src/home/user-record-util.c b/src/home/user-record-util.c index 430a952e6f7..8f51f8d6e82 100644 --- a/src/home/user-record-util.c +++ b/src/home/user-record-util.c @@ -276,7 +276,7 @@ int user_record_add_binding( _cleanup_(json_variant_unrefp) JsonVariant *new_binding_entry = NULL, *binding = NULL; char smid[SD_ID128_STRING_MAX], partition_uuids[37], luks_uuids[37], fs_uuids[37]; - _cleanup_free_ char *ip = NULL, *hd = NULL; + _cleanup_free_ char *ip = NULL, *hd = NULL, *ip_auto = NULL, *lc = NULL, *lcm = NULL, *fst = NULL; sd_id128_t mid; int r; @@ -294,6 +294,10 @@ int user_record_add_binding( ip = strdup(image_path); if (!ip) return -ENOMEM; + } else if (!h->image_path && storage >= 0) { + r = user_record_build_image_path(storage, user_record_user_name_and_realm(h), &ip_auto); + if (r < 0) + return r; } if (home_directory) { @@ -302,6 +306,24 @@ int user_record_add_binding( return -ENOMEM; } + if (file_system_type) { + fst = strdup(file_system_type); + if (!fst) + return -ENOMEM; + } + + if (luks_cipher) { + lc = strdup(luks_cipher); + if (!lc) + return -ENOMEM; + } + + if (luks_cipher_mode) { + lcm = strdup(luks_cipher_mode); + if (!lcm) + return -ENOMEM; + } + r = json_build(&new_binding_entry, JSON_BUILD_OBJECT( JSON_BUILD_PAIR_CONDITION(!!image_path, "imagePath", JSON_BUILD_STRING(image_path)), @@ -348,6 +370,8 @@ int user_record_add_binding( if (ip) free_and_replace(h->image_path, ip); + if (ip_auto) + free_and_replace(h->image_path_auto, ip_auto); if (!sd_id128_is_null(partition_uuid)) h->partition_uuid = partition_uuid; @@ -358,11 +382,22 @@ int user_record_add_binding( if (!sd_id128_is_null(fs_uuid)) h->file_system_uuid = fs_uuid; + if (lc) + free_and_replace(h->luks_cipher, lc); + if (lcm) + free_and_replace(h->luks_cipher_mode, lcm); + if (luks_volume_key_size != UINT64_MAX) + h->luks_volume_key_size = luks_volume_key_size; + + if (fst) + free_and_replace(h->file_system_type, fst); if (hd) free_and_replace(h->home_directory, hd); if (uid_is_valid(uid)) h->uid = uid; + if (gid_is_valid(gid)) + h->gid = gid; h->mask |= USER_RECORD_BINDING; return 1; diff --git a/src/shared/user-record.c b/src/shared/user-record.c index f6483112087..83d86f69e76 100644 --- a/src/shared/user-record.c +++ b/src/shared/user-record.c @@ -1059,7 +1059,34 @@ static int dispatch_status(const char *name, JsonVariant *variant, JsonDispatchF return json_dispatch(m, status_dispatch_table, NULL, flags, userdata); } +int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret) { + const char *suffix; + char *z; + + assert(storage >= 0); + assert(user_name_and_realm); + assert(ret); + + if (storage == USER_LUKS) + suffix = ".home"; + else if (IN_SET(storage, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT)) + suffix = ".homedir"; + else { + *ret = NULL; + return 0; + } + + z = strjoin("/home/", user_name_and_realm, suffix); + if (!z) + return -ENOMEM; + + *ret = z; + return 1; +} + static int user_record_augment(UserRecord *h, JsonDispatchFlags json_flags) { + int r; + assert(h); if (!FLAGS_SET(h->mask, USER_RECORD_REGULAR)) @@ -1084,22 +1111,9 @@ static int user_record_augment(UserRecord *h, JsonDispatchFlags json_flags) { } if (!h->image_path && !h->image_path_auto) { - const char *suffix; - UserStorage storage; - - storage = user_record_storage(h); - if (storage == USER_LUKS) - suffix = ".home"; - else if (IN_SET(storage, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT)) - suffix = ".homedir"; - else - suffix = NULL; - - if (suffix) { - h->image_path_auto = strjoin("/home/", user_record_user_name_and_realm(h), suffix); - if (!h->image_path_auto) - return json_log_oom(h->json, json_flags); - } + r = user_record_build_image_path(user_record_storage(h), user_record_user_name_and_realm(h), &h->image_path_auto); + if (r < 0) + return json_log(h->json, json_flags, r, "Failed to determine default image path: %m"); } return 0; diff --git a/src/shared/user-record.h b/src/shared/user-record.h index 83c5a71d4e7..9fd10610d92 100644 --- a/src/shared/user-record.h +++ b/src/shared/user-record.h @@ -349,6 +349,8 @@ usec_t user_record_ratelimit_interval_usec(UserRecord *h); uint64_t user_record_ratelimit_burst(UserRecord *h); bool user_record_can_authenticate(UserRecord *h); +int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret); + bool user_record_equal(UserRecord *a, UserRecord *b); bool user_record_compatible(UserRecord *a, UserRecord *b); int user_record_compare_last_change(UserRecord *a, UserRecord *b); diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index d97ccfda3bc..d005b3e8e5f 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -846,6 +846,28 @@ static void test_chmod_and_chown_unsafe(void) { assert_se(S_ISLNK(st.st_mode)); } +static void test_path_is_encrypted_one(const char *p, int expect) { + int r; + + r = path_is_encrypted(p); + assert_se(r >= 0); + + printf("%s encrypted: %s\n", p, yes_no(r)); + + assert_se(expect < 0 || ((r > 0) == (expect > 0))); +} + +static void test_path_is_encrypted(void) { + log_info("/* %s */", __func__); + + test_path_is_encrypted_one("/home", -1); + test_path_is_encrypted_one("/var", -1); + test_path_is_encrypted_one("/", -1); + test_path_is_encrypted_one("/proc", false); + test_path_is_encrypted_one("/sys", false); + test_path_is_encrypted_one("/dev", false); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_INFO); @@ -864,6 +886,7 @@ int main(int argc, char *argv[]) { test_rename_noreplace(); test_chmod_and_chown(); test_chmod_and_chown_unsafe(); + test_path_is_encrypted(); return 0; }