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.
This commit is contained in:
Lennart Poettering 2020-09-18 17:55:51 +02:00
parent 79a6b4cc55
commit cc9886bc20
6 changed files with 107 additions and 30 deletions

View 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;

View 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);
}

View 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");

View 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*] */

View 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) {

View 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);