diff options
-rw-r--r-- | src/login/logind-dbus.c | 111 | ||||
-rw-r--r-- | src/login/logind-seat-dbus.c | 70 | ||||
-rw-r--r-- | src/login/logind-seat.h | 8 | ||||
-rw-r--r-- | src/login/logind-session-dbus.c | 68 | ||||
-rw-r--r-- | 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; - - message = sd_bus_get_current_message(bus); - if (!message) - return 0; - - 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; + p = startswith(path, "/org/freedesktop/login1/seat/"); + if (!p) + return 0; - p = startswith(path, "/org/freedesktop/login1/seat/"); - if (!p) - return 0; + e = bus_label_unescape(p); + if (!e) + return -ENOMEM; - e = bus_label_unescape(p); - if (!e) - return -ENOMEM; + message = sd_bus_get_current_message(bus); + if (!message) + return 0; - 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; - - message = sd_bus_get_current_message(bus); - if (!message) - return 0; - - 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; + p = startswith(path, "/org/freedesktop/login1/session/"); + if (!p) + return 0; - p = startswith(path, "/org/freedesktop/login1/session/"); - if (!p) - return 0; + e = bus_label_unescape(p); + if (!e) + return -ENOMEM; - e = bus_label_unescape(p); - if (!e) - return -ENOMEM; + message = sd_bus_get_current_message(bus); + if (!message) + return 0; - 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"); +} |