summaryrefslogtreecommitdiffstats
path: root/src/home
diff options
context:
space:
mode:
Diffstat (limited to 'src/home')
-rw-r--r--src/home/homed-home-bus.c56
-rw-r--r--src/home/homed-home-bus.h1
-rw-r--r--src/home/homed-home.c60
-rw-r--r--src/home/homed-home.h23
-rw-r--r--src/home/homed-manager-bus.c10
-rw-r--r--src/home/org.freedesktop.home1.conf8
-rw-r--r--src/home/org.freedesktop.home1.policy9
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>