Merge pull request #17100 from poettering/homed-fixes

various homed fixes
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2020-09-19 18:17:56 +02:00 committed by GitHub
commit 8a4024120f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 147 additions and 38 deletions

View File

@ -566,10 +566,13 @@
<listitem><para>Takes a file system path. Configures where to place the user's home directory. When
LUKS2 storage is used refers to the path to the loopback file, otherwise to the path to the home
directory. When unspecified defaults to <filename>/home/$USER.home</filename> when LUKS storage is
used and <filename>/home/$USER.homedir</filename> for the other storage mechanisms. Not defined for
the <literal>cifs</literal> storage mechanism. To use LUKS2 storage on a regular block device (for
example a USB stick) pass the path to the block device here.</para></listitem>
directory (which may be in <filename>/home/</filename> or any other accessible filesystem). When
unspecified defaults to <filename>/home/$USER.home</filename> when LUKS storage is used and
<filename>/home/$USER.homedir</filename> for the other storage mechanisms. Not defined for the
<literal>cifs</literal> storage mechanism. To use LUKS2 storage on a regular block device (for
example a USB stick) pass the path to the block device here. Specifying the path to a directory here
when using LUKS2 storage is not allowed. Similar, specifying the path to a regular file or device
node is not allowed if any of the other storage backends are used.</para></listitem>
</varlistentry>
<varlistentry>

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

@ -1,3 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "homed-bus.h"
#include "strv.h"

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);
}
@ -1274,15 +1280,22 @@ int home_create(Home *h, UserRecord *secret, sd_bus_error *error) {
assert(h);
switch (home_get_state(h)) {
case HOME_INACTIVE:
case HOME_INACTIVE: {
int t;
if (h->record->storage < 0)
break; /* if no storage is defined we don't know what precisely to look for, hence
* HOME_INACTIVE is OK in that case too. */
if (IN_SET(user_record_test_image_path(h->record), USER_TEST_MAYBE, USER_TEST_UNDEFINED))
t = user_record_test_image_path(h->record);
if (IN_SET(t, USER_TEST_MAYBE, USER_TEST_UNDEFINED))
break; /* And if the image path test isn't conclusive, let's also go on */
_fallthrough_;
if (IN_SET(t, -EBADFD, -ENOTDIR))
return sd_bus_error_setf(error, BUS_ERROR_HOME_EXISTS, "Selected home image of user %s already exists or has wrong inode type.", h->user_name);
return sd_bus_error_setf(error, BUS_ERROR_HOME_EXISTS, "Selected home image of user %s already exists.", h->user_name);
}
case HOME_UNFIXATED:
case HOME_DIRTY:
return sd_bus_error_setf(error, BUS_ERROR_HOME_EXISTS, "Home of user %s already exists.", h->user_name);
@ -2733,6 +2746,19 @@ int home_set_current_message(Home *h, sd_bus_message *m) {
return 1;
}
int home_wait_for_worker(Home *h) {
assert(h);
if (h->worker_pid <= 0)
return 0;
log_info("Worker process for home %s is still running while exiting. Waiting for it to finish.", h->user_name);
(void) wait_for_terminate(h->worker_pid, NULL);
(void) hashmap_remove_value(h->manager->homes_by_worker_pid, PID_TO_PTR(h->worker_pid), h);
h->worker_pid = 0;
return 1;
}
static const char* const home_state_table[_HOME_STATE_MAX] = {
[HOME_UNFIXATED] = "unfixated",
[HOME_ABSENT] = "absent",

View File

@ -165,5 +165,7 @@ int home_auto_login(Home *h, char ***ret_seats);
int home_set_current_message(Home *h, sd_bus_message *m);
int home_wait_for_worker(Home *h);
const char *home_state_to_string(HomeState state);
HomeState home_state_from_string(const char *s);

View File

@ -232,8 +232,13 @@ int manager_new(Manager **ret) {
}
Manager* manager_free(Manager *m) {
Home *h;
assert(m);
HASHMAP_FOREACH(h, m->homes_by_worker_pid)
(void) home_wait_for_worker(h);
hashmap_free(m->homes_by_uid);
hashmap_free(m->homes_by_name);
hashmap_free(m->homes_by_worker_pid);
@ -259,6 +264,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 +916,7 @@ int manager_enumerate_images(Manager *m) {
}
static int manager_connect_bus(Manager *m) {
const char *suffix, *busname;
int r;
assert(m);
@ -923,7 +930,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 +950,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 +972,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 +988,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 +1117,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);

View File

@ -14,7 +14,7 @@ After=home.mount
[Service]
BusName=org.freedesktop.home1
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID CAP_SETGID CAP_SETUID
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE
DeviceAllow=/dev/loop-control rw
DeviceAllow=/dev/mapper/control rw
DeviceAllow=block-* rw