-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <grp.h>
#include <linux/fs.h>
assert(m);
- m->inotify_event_source = sd_event_source_unref(m->inotify_event_source);
+ m->inotify_event_source = sd_event_source_disable_unref(m->inotify_event_source);
m->scan_slash_home = false;
if (statfs("/home/", &sfs) < 0) {
m->scan_slash_home = true;
- r = sd_event_add_inotify(m->event, &m->inotify_event_source, "/home/", IN_CREATE|IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF|IN_ONLYDIR|IN_MOVED_TO|IN_MOVED_FROM|IN_DELETE, on_home_inotify, m);
+ r = sd_event_add_inotify(m->event, &m->inotify_event_source, "/home/",
+ IN_CREATE|IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF|IN_ONLYDIR|IN_MOVED_TO|IN_MOVED_FROM|IN_DELETE,
+ on_home_inotify, m);
if (r < 0)
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to create inotify watch on /home/, ignoring.");
(void) bus_manager_emit_auto_login_changed(m);
}
- if ((event->mask & (IN_DELETE|IN_MOVED_FROM|IN_DELETE)) != 0) {
+ if ((event->mask & (IN_DELETE | IN_CLOSE_WRITE | IN_MOVED_FROM)) != 0) {
Home *h;
if (FLAGS_SET(event->mask, IN_DELETE))
}
Manager* manager_free(Manager *m) {
- assert(m);
-
- hashmap_free(m->homes_by_uid);
- hashmap_free(m->homes_by_name);
- hashmap_free(m->homes_by_worker_pid);
- hashmap_free(m->homes_by_sysfs);
+ Home *h;
- m->inotify_event_source = sd_event_source_unref(m->inotify_event_source);
+ assert(m);
- bus_verify_polkit_async_registry_free(m->polkit_registry);
+ HASHMAP_FOREACH(h, m->homes_by_worker_pid)
+ (void) home_wait_for_worker(h);
sd_bus_flush_close_unref(m->bus);
- sd_event_unref(m->event);
+ bus_verify_polkit_async_registry_free(m->polkit_registry);
- m->notify_socket_event_source = sd_event_source_unref(m->notify_socket_event_source);
m->device_monitor = sd_device_monitor_unref(m->device_monitor);
+ m->inotify_event_source = sd_event_source_unref(m->inotify_event_source);
+ m->notify_socket_event_source = sd_event_source_unref(m->notify_socket_event_source);
m->deferred_rescan_event_source = sd_event_source_unref(m->deferred_rescan_event_source);
m->deferred_gc_event_source = sd_event_source_unref(m->deferred_gc_event_source);
m->deferred_auto_login_event_source = sd_event_source_unref(m->deferred_auto_login_event_source);
+ sd_event_unref(m->event);
+
+ hashmap_free(m->homes_by_uid);
+ hashmap_free(m->homes_by_name);
+ hashmap_free(m->homes_by_worker_pid);
+ hashmap_free(m->homes_by_sysfs);
+
if (m->private_key)
EVP_PKEY_free(m->private_key);
hashmap_free(m->public_keys);
varlink_server_unref(m->varlink_server);
+ free(m->userdb_service);
free(m->default_file_system_type);
int manager_verify_user_record(Manager *m, UserRecord *hr) {
EVP_PKEY *pkey;
- Iterator i;
int r;
assert(m);
}
}
- HASHMAP_FOREACH(pkey, m->public_keys, i) {
+ HASHMAP_FOREACH(pkey, m->public_keys) {
r = user_record_verify(hr, pkey);
switch (r) {
if (!hr)
return log_oom();
- r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG);
+ r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
if (!streq_ptr(hr->user_name, name))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Identity's user name %s does not match file name %s, refusing.", hr->user_name, name);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Identity's user name %s does not match file name %s, refusing.",
+ hr->user_name, name);
is_signed = manager_verify_user_record(m, hr);
switch (is_signed) {
if (r < 0) {
if (ERRNO_IS_NOT_SUPPORTED(r))
log_debug_errno(r, "No UID quota support on %s, ignoring.", where);
+ else if (ERRNO_IS_PRIVILEGE(r))
+ log_debug_errno(r, "UID quota support for %s prohibited, ignoring.", where);
else
log_warning_errno(r, "Failed to query quota on %s, ignoring: %m", where);
other = hashmap_get(m->homes_by_uid, UID_TO_PTR(candidate));
if (other) {
- log_debug("Candidate UID " UID_FMT " already used by another home directory (%s), let's try another.", candidate, other->user_name);
+ log_debug("Candidate UID " UID_FMT " already used by another home directory (%s), let's try another.",
+ candidate, other->user_name);
continue;
}
pw = getpwuid(candidate);
if (pw) {
- log_debug("Candidate UID " UID_FMT " already registered by another user in NSS (%s), let's try another.", candidate, pw->pw_name);
+ log_debug("Candidate UID " UID_FMT " already registered by another user in NSS (%s), let's try another.",
+ candidate, pw->pw_name);
continue;
}
gr = getgrgid((gid_t) candidate);
if (gr) {
- log_debug("Candidate UID " UID_FMT " already registered by another group in NSS (%s), let's try another.", candidate, gr->gr_name);
+ log_debug("Candidate UID " UID_FMT " already registered by another group in NSS (%s), let's try another.",
+ candidate, gr->gr_name);
continue;
}
if (r < 0)
continue;
if (r > 0) {
- log_debug_errno(r, "Candidate UID " UID_FMT " already owns IPC objects, let's try another: %m", candidate);
+ log_debug_errno(r, "Candidate UID " UID_FMT " already owns IPC objects, let's try another: %m",
+ candidate);
continue;
}
if (h && uid_is_valid(h->uid))
uid = h->uid;
else {
- r = manager_acquire_uid(m, start_uid, user_name, IN_SET(storage, USER_SUBVOLUME, USER_DIRECTORY, USER_FSCRYPT) ? image_path : NULL, &uid);
+ r = manager_acquire_uid(m, start_uid, user_name,
+ IN_SET(storage, USER_SUBVOLUME, USER_DIRECTORY, USER_FSCRYPT) ? image_path : NULL,
+ &uid);
if (r < 0)
return log_warning_errno(r, "Failed to acquire unused UID for %s: %m", user_name);
}
}
static int manager_connect_bus(Manager *m) {
+ const char *suffix, *busname;
int r;
assert(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");
}
static int manager_bind_varlink(Manager *m) {
+ const char *suffix, *socket_path;
int r;
assert(m);
assert(!m->varlink_server);
- r = varlink_server_new(&m->varlink_server, VARLINK_SERVER_ACCOUNT_UID);
+ r = varlink_server_new(&m->varlink_server, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA);
if (r < 0)
return log_error_errno(r, "Failed to allocate varlink server object: %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");
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;
}
.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");
assert(m);
assert(d);
- if (device_for_action(d, DEVICE_ACTION_REMOVE)) {
+ if (device_for_action(d, SD_DEVICE_REMOVE)) {
const char *sysfs;
Home *h;
m->private_key = NULL;
}
- r = search_and_fopen_nulstr("local.private", "re", NULL, KEY_PATHS_NULSTR, &f);
+ r = search_and_fopen_nulstr("local.private", "re", NULL, KEY_PATHS_NULSTR, &f, NULL);
if (r == -ENOENT)
return 0;
if (r < 0)
return 1;
}
-DEFINE_TRIVIAL_CLEANUP_FUNC(EVP_PKEY_CTX*, EVP_PKEY_CTX_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_PKEY_CTX*, EVP_PKEY_CTX_free, NULL);
static int manager_generate_key_pair(Manager *m) {
_cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = NULL;
if (r < 0)
return r;
if (r == 0)
- return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_KEY, "Can't sign without local key.");
+ return sd_bus_error_set(error, BUS_ERROR_NO_PRIVATE_KEY, "Can't sign without local key.");
return user_record_sign(u, m->private_key, ret);
}
DEFINE_PRIVATE_HASH_OPS_FULL(public_key_hash_ops, char, string_hash_func, string_compare_func, free, EVP_PKEY, EVP_PKEY_free);
-DEFINE_TRIVIAL_CLEANUP_FUNC(EVP_PKEY*, EVP_PKEY_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_PKEY*, EVP_PKEY_free, NULL);
static int manager_load_public_key_one(Manager *m, const char *path) {
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
manager_revalidate_image(m, h);
} else {
/* Gc all */
- Iterator i;
- HASHMAP_FOREACH(h, m->homes_by_name, i)
+ HASHMAP_FOREACH(h, m->homes_by_name)
manager_revalidate_image(m, h);
}
assert(m);
- m->deferred_rescan_event_source = sd_event_source_unref(m->deferred_rescan_event_source);
+ m->deferred_rescan_event_source = sd_event_source_disable_unref(m->deferred_rescan_event_source);
manager_enumerate_devices(m);
manager_enumerate_images(m);
assert(m);
- m->deferred_gc_event_source = sd_event_source_unref(m->deferred_gc_event_source);
+ m->deferred_gc_event_source = sd_event_source_disable_unref(m->deferred_gc_event_source);
manager_gc_images(m);
return 0;