From cc9886bc207021fa4b0a4687f1beb88e0457d21e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Sep 2020 17:55:51 +0200 Subject: [PATCH] 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);