diff options
Diffstat (limited to 'src/home')
-rw-r--r-- | src/home/homed-home-bus.c | 56 | ||||
-rw-r--r-- | src/home/homed-home-bus.h | 1 | ||||
-rw-r--r-- | src/home/homed-home.c | 60 | ||||
-rw-r--r-- | src/home/homed-home.h | 23 | ||||
-rw-r--r-- | src/home/homed-manager-bus.c | 10 | ||||
-rw-r--r-- | src/home/org.freedesktop.home1.conf | 8 | ||||
-rw-r--r-- | src/home/org.freedesktop.home1.policy | 9 |
7 files changed, 141 insertions, 26 deletions
diff --git a/src/home/homed-home-bus.c b/src/home/homed-home-bus.c index 413a706f4c..30f5735443 100644 --- a/src/home/homed-home-bus.c +++ b/src/home/homed-home-bus.c @@ -595,7 +595,7 @@ int bus_home_method_acquire( return r; /* This operation might not be something we can executed immediately, hence queue it */ - fd = home_create_fifo(h, please_suspend); + fd = home_create_fifo(h, please_suspend ? HOME_FIFO_PLEASE_SUSPEND : HOME_FIFO_DONT_SUSPEND); if (fd < 0) return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name); @@ -646,7 +646,7 @@ int bus_home_method_ref( return sd_bus_error_setf(error, BUS_ERROR_HOME_BUSY, "An operation on home %s is currently being executed.", h->user_name); } - fd = home_create_fifo(h, please_suspend); + fd = home_create_fifo(h, please_suspend ? HOME_FIFO_PLEASE_SUSPEND : HOME_FIFO_DONT_SUSPEND); if (fd < 0) return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name); @@ -675,6 +675,53 @@ int bus_home_method_release( return 1; } +int bus_home_method_inhibit_suspend( + sd_bus_message *message, + void *userdata, + sd_bus_error *error) { + + _cleanup_close_ int fd = -EBADF; + Home *h = ASSERT_PTR(userdata); + HomeState state; + int r; + + r = bus_verify_polkit_async_full( + message, + "org.freedesktop.home1.inhibit-suspend", + /* details= */ NULL, + /* interactive= */ false, + h->uid, + &h->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + + state = home_get_state(h); + switch (state) { + case HOME_ABSENT: + return sd_bus_error_setf(error, BUS_ERROR_HOME_ABSENT, "Home %s is currently missing or not plugged in.", h->user_name); + case HOME_UNFIXATED: + case HOME_INACTIVE: + case HOME_DIRTY: + return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_ACTIVE, "Home %s not active.", h->user_name); + case HOME_LOCKED: + return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name); + default: + if (HOME_STATE_IS_ACTIVE(state)) + break; + + return sd_bus_error_setf(error, BUS_ERROR_HOME_BUSY, "An operation on home %s is currently being executed.", h->user_name); + } + + fd = home_create_fifo(h, HOME_FIFO_INHIBIT_SUSPEND); + if (fd < 0) + return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name); + + return sd_bus_reply_method_return(message, "h", fd); +} + /* We map a uid_t as uint32_t bus property, let's ensure this is safe. */ assert_cc(sizeof(uid_t) == sizeof(uint32_t)); @@ -819,6 +866,11 @@ const sd_bus_vtable home_vtable[] = { bus_home_method_ref, 0), SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0), + SD_BUS_METHOD_WITH_ARGS("InhibitSuspend", + SD_BUS_NO_ARGS, + SD_BUS_RESULT("h", send_fd), + bus_home_method_inhibit_suspend, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END }; diff --git a/src/home/homed-home-bus.h b/src/home/homed-home-bus.h index 5522178055..a791c76312 100644 --- a/src/home/homed-home-bus.h +++ b/src/home/homed-home-bus.h @@ -25,6 +25,7 @@ int bus_home_method_unlock(sd_bus_message *message, void *userdata, sd_bus_error int bus_home_method_acquire(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_home_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_home_method_release(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_home_method_inhibit_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error); extern const BusObjectImplementation home_object; diff --git a/src/home/homed-home.c b/src/home/homed-home.c index 00fc7f114a..fc9dfcff24 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -211,6 +211,7 @@ Home *home_free(Home *h) { h->ref_event_source_please_suspend = sd_event_source_disable_unref(h->ref_event_source_please_suspend); h->ref_event_source_dont_suspend = sd_event_source_disable_unref(h->ref_event_source_dont_suspend); + h->inhibit_suspend_event_source = sd_event_source_disable_unref(h->inhibit_suspend_event_source); h->pending_operations = ordered_set_free(h->pending_operations); h->pending_event_source = sd_event_source_disable_unref(h->pending_event_source); @@ -2614,6 +2615,9 @@ static int on_home_ref_eof(sd_event_source *s, int fd, uint32_t revents, void *u if (h->ref_event_source_dont_suspend == s) h->ref_event_source_dont_suspend = sd_event_source_disable_unref(h->ref_event_source_dont_suspend); + if (h->inhibit_suspend_event_source == s) + h->inhibit_suspend_event_source = sd_event_source_disable_unref(h->inhibit_suspend_event_source); + if (home_is_referenced(h)) return 0; @@ -2629,25 +2633,42 @@ static int on_home_ref_eof(sd_event_source *s, int fd, uint32_t revents, void *u return 0; } -int home_create_fifo(Home *h, bool please_suspend) { +int home_create_fifo(Home *h, HomeFifoType type) { + static const struct { + const char *suffix; + const char *description; + size_t event_source; + } table[_HOME_FIFO_TYPE_MAX] = { + [HOME_FIFO_PLEASE_SUSPEND] = { + .suffix = ".please-suspend", + .description = "acquire-ref", + .event_source = offsetof(Home, ref_event_source_please_suspend), + }, + [HOME_FIFO_DONT_SUSPEND] = { + .suffix = ".dont-suspend", + .description = "acquire-ref-dont-suspend", + .event_source = offsetof(Home, ref_event_source_dont_suspend), + }, + [HOME_FIFO_INHIBIT_SUSPEND] = { + .suffix = ".inhibit-suspend", + .description = "inhibit-suspend", + .event_source = offsetof(Home, inhibit_suspend_event_source), + }, + }; + _cleanup_close_ int ret_fd = -EBADF; - sd_event_source **ss; - const char *fn, *suffix; + sd_event_source **evt; + const char *fn; int r; assert(h); + assert(type >= 0 && type < _HOME_FIFO_TYPE_MAX); - if (please_suspend) { - suffix = ".please-suspend"; - ss = &h->ref_event_source_please_suspend; - } else { - suffix = ".dont-suspend"; - ss = &h->ref_event_source_dont_suspend; - } + evt = (sd_event_source**) ((uint8_t*) h + table[type].event_source); - fn = strjoina("/run/systemd/home/", h->user_name, suffix); + fn = strjoina("/run/systemd/home/", h->user_name, table[type].suffix); - if (!*ss) { + if (!*evt) { _cleanup_close_ int ref_fd = -EBADF; (void) mkdir("/run/systemd/home/", 0755); @@ -2658,20 +2679,19 @@ int home_create_fifo(Home *h, bool please_suspend) { if (ref_fd < 0) return log_error_errno(errno, "Failed to open FIFO %s for reading: %m", fn); - r = sd_event_add_io(h->manager->event, ss, ref_fd, 0, on_home_ref_eof, h); + r = sd_event_add_io(h->manager->event, evt, ref_fd, 0, on_home_ref_eof, h); if (r < 0) return log_error_errno(r, "Failed to allocate reference FIFO event source: %m"); - (void) sd_event_source_set_description(*ss, "acquire-ref"); + (void) sd_event_source_set_description(*evt, table[type].description); - r = sd_event_source_set_priority(*ss, SD_EVENT_PRIORITY_IDLE-1); + r = sd_event_source_set_priority(*evt, SD_EVENT_PRIORITY_IDLE-1); if (r < 0) return r; - r = sd_event_source_set_io_fd_own(*ss, true); + r = sd_event_source_set_io_fd_own(*evt, true); if (r < 0) return log_error_errno(r, "Failed to pass ownership of FIFO event fd to event source: %m"); - TAKE_FD(ref_fd); } @@ -2751,8 +2771,10 @@ bool home_is_referenced(Home *h) { bool home_shall_suspend(Home *h) { assert(h); - /* Suspend if there's at least one client referencing this home directory that wants a suspend and none who does not. */ - return h->ref_event_source_please_suspend && !h->ref_event_source_dont_suspend; + /* We lock the home area on suspend if... */ + return h->ref_event_source_please_suspend && /* at least one client supports suspend, and... */ + !h->ref_event_source_dont_suspend && /* no clients lack support for suspend, and... */ + !h->inhibit_suspend_event_source; /* no client is temporarily inhibiting suspend */ } static int home_dispatch_release(Home *h, Operation *o) { diff --git a/src/home/homed-home.h b/src/home/homed-home.h index 1226c0c6ba..b8b0046422 100644 --- a/src/home/homed-home.h +++ b/src/home/homed-home.h @@ -138,12 +138,17 @@ struct Home { bool unregister_on_failure; /* The reading side of a FIFO stored in /run/systemd/home/, the writing side being used for reference - * counting. The references dropped to zero as soon as we see EOF. This concept exists twice: once - * for clients that are fine if we suspend the home directory on system suspend, and once for clients - * that are not ok with that. This allows us to determine for each home whether there are any clients - * that support unsuspend. */ + * counting. The references dropped to zero as soon as we see EOF. This concept exists thrice: once + * for clients that are fine if we lock the home directory on system suspend, once for clients + * that are not ok with that, and once for clients that are usually ok with it but temporarily + * want to opt-out so that they can implement more advanced behavior on their own. This allows + * us to determine for each home whether there are any clients that don't support suspend at this + * moment. */ sd_event_source *ref_event_source_please_suspend; sd_event_source *ref_event_source_dont_suspend; + /* This is distinct from ref_event_source_dont_suspend because it can be obtained from unprivileged + * code, and thus we don't count it as a reference on the home area. */ + sd_event_source *inhibit_suspend_event_source; /* Any pending operations we still need to execute. These are for operations we want to queue if we * can't execute them right-away. */ @@ -209,7 +214,15 @@ int home_killall(Home *h); int home_augment_status(Home *h, UserRecordLoadFlags flags, UserRecord **ret); -int home_create_fifo(Home *h, bool please_suspend); +typedef enum { + HOME_FIFO_PLEASE_SUSPEND, + HOME_FIFO_DONT_SUSPEND, + HOME_FIFO_INHIBIT_SUSPEND, + _HOME_FIFO_TYPE_MAX, + _HOME_FIFO_TYPE_INVALID = -EINVAL, +} HomeFifoType; +int home_create_fifo(Home *h, HomeFifoType mode); + int home_schedule_operation(Home *h, Operation *o, sd_bus_error *error); int home_auto_login(Home *h, char ***ret_seats); diff --git a/src/home/homed-manager-bus.c b/src/home/homed-manager-bus.c index d45e0f1238..c613eed4d5 100644 --- a/src/home/homed-manager-bus.c +++ b/src/home/homed-manager-bus.c @@ -591,6 +591,10 @@ static int method_release_home(sd_bus_message *message, void *userdata, sd_bus_e return generic_home_method(userdata, message, bus_home_method_release, error); } +static int method_inhibit_suspend_home(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return generic_home_method(userdata, message, bus_home_method_inhibit_suspend, error); +} + static int method_lock_all_homes(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(operation_unrefp) Operation *o = NULL; bool waiting = false; @@ -845,6 +849,12 @@ static const sd_bus_vtable manager_vtable[] = { method_release_home, 0), + SD_BUS_METHOD_WITH_ARGS("InhibitSuspendHome", + SD_BUS_ARGS("s", user_name), + SD_BUS_RESULT("h", send_fd), + method_inhibit_suspend_home, + SD_BUS_VTABLE_UNPRIVILEGED), + /* An operation that acts on all homes that allow it */ SD_BUS_METHOD("LockAllHomes", NULL, NULL, method_lock_all_homes, 0), SD_BUS_METHOD("DeactivateAllHomes", NULL, NULL, method_deactivate_all_homes, 0), diff --git a/src/home/org.freedesktop.home1.conf b/src/home/org.freedesktop.home1.conf index 5af1a68607..6d13535f95 100644 --- a/src/home/org.freedesktop.home1.conf +++ b/src/home/org.freedesktop.home1.conf @@ -123,6 +123,10 @@ <allow send_destination="org.freedesktop.home1" send_interface="org.freedesktop.home1.Manager" + send_member="InhibitSuspendHome"/> + + <allow send_destination="org.freedesktop.home1" + send_interface="org.freedesktop.home1.Manager" send_member="LockAllHomes"/> <allow send_destination="org.freedesktop.home1" @@ -195,6 +199,10 @@ send_interface="org.freedesktop.home1.Home" send_member="Release"/> + <allow send_destination="org.freedesktop.home1" + send_interface="org.freedesktop.home1.Home" + send_member="InhibitSuspend"/> + <allow receive_sender="org.freedesktop.home1"/> </policy> diff --git a/src/home/org.freedesktop.home1.policy b/src/home/org.freedesktop.home1.policy index a337b32237..2ac710d66c 100644 --- a/src/home/org.freedesktop.home1.policy +++ b/src/home/org.freedesktop.home1.policy @@ -69,4 +69,13 @@ </defaults> </action> + <action id="org.freedesktop.home1.inhibit-suspend"> + <description gettext-domain="systemd">Inhibit automatic lock of a home area</description> + <message gettext-domain="systemd">Authentication is required to inhibit automatic lock of a user's home area.</message> + <defaults> + <allow_any>auth_admin_keep</allow_any> + <allow_inactive>auth_admin_keep</allow_inactive> + <allow_active>auth_admin_keep</allow_active> + </defaults> + </action> </policyconfig> |