From 3b92c086a8d5338e2164ffa0ae48b3d03d10cfb5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Apr 2019 17:55:36 +0200 Subject: [PATCH] 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 be767186ff..6dd4bcb17e 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 6ee5a1c95d..fa67d9c786 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 6236f1360b..d1a105addd 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 c6b8794096..5eb240834a 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 f3c17a8d91..884a8f45b8 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"); +}