[gdm/wip/benzea/systemd-user: 20/20] manager: Find user's current graphical session, not session of caller



commit 854101ea6a88041c41e5b641ecbb1dc2115c2a43
Author: Iain Lane <iain orangesquash org uk>
Date:   Fri Jan 5 11:53:34 2018 +0000

    manager: Find user's current graphical session, not session of caller
    
    If (e.g.) gnome-shell is started as a systemd --user unit, it won't be
    part of the login session. We should instead look through all of the
    user's sessions until we find the login session, and take that as our
    session.

 common/gdm-common.c         | 117 ++++++++++++++++++++++++++++++++++++++++++--
 common/gdm-common.h         |   7 +++
 daemon/gdm-manager.c        |  11 +++--
 libgdm/Makefile.am          |   1 +
 libgdm/gdm-user-switching.c |   8 ++-
 5 files changed, 130 insertions(+), 14 deletions(-)
---
diff --git a/common/gdm-common.c b/common/gdm-common.c
index 373d5b85..41bdb389 100644
--- a/common/gdm-common.c
+++ b/common/gdm-common.c
@@ -484,6 +484,7 @@ goto_login_session (GDBusConnection  *connection,
         char           *our_session;
         char           *session_id;
         char           *seat_id;
+        GError         *local_error = NULL;
 
         ret = FALSE;
         session_id = NULL;
@@ -496,10 +497,8 @@ goto_login_session (GDBusConnection  *connection,
          * since the data allocated is from libsystemd-logind, which
          * does not use GLib's g_malloc (). */
 
-        res = sd_pid_get_session (0, &our_session);
-        if (res < 0) {
-                g_debug ("failed to determine own session: %s", strerror (-res));
-                g_set_error (error, GDM_COMMON_ERROR, 0, _("Could not identify the current session."));
+        if (!gdm_find_display_session_for_uid (getuid (), &our_session, &local_error)) {
+                g_propagate_prefixed_error (error, local_error, _("Could not identify the current session: 
"));
 
                 return FALSE;
         }
@@ -843,3 +842,113 @@ gdm_shell_expand (const char *str,
         }
         return g_string_free (s, FALSE);
 }
+
+static gboolean
+_systemd_session_is_graphical (const char *session_id)
+{
+        const gchar * const graphical_session_types[] = { "wayland", "x11", "mir", NULL };
+        int saved_errno;
+        g_autofree gchar *type = NULL;
+
+        saved_errno = sd_session_get_type (session_id, &type);
+        if (saved_errno < 0) {
+                g_warning ("Couldn't get type for session '%s': %s",
+                           session_id,
+                           g_strerror (-saved_errno));
+                return FALSE;
+        }
+
+        if (!g_strv_contains (graphical_session_types, type)) {
+                g_debug ("Session '%s' is not a graphical session (type: '%s')",
+                         session_id,
+                         type);
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+static gboolean
+_systemd_session_is_active (const char *session_id)
+{
+        const gchar * const active_states[] = { "active", "online", NULL };
+        int saved_errno;
+        g_autofree gchar *state = NULL;
+
+        /*
+         * display sessions can be 'closing' if they are logged out but some
+         * processes are lingering; we shouldn't consider these (this is
+         * checking for a race condition since we specified
+         * GDM_SYSTEMD_SESSION_REQUIRE_ONLINE)
+         */
+        saved_errno = sd_session_get_state (session_id, &state);
+        if (saved_errno < 0) {
+                g_warning ("Couldn't get state for session '%s': %s",
+                           session_id,
+                           g_strerror (-saved_errno));
+                return FALSE;
+        }
+
+        if (!g_strv_contains (active_states, state)) {
+                g_debug ("Session '%s' is not active or online", session_id);
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+gboolean
+gdm_find_display_session_for_uid (const uid_t uid,
+                                  char      **out_session_id,
+                                  GError    **error)
+{
+        char *local_session_id = NULL;
+        g_auto(GStrv) sessions = NULL;
+        int n_sessions;
+
+        g_return_val_if_fail (out_session_id != NULL, FALSE);
+
+        g_debug ("Finding a graphical session for user %d", uid);
+
+        n_sessions = sd_uid_get_sessions (uid,
+                                          GDM_SYSTEMD_SESSION_REQUIRE_ONLINE,
+                                          &sessions);
+
+        if (n_sessions < 0) {
+                g_set_error (error,
+                             GDM_COMMON_ERROR,
+                             0,
+                             "Failed to get sessions for user %d",
+                             uid);
+                return FALSE;
+        }
+
+        for (int i = 0; i < n_sessions; ++i) {
+                g_debug ("Considering session '%s'", sessions[i]);
+
+                if (!_systemd_session_is_graphical (sessions[i]))
+                        continue;
+
+                if (!_systemd_session_is_active (sessions[i]))
+                        continue;
+
+                /*
+                 * We get the sessions from newest to oldest, so take the last
+                 * one we find that's good
+                 */
+                local_session_id = sessions[i];
+        }
+
+        if (local_session_id == NULL) {
+                g_set_error (error,
+                             GDM_COMMON_ERROR,
+                             0,
+                             "Could not find a graphical session for user %d",
+                             uid);
+                return FALSE;
+        }
+
+        *out_session_id = g_strdup (local_session_id);
+
+        return TRUE;
+}
diff --git a/common/gdm-common.h b/common/gdm-common.h
index 58814aa2..5c3fe137 100644
--- a/common/gdm-common.h
+++ b/common/gdm-common.h
@@ -35,6 +35,8 @@
                 expr;                \
         } while G_UNLIKELY (errno == EINTR);
 
+#define GDM_SYSTEMD_SESSION_REQUIRE_ONLINE 0
+
 GQuark gdm_common_error_quark (void);
 #define GDM_COMMON_ERROR gdm_common_error_quark()
 
@@ -48,6 +50,11 @@ int            gdm_wait_on_and_disown_pid (int pid,
                                            int timeout);
 int            gdm_signal_pid            (int pid,
                                           int signal);
+
+gboolean       gdm_find_display_session_for_uid (const uid_t uid,
+                                                 char      **out_session_id,
+                                                 GError    **error);
+
 gboolean       gdm_get_pwent_for_name    (const char     *name,
                                           struct passwd **pwentp);
 
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 23e3b85d..c9150bfd 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -494,21 +494,22 @@ get_display_and_details_for_bus_sender (GdmManager       *self,
         ret = gdm_dbus_get_uid_for_name (sender, &caller_uid, &error);
 
         if (!ret) {
-                g_debug ("GdmManager: Error while retrieving uid for sender: %s",
+                g_debug ("GdmManager: Error while retrieving uid for sender: %d",
                          error->message);
                 g_error_free (error);
                 goto out;
         }
 
-        session_id = get_session_id_for_pid (pid, &error);
+        ret = gdm_find_display_session_for_uid (caller_uid, &session_id, &error);
 
-        if (session_id == NULL) {
-                g_debug ("GdmManager: Error while retrieving session id for sender: %s",
+        if (!ret) {
+                g_debug ("GdmManager: Unable to find display session for uid %s: %s",
+                         caller_uid,
                          error->message);
                 g_error_free (error);
                 goto out;
         }
- 
+
         if (out_session_id != NULL) {
                 *out_session_id = g_strdup (session_id);
         }
diff --git a/libgdm/Makefile.am b/libgdm/Makefile.am
index 88534a54..fadffbec 100644
--- a/libgdm/Makefile.am
+++ b/libgdm/Makefile.am
@@ -66,6 +66,7 @@ libgdm_la_LDFLAGS =                                                    \
         $(END_OF_LIST)
 
 libgdm_la_LIBADD =                                                     \
+        $(top_builddir)/common/libgdmcommon.la                         \
         $(LIBGDM_LIBS)                                                 \
         $(SYSTEMD_LIBS)                                                \
         $(END_OF_LIST)
diff --git a/libgdm/gdm-user-switching.c b/libgdm/gdm-user-switching.c
index 3d4303e3..3a33fcbb 100644
--- a/libgdm/gdm-user-switching.c
+++ b/libgdm/gdm-user-switching.c
@@ -191,6 +191,7 @@ goto_login_session (GDBusConnection  *connection,
         char           *our_session;
         char           *session_id;
         char           *seat_id;
+        GError         *local_error = NULL;
 
         ret = FALSE;
         session_id = NULL;
@@ -202,11 +203,8 @@ goto_login_session (GDBusConnection  *connection,
         /* Note that we mostly use free () here, instead of g_free ()
          * since the data allocated is from libsystemd-logind, which
          * does not use GLib's g_malloc (). */
-
-        res = sd_pid_get_session (0, &our_session);
-        if (res < 0) {
-                g_debug ("failed to determine own session: %s", strerror (-res));
-                g_set_error (error, GDM_CLIENT_ERROR, 0, _("Could not identify the current session."));
+        if (!gdm_find_display_session_for_uid (getuid (), &our_session, &local_error)) {
+                g_propagate_prefixed_error (error, local_error, _("Could not identify the current session: 
"));
 
                 return FALSE;
         }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]