From 3841f57b87bbc3060e91a731bb50d0792a98ea90 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Apr 2019 11:05:07 +0200 Subject: [PATCH 01/14] udev: tag "leds" and "backlight" devices for association to a seat These devices do not become user-accessible this way, but they are logically assigned to a seat, which makes a lot of sense, since they are human-facing output devices, and such should belong to one. --- src/login/71-seat.rules.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/login/71-seat.rules.in b/src/login/71-seat.rules.in index b67966cdf6d..6010f048aef 100644 --- a/src/login/71-seat.rules.in +++ b/src/login/71-seat.rules.in @@ -14,6 +14,10 @@ SUBSYSTEM=="sound", KERNEL=="card*", TAG+="seat" SUBSYSTEM=="input", KERNEL=="input*", TAG+="seat" SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat" +# Assign keyboard and LCD backlights to the seat +SUBSYSTEM=="leds", TAG+="seat" +SUBSYSTEM=="backlight", TAG+="seat" + # HyperV currently doesn't do DRM, hence we need to synthesize for HyperV's fb device instead SUBSYSTEM=="graphics", KERNEL=="fb[0-9]", DRIVERS=="hyperv_fb", TAG+="master-of-seat" From e83b8b6bc2e34ccc82ce62c99b34f1c8e67ba83d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Apr 2019 11:06:50 +0200 Subject: [PATCH 02/14] logind: small simplification --- src/login/logind.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/login/logind.c b/src/login/logind.c index 4c0e8ce6b1c..f8a01d156e9 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -44,10 +44,9 @@ static int manager_new(Manager **ret) { *m = (Manager) { .console_active_fd = -1, .reserve_vt_fd = -1, + .idle_action_not_before_usec = now(CLOCK_MONOTONIC), }; - m->idle_action_not_before_usec = now(CLOCK_MONOTONIC); - m->devices = hashmap_new(&string_hash_ops); m->seats = hashmap_new(&string_hash_ops); m->sessions = hashmap_new(&string_hash_ops); From 2a66c2a1eda48433cb7f4ac6e9b9abcf4bd41bf3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Apr 2019 11:07:56 +0200 Subject: [PATCH 03/14] logind: add SetBrightness() bus call for setting brightness of leds/backlight devices associated with a seat This augments the drm/input device management by adding a single method call for setting the brightness of an "leds" or "backlight" kernel class device. This method call requires no privileges to call, but a caller can only change the brightness on sessions that are currently active, and they must own the session. This does not do enumeration of such class devices, feature or range probing, chnage notification; it doesn't help associating graphics or input devices with their backlight or leds devices. For all that clients should go directly to udev/sysfs. The SetBrightness() call is just for executing the actual change operation, that is otherwise privileged. Example line: busctl call org.freedesktop.login1 /org/freedesktop/login1/session/self org.freedesktop.login1.Session SetBrightness ssu "backlight" "intel_backlight" 200 The parameter the SetBrightness() call takes are the kernel subsystem (i.e. "leds" or "backlight"), the device name, and the brightness value. On some hw setting the brightness is slow, and implementation and write access to the sysfs knobs exposes this slowness. Due to this we'll fork off a writer process in the background so that logind doesn't have to block. Moreover, write requestes are coalesced: when a write request is enqueued while one is already being executed it is queued. When another write reques is then enqueued the earlier one is replaced by the newer one, so that only one queued write request per device remains at any time. Method replies are sent as soon as the first write request that happens after the request was received is completed. It is recommended that bus clients turn off the "expect_reply" flag on the dbus messages they send though, that relieves logind from sending completion notification and is particularly a good idea if clients implement reactive UI sliders that send a quick secession of write requests. Replaces: #12413 --- src/libsystemd/sd-bus/bus-common-errors.c | 1 + src/libsystemd/sd-bus/bus-common-errors.h | 1 + src/login/logind-brightness.c | 256 ++++++++++++++++++++++ src/login/logind-brightness.h | 9 + src/login/logind-session-dbus.c | 54 +++++ src/login/logind.c | 3 +- src/login/logind.h | 1 + src/login/meson.build | 34 +-- src/login/org.freedesktop.login1.conf | 4 + src/shared/bus-util.c | 10 + src/shared/bus-util.h | 2 + 11 files changed, 358 insertions(+), 17 deletions(-) create mode 100644 src/login/logind-brightness.c create mode 100644 src/login/logind-brightness.h diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index 6e5fe00e06b..f1b0bfaae2d 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -56,6 +56,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_OPERATION_IN_PROGRESS, EINPROGRESS), SD_BUS_ERROR_MAP(BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, EOPNOTSUPP), SD_BUS_ERROR_MAP(BUS_ERROR_SESSION_BUSY, EBUSY), + SD_BUS_ERROR_MAP(BUS_ERROR_NOT_YOUR_DEVICE, EPERM), SD_BUS_ERROR_MAP(BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, EALREADY), SD_BUS_ERROR_MAP(BUS_ERROR_NO_NTP_SUPPORT, EOPNOTSUPP), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index 8339feb7686..6120fed2cd3 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -51,6 +51,7 @@ #define BUS_ERROR_OPERATION_IN_PROGRESS "org.freedesktop.login1.OperationInProgress" #define BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED "org.freedesktop.login1.SleepVerbNotSupported" #define BUS_ERROR_SESSION_BUSY "org.freedesktop.login1.SessionBusy" +#define BUS_ERROR_NOT_YOUR_DEVICE "org.freedesktop.login1.NotYourDevice" #define BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED "org.freedesktop.timedate1.AutomaticTimeSyncEnabled" #define BUS_ERROR_NO_NTP_SUPPORT "org.freedesktop.timedate1.NoNTPSupport" diff --git a/src/login/logind-brightness.c b/src/login/logind-brightness.c new file mode 100644 index 00000000000..8dfa97d7aed --- /dev/null +++ b/src/login/logind-brightness.c @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "bus-util.h" +#include "device-util.h" +#include "hash-funcs.h" +#include "logind-brightness.h" +#include "logind.h" +#include "process-util.h" +#include "stdio-util.h" + +/* Brightness and LED devices tend to be very slow to write to (often being I2C and such). Writes to the + * sysfs attributes are synchronous, and hence will freeze our process on access. We can't really have that, + * hence we add some complexity: whenever we need to write to the brightness attribute, we do so in a forked + * off process, which terminates when it is done. Watching that process allows us to watch completion of the + * write operation. + * + * To make this even more complex: clients are likely to send us many write requests in a short time-frame + * (because they implement reactive brightness sliders on screen). Let's coalesce writes to make this + * efficient: whenever we get requests to change brightness while we are still writing to the brightness + * attribute, let's remember the request and restart a new one when the initial operation finished. When we + * get another request while one is ongoing and one is pending we'll replace the pending one with the new + * one. + * + * The bus messages are answered when the first write operation finishes that started either due to the + * request or due to a later request that overrode the requested one. + * + * Yes, this is complex, but I don't see an easier way if we want to be both efficient and still support + * completion notification. */ + +typedef struct BrightnessWriter { + Manager *manager; + + sd_device *device; + char *path; + + pid_t child; + + uint32_t brightness; + bool again; + + Set *current_messages; + Set *pending_messages; + + sd_event_source* child_event_source; +} BrightnessWriter; + +static void brightness_writer_free(BrightnessWriter *w) { + if (!w) + return; + + if (w->manager && w->path) + (void) hashmap_remove_value(w->manager->brightness_writers, w->path, w); + + sd_device_unref(w->device); + free(w->path); + + set_free(w->current_messages); + set_free(w->pending_messages); + + w->child_event_source = sd_event_source_unref(w->child_event_source); + + free(w); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(BrightnessWriter*, brightness_writer_free); + +DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR( + brightness_writer_hash_ops, + char, + string_hash_func, + string_compare_func, + BrightnessWriter, + brightness_writer_free); + +static void brightness_writer_reply(BrightnessWriter *w, int error) { + int r; + + assert(w); + + for (;;) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + + m = set_steal_first(w->current_messages); + if (!m) + break; + + if (error == 0) + r = sd_bus_reply_method_return(m, NULL); + else + r = sd_bus_reply_method_errnof(m, error, "Failed to write to brightness device: %m"); + if (r < 0) + log_warning_errno(r, "Failed to send method reply, ignoring: %m"); + } +} + +static int brightness_writer_fork(BrightnessWriter *w); + +static int on_brightness_writer_exit(sd_event_source *s, const siginfo_t *si, void *userdata) { + BrightnessWriter *w = userdata; + int r; + + assert(s); + assert(si); + assert(w); + + assert(si->si_pid == w->child); + w->child = 0; + w->child_event_source = sd_event_source_unref(w->child_event_source); + + brightness_writer_reply(w, + si->si_code == CLD_EXITED && + si->si_status == EXIT_SUCCESS ? 0 : -EPROTO); + + if (w->again) { + /* Another request to change the brightness has been queued. Act on it, but make the pending + * messages the current ones. */ + w->again = false; + set_free(w->current_messages); + w->current_messages = TAKE_PTR(w->pending_messages); + + r = brightness_writer_fork(w); + if (r >= 0) + return 0; + + brightness_writer_reply(w, r); + } + + brightness_writer_free(w); + return 0; +} + +static int brightness_writer_fork(BrightnessWriter *w) { + int r; + + assert(w); + assert(w->manager); + assert(w->child == 0); + assert(!w->child_event_source); + + r = safe_fork("(sd-bright)", FORK_DEATHSIG|FORK_NULL_STDIO|FORK_CLOSE_ALL_FDS|FORK_LOG, &w->child); + if (r < 0) + return r; + if (r == 0) { + char brs[DECIMAL_STR_MAX(uint32_t)+1]; + + /* Child */ + xsprintf(brs, "%" PRIu32, w->brightness); + + r = sd_device_set_sysattr_value(w->device, "brightness", brs); + if (r < 0) { + log_device_error_errno(w->device, r, "Failed to write brightness to device: %m"); + _exit(EXIT_FAILURE); + } + + _exit(EXIT_SUCCESS); + } + + r = sd_event_add_child(w->manager->event, &w->child_event_source, w->child, WEXITED, on_brightness_writer_exit, w); + if (r < 0) + return log_error_errno(r, "Failed to watch brightness writer child " PID_FMT ": %m", w->child); + + return 0; +} + +static int set_add_message(Set **set, sd_bus_message *message) { + int r; + + assert(set); + + if (!message) + return 0; + + r = sd_bus_message_get_expect_reply(message); + if (r <= 0) + return r; + + r = set_ensure_allocated(set, &bus_message_hash_ops); + if (r < 0) + return r; + + r = set_put(*set, message); + if (r < 0) + return r; + + sd_bus_message_ref(message); + return 1; +} + +int manager_write_brightness( + Manager *m, + sd_device *device, + uint32_t brightness, + sd_bus_message *message) { + + _cleanup_(brightness_writer_freep) BrightnessWriter *w = NULL; + BrightnessWriter *existing; + const char *path; + int r; + + assert(m); + assert(device); + + r = sd_device_get_syspath(device, &path); + if (r < 0) + return log_device_error_errno(device, r, "Failed to get sysfs path for brightness device: %m"); + + existing = hashmap_get(m->brightness_writers, path); + if (existing) { + /* There's already a writer for this device. Let's update it with the new brightness, and add + * our message to the set of message to reply when done. */ + + r = set_add_message(&existing->pending_messages, message); + if (r < 0) + return log_error_errno(r, "Failed to add message to set: %m"); + + /* We overide any previously requested brightness here: we coalesce writes, and the newest + * requested brightness is the one we'll put into effect. */ + existing->brightness = brightness; + existing->again = true; /* request another iteration of the writer when the current one is + * complete */ + return 0; + } + + r = hashmap_ensure_allocated(&m->brightness_writers, &brightness_writer_hash_ops); + if (r < 0) + return log_oom(); + + w = new(BrightnessWriter, 1); + if (!w) + return log_oom(); + + *w = (BrightnessWriter) { + .device = sd_device_ref(device), + .path = strdup(path), + .brightness = brightness, + }; + + if (!w->path) + return log_oom(); + + r = hashmap_put(m->brightness_writers, w->path, w); + if (r < 0) + return log_error_errno(r, "Failed to add brightness writer to hashmap: %m"); + w->manager = m; + + r = set_add_message(&w->current_messages, message); + if (r < 0) + return log_error_errno(r, "Failed to add message to set: %m"); + + r = brightness_writer_fork(w); + if (r < 0) + return r; + + TAKE_PTR(w); + return 0; +} diff --git a/src/login/logind-brightness.h b/src/login/logind-brightness.h new file mode 100644 index 00000000000..b22ee37ba77 --- /dev/null +++ b/src/login/logind-brightness.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "sd-bus.h" +#include "sd-device.h" + +#include "logind.h" + +int manager_write_brightness(Manager *m, sd_device *device, uint32_t brightness, sd_bus_message *message); diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index df5bfba9821..c6b8794096a 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -8,10 +8,12 @@ #include "bus-label.h" #include "bus-util.h" #include "fd-util.h" +#include "logind-brightness.h" #include "logind-session-device.h" #include "logind-session.h" #include "logind.h" #include "missing_capability.h" +#include "path-util.h" #include "signal-util.h" #include "stat-util.h" #include "strv.h" @@ -479,6 +481,57 @@ static int method_pause_device_complete(sd_bus_message *message, void *userdata, return sd_bus_reply_method_return(message, NULL); } +static int method_set_brightness(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + _cleanup_(sd_device_unrefp) sd_device *d = NULL; + const char *subsystem, *name, *seat; + Session *s = userdata; + uint32_t brightness; + uid_t uid; + int r; + + assert(message); + assert(s); + + r = sd_bus_message_read(message, "ssu", &subsystem, &name, &brightness); + if (r < 0) + return r; + + if (!STR_IN_SET(subsystem, "backlight", "leds")) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Subsystem type %s not supported, must be one of 'backlight' or 'leds'.", subsystem); + if (!filename_is_valid(name)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not a valid device name %s, refusing.", name); + + if (!s->seat) + return sd_bus_error_setf(error, BUS_ERROR_NOT_YOUR_DEVICE, "Your session has no seat, refusing."); + if (s->seat->active != s) + return sd_bus_error_setf(error, BUS_ERROR_NOT_YOUR_DEVICE, "Session is not in foreground, refusing."); + + 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; + + if (uid != 0 && uid != s->user->uid) + return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may change brightness."); + + r = sd_device_new_from_subsystem_sysname(&d, subsystem, name); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to open device %s:%s: %m", subsystem, name); + + if (sd_device_get_property_value(d, "ID_SEAT", &seat) >= 0 && !streq_ptr(seat, s->seat->id)) + return sd_bus_error_setf(error, BUS_ERROR_NOT_YOUR_DEVICE, "Device %s:%s does not belong to your seat %s, refusing.", subsystem, name, s->seat->id); + + r = manager_write_brightness(s->manager, d, brightness, message); + if (r < 0) + return r; + + return 1; +} + const sd_bus_vtable session_vtable[] = { SD_BUS_VTABLE_START(0), @@ -519,6 +572,7 @@ const sd_bus_vtable session_vtable[] = { SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetBrightness", "ssu", NULL, method_set_brightness, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_SIGNAL("PauseDevice", "uus", 0), SD_BUS_SIGNAL("ResumeDevice", "uuh", 0), diff --git a/src/login/logind.c b/src/login/logind.c index f8a01d156e9..89807dc917d 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -117,6 +117,7 @@ static Manager* manager_unref(Manager *m) { hashmap_free(m->users); hashmap_free(m->inhibitors); hashmap_free(m->buttons); + hashmap_free(m->brightness_writers); hashmap_free(m->user_units); hashmap_free(m->session_units); @@ -1214,7 +1215,7 @@ static int run(int argc, char *argv[]) { (void) mkdir_label("/run/systemd/users", 0755); (void) mkdir_label("/run/systemd/sessions", 0755); - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGHUP, SIGTERM, SIGINT, -1) >= 0); + assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGHUP, SIGTERM, SIGINT, SIGCHLD, -1) >= 0); r = manager_new(&m); if (r < 0) diff --git a/src/login/logind.h b/src/login/logind.h index 7b6f73c6ec6..0089fff87a7 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -31,6 +31,7 @@ struct Manager { Hashmap *users; Hashmap *inhibitors; Hashmap *buttons; + Hashmap *brightness_writers; LIST_HEAD(Seat, seat_gc_queue); LIST_HEAD(Session, session_gc_queue); diff --git a/src/login/meson.build b/src/login/meson.build index 1cc75fd1cfe..89ce81f767f 100644 --- a/src/login/meson.build +++ b/src/login/meson.build @@ -12,29 +12,31 @@ logind_gperf_c = custom_target( command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) liblogind_core_sources = files(''' - logind-core.c - logind-device.c - logind-device.h - logind-button.c - logind-button.h + logind-acl.h logind-action.c logind-action.h - logind-seat.c - logind-seat.h - logind-session.c - logind-session.h - logind-session-device.c - logind-session-device.h - logind-user.c - logind-user.h + logind-brightness.c + logind-brightness.h + logind-button.c + logind-button.h + logind-core.c + logind-dbus.c + logind-device.c + logind-device.h logind-inhibit.c logind-inhibit.h - logind-dbus.c - logind-session-dbus.c logind-seat-dbus.c + logind-seat.c + logind-seat.h + logind-session-dbus.c + logind-session-device.c + logind-session-device.h + logind-session.c + logind-session.h logind-user-dbus.c + logind-user.c + logind-user.h logind-utmp.c - logind-acl.h '''.split()) liblogind_core_sources += [logind_gperf_c] diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf index f3c13ad89a0..124a25810e3 100644 --- a/src/login/org.freedesktop.login1.conf +++ b/src/login/org.freedesktop.login1.conf @@ -302,6 +302,10 @@ send_interface="org.freedesktop.login1.Session" send_member="PauseDeviceComplete"/> + + diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index c2440271feb..81acff4602b 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1767,3 +1767,13 @@ int bus_reply_pair_array(sd_bus_message *m, char **l) { return sd_bus_send(NULL, reply, NULL); } + +static void bus_message_unref_wrapper(void *m) { + sd_bus_message_unref(m); +} + +const struct hash_ops bus_message_hash_ops = { + .hash = trivial_hash_func, + .compare = trivial_compare_func, + .free_value = bus_message_unref_wrapper, +}; diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index 59bfdb23981..3216b0c37a1 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -179,3 +179,5 @@ static inline int bus_open_system_watch_bind(sd_bus **ret) { } int bus_reply_pair_array(sd_bus_message *m, char **l); + +extern const struct hash_ops bus_message_hash_ops; From 19483c60bb105fa33831dfdee221c86db7f12a4e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Apr 2019 11:17:59 +0200 Subject: [PATCH 04/14] logind: make sure the service gets access to the linger directory Fixes: #12401 --- units/systemd-logind.service.in | 1 + 1 file changed, 1 insertion(+) diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in index 3eef95c6614..8a7262776f9 100644 --- a/units/systemd-logind.service.in +++ b/units/systemd-logind.service.in @@ -43,6 +43,7 @@ RestrictRealtime=yes RestrictSUIDSGID=yes RuntimeDirectory=systemd/sessions systemd/seats systemd/users systemd/inhibit systemd/shutdown RuntimeDirectoryPreserve=yes +StateDirectory=systemd/linger SystemCallArchitectures=native SystemCallErrorNumber=EPERM SystemCallFilter=@system-service From a2dcb1d78737d3daa301ee63fbdd02837acb71a8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Apr 2019 11:24:15 +0200 Subject: [PATCH 05/14] logind: consider "greeter" sessions suitable as "display" sessions of a user Interestingly, elect_display_compare() already ordered "user" sessions before "greeter" sessions, though nothing other than "user" sessions where ever considered anyway. Fixes: #12399 --- src/login/logind-user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/login/logind-user.c b/src/login/logind-user.c index c5d442865cc..05c57c1c327 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -663,7 +663,7 @@ static bool elect_display_filter(Session *s) { /* Return true if the session is a candidate for the user’s ‘primary session’ or ‘display’. */ assert(s); - return s->class == SESSION_USER && s->started && !s->stopping; + return IN_SET(s->class, SESSION_USER, SESSION_GREETER) && s->started && !s->stopping; } static int elect_display_compare(Session *s1, Session *s2) { From 469df514c7e10fbfdc3abb243e0458fd44084fc2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Apr 2019 11:25:48 +0200 Subject: [PATCH 06/14] logind: make a constant array static --- src/login/logind-user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 05c57c1c327..1f07a98dd8e 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -668,7 +668,7 @@ static bool elect_display_filter(Session *s) { static int elect_display_compare(Session *s1, Session *s2) { /* Indexed by SessionType. Lower numbers mean more preferred. */ - const int type_ranks[_SESSION_TYPE_MAX] = { + static const int type_ranks[_SESSION_TYPE_MAX] = { [SESSION_UNSPECIFIED] = 0, [SESSION_TTY] = -2, [SESSION_X11] = -3, From 3b92c086a8d5338e2164ffa0ae48b3d03d10cfb5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Apr 2019 17:55:36 +0200 Subject: [PATCH 07/14] logind: make "self" and "auto" magic strings when operating on seats + sessions Most of the operations one can do on sessions so far accepted an empty session name as a shortcut for the caller's session. This is quite useful traditionally, but much less useful than it used to be, since most user code now (rightfully) runs in --user context, not in a session. With this change we tweak the logic a bit: we introduce the two special session and seat names "self" and "auto". The former refers to the session/seat the client is in, and is hence mostly equivalent to te empty string "" as before. However, the latter refers to the session/seat the client is in if that exists, with a fallback of the user's display session if not. Clients can hence reference "auto" instead of the empty string if they really don't want to think much about sessions. Why "self" btw? Previously, we'd already expose a special dbus object with the path /org/freedesktop/login1/session/self (and similar for the seat), matching what the empty string did for bus calls that took a session name. With this scheme we reuse this identifier and introduce "auto" in a similar way. Of course this means real-life seats and sessions can never be named "self" or "auto", but they aren't anyway: valid seat names have to start with "seat" anyway, and sessions are generated server-side as either a numeric value or "c" suffixed with a counter ID. Fixes: #12399 --- src/login/logind-dbus.c | 111 +++++++++++++++++++++----------- src/login/logind-seat-dbus.c | 70 ++++++++++++-------- src/login/logind-seat.h | 8 +++ src/login/logind-session-dbus.c | 68 ++++++++++++------- src/login/logind-session.h | 9 +++ 5 files changed, 179 insertions(+), 87 deletions(-) diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index be767186ff8..6dd4bcb17eb 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -46,47 +46,78 @@ #include "utmp-wtmp.h" #include "virt.h" -static int get_sender_session(Manager *m, sd_bus_message *message, sd_bus_error *error, Session **ret) { +static int get_sender_session( + Manager *m, + sd_bus_message *message, + bool consult_display, + sd_bus_error *error, + Session **ret) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + Session *session = NULL; const char *name; - Session *session; int r; - /* Get client login session. This is not what you are looking for these days, - * as apps may instead belong to a user service unit. This includes terminal - * emulators and hence command-line apps. */ - r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds); + /* Acquire the sender's session. This first checks if the sending process is inside a session itself, + * and returns that. If not and 'consult_display' is true, this returns the display session of the + * owning user of the caller. */ + + r = sd_bus_query_sender_creds(message, + SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT| + (consult_display ? SD_BUS_CREDS_OWNER_UID : 0), &creds); if (r < 0) return r; r = sd_bus_creds_get_session(creds, &name); - if (r == -ENXIO) - goto err_no_session; - if (r < 0) - return r; + if (r < 0) { + if (r != -ENXIO) + return r; + + if (consult_display) { + uid_t uid; + + r = sd_bus_creds_get_owner_uid(creds, &uid); + if (r < 0) { + if (r != -ENXIO) + return r; + } else { + User *user; + + user = hashmap_get(m->users, UID_TO_PTR(uid)); + if (user) + session = user->display; + } + } + } else + session = hashmap_get(m->sessions, name); - session = hashmap_get(m->sessions, name); if (!session) - goto err_no_session; + return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, + consult_display ? + "Caller does not belong to any known session and doesn't own any suitable session." : + "Caller does not belong to any known session."); *ret = session; return 0; - -err_no_session: - return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, - "Caller does not belong to any known session"); } -int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) { +int manager_get_session_from_creds( + Manager *m, + sd_bus_message *message, + const char *name, + sd_bus_error *error, + Session **ret) { + Session *session; assert(m); assert(message); assert(ret); - if (isempty(name)) - return get_sender_session(m, message, error, ret); + if (SEAT_IS_SELF(name)) /* the caller's own session */ + return get_sender_session(m, message, false, error, ret); + if (SEAT_IS_AUTO(name)) /* The caller's own session if they have one, otherwise their user's display session */ + return get_sender_session(m, message, true, error, ret); session = hashmap_get(m->sessions, name); if (!session) @@ -97,7 +128,6 @@ int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const ch } static int get_sender_user(Manager *m, sd_bus_message *message, sd_bus_error *error, User **ret) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; uid_t uid; User *user; @@ -109,21 +139,20 @@ static int get_sender_user(Manager *m, sd_bus_message *message, sd_bus_error *er return r; r = sd_bus_creds_get_owner_uid(creds, &uid); - if (r == -ENXIO) - goto err_no_user; - if (r < 0) - return r; + if (r < 0) { + if (r != -ENXIO) + return r; + + user = NULL; + } else + user = hashmap_get(m->users, UID_TO_PTR(uid)); - user = hashmap_get(m->users, UID_TO_PTR(uid)); if (!user) - goto err_no_user; + return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID, + "Caller does not belong to any logged in or lingering user"); *ret = user; return 0; - -err_no_user: - return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID, - "Caller does not belong to any logged in user or lingering user"); } int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret) { @@ -145,7 +174,13 @@ int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, return 0; } -int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Seat **ret) { +int manager_get_seat_from_creds( + Manager *m, + sd_bus_message *message, + const char *name, + sd_bus_error *error, + Seat **ret) { + Seat *seat; int r; @@ -153,16 +188,17 @@ int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char assert(message); assert(ret); - if (isempty(name)) { + if (SEAT_IS_SELF(name) || SEAT_IS_AUTO(name)) { Session *session; - r = manager_get_session_from_creds(m, message, NULL, error, &session); + /* Use these special seat names as session names */ + r = manager_get_session_from_creds(m, message, name, error, &session); if (r < 0) return r; seat = session->seat; if (!seat) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "Session has no seat."); + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "Session '%s' has no seat.", session->id); } else { seat = hashmap_get(m->seats, name); if (!seat) @@ -830,6 +866,10 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus } while (hashmap_get(m->sessions, id)); } + /* The generated names should not clash with 'auto' or 'self' */ + assert(!SESSION_IS_SELF(id)); + assert(!SESSION_IS_AUTO(id)); + /* If we are not watching utmp already, try again */ manager_reconnect_utmp(m); @@ -990,8 +1030,7 @@ static int method_activate_session_on_seat(sd_bus_message *message, void *userda assert(message); assert(m); - /* Same as ActivateSession() but refuses to work if - * the seat doesn't match */ + /* Same as ActivateSession() but refuses to work if the seat doesn't match */ r = sd_bus_message_read(message, "ss", &session_name, &seat_name); if (r < 0) diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index 6ee5a1c95d2..fa67d9c786d 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -255,7 +255,10 @@ const sd_bus_vtable seat_vtable[] = { }; int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + _cleanup_free_ char *e = NULL; + sd_bus_message *message; Manager *m = userdata; + const char *p; Seat *seat; int r; @@ -265,32 +268,25 @@ int seat_object_find(sd_bus *bus, const char *path, const char *interface, void assert(found); assert(m); - if (streq(path, "/org/freedesktop/login1/seat/self")) { - sd_bus_message *message; + p = startswith(path, "/org/freedesktop/login1/seat/"); + if (!p) + return 0; - message = sd_bus_get_current_message(bus); - if (!message) - return 0; + e = bus_label_unescape(p); + if (!e) + return -ENOMEM; - r = manager_get_seat_from_creds(m, message, NULL, error, &seat); - if (r < 0) - return r; - } else { - _cleanup_free_ char *e = NULL; - const char *p; + message = sd_bus_get_current_message(bus); + if (!message) + return 0; - p = startswith(path, "/org/freedesktop/login1/seat/"); - if (!p) - return 0; - - e = bus_label_unescape(p); - if (!e) - return -ENOMEM; - - seat = hashmap_get(m->seats, e); - if (!seat) - return 0; + r = manager_get_seat_from_creds(m, message, e, error, &seat); + if (r == -ENXIO) { + sd_bus_error_free(error); + return 0; } + if (r < 0) + return r; *found = seat; return 1; @@ -335,25 +331,47 @@ int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char *** message = sd_bus_get_current_message(bus); if (message) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - const char *name; - Session *session; - r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds); + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds); if (r >= 0) { + bool may_auto = false; + const char *name; + r = sd_bus_creds_get_session(creds, &name); if (r >= 0) { + Session *session; + session = hashmap_get(m->sessions, name); if (session && session->seat) { r = strv_extend(&l, "/org/freedesktop/login1/seat/self"); if (r < 0) return r; + + may_auto = true; } } + + if (!may_auto) { + uid_t uid; + + r = sd_bus_creds_get_owner_uid(creds, &uid); + if (r >= 0) { + User *user; + + user = hashmap_get(m->users, UID_TO_PTR(uid)); + may_auto = user && user->display && user->display->seat; + } + } + + if (may_auto) { + r = strv_extend(&l, "/org/freedesktop/login1/seat/auto"); + if (r < 0) + return r; + } } } *nodes = TAKE_PTR(l); - return 1; } diff --git a/src/login/logind-seat.h b/src/login/logind-seat.h index 6236f1360bc..d1a105adddd 100644 --- a/src/login/logind-seat.h +++ b/src/login/logind-seat.h @@ -77,3 +77,11 @@ int seat_send_signal(Seat *s, bool new_seat); int seat_send_changed(Seat *s, const char *properties, ...) _sentinel_; int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error); + +static inline bool SEAT_IS_SELF(const char *name) { + return isempty(name) || streq(name, "self"); +} + +static inline bool SEAT_IS_AUTO(const char *name) { + return streq_ptr(name, "auto"); +} diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index c6b8794096a..5eb240834ad 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -17,6 +17,7 @@ #include "signal-util.h" #include "stat-util.h" #include "strv.h" +#include "user-util.h" #include "util.h" static int property_get_user( @@ -583,8 +584,11 @@ const sd_bus_vtable session_vtable[] = { }; int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + _cleanup_free_ char *e = NULL; + sd_bus_message *message; Manager *m = userdata; Session *session; + const char *p; int r; assert(bus); @@ -593,32 +597,25 @@ int session_object_find(sd_bus *bus, const char *path, const char *interface, vo assert(found); assert(m); - if (streq(path, "/org/freedesktop/login1/session/self")) { - sd_bus_message *message; + p = startswith(path, "/org/freedesktop/login1/session/"); + if (!p) + return 0; - message = sd_bus_get_current_message(bus); - if (!message) - return 0; + e = bus_label_unescape(p); + if (!e) + return -ENOMEM; - r = manager_get_session_from_creds(m, message, NULL, error, &session); - if (r < 0) - return r; - } else { - _cleanup_free_ char *e = NULL; - const char *p; + message = sd_bus_get_current_message(bus); + if (!message) + return 0; - p = startswith(path, "/org/freedesktop/login1/session/"); - if (!p) - return 0; - - e = bus_label_unescape(p); - if (!e) - return -ENOMEM; - - session = hashmap_get(m->sessions, e); - if (!session) - return 0; + r = manager_get_session_from_creds(m, message, e, error, &session); + if (r == -ENXIO) { + sd_bus_error_free(error); + return 0; } + if (r < 0) + return r; *found = session; return 1; @@ -663,10 +660,12 @@ int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char message = sd_bus_get_current_message(bus); if (message) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - const char *name; - r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds); + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds); if (r >= 0) { + bool may_auto = false; + const char *name; + r = sd_bus_creds_get_session(creds, &name); if (r >= 0) { session = hashmap_get(m->sessions, name); @@ -674,13 +673,32 @@ int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char r = strv_extend(&l, "/org/freedesktop/login1/session/self"); if (r < 0) return r; + + may_auto = true; } } + + if (!may_auto) { + uid_t uid; + + r = sd_bus_creds_get_owner_uid(creds, &uid); + if (r >= 0) { + User *user; + + user = hashmap_get(m->users, UID_TO_PTR(uid)); + may_auto = user && user->display; + } + } + + if (may_auto) { + r = strv_extend(&l, "/org/freedesktop/login1/session/auto"); + if (r < 0) + return r; + } } } *nodes = TAKE_PTR(l); - return 1; } diff --git a/src/login/logind-session.h b/src/login/logind-session.h index f3c17a8d918..884a8f45b89 100644 --- a/src/login/logind-session.h +++ b/src/login/logind-session.h @@ -7,6 +7,7 @@ typedef enum KillWho KillWho; #include "list.h" #include "login-util.h" #include "logind-user.h" +#include "string-util.h" typedef enum SessionState { SESSION_OPENING, /* Session scope is being created */ @@ -183,3 +184,11 @@ int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_ int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error); + +static inline bool SESSION_IS_SELF(const char *name) { + return isempty(name) || streq(name, "self"); +} + +static inline bool SESSION_IS_AUTO(const char *name) { + return streq_ptr(name, "auto"); +} From 544c4e1eda4b15beec8a9d7e3708b262b954e757 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Apr 2019 18:02:03 +0200 Subject: [PATCH 08/14] loginctl: drop $XDG_SESSION_ID env var magic The server side can do something similar, but better on its own, let's hence rely on that. --- src/login/loginctl.c | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 687a534f7b8..2ad9887066f 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -846,23 +846,11 @@ static int show_session(int argc, char *argv[], void *userdata) { (void) pager_open(arg_pager_flags); if (argc <= 1) { - const char *session, *p = "/org/freedesktop/login1/session/self"; - + /* If no argument is specified inspect the manager itself */ if (properties) - /* If no argument is specified inspect the manager itself */ return show_properties(bus, "/org/freedesktop/login1", &new_line); - /* And in the pretty case, show data of the calling session */ - session = getenv("XDG_SESSION_ID"); - if (session) { - r = get_session_path(bus, session, &error, &path); - if (r < 0) - return log_error_errno(r, "Failed to get session path: %s", bus_error_message(&error, r)); - - p = path; - } - - return print_session_status_info(bus, p, &new_line); + return print_session_status_info(bus, "/org/freedesktop/login1/session/auto", &new_line); } for (i = 1; i < argc; i++) { @@ -895,8 +883,7 @@ static int show_user(int argc, char *argv[], void *userdata) { (void) pager_open(arg_pager_flags); if (argc <= 1) { - /* If not argument is specified inspect the manager - * itself */ + /* If no argument is specified inspect the manager itself */ if (properties) return show_properties(bus, "/org/freedesktop/login1", &new_line); @@ -953,12 +940,11 @@ static int show_seat(int argc, char *argv[], void *userdata) { (void) pager_open(arg_pager_flags); if (argc <= 1) { - /* If not argument is specified inspect the manager - * itself */ + /* If no argument is specified inspect the manager itself */ if (properties) return show_properties(bus, "/org/freedesktop/login1", &new_line); - return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line); + return print_seat_status_info(bus, "/org/freedesktop/login1/seat/auto", &new_line); } for (i = 1; i < argc; i++) { @@ -1005,11 +991,8 @@ static int activate(int argc, char *argv[], void *userdata) { polkit_agent_open_if_enabled(arg_transport, arg_ask_password); if (argc < 2) { - /* No argument? Let's either use $XDG_SESSION_ID (if specified), or an empty - * session name, in which case logind will try to guess our session. */ - short_argv[0] = argv[0]; - short_argv[1] = getenv("XDG_SESSION_ID") ?: (char*) ""; + short_argv[1] = (char*) ""; short_argv[2] = NULL; argv = short_argv; @@ -1030,7 +1013,7 @@ static int activate(int argc, char *argv[], void *userdata) { &error, NULL, "s", argv[i]); if (r < 0) - return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, -r)); + return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r)); } return 0; From b0bd159f678dc903b30b437df1a8bcf59e14182b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Apr 2019 13:47:33 +0200 Subject: [PATCH 09/14] logind: prefer hashmap_contains() over hashmap_get() --- src/login/logind-dbus.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 6dd4bcb17eb..1623151f8c3 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -845,11 +845,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus if (asprintf(&id, "%"PRIu32, audit_id) < 0) return -ENOMEM; - /* Wut? There's already a session by this name and we - * didn't find it above? Weird, then let's not trust - * the audit data and let's better register a new - * ID */ - if (hashmap_get(m->sessions, id)) { + /* Wut? There's already a session by this name and we didn't find it above? Weird, then let's + * not trust the audit data and let's better register a new ID */ + if (hashmap_contains(m->sessions, id)) { log_warning("Existing logind session ID %s used by new audit session, ignoring.", id); audit_id = AUDIT_SESSION_INVALID; id = mfree(id); @@ -863,7 +861,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus if (asprintf(&id, "c%lu", ++m->session_counter) < 0) return -ENOMEM; - } while (hashmap_get(m->sessions, id)); + } while (hashmap_contains(m->sessions, id)); } /* The generated names should not clash with 'auto' or 'self' */ From bda0613072b82c357e11cdc2171593dffd0e8d31 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Apr 2019 13:47:52 +0200 Subject: [PATCH 10/14] logind: validate /sys fs path a bit more strictly --- src/login/logind-dbus.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 1623151f8c3..e1b182150b4 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1404,6 +1404,8 @@ static int method_attach_device(sd_bus_message *message, void *userdata, sd_bus_ if (r < 0) return r; + if (!path_is_normalized(sysfs)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not normalized", sysfs); if (!path_startswith(sysfs, "/sys")) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not in /sys", sysfs); From ed179418aeb550138d308263eb4742683282c727 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Apr 2019 13:48:11 +0200 Subject: [PATCH 11/14] logind: support self/auto seats for AttachDevice(), too --- src/login/logind-dbus.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index e1b182150b4..6655d395ce6 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1409,8 +1409,17 @@ static int method_attach_device(sd_bus_message *message, void *userdata, sd_bus_ if (!path_startswith(sysfs, "/sys")) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not in /sys", sysfs); - if (!seat_name_is_valid(seat)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat %s is not valid", seat); + if (SEAT_IS_SELF(seat) || SEAT_IS_AUTO(seat)) { + Seat *found; + + r = manager_get_seat_from_creds(m, message, seat, error, &found); + if (r < 0) + return r; + + seat = found->id; + + } else if (!seat_name_is_valid(seat)) /* Note that a seat does not have to exist yet for this operation to succeed */ + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat name %s is not valid", seat); r = bus_verify_polkit_async( message, From 77c45ce3369f95f1f143830de460639619489ac0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Apr 2019 13:48:34 +0200 Subject: [PATCH 12/14] logind: convert ENXIO into 0, to signal 'not found' cleanly --- src/login/logind-user-dbus.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index fcaeba13f6b..ca3ea7e432f 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -245,6 +245,10 @@ int user_object_find(sd_bus *bus, const char *path, const char *interface, void return 0; r = manager_get_user_from_creds(m, message, UID_INVALID, error, &user); + if (r == -ENXIO) { + sd_bus_error_free(error); + return 0; + } if (r < 0) return r; } else { @@ -305,10 +309,11 @@ int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char *** message = sd_bus_get_current_message(bus); if (message) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - uid_t uid; r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds); if (r >= 0) { + uid_t uid; + r = sd_bus_creds_get_owner_uid(creds, &uid); if (r >= 0) { user = hashmap_get(m->users, UID_TO_PTR(uid)); From 5802d977c9477f0c15aee1d595f1ed947c2b9db8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Apr 2019 13:00:36 +0200 Subject: [PATCH 13/14] update TODO --- TODO | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/TODO b/TODO index e8f59d0932f..0c26f9d37e0 100644 --- a/TODO +++ b/TODO @@ -27,6 +27,13 @@ Features: * when killing due to service watchdog timeout maybe detect whether target process is under ptracing and then log loudly and continue instead. +* introduce a new group to own TPM devices + +* make rfkill uaccess controllable by default, i.e. steal rule from + gnome-bluetooth and friends + +* warn if udev rules files are marked executable (docker?) + * tweak journald context caching. In addition to caching per-process attributes keyed by PID, cache per-cgroup attributes (i.e. the various xattrs we read) keyed by cgroup path, and guarded by ctime changes. This should provide us From 6ecda0fbefa3a49990fbadc48892459b97bf3002 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Apr 2019 15:05:14 +0200 Subject: [PATCH 14/14] logind: split out dbus header files into their own Previously, logind's logind-session.h would define prototypes for logind-session.c and logind-session-dbus.c. Split that out, so that there's a separate logind-session-dbus.h for that. Similar for seats and users as well as the manager itself. This changes no code, just rearranges where protoypes are located. --- src/login/logind-action.c | 2 ++ src/login/logind-dbus.c | 4 ++++ src/login/logind-dbus.h | 31 +++++++++++++++++++++++++++++++ src/login/logind-device.c | 1 + src/login/logind-inhibit.c | 1 + src/login/logind-seat-dbus.c | 3 +++ src/login/logind-seat-dbus.h | 17 +++++++++++++++++ src/login/logind-seat.c | 2 ++ src/login/logind-seat.h | 11 ----------- src/login/logind-session-dbus.c | 4 ++++ src/login/logind-session-dbus.h | 23 +++++++++++++++++++++++ src/login/logind-session-device.c | 3 ++- src/login/logind-session.c | 4 ++++ src/login/logind-session.h | 17 ----------------- src/login/logind-user-dbus.c | 3 +++ src/login/logind-user-dbus.h | 17 +++++++++++++++++ src/login/logind-user.c | 2 ++ src/login/logind-user.h | 11 ----------- src/login/logind.c | 4 ++++ src/login/logind.h | 24 ------------------------ src/login/meson.build | 4 ++++ 21 files changed, 124 insertions(+), 64 deletions(-) create mode 100644 src/login/logind-dbus.h create mode 100644 src/login/logind-seat-dbus.h create mode 100644 src/login/logind-session-dbus.h create mode 100644 src/login/logind-user-dbus.h diff --git a/src/login/logind-action.c b/src/login/logind-action.c index 6c9366761da..4f97e0d9bb5 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -8,6 +8,8 @@ #include "conf-parser.h" #include "format-util.h" #include "logind-action.h" +#include "logind-dbus.h" +#include "logind-session-dbus.h" #include "process-util.h" #include "sleep-config.h" #include "special.h" diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 6655d395ce6..0e8925ab944 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -27,6 +27,10 @@ #include "fileio.h" #include "format-util.h" #include "fs-util.h" +#include "logind-dbus.h" +#include "logind-seat-dbus.h" +#include "logind-session-dbus.h" +#include "logind-user-dbus.h" #include "logind.h" #include "missing_capability.h" #include "mkdir.h" diff --git a/src/login/logind-dbus.h b/src/login/logind-dbus.h new file mode 100644 index 00000000000..6c73a9654f6 --- /dev/null +++ b/src/login/logind-dbus.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "sd-bus.h" + +#include "logind.h" +#include "logind-session.h" +#include "logind-user.h" + +int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret); +int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret); +int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Seat **ret); + +int manager_dispatch_delayed(Manager *manager, bool timeout); + +int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name, InhibitWhat w, sd_bus_error *error); + +int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error); +int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error); +int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error); +int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error); + +int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_; + +int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, char **wants, char **after, const char *requires_mounts_for, sd_bus_message *more_properties, sd_bus_error *error, char **job); +int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); +int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); +int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error); +int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error); +int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *error); +int manager_job_is_active(Manager *manager, const char *path, sd_bus_error *error); diff --git a/src/login/logind-device.c b/src/login/logind-device.c index e724365b131..20108544aad 100644 --- a/src/login/logind-device.c +++ b/src/login/logind-device.c @@ -4,6 +4,7 @@ #include "alloc-util.h" #include "logind-device.h" +#include "logind-seat-dbus.h" #include "util.h" Device* device_new(Manager *m, const char *sysfs, bool master) { diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index d427dcaa012..d963706dcef 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -13,6 +13,7 @@ #include "fd-util.h" #include "fileio.h" #include "format-util.h" +#include "logind-dbus.h" #include "logind-inhibit.h" #include "mkdir.h" #include "parse-util.h" diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index fa67d9c786d..c33a0e0ad43 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -7,7 +7,10 @@ #include "bus-common-errors.h" #include "bus-label.h" #include "bus-util.h" +#include "logind-dbus.h" +#include "logind-seat-dbus.h" #include "logind-seat.h" +#include "logind-session-dbus.h" #include "logind.h" #include "missing_capability.h" #include "strv.h" diff --git a/src/login/logind-seat-dbus.h b/src/login/logind-seat-dbus.h new file mode 100644 index 00000000000..2590f64922b --- /dev/null +++ b/src/login/logind-seat-dbus.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "sd-bus.h" + +#include "logind-seat.h" + +extern const sd_bus_vtable seat_vtable[]; + +int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); +int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); +char *seat_bus_path(Seat *s); + +int seat_send_signal(Seat *s, bool new_seat); +int seat_send_changed(Seat *s, const char *properties, ...) _sentinel_; + +int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c index f5ffb68238e..dc578adf638 100644 --- a/src/login/logind-seat.c +++ b/src/login/logind-seat.c @@ -13,7 +13,9 @@ #include "fileio.h" #include "format-util.h" #include "logind-acl.h" +#include "logind-seat-dbus.h" #include "logind-seat.h" +#include "logind-session-dbus.h" #include "mkdir.h" #include "parse-util.h" #include "stdio-util.h" diff --git a/src/login/logind-seat.h b/src/login/logind-seat.h index d1a105adddd..64cdf2f25ae 100644 --- a/src/login/logind-seat.h +++ b/src/login/logind-seat.h @@ -67,17 +67,6 @@ void seat_add_to_gc_queue(Seat *s); bool seat_name_is_valid(const char *name); -extern const sd_bus_vtable seat_vtable[]; - -int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); -int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); -char *seat_bus_path(Seat *s); - -int seat_send_signal(Seat *s, bool new_seat); -int seat_send_changed(Seat *s, const char *properties, ...) _sentinel_; - -int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error); - static inline bool SEAT_IS_SELF(const char *name) { return isempty(name) || streq(name, "self"); } diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index 5eb240834ad..c297f62cdf9 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -9,8 +9,12 @@ #include "bus-util.h" #include "fd-util.h" #include "logind-brightness.h" +#include "logind-dbus.h" +#include "logind-seat-dbus.h" +#include "logind-session-dbus.h" #include "logind-session-device.h" #include "logind-session.h" +#include "logind-user-dbus.h" #include "logind.h" #include "missing_capability.h" #include "path-util.h" diff --git a/src/login/logind-session-dbus.h b/src/login/logind-session-dbus.h new file mode 100644 index 00000000000..9d2315cc60d --- /dev/null +++ b/src/login/logind-session-dbus.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "sd-bus.h" + +#include "logind-session.h" + +extern const sd_bus_vtable session_vtable[]; +int session_node_enumerator(sd_bus *bus, const char *path,void *userdata, char ***nodes, sd_bus_error *error); +int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); +char *session_bus_path(Session *s); + +int session_send_signal(Session *s, bool new_session); +int session_send_changed(Session *s, const char *properties, ...) _sentinel_; +int session_send_lock(Session *s, bool lock); +int session_send_lock_all(Manager *m, bool lock); + +int session_send_create_reply(Session *s, sd_bus_error *error); + +int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/login/logind-session-device.c b/src/login/logind-session-device.c index 3e2ff6d5b8d..3057e72394d 100644 --- a/src/login/logind-session-device.c +++ b/src/login/logind-session-device.c @@ -7,14 +7,15 @@ #include #include "sd-device.h" +#include "sd-daemon.h" #include "alloc-util.h" #include "bus-util.h" #include "fd-util.h" +#include "logind-session-dbus.h" #include "logind-session-device.h" #include "missing.h" #include "parse-util.h" -#include "sd-daemon.h" #include "util.h" enum SessionDeviceNotifications { diff --git a/src/login/logind-session.c b/src/login/logind-session.c index f1efeb0e017..17700c69219 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -22,7 +22,11 @@ #include "fileio.h" #include "format-util.h" #include "io-util.h" +#include "logind-dbus.h" +#include "logind-seat-dbus.h" +#include "logind-session-dbus.h" #include "logind-session.h" +#include "logind-user-dbus.h" #include "mkdir.h" #include "parse-util.h" #include "path-util.h" diff --git a/src/login/logind-session.h b/src/login/logind-session.h index 884a8f45b89..50fe29e7970 100644 --- a/src/login/logind-session.h +++ b/src/login/logind-session.h @@ -146,18 +146,6 @@ int session_kill(Session *s, KillWho who, int signo); SessionState session_get_state(Session *u); -extern const sd_bus_vtable session_vtable[]; -int session_node_enumerator(sd_bus *bus, const char *path,void *userdata, char ***nodes, sd_bus_error *error); -int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); -char *session_bus_path(Session *s); - -int session_send_signal(Session *s, bool new_session); -int session_send_changed(Session *s, const char *properties, ...) _sentinel_; -int session_send_lock(Session *s, bool lock); -int session_send_lock_all(Manager *m, bool lock); - -int session_send_create_reply(Session *s, sd_bus_error *error); - const char* session_state_to_string(SessionState t) _const_; SessionState session_state_from_string(const char *s) _pure_; @@ -180,11 +168,6 @@ bool session_is_controller(Session *s, const char *sender); int session_set_controller(Session *s, const char *sender, bool force, bool prepare); void session_drop_controller(Session *s); -int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_error *error); -int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error); -int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error); -int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error); - static inline bool SESSION_IS_SELF(const char *name) { return isempty(name) || streq(name, "self"); } diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index ca3ea7e432f..beb97362e73 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -6,6 +6,9 @@ #include "alloc-util.h" #include "bus-util.h" #include "format-util.h" +#include "logind-dbus.h" +#include "logind-session-dbus.h" +#include "logind-user-dbus.h" #include "logind-user.h" #include "logind.h" #include "missing_capability.h" diff --git a/src/login/logind-user-dbus.h b/src/login/logind-user-dbus.h new file mode 100644 index 00000000000..acfcb981cf3 --- /dev/null +++ b/src/login/logind-user-dbus.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "sd-bus.h" + +#include "logind-user.h" + +extern const sd_bus_vtable user_vtable[]; +int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); +int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); +char *user_bus_path(User *s); + +int user_send_signal(User *u, bool new_user); +int user_send_changed(User *u, const char *properties, ...) _sentinel_; + +int bus_user_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 1f07a98dd8e..b17fb2e3225 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -19,7 +19,9 @@ #include "hashmap.h" #include "label.h" #include "limits-util.h" +#include "logind-dbus.h" #include "logind-user.h" +#include "logind-user-dbus.h" #include "mkdir.h" #include "parse-util.h" #include "path-util.h" diff --git a/src/login/logind-user.h b/src/login/logind-user.h index c41973e27dc..4bd65d83734 100644 --- a/src/login/logind-user.h +++ b/src/login/logind-user.h @@ -69,18 +69,7 @@ int user_check_linger_file(User *u); void user_elect_display(User *u); void user_update_last_session_timer(User *u); -extern const sd_bus_vtable user_vtable[]; -int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); -int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); -char *user_bus_path(User *s); - -int user_send_signal(User *u, bool new_user); -int user_send_changed(User *u, const char *properties, ...) _sentinel_; - const char* user_state_to_string(UserState s) _const_; UserState user_state_from_string(const char *s) _pure_; -int bus_user_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error); -int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error); - CONFIG_PARSER_PROTOTYPE(config_parse_compat_user_tasks_max); diff --git a/src/login/logind.c b/src/login/logind.c index 89807dc917d..d60223db686 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -18,6 +18,10 @@ #include "fd-util.h" #include "format-util.h" #include "fs-util.h" +#include "logind-dbus.h" +#include "logind-seat-dbus.h" +#include "logind-session-dbus.h" +#include "logind-user-dbus.h" #include "logind.h" #include "main-func.h" #include "parse-util.h" diff --git a/src/login/logind.h b/src/login/logind.h index 0089fff87a7..f260f2dc96d 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -159,24 +159,6 @@ void manager_reconnect_utmp(Manager *m); extern const sd_bus_vtable manager_vtable[]; -int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error); -int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error); -int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error); -int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error); -int match_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error); - -int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name, InhibitWhat w, sd_bus_error *error); - -int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_; - -int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, char **wants, char **after, const char *requires_mounts_for, sd_bus_message *more_properties, sd_bus_error *error, char **job); -int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); -int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); -int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error); -int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error); -int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *error); -int manager_job_is_active(Manager *manager, const char *path, sd_bus_error *error); - /* gperf lookup function */ const struct ConfigPerfItem* logind_gperf_lookup(const char *key, GPERF_LEN_TYPE length); @@ -185,11 +167,5 @@ int manager_set_lid_switch_ignore(Manager *m, usec_t until); CONFIG_PARSER_PROTOTYPE(config_parse_n_autovts); CONFIG_PARSER_PROTOTYPE(config_parse_tmpfs_size); -int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret); -int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret); -int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Seat **ret); - int manager_setup_wall_message_timer(Manager *m); bool logind_wall_tty_filter(const char *tty, void *userdata); - -int manager_dispatch_delayed(Manager *manager, bool timeout); diff --git a/src/login/meson.build b/src/login/meson.build index 89ce81f767f..832274af787 100644 --- a/src/login/meson.build +++ b/src/login/meson.build @@ -21,19 +21,23 @@ liblogind_core_sources = files(''' logind-button.h logind-core.c logind-dbus.c + logind-dbus.h logind-device.c logind-device.h logind-inhibit.c logind-inhibit.h logind-seat-dbus.c + logind-seat-dbus.h logind-seat.c logind-seat.h logind-session-dbus.c + logind-session-dbus.h logind-session-device.c logind-session-device.h logind-session.c logind-session.h logind-user-dbus.c + logind-user-dbus.h logind-user.c logind-user.h logind-utmp.c