From 2700fecdb33058a4a6119880978f92a01499f31a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Oct 2021 22:20:25 +0200 Subject: [PATCH] homed: allow overriding the root directory for home dirs via env var (i.e. use a different path than /home/) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This is a debugging feature. It's sometimes incredibly useful to be able to run a second instance of homed that operates on another dir than /home/. Specifically, if you build homed from the source tree you can now run an instance of it pretty reasonably directly from the build tree via: sudo SYSTEMD_HOME_DEBUG_SUFFIX=foo SYSTEMD_HOMEWORK_PATH=$(pwd)/build/systemd-homework SYSTEMD_HOME_ROOT=/home/foo ./build/systemd-homed And then talk to it via sudo SYSTEMD_HOME_DEBUG_SUFFIX=foo homectl … (you might need to tweak your dbus policy for this to work fully though) --- src/basic/user-util.c | 11 ++++++++ src/basic/user-util.h | 2 ++ src/home/homed-manager.c | 53 +++++++++++++++++++++---------------- src/home/homework.c | 14 +++++----- src/home/user-record-util.c | 2 +- src/shared/user-record.c | 6 ++--- 6 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 385ec514b41..aee2d9dc595 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -1085,3 +1085,14 @@ int is_this_me(const char *username) { return uid == getuid(); } + +const char *get_home_root(void) { + const char *e; + + /* For debug purposes allow overriding where we look for home dirs */ + e = secure_getenv("SYSTEMD_HOME_ROOT"); + if (e && path_is_absolute(e) && path_is_normalized(e)) + return e; + + return "/home"; +} diff --git a/src/basic/user-util.h b/src/basic/user-util.h index fd00b47b766..ab1ce48b2df 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -112,6 +112,8 @@ bool is_nologin_shell(const char *shell); int is_this_me(const char *username); +const char *get_home_root(void); + /* A locked *and* invalid password for "struct spwd"'s .sp_pwdp and "struct passwd"'s .pw_passwd field */ #define PASSWORD_LOCKED_AND_INVALID "!*" diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index 39782304f64..38283ff1ede 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -83,35 +83,38 @@ static void manager_watch_home(Manager *m) { m->inotify_event_source = sd_event_source_disable_unref(m->inotify_event_source); m->scan_slash_home = false; - if (statfs("/home/", &sfs) < 0) { + if (statfs(get_home_root(), &sfs) < 0) { log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, - "Failed to statfs() /home/ directory, disabling automatic scanning."); + "Failed to statfs() %s directory, disabling automatic scanning.", get_home_root()); return; } if (is_network_fs(&sfs)) { - log_info("/home/ is a network file system, disabling automatic scanning."); + log_info("%s is a network file system, disabling automatic scanning.", get_home_root()); return; } if (is_fs_type(&sfs, AUTOFS_SUPER_MAGIC)) { - log_info("/home/ is on autofs, disabling automatic scanning."); + log_info("%s is on autofs, disabling automatic scanning.", get_home_root()); return; } m->scan_slash_home = true; - r = sd_event_add_inotify(m->event, &m->inotify_event_source, "/home/", + r = sd_event_add_inotify(m->event, &m->inotify_event_source, get_home_root(), IN_CREATE|IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF|IN_ONLYDIR|IN_MOVED_TO|IN_MOVED_FROM|IN_DELETE, on_home_inotify, m); if (r < 0) log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, - "Failed to create inotify watch on /home/, ignoring."); + "Failed to create inotify watch on %s, ignoring.", get_home_root()); (void) sd_event_source_set_description(m->inotify_event_source, "home-inotify"); + + log_info("Watching %s.", get_home_root()); } static int on_home_inotify(sd_event_source *s, const struct inotify_event *event, void *userdata) { + _cleanup_free_ char *j = NULL; Manager *m = userdata; const char *e, *n; @@ -121,15 +124,15 @@ static int on_home_inotify(sd_event_source *s, const struct inotify_event *event if ((event->mask & (IN_Q_OVERFLOW|IN_MOVE_SELF|IN_DELETE_SELF|IN_IGNORED|IN_UNMOUNT)) != 0) { if (FLAGS_SET(event->mask, IN_Q_OVERFLOW)) - log_debug("/home/ inotify queue overflow, rescanning."); + log_debug("%s inotify queue overflow, rescanning.", get_home_root()); else if (FLAGS_SET(event->mask, IN_MOVE_SELF)) - log_info("/home/ moved or renamed, recreating watch and rescanning."); + log_info("%s moved or renamed, recreating watch and rescanning.", get_home_root()); else if (FLAGS_SET(event->mask, IN_DELETE_SELF)) - log_info("/home/ deleted, recreating watch and rescanning."); + log_info("%s deleted, recreating watch and rescanning.", get_home_root()); else if (FLAGS_SET(event->mask, IN_UNMOUNT)) - log_info("/home/ unmounted, recreating watch and rescanning."); + log_info("%s unmounted, recreating watch and rescanning.", get_home_root()); else if (FLAGS_SET(event->mask, IN_IGNORED)) - log_info("/home/ watch invalidated, recreating watch and rescanning."); + log_info("%s watch invalidated, recreating watch and rescanning.", get_home_root()); manager_watch_home(m); (void) manager_gc_images(m); @@ -150,15 +153,19 @@ static int on_home_inotify(sd_event_source *s, const struct inotify_event *event if (!suitable_user_name(n)) return 0; + j = path_join(get_home_root(), event->name); + if (!j) + return log_oom(); + if ((event->mask & (IN_CREATE|IN_CLOSE_WRITE|IN_MOVED_TO)) != 0) { if (FLAGS_SET(event->mask, IN_CREATE)) - log_debug("/home/%s has been created, having a look.", event->name); + log_debug("%s has been created, having a look.", j); else if (FLAGS_SET(event->mask, IN_CLOSE_WRITE)) - log_debug("/home/%s has been modified, having a look.", event->name); + log_debug("%s has been modified, having a look.", j); else if (FLAGS_SET(event->mask, IN_MOVED_TO)) - log_debug("/home/%s has been moved in, having a look.", event->name); + log_debug("%s has been moved in, having a look.", j); - (void) manager_assess_image(m, -1, "/home/", event->name); + (void) manager_assess_image(m, -1, get_home_root(), event->name); (void) bus_manager_emit_auto_login_changed(m); } @@ -166,11 +173,11 @@ static int on_home_inotify(sd_event_source *s, const struct inotify_event *event Home *h; if (FLAGS_SET(event->mask, IN_DELETE)) - log_debug("/home/%s has been deleted, revalidating.", event->name); + log_debug("%s has been deleted, revalidating.", j); else if (FLAGS_SET(event->mask, IN_CLOSE_WRITE)) - log_debug("/home/%s has been closed after writing, revalidating.", event->name); + log_debug("%s has been closed after writing, revalidating.", j); else if (FLAGS_SET(event->mask, IN_MOVED_FROM)) - log_debug("/home/%s has been moved away, revalidating.", event->name); + log_debug("%s has been moved away, revalidating.", j); h = hashmap_get(m->homes_by_name, n); if (h) { @@ -487,7 +494,7 @@ static int search_quota(uid_t uid, const char *exclude_quota_path) { * comprehensive, but should cover most cases. Note that in an ideal world every user would be * registered in NSS and avoid our own UID range, but for all other cases, it's a good idea to be * paranoid and check quota if we can. */ - FOREACH_STRING(where, "/home/", "/tmp/", "/var/", "/var/mail/", "/var/tmp/", "/var/spool/") { + FOREACH_STRING(where, get_home_root(), "/tmp/", "/var/", "/var/mail/", "/var/tmp/", "/var/spool/") { struct dqblk req; struct stat st; @@ -914,13 +921,13 @@ int manager_enumerate_images(Manager *m) { if (!m->scan_slash_home) return 0; - d = opendir("/home/"); + d = opendir(get_home_root()); if (!d) return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, - "Failed to open /home/: %m"); + "Failed to open %s: %m", get_home_root()); - FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read /home/ directory: %m")) - (void) manager_assess_image(m, dirfd(d), "/home", de->d_name); + FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read %s directory: %m", get_home_root())) + (void) manager_assess_image(m, dirfd(d), get_home_root(), de->d_name); return 0; } diff --git a/src/home/homework.c b/src/home/homework.c index 49533b24229..ae3fffed02c 100644 --- a/src/home/homework.c +++ b/src/home/homework.c @@ -1129,12 +1129,12 @@ static int determine_default_storage(UserStorage *ret) { 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"); + r = path_is_encrypted(get_home_root()); if (r > 0) - log_info("/home is encrypted, not using '%s' storage, in order to avoid double encryption.", user_storage_to_string(USER_LUKS)); + log_info("%s is encrypted, not using '%s' storage, in order to avoid double encryption.", get_home_root(), user_storage_to_string(USER_LUKS)); else { if (r < 0) - log_warning_errno(r, "Failed to determine if /home is encrypted, ignoring: %m"); + log_warning_errno(r, "Failed to determine if %s is encrypted, ignoring: %m", get_home_root()); r = dlopen_cryptsetup(); if (r < 0) @@ -1148,14 +1148,14 @@ static int determine_default_storage(UserStorage *ret) { } 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); + r = path_is_fs_type(get_home_root(), BTRFS_SUPER_MAGIC); if (r < 0) - log_warning_errno(r, "Failed to determine file system of /home, ignoring: %m"); + log_warning_errno(r, "Failed to determine file system of %s, ignoring: %m", get_home_root()); if (r > 0) { - log_info("/home is on btrfs, using '%s' as storage.", user_storage_to_string(USER_SUBVOLUME)); + log_info("%s is on btrfs, using '%s' as storage.", get_home_root(), 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)); + log_info("%s is on simple file system, using '%s' as storage.", get_home_root(), user_storage_to_string(USER_DIRECTORY)); *ret = USER_DIRECTORY; } diff --git a/src/home/user-record-util.c b/src/home/user-record-util.c index bc0c4171b4f..464f1dbb7a0 100644 --- a/src/home/user-record-util.c +++ b/src/home/user-record-util.c @@ -75,7 +75,7 @@ int user_record_synthesize( if (!ip) return -ENOMEM; - hd = path_join("/home/", user_name); + hd = path_join(get_home_root(), user_name); if (!hd) return -ENOMEM; diff --git a/src/shared/user-record.c b/src/shared/user-record.c index 44f629a910b..9b2029bfcfb 100644 --- a/src/shared/user-record.c +++ b/src/shared/user-record.c @@ -1408,11 +1408,11 @@ int user_record_build_image_path(UserStorage storage, const char *user_name_and_ return 0; } - z = strjoin("/home/", user_name_and_realm, suffix); + z = strjoin(get_home_root(), "/", user_name_and_realm, suffix); if (!z) return -ENOMEM; - *ret = z; + *ret = path_simplify(z); return 1; } @@ -1437,7 +1437,7 @@ static int user_record_augment(UserRecord *h, JsonDispatchFlags json_flags) { return 0; if (!h->home_directory && !h->home_directory_auto) { - h->home_directory_auto = path_join("/home/", h->user_name); + h->home_directory_auto = path_join(get_home_root(), h->user_name); if (!h->home_directory_auto) return json_log_oom(h->json, json_flags); } -- 2.39.2