]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
homed: make it easier to run multiple instances of homed
authorLennart Poettering <lennart@poettering.net>
Fri, 18 Sep 2020 15:55:51 +0000 (17:55 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 18 Sep 2020 20:35:36 +0000 (22:35 +0200)
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
src/home/homed-home.c
src/home/homed-manager.c
src/home/homed-manager.h
src/home/homed-varlink.c
src/home/homed.c

index b83fa837ad81956fd3b99f0d3cb934846a3b5710..35c98c9d6dd6a8e913af5d1e241488a71718839a 100644 (file)
@@ -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;
index db88d60c094249176110bd215b7a660e9f62c04d..c7156c0d5070403a2a70f143f4945b7c32d17950 100644 (file)
@@ -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);
                 }
index 9ac375abd62f84dda2dafbdfbaa9d994682d6de1..711f178c55568dba33762e51d9b8eacbd5deb262 100644 (file)
@@ -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");
index 83a714462792a103cc0d0f010df40fe40ad52555..c86bf4300b35a9d72290558a1fa5ceb1ede3d5dd 100644 (file)
@@ -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*] */
index 8131a16bc03c1c7b7cc98a602d4a8922469e6273..dfc615a0973836ff7d7e28db0a6dad34b19e5ba7 100644 (file)
@@ -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) {
index ed8404d7e3da2585921877df3bea812185a99b16..eb5a4a2ea50b2e486a9c7e11f1b54e84463fe800 100644 (file)
@@ -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);