]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
homed: Create & advertise blob directory
authorAdrian Vovk <adrianvovk@gmail.com>
Mon, 8 Jan 2024 23:37:52 +0000 (18:37 -0500)
committerLuca Boccassi <bluca@debian.org>
Mon, 19 Feb 2024 11:18:11 +0000 (11:18 +0000)
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.

man/systemd-homed.service.xml
src/home/home-util.c
src/home/home-util.h
src/home/homed-home.c
src/home/homed-manager.c
src/home/user-record-util.c
units/systemd-homed.service.in

index a4561776c9fd616812812f7dec76cf88729d00b4..42e5780cccc4f478d6dc520f6a4f72cc4e60277a 100644 (file)
     url="https://systemd.io/USER_GROUP_API">User/Group Record Lookup API via Varlink</ulink>, and thus may be
     browsed with
     <citerefentry><refentrytitle>userdbctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
+
+    <para><filename>systemd-homed.service</filename> also manages blob directories for each home directory
+    it manages. See <ulink url="https://systemd.io/USER_RECORD_BLOB_DIRS">User Record Blob Directories</ulink>
+    for more details.</para>
   </refsect1>
 
   <refsect1>
index c777d7b0eb6f3761116e41fab4ca39afa0c96a12..9c9c0ff78aaace5a8bff9af3f1c29fd2aa7629fb 100644 (file)
@@ -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/";
+}
index 36b301d236031c17c7875463ff5831e5d84f4f16..ead8f5637ee521f07bcd2a256eef54d9ee1317aa 100644 (file)
@@ -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);
index e1422475dceef8d34f1e518e4ae96a2c910ced96..7bb078ee2c8f2d13bbc09e11ccdb0e2d26eefad8 100644 (file)
@@ -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;
 }
 
index 810ecb23fcfc843b0334cc87a0d4788429c2432b..2e07e90f9c723857ff759e030baaa21a9ebb4fab 100644 (file)
@@ -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);
 
index 8620371ac6a1845dfd9df80efa1e4f7577de91b1..b18a77d7407e98b1b44acc1224d06ef67c0eb644 100644 (file)
@@ -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;
 }
 
index ee72c75ac96ed3a6e8eed218e303797d272ddb79..ff4f429498c702a095f0dcaa29c729d563021959 100644 (file)
@@ -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