From 79a6b4cc55ace84481a7faecfff8dd36b51b6cda Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Sep 2020 17:55:27 +0200 Subject: [PATCH 1/5] homed-bus: add missing spdx header --- src/home/homed-bus.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/home/homed-bus.c b/src/home/homed-bus.c index 0193089668..a5627d0a1f 100644 --- a/src/home/homed-bus.c +++ b/src/home/homed-bus.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + #include "homed-bus.h" #include "strv.h" From cc9886bc207021fa4b0a4687f1beb88e0457d21e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Sep 2020 17:55:51 +0200 Subject: [PATCH 2/5] homed: make it easier to run multiple instances of homed When debugging homed while being logged into a user account manged by homed it is a good idea to be able to run a second copy of homed. In order to not collide with its AF_UNIX socket and bus name use, let's add a new env var $SYSTEMD_HOME_DEBUG_SUFFIX, when set the busnames/socket names are suffixed by it. When setting this while debugging one can invoke an additional copy without interfering with the host one. --- src/home/homectl.c | 76 +++++++++++++++++++++++++++++----------- src/home/homed-home.c | 10 ++++-- src/home/homed-manager.c | 41 ++++++++++++++++++++-- src/home/homed-manager.h | 1 + src/home/homed-varlink.c | 6 ++-- src/home/homed.c | 3 -- 6 files changed, 107 insertions(+), 30 deletions(-) diff --git a/src/home/homectl.c b/src/home/homectl.c index b83fa837ad..35c98c9d6d 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -74,6 +74,8 @@ STATIC_DESTRUCTOR_REGISTER(arg_identity_filter_rlimits, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_token_uri, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_fido2_device, strv_freep); +static const BusLocator *bus_mgr; + static bool identity_properties_specified(void) { return arg_identity || @@ -117,7 +119,7 @@ static int list_homes(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = bus_call_method(bus, bus_home_mgr, "ListHomes", &error, &reply, NULL); + r = bus_call_method(bus, bus_mgr, "ListHomes", &error, &reply, NULL); if (r < 0) return log_error_errno(r, "Failed to list homes: %s", bus_error_message(&error, r)); @@ -392,7 +394,7 @@ static int activate_home(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ActivateHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "ActivateHome"); if (r < 0) return bus_log_create_error(r); @@ -434,7 +436,7 @@ static int deactivate_home(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "DeactivateHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "DeactivateHome"); if (r < 0) return bus_log_create_error(r); @@ -541,9 +543,9 @@ static int inspect_home(int argc, char *argv[], void *userdata) { continue; } - r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByName", &error, &reply, "s", *i); + r = bus_call_method(bus, bus_mgr, "GetUserRecordByName", &error, &reply, "s", *i); } else - r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByUID", &error, &reply, "u", (uint32_t) uid); + r = bus_call_method(bus, bus_mgr, "GetUserRecordByUID", &error, &reply, "u", (uint32_t) uid); if (r < 0) { log_error_errno(r, "Failed to inspect home: %s", bus_error_message(&error, r)); @@ -617,7 +619,7 @@ static int authenticate_home(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "AuthenticateHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "AuthenticateHome"); if (r < 0) return bus_log_create_error(r); @@ -1139,7 +1141,7 @@ static int create_home(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to format user record: %m"); - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "CreateHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "CreateHome"); if (r < 0) return bus_log_create_error(r); @@ -1191,7 +1193,7 @@ static int remove_home(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "RemoveHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "RemoveHome"); if (r < 0) return bus_log_create_error(r); @@ -1254,7 +1256,7 @@ static int acquire_updated_home_record( if (!identity_properties_specified()) return log_error_errno(SYNTHETIC_ERRNO(EALREADY), "No field to change specified."); - r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByName", &error, &reply, "s", username); + r = bus_call_method(bus, bus_mgr, "GetUserRecordByName", &error, &reply, "s", username); if (r < 0) return log_error_errno(r, "Failed to acquire user home record: %s", bus_error_message(&error, r)); @@ -1372,7 +1374,7 @@ static int update_home(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *formatted = NULL; - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "UpdateHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "UpdateHome"); if (r < 0) return bus_log_create_error(r); @@ -1412,7 +1414,7 @@ static int update_home(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ResizeHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "ResizeHome"); if (r < 0) return bus_log_create_error(r); @@ -1448,7 +1450,7 @@ static int update_home(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ChangePasswordHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "ChangePasswordHome"); if (r < 0) return bus_log_create_error(r); @@ -1522,7 +1524,7 @@ static int passwd_home(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ChangePasswordHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "ChangePasswordHome"); if (r < 0) return bus_log_create_error(r); @@ -1601,7 +1603,7 @@ static int resize_home(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ResizeHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "ResizeHome"); if (r < 0) return bus_log_create_error(r); @@ -1638,7 +1640,7 @@ static int lock_home(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "LockHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "LockHome"); if (r < 0) return bus_log_create_error(r); @@ -1677,7 +1679,7 @@ static int unlock_home(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "UnlockHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "UnlockHome"); if (r < 0) return bus_log_create_error(r); @@ -1740,7 +1742,7 @@ static int with_home(int argc, char *argv[], void *userdata) { return log_oom(); for (;;) { - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "AcquireHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "AcquireHome"); if (r < 0) return bus_log_create_error(r); @@ -1780,7 +1782,7 @@ static int with_home(int argc, char *argv[], void *userdata) { } } - r = bus_call_method(bus, bus_home_mgr, "GetHomeByName", &error, &reply, "s", argv[1]); + r = bus_call_method(bus, bus_mgr, "GetHomeByName", &error, &reply, "s", argv[1]); if (r < 0) return log_error_errno(r, "Failed to inspect home: %s", bus_error_message(&error, r)); @@ -1807,7 +1809,7 @@ static int with_home(int argc, char *argv[], void *userdata) { /* Close the fd that pings the home now. */ acquired_fd = safe_close(acquired_fd); - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ReleaseHome"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "ReleaseHome"); if (r < 0) return bus_log_create_error(r); @@ -1836,7 +1838,7 @@ static int lock_all_homes(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = bus_message_new_method_call(bus, &m, bus_home_mgr, "LockAllHomes"); + r = bus_message_new_method_call(bus, &m, bus_mgr, "LockAllHomes"); if (r < 0) return bus_log_create_error(r); @@ -3294,6 +3296,36 @@ static int parse_argv(int argc, char *argv[]) { return 1; } +static int redirect_bus_mgr(void) { + const char *suffix; + + /* Talk to a different service if that's requested. (The same env var is also understood by homed, so + * that it is relatively easily possible to invoke a second instance of homed for debug purposes and + * have homectl talk to it, without colliding with the host version. This is handy when operating + * from a homed-managed account.) */ + + suffix = getenv("SYSTEMD_HOME_DEBUG_SUFFIX"); + if (suffix) { + static BusLocator locator = { + .path = "/org/freedesktop/home1", + .interface = "org.freedesktop.home1.Manager", + }; + + /* Yes, we leak this memory, but there's little point to collect this, given that we only do + * this in a debug environment, do it only once, and the string shall live for out entire + * process runtime. */ + + locator.destination = strjoin("org.freedesktop.home1.", suffix); + if (!locator.destination) + return log_oom(); + + bus_mgr = &locator; + } else + bus_mgr = bus_home_mgr; + + return 0; +} + static int run(int argc, char *argv[]) { static const Verb verbs[] = { { "help", VERB_ANY, VERB_ANY, 0, help }, @@ -3318,6 +3350,10 @@ static int run(int argc, char *argv[]) { log_setup_cli(); + r = redirect_bus_mgr(); + if (r < 0) + return r; + r = parse_argv(argc, argv); if (r <= 0) return r; diff --git a/src/home/homed-home.c b/src/home/homed-home.c index db88d60c09..c7156c0d50 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -1011,11 +1011,17 @@ static int home_start_work(Home *h, const char *verb, UserRecord *hr, UserRecord if (r < 0) return r; if (r == 0) { - const char *homework; + const char *homework, *suffix, *unix_path; /* Child */ - if (setenv("NOTIFY_SOCKET", "/run/systemd/home/notify", 1) < 0) { + suffix = getenv("SYSTEMD_HOME_DEBUG_SUFFIX"); + if (suffix) + unix_path = strjoina("/run/systemd/home/notify.", suffix); + else + unix_path = "/run/systemd/home/notify"; + + if (setenv("NOTIFY_SOCKET", unix_path, 1) < 0) { log_error_errno(errno, "Failed to set $NOTIFY_SOCKET: %m"); _exit(EXIT_FAILURE); } diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index 9ac375abd6..711f178c55 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -259,6 +259,7 @@ Manager* manager_free(Manager *m) { hashmap_free(m->public_keys); varlink_server_unref(m->varlink_server); + free(m->userdb_service); free(m->default_file_system_type); @@ -910,6 +911,7 @@ int manager_enumerate_images(Manager *m) { } static int manager_connect_bus(Manager *m) { + const char *suffix, *busname; int r; assert(m); @@ -923,7 +925,13 @@ static int manager_connect_bus(Manager *m) { if (r < 0) return r; - r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.home1", 0, NULL, NULL); + suffix = getenv("SYSTEMD_HOME_DEBUG_SUFFIX"); + if (suffix) + busname = strjoina("org.freedesktop.home1.", suffix); + else + busname = "org.freedesktop.home1"; + + r = sd_bus_request_name_async(m->bus, NULL, busname, 0, NULL, NULL); if (r < 0) return log_error_errno(r, "Failed to request name: %m"); @@ -937,6 +945,7 @@ static int manager_connect_bus(Manager *m) { } static int manager_bind_varlink(Manager *m) { + const char *suffix, *socket_path; int r; assert(m); @@ -958,7 +967,15 @@ static int manager_bind_varlink(Manager *m) { (void) mkdir_p("/run/systemd/userdb", 0755); - r = varlink_server_listen_address(m->varlink_server, "/run/systemd/userdb/io.systemd.Home", 0666); + /* To make things easier to debug, when working from a homed managed home directory, let's optionally + * use a different varlink socket name */ + suffix = getenv("SYSTEMD_HOME_DEBUG_SUFFIX"); + if (suffix) + socket_path = strjoina("/run/systemd/userdb/io.systemd.Home.", suffix); + else + socket_path = "/run/systemd/userdb/io.systemd.Home"; + + r = varlink_server_listen_address(m->varlink_server, socket_path, 0666); if (r < 0) return log_error_errno(r, "Failed to bind to varlink socket: %m"); @@ -966,6 +983,15 @@ static int manager_bind_varlink(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to attach varlink connection to event loop: %m"); + assert(!m->userdb_service); + m->userdb_service = strdup(basename(socket_path)); + if (!m->userdb_service) + return log_oom(); + + /* Avoid recursion */ + if (setenv("SYSTEMD_BYPASS_USERDB", m->userdb_service, 1) < 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set $SYSTEMD_BYPASS_USERDB: %m"); + return 0; } @@ -1086,11 +1112,22 @@ static int manager_listen_notify(Manager *m) { .un.sun_family = AF_UNIX, .un.sun_path = "/run/systemd/home/notify", }; + const char *suffix; int r; assert(m); assert(!m->notify_socket_event_source); + suffix = getenv("SYSTEMD_HOME_DEBUG_SUFFIX"); + if (suffix) { + const char *unix_path; + + unix_path = strjoina("/run/systemd/home/notify.", suffix); + r = sockaddr_un_set_path(&sa.un, unix_path); + if (r < 0) + return log_error_errno(r, "Socket path %s does not fit in sockaddr_un: %m", unix_path); + } + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (fd < 0) return log_error_errno(errno, "Failed to create listening socket: %m"); diff --git a/src/home/homed-manager.h b/src/home/homed-manager.h index 83a7144627..c86bf4300b 100644 --- a/src/home/homed-manager.h +++ b/src/home/homed-manager.h @@ -45,6 +45,7 @@ struct Manager { Home *gc_focus; VarlinkServer *varlink_server; + char *userdb_service; EVP_PKEY *private_key; /* actually a pair of private and public key */ Hashmap *public_keys; /* key name [char*] → publick key [EVP_PKEY*] */ diff --git a/src/home/homed-varlink.c b/src/home/homed-varlink.c index 8131a16bc0..dfc615a097 100644 --- a/src/home/homed-varlink.c +++ b/src/home/homed-varlink.c @@ -95,7 +95,7 @@ int vl_method_get_user_record(Varlink *link, JsonVariant *parameters, VarlinkMet if (r < 0) return r; - if (!streq_ptr(p.service, "io.systemd.Home")) + if (!streq_ptr(p.service, m->userdb_service)) return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL); if (uid_is_valid(p.uid)) @@ -210,7 +210,7 @@ int vl_method_get_group_record(Varlink *link, JsonVariant *parameters, VarlinkMe if (r < 0) return r; - if (!streq_ptr(p.service, "io.systemd.Home")) + if (!streq_ptr(p.service, m->userdb_service)) return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL); if (gid_is_valid(p.gid)) @@ -277,7 +277,7 @@ int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, VarlinkMet if (r < 0) return r; - if (!streq_ptr(p.service, "io.systemd.Home")) + if (!streq_ptr(p.service, m->userdb_service)) return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL); if (p.user_name) { diff --git a/src/home/homed.c b/src/home/homed.c index ed8404d7e3..eb5a4a2ea5 100644 --- a/src/home/homed.c +++ b/src/home/homed.c @@ -29,9 +29,6 @@ static int run(int argc, char *argv[]) { umask(0022); - if (setenv("SYSTEMD_BYPASS_USERDB", "io.systemd.Home", 1) < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set $SYSTEMD_BYPASS_USERDB: %m"); - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, -1) >= 0); r = manager_new(&m); From 9796a9fbad5bae4d66bb40d848f6245d1ee327d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Sep 2020 18:53:12 +0200 Subject: [PATCH 3/5] homed: make sure our worker processes finish before we exit When exiting, let's explicitly wait for our worker processes to finish first. That's useful if unmounting of /home/ is scheduled to happen right after homed is down, as we then can be sure that the home directories are properly unmounted and detached by the time homed is fully terminated (otherwise it might happen that our worker gets killed by the service manager, thus leaving the home directory and its backing devices up/left for auto-clean which might be async). Likely fixes #16842 --- src/home/homed-home.c | 13 +++++++++++++ src/home/homed-home.h | 2 ++ src/home/homed-manager.c | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/src/home/homed-home.c b/src/home/homed-home.c index c7156c0d50..5504173545 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -2739,6 +2739,19 @@ int home_set_current_message(Home *h, sd_bus_message *m) { return 1; } +int home_wait_for_worker(Home *h) { + assert(h); + + if (h->worker_pid <= 0) + return 0; + + log_info("Worker process for home %s is still running while exiting. Waiting for it to finish.", h->user_name); + (void) wait_for_terminate(h->worker_pid, NULL); + (void) hashmap_remove_value(h->manager->homes_by_worker_pid, PID_TO_PTR(h->worker_pid), h); + h->worker_pid = 0; + return 1; +} + static const char* const home_state_table[_HOME_STATE_MAX] = { [HOME_UNFIXATED] = "unfixated", [HOME_ABSENT] = "absent", diff --git a/src/home/homed-home.h b/src/home/homed-home.h index b638c6cbb1..97879940df 100644 --- a/src/home/homed-home.h +++ b/src/home/homed-home.h @@ -165,5 +165,7 @@ int home_auto_login(Home *h, char ***ret_seats); int home_set_current_message(Home *h, sd_bus_message *m); +int home_wait_for_worker(Home *h); + const char *home_state_to_string(HomeState state); HomeState home_state_from_string(const char *s); diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index 711f178c55..0490032416 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -232,8 +232,13 @@ int manager_new(Manager **ret) { } Manager* manager_free(Manager *m) { + Home *h; + assert(m); + HASHMAP_FOREACH(h, m->homes_by_worker_pid) + (void) home_wait_for_worker(h); + hashmap_free(m->homes_by_uid); hashmap_free(m->homes_by_name); hashmap_free(m->homes_by_worker_pid); From f9d525ae558105bf7fd77ad76e4fdb135bb9f634 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Sep 2020 19:37:05 +0200 Subject: [PATCH 4/5] homed: make clean that --storage=directory --image-path=/dev/some-block-device is not supported The directory backend needs a file system path, and not a raw block device. That's only supported for the LUKS2 backend. Let's make this clearer in the man page and also generate a better error message if attempted anyway. Fixes: #17068 --- man/homectl.xml | 11 +++++++---- src/home/homed-home.c | 13 ++++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/man/homectl.xml b/man/homectl.xml index 4c792ca8cb..dd16e47beb 100644 --- a/man/homectl.xml +++ b/man/homectl.xml @@ -566,10 +566,13 @@ Takes a file system path. Configures where to place the user's home directory. When LUKS2 storage is used refers to the path to the loopback file, otherwise to the path to the home - directory. When unspecified defaults to /home/$USER.home when LUKS storage is - used and /home/$USER.homedir for the other storage mechanisms. Not defined for - the cifs storage mechanism. To use LUKS2 storage on a regular block device (for - example a USB stick) pass the path to the block device here. + directory (which may be in /home/ or any other accessible filesystem). When + unspecified defaults to /home/$USER.home when LUKS storage is used and + /home/$USER.homedir for the other storage mechanisms. Not defined for the + cifs storage mechanism. To use LUKS2 storage on a regular block device (for + example a USB stick) pass the path to the block device here. Specifying the path to a directory here + when using LUKS2 storage is not allowed. Similar, specifying the path to a regular file or device + node is not allowed if any of the other storage backends are used. diff --git a/src/home/homed-home.c b/src/home/homed-home.c index 5504173545..e4757c724a 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -1280,15 +1280,22 @@ int home_create(Home *h, UserRecord *secret, sd_bus_error *error) { assert(h); switch (home_get_state(h)) { - case HOME_INACTIVE: + case HOME_INACTIVE: { + int t; + if (h->record->storage < 0) break; /* if no storage is defined we don't know what precisely to look for, hence * HOME_INACTIVE is OK in that case too. */ - if (IN_SET(user_record_test_image_path(h->record), USER_TEST_MAYBE, USER_TEST_UNDEFINED)) + t = user_record_test_image_path(h->record); + if (IN_SET(t, USER_TEST_MAYBE, USER_TEST_UNDEFINED)) break; /* And if the image path test isn't conclusive, let's also go on */ - _fallthrough_; + if (IN_SET(t, -EBADFD, -ENOTDIR)) + return sd_bus_error_setf(error, BUS_ERROR_HOME_EXISTS, "Selected home image of user %s already exists or has wrong inode type.", h->user_name); + + return sd_bus_error_setf(error, BUS_ERROR_HOME_EXISTS, "Selected home image of user %s already exists.", h->user_name); + } case HOME_UNFIXATED: case HOME_DIRTY: return sd_bus_error_setf(error, BUS_ERROR_HOME_EXISTS, "Home of user %s already exists.", h->user_name); From c9ef77ec5ff5e7e283181e9dcfb93acfb0656ae6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Sep 2020 22:01:49 +0200 Subject: [PATCH 5/5] units: pass CAP_SYS_RESOURCE to homed The ext4 fs resize ioctl needs CAP_SYS_RESOURCE, irritatingly. Let's grant it to homed hence. Fixes: #15115 --- units/systemd-homed.service.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/units/systemd-homed.service.in b/units/systemd-homed.service.in index 45dc9306dd..7109e0351c 100644 --- a/units/systemd-homed.service.in +++ b/units/systemd-homed.service.in @@ -14,7 +14,7 @@ After=home.mount [Service] BusName=org.freedesktop.home1 -CapabilityBoundingSet=CAP_SYS_ADMIN CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID CAP_SETGID CAP_SETUID +CapabilityBoundingSet=CAP_SYS_ADMIN CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE DeviceAllow=/dev/loop-control rw DeviceAllow=/dev/mapper/control rw DeviceAllow=block-* rw