diff options
Diffstat (limited to 'src/home/homed-manager-bus.c')
-rw-r--r-- | src/home/homed-manager-bus.c | 195 |
1 files changed, 147 insertions, 48 deletions
diff --git a/src/home/homed-manager-bus.c b/src/home/homed-manager-bus.c index 7cf5439..58cd037 100644 --- a/src/home/homed-manager-bus.c +++ b/src/home/homed-manager-bus.c @@ -6,6 +6,7 @@ #include "bus-common-errors.h" #include "bus-polkit.h" #include "format-util.h" +#include "home-util.h" #include "homed-bus.h" #include "homed-home-bus.h" #include "homed-manager-bus.h" @@ -61,6 +62,53 @@ static int property_get_auto_login( return sd_bus_message_close_container(reply); } +static int lookup_user_name( + Manager *m, + sd_bus_message *message, + const char *user_name, + sd_bus_error *error, + Home **ret) { + + Home *h; + int r; + + assert(m); + assert(message); + assert(user_name); + assert(ret); + + if (isempty(user_name)) { + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + uid_t uid; + + /* If an empty user name is specified, then identify caller's EUID and find home by that. */ + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_euid(creds, &uid); + if (r < 0) + return r; + + h = hashmap_get(m->homes_by_uid, UID_TO_PTR(uid)); + if (!h) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "Client's UID " UID_FMT " not managed.", uid); + + } else { + + if (!valid_user_group_name(user_name, 0)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name); + + h = hashmap_get(m->homes_by_name, user_name); + if (!h) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", user_name); + } + + *ret = h; + return 0; +} + static int method_get_home_by_name( sd_bus_message *message, void *userdata, @@ -77,12 +125,10 @@ static int method_get_home_by_name( r = sd_bus_message_read(message, "s", &user_name); if (r < 0) return r; - if (!valid_user_group_name(user_name, 0)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name); - h = hashmap_get(m->homes_by_name, user_name); - if (!h) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", user_name); + r = lookup_user_name(m, message, user_name, error, &h); + if (r < 0) + return r; r = bus_home_path(h, &path); if (r < 0) @@ -204,12 +250,10 @@ static int method_get_user_record_by_name( r = sd_bus_message_read(message, "s", &user_name); if (r < 0) return r; - if (!valid_user_group_name(user_name, 0)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name); - h = hashmap_get(m->homes_by_name, user_name); - if (!h) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", user_name); + r = lookup_user_name(m, message, user_name, error, &h); + if (r < 0) + return r; r = bus_home_get_record_json(h, message, &json, &incomplete); if (r < 0) @@ -274,16 +318,17 @@ static int generic_home_method( Home *h; int r; + assert(m); + assert(message); + assert(handler); + r = sd_bus_message_read(message, "s", &user_name); if (r < 0) return r; - if (!valid_user_group_name(user_name, 0)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name); - - h = hashmap_get(m->homes_by_name, user_name); - if (!h) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", user_name); + r = lookup_user_name(m, message, user_name, error, &h); + if (r < 0) + return r; return handler(message, h, error); } @@ -296,10 +341,8 @@ static int method_deactivate_home(sd_bus_message *message, void *userdata, sd_bu return generic_home_method(userdata, message, bus_home_method_deactivate, error); } -static int validate_and_allocate_home(Manager *m, UserRecord *hr, Home **ret, sd_bus_error *error) { +static int validate_and_allocate_home(Manager *m, UserRecord *hr, Hashmap *blobs, Home **ret, sd_bus_error *error) { _cleanup_(user_record_unrefp) UserRecord *signed_hr = NULL; - struct passwd *pw; - struct group *gr; bool signed_locally; Home *other; int r; @@ -316,13 +359,26 @@ static int validate_and_allocate_home(Manager *m, UserRecord *hr, Home **ret, sd if (other) return sd_bus_error_setf(error, BUS_ERROR_USER_NAME_EXISTS, "Specified user name %s exists already, refusing.", hr->user_name); - pw = getpwnam(hr->user_name); - if (pw) + r = getpwnam_malloc(hr->user_name, /* ret= */ NULL); + if (r >= 0) return sd_bus_error_setf(error, BUS_ERROR_USER_NAME_EXISTS, "Specified user name %s exists in the NSS user database, refusing.", hr->user_name); + if (r != -ESRCH) + return r; - gr = getgrnam(hr->user_name); - if (gr) + r = getgrnam_malloc(hr->user_name, /* ret= */ NULL); + if (r >= 0) return sd_bus_error_setf(error, BUS_ERROR_USER_NAME_EXISTS, "Specified user name %s conflicts with an NSS group by the same name, refusing.", hr->user_name); + if (r != -ESRCH) + return r; + + if (blobs) { + const char *failed = NULL; + r = user_record_ensure_blob_manifest(hr, blobs, &failed); + if (r == -EINVAL) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Provided blob files do not correspond to blob manifest."); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to generate hash for blob %s: %m", strnull(failed)); + } r = manager_verify_user_record(m, hr); switch (r) { @@ -353,17 +409,24 @@ static int validate_and_allocate_home(Manager *m, UserRecord *hr, Home **ret, sd } if (uid_is_valid(hr->uid)) { + _cleanup_free_ struct passwd *pw = NULL; + _cleanup_free_ struct group *gr = NULL; + other = hashmap_get(m->homes_by_uid, UID_TO_PTR(hr->uid)); if (other) return sd_bus_error_setf(error, BUS_ERROR_UID_IN_USE, "Specified UID " UID_FMT " already in use by home %s, refusing.", hr->uid, other->user_name); - pw = getpwuid(hr->uid); - if (pw) + r = getpwuid_malloc(hr->uid, &pw); + if (r >= 0) return sd_bus_error_setf(error, BUS_ERROR_UID_IN_USE, "Specified UID " UID_FMT " already in use by NSS user %s, refusing.", hr->uid, pw->pw_name); + if (r != -ESRCH) + return r; - gr = getgrgid(hr->uid); - if (gr) + r = getgrgid_malloc(hr->uid, &gr); + if (r >= 0) return sd_bus_error_setf(error, BUS_ERROR_UID_IN_USE, "Specified UID " UID_FMT " already in use as GID by NSS group %s, refusing.", hr->uid, gr->gr_name); + if (r != -ESRCH) + return r; } else { r = manager_augment_record_with_uid(m, hr); if (r < 0) @@ -396,11 +459,8 @@ static int method_register_home( r = bus_verify_polkit_async( message, - CAP_SYS_ADMIN, "org.freedesktop.home1.create-home", - NULL, - true, - UID_INVALID, + /* details= */ NULL, &m->polkit_registry, error); if (r < 0) @@ -408,7 +468,7 @@ static int method_register_home( if (r == 0) return 1; /* Will call us back */ - r = validate_and_allocate_home(m, hr, &h, error); + r = validate_and_allocate_home(m, hr, NULL, &h, error); if (r < 0) return r; @@ -425,12 +485,11 @@ static int method_unregister_home(sd_bus_message *message, void *userdata, sd_bu return generic_home_method(userdata, message, bus_home_method_unregister, error); } -static int method_create_home( - sd_bus_message *message, - void *userdata, - sd_bus_error *error) { +static int method_create_home(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(user_record_unrefp) UserRecord *hr = NULL; + _cleanup_hashmap_free_ Hashmap *blobs = NULL; + uint64_t flags = 0; Manager *m = ASSERT_PTR(userdata); Home *h; int r; @@ -441,13 +500,22 @@ static int method_create_home( if (r < 0) return r; + if (endswith(sd_bus_message_get_member(message), "Ex")) { + r = bus_message_read_blobs(message, &blobs, error); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "t", &flags); + if (r < 0) + return r; + if ((flags & ~SD_HOMED_CREATE_FLAGS_ALL) != 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags provided."); + } + r = bus_verify_polkit_async( message, - CAP_SYS_ADMIN, "org.freedesktop.home1.create-home", - NULL, - true, - UID_INVALID, + /* details= */ NULL, &m->polkit_registry, error); if (r < 0) @@ -455,11 +523,11 @@ static int method_create_home( if (r == 0) return 1; /* Will call us back */ - r = validate_and_allocate_home(m, hr, &h, error); + r = validate_and_allocate_home(m, hr, blobs, &h, error); if (r < 0) return r; - r = home_create(h, hr, error); + r = home_create(h, hr, blobs, flags, error); if (r < 0) goto fail; @@ -471,6 +539,8 @@ static int method_create_home( if (r < 0) return r; + h->current_operation->call_flags = flags; + return 1; fail: @@ -497,6 +567,8 @@ static int method_authenticate_home(sd_bus_message *message, void *userdata, sd_ static int method_update_home(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(user_record_unrefp) UserRecord *hr = NULL; + _cleanup_hashmap_free_ Hashmap *blobs = NULL; + uint64_t flags = 0; Manager *m = ASSERT_PTR(userdata); Home *h; int r; @@ -507,13 +579,23 @@ static int method_update_home(sd_bus_message *message, void *userdata, sd_bus_er if (r < 0) return r; + if (endswith(sd_bus_message_get_member(message), "Ex")) { + r = bus_message_read_blobs(message, &blobs, error); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "t", &flags); + if (r < 0) + return r; + } + assert(hr->user_name); h = hashmap_get(m->homes_by_name, hr->user_name); if (!h) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", hr->user_name); - return bus_home_method_update_record(h, message, hr, error); + return bus_home_update_record(h, message, hr, blobs, flags, error); } static int method_resize_home(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -557,10 +639,7 @@ static int method_lock_all_homes(sd_bus_message *message, void *userdata, sd_bus HASHMAP_FOREACH(h, m->homes_by_name) { - /* Automatically suspend all homes that have at least one client referencing it that asked - * for "please suspend", and no client that asked for "please do not suspend". */ - if (h->ref_event_source_dont_suspend || - !h->ref_event_source_please_suspend) + if (!home_shall_suspend(h)) continue; if (!o) { @@ -689,7 +768,12 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_ARGS("s", user_name, "s", secret), SD_BUS_NO_RESULT, method_activate_home, - SD_BUS_VTABLE_SENSITIVE), + SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), + SD_BUS_METHOD_WITH_ARGS("ActivateHomeIfReferenced", + SD_BUS_ARGS("s", user_name, "s", secret), + SD_BUS_NO_RESULT, + method_activate_home, + SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), SD_BUS_METHOD_WITH_ARGS("DeactivateHome", SD_BUS_ARGS("s", user_name), SD_BUS_NO_RESULT, @@ -716,6 +800,11 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_NO_RESULT, method_create_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), + SD_BUS_METHOD_WITH_ARGS("CreateHomeEx", + SD_BUS_ARGS("s", user_record, "a{sh}", blobs, "t", flags), + SD_BUS_NO_RESULT, + method_create_home, + SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), /* Create $HOME for already registered JSON entry */ SD_BUS_METHOD_WITH_ARGS("RealizeHome", @@ -751,6 +840,11 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_NO_RESULT, method_update_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), + SD_BUS_METHOD_WITH_ARGS("UpdateHomeEx", + SD_BUS_ARGS("s", user_record, "a{sh}", blobs, "t", flags), + SD_BUS_NO_RESULT, + method_update_home, + SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), SD_BUS_METHOD_WITH_ARGS("ResizeHome", SD_BUS_ARGS("s", user_name, "t", size, "s", secret), @@ -795,6 +889,11 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_RESULT("h", send_fd), method_ref_home, 0), + SD_BUS_METHOD_WITH_ARGS("RefHomeUnrestricted", + SD_BUS_ARGS("s", user_name, "b", please_suspend), + SD_BUS_RESULT("h", send_fd), + method_ref_home, + 0), SD_BUS_METHOD_WITH_ARGS("ReleaseHome", SD_BUS_ARGS("s", user_name), SD_BUS_NO_RESULT, |