]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
logind: make "self" and "auto" magic strings when operating on seats + sessions
authorLennart Poettering <lennart@poettering.net>
Sun, 28 Apr 2019 15:55:36 +0000 (17:55 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 24 May 2019 13:05:27 +0000 (15:05 +0200)
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
src/login/logind-seat-dbus.c
src/login/logind-seat.h
src/login/logind-session-dbus.c
src/login/logind-session.h

index be767186ff8f04dd43e07adfdadb03c9d05729bd..6dd4bcb17eb35d3af940da6957aa605e52baa821 100644 (file)
 #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)
index 6ee5a1c95d27ce94ee30c1a85a1ee1cd3a83af2f..fa67d9c786d80f8d05e8072e597b5aae2bb3cdd6 100644 (file)
@@ -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;
 }
 
index 6236f1360bce0b77936785fa5d03c991f6a4cd84..d1a105adddd8ee12f3b205556896d333aea022df 100644 (file)
@@ -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");
+}
index c6b8794096a759690ea2f00f55226ecb9a3c4e99..5eb240834ad0e751b4f64b48255e7d1edbf1d5c7 100644 (file)
@@ -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;
 }
 
index f3c17a8d918e6694d8fa643f9d6c5905af24cf2a..884a8f45b894620bfc1031c85fa762cfe2256289 100644 (file)
@@ -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");
+}