From: Adrian Vovk Date: Mon, 8 Jan 2024 23:37:52 +0000 (-0500) Subject: homed: Create & advertise blob directory X-Git-Tag: v256-rc1~817^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c3d50255fc90859a80b8e2f5e009ecc17b83ef0d;p=thirdparty%2Fsystemd.git homed: Create & advertise blob directory This ensures that a user-specific blob directory exists in /var/cache/systemd/homed for as long as the user exists, and gets deleted if the user gets deleted. It also advertises this blob directory via the user record, so that clients can find and use it. --- diff --git a/man/systemd-homed.service.xml b/man/systemd-homed.service.xml index a4561776c9f..42e5780cccc 100644 --- a/man/systemd-homed.service.xml +++ b/man/systemd-homed.service.xml @@ -46,6 +46,10 @@ url="https://systemd.io/USER_GROUP_API">User/Group Record Lookup API via Varlink, and thus may be browsed with userdbctl1. + + systemd-homed.service also manages blob directories for each home directory + it manages. See User Record Blob Directories + for more details. diff --git a/src/home/home-util.c b/src/home/home-util.c index c777d7b0eb6..9c9c0ff78aa 100644 --- a/src/home/home-util.c +++ b/src/home/home-util.c @@ -137,3 +137,7 @@ int bus_message_append_secret(sd_bus_message *m, UserRecord *secret) { const char *home_record_dir(void) { return secure_getenv("SYSTEMD_HOME_RECORD_DIR") ?: "/var/lib/systemd/home/"; } + +const char *home_system_blob_dir(void) { + return secure_getenv("SYSTEMD_HOME_SYSTEM_BLOB_DIR") ?: "/var/cache/systemd/home/"; +} diff --git a/src/home/home-util.h b/src/home/home-util.h index 36b301d2360..ead8f5637ee 100644 --- a/src/home/home-util.h +++ b/src/home/home-util.h @@ -35,3 +35,4 @@ int bus_message_append_secret(sd_bus_message *m, UserRecord *secret); #define HOME_SLOW_BUS_CALL_TIMEOUT_USEC (2*USEC_PER_MINUTE) const char *home_record_dir(void); +const char *home_system_blob_dir(void); diff --git a/src/home/homed-home.c b/src/home/homed-home.c index e1422475dce..7bb078ee2c8 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -33,6 +33,7 @@ #include "process-util.h" #include "quota-util.h" #include "resize-fs.h" +#include "rm-rf.h" #include "set.h" #include "signal-util.h" #include "stat-util.h" @@ -96,7 +97,7 @@ static int suitable_home_record(UserRecord *hr) { int home_new(Manager *m, UserRecord *hr, const char *sysfs, Home **ret) { _cleanup_(home_freep) Home *home = NULL; - _cleanup_free_ char *nm = NULL, *ns = NULL; + _cleanup_free_ char *nm = NULL, *ns = NULL, *blob = NULL; int r; assert(m); @@ -162,6 +163,13 @@ int home_new(Manager *m, UserRecord *hr, const char *sysfs, Home **ret) { if (r < 0) return r; + blob = path_join(home_system_blob_dir(), hr->user_name); + if (!blob) + return -ENOMEM; + r = mkdir_safe(blob, 0755, 0, 0, MKDIR_IGNORE_EXISTING); + if (r < 0) + log_warning_errno(r, "Failed to create blob dir for user '%s': %m", home->user_name); + (void) bus_manager_emit_auto_login_changed(m); (void) bus_home_emit_change(home); (void) manager_schedule_rebalance(m, /* immediately= */ false); @@ -323,7 +331,9 @@ int home_save_record(Home *h) { } int home_unlink_record(Home *h) { + _cleanup_free_ char *blob = NULL; const char *fn; + int r; assert(h); @@ -335,6 +345,13 @@ int home_unlink_record(Home *h) { if (unlink(fn) < 0 && errno != ENOENT) return -errno; + blob = path_join(home_system_blob_dir(), h->user_name); + if (!blob) + return -ENOMEM; + r = rm_rf(blob, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_MISSING_OK); + if (r < 0) + return r; + return 0; } diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index 810ecb23fcf..2e07e90f9c7 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -42,6 +42,7 @@ #include "quota-util.h" #include "random-util.h" #include "resize-fs.h" +#include "rm-rf.h" #include "socket-util.h" #include "sort-util.h" #include "stat-util.h" @@ -79,6 +80,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(homes_by_sysfs_hash_ops, char, pat static int on_home_inotify(sd_event_source *s, const struct inotify_event *event, void *userdata); static int manager_gc_images(Manager *m); +static int manager_gc_blob(Manager *m); static int manager_enumerate_images(Manager *m); static int manager_assess_image(Manager *m, int dir_fd, const char *dir_path, const char *dentry_name); static void manager_revalidate_image(Manager *m, Home *h); @@ -1627,6 +1629,9 @@ int manager_startup(Manager *m) { /* Let's clean up home directories whose devices got removed while we were not running */ (void) manager_enqueue_gc(m, NULL); + /* Let's clean up blob directories for home dirs that no longer exist */ + (void) manager_gc_blob(m); + return 0; } @@ -1715,6 +1720,29 @@ int manager_gc_images(Manager *m) { return 0; } +static int manager_gc_blob(Manager *m) { + _cleanup_closedir_ DIR *d = NULL; + int r; + + assert(m); + + d = opendir(home_system_blob_dir()); + if (!d) { + if (errno == ENOENT) + return 0; + return log_error_errno(errno, "Failed to open %s: %m", home_system_blob_dir()); + } + + FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read system blob directory: %m")) + if (!hashmap_contains(m->homes_by_name, de->d_name)) { + r = rm_rf_at(dirfd(d), de->d_name, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); + if (r < 0) + log_warning_errno(r, "Failed to delete blob dir for missing user '%s', ignoring: %m", de->d_name); + } + + return 0; +} + static int on_deferred_rescan(sd_event_source *s, void *userdata) { Manager *m = ASSERT_PTR(userdata); diff --git a/src/home/user-record-util.c b/src/home/user-record-util.c index 8620371ac6a..b18a77d7407 100644 --- a/src/home/user-record-util.c +++ b/src/home/user-record-util.c @@ -282,7 +282,7 @@ int user_record_add_binding( gid_t gid) { _cleanup_(json_variant_unrefp) JsonVariant *new_binding_entry = NULL, *binding = NULL; - _cleanup_free_ char *ip = NULL, *hd = NULL, *ip_auto = NULL, *lc = NULL, *lcm = NULL, *fst = NULL; + _cleanup_free_ char *blob = NULL, *ip = NULL, *hd = NULL, *ip_auto = NULL, *lc = NULL, *lcm = NULL, *fst = NULL; sd_id128_t mid; int r; @@ -291,6 +291,10 @@ int user_record_add_binding( if (!h->json) return -EUNATCH; + blob = path_join(home_system_blob_dir(), h->user_name); + if (!blob) + return -ENOMEM; + r = sd_id128_get_machine(&mid); if (r < 0) return r; @@ -331,6 +335,7 @@ int user_record_add_binding( r = json_build(&new_binding_entry, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("blobDirectory", JSON_BUILD_STRING(blob)), JSON_BUILD_PAIR_CONDITION(!!image_path, "imagePath", JSON_BUILD_STRING(image_path)), JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(partition_uuid), "partitionUuid", JSON_BUILD_STRING(SD_ID128_TO_UUID_STRING(partition_uuid))), JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(luks_uuid), "luksUuid", JSON_BUILD_STRING(SD_ID128_TO_UUID_STRING(luks_uuid))), @@ -370,6 +375,8 @@ int user_record_add_binding( if (r < 0) return r; + free_and_replace(h->blob_directory, blob); + if (storage >= 0) h->storage = storage; @@ -1383,6 +1390,12 @@ int user_record_is_supported(UserRecord *hr, sd_bus_error *error) { if (hr->service && !streq(hr->service, "io.systemd.Home")) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Not accepted with service not matching io.systemd.Home."); + if (hr->blob_directory) { + /* This function is always called w/o binding section, so if hr->blob_dir is set then the caller set it themselves */ + assert((hr->mask & USER_RECORD_BINDING) == 0); + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot manage custom blob directories."); + } + return 0; } diff --git a/units/systemd-homed.service.in b/units/systemd-homed.service.in index ee72c75ac96..ff4f429498c 100644 --- a/units/systemd-homed.service.in +++ b/units/systemd-homed.service.in @@ -30,6 +30,7 @@ RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_ALG AF_INET AF_INET6 RestrictNamespaces=mnt user RestrictRealtime=yes StateDirectory=systemd/home +CacheDirectory=systemd/home SystemCallArchitectures=native SystemCallErrorNumber=EPERM SystemCallFilter=@system-service @mount quotactl