$NetBSD: patch-common_gdm-common_c,v 1.1 2021/04/16 13:57:52 cirnatdan Exp $

$OpenBSD: patch-common_gdm-common_c,v 1.8 2020/05/14 15:25:54 ajacoutot Exp $

REVERT - OpenBSD does not have a systemd implementation (we need ConsoleKit)
From fcba1e1a5d556ce7b52101dbd2d1ba4a19469161 Mon Sep 17 00:00:00 2001
From: Iain Lane <iain@orangesquash.org.uk>
Date: Fri, 5 Jan 2018 11:53:34 +0000
Subject: [PATCH] manager: Find user's current graphical session, not session of caller

REVERT - OpenBSD does not have a systemd implementation (we need ConsoleKit)
From 9be58c9ec9a3a411492a5182ac4b0d51fdc3a323 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 12 Jun 2015 13:48:52 -0400
Subject: require logind support

REVERT - OpenBSD does not have a systemd implementation (we need ConsoleKit)
From 1ac67f522f5690c27023d98096ca817f12f7eb88 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 12 Jun 2015 13:28:01 -0400
Subject: drop consolekit support

Index: common/gdm-common.c
--- common/gdm-common.c.orig	2020-05-04 20:11:25.000000000 +0000
+++ common/gdm-common.c
@@ -36,12 +36,25 @@
 
 #include "gdm-common.h"
 
+#ifdef WITH_SYSTEMD
 #include <systemd/sd-login.h>
+#endif
 
 #define GDM_DBUS_NAME                            "org.gnome.DisplayManager"
 #define GDM_DBUS_LOCAL_DISPLAY_FACTORY_PATH      "/org/gnome/DisplayManager/LocalDisplayFactory"
 #define GDM_DBUS_LOCAL_DISPLAY_FACTORY_INTERFACE "org.gnome.DisplayManager.LocalDisplayFactory"
 
+#ifdef WITH_CONSOLE_KIT
+#define CK_NAME      "org.freedesktop.ConsoleKit"
+#define CK_PATH      "/org/freedesktop/ConsoleKit"
+#define CK_INTERFACE "org.freedesktop.ConsoleKit"
+
+#define CK_MANAGER_PATH      "/org/freedesktop/ConsoleKit/Manager"
+#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager"
+#define CK_SEAT_INTERFACE    "org.freedesktop.ConsoleKit.Seat"
+#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
+#endif
+
 G_DEFINE_QUARK (gdm-common-error, gdm_common_error);
 
 gboolean
@@ -352,8 +365,87 @@ create_transient_display (GDBusConnectio
         return TRUE;
 }
 
+#ifdef WITH_CONSOLE_KIT
 gboolean
-gdm_activate_session_by_id (GDBusConnection *connection,
+get_current_session_id (GDBusConnection  *connection,
+                        char            **session_id)
+{
+        GError *local_error = NULL;
+        GVariant *reply;
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             CK_NAME,
+                                             CK_MANAGER_PATH,
+                                             CK_MANAGER_INTERFACE,
+                                             "GetCurrentSession",
+                                             NULL, /* parameters */
+                                             G_VARIANT_TYPE ("(o)"),
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL, &local_error);
+        if (reply == NULL) {
+                g_warning ("Unable to determine session: %s", local_error->message);
+                g_error_free (local_error);
+                return FALSE;
+        }
+
+        g_variant_get (reply, "(o)", session_id);
+        g_variant_unref (reply);
+
+        return TRUE;
+}
+
+static gboolean
+get_seat_id_for_session (GDBusConnection  *connection,
+                         const char       *session_id,
+                         char            **seat_id)
+{
+        GError *local_error = NULL;
+        GVariant *reply;
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             CK_NAME,
+                                             session_id,
+                                             CK_SESSION_INTERFACE,
+                                             "GetSeatId",
+                                             NULL, /* parameters */
+                                             G_VARIANT_TYPE ("(o)"),
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL, &local_error);
+        if (reply == NULL) {
+                g_warning ("Unable to determine seat: %s", local_error->message);
+                g_error_free (local_error);
+                return FALSE;
+        }
+
+        g_variant_get (reply, "(o)", seat_id);
+        g_variant_unref (reply);
+
+        return TRUE;
+}
+
+static char *
+get_current_seat_id (GDBusConnection *connection)
+{
+        gboolean res;
+        char    *session_id;
+        char    *seat_id;
+
+        session_id = NULL;
+        seat_id = NULL;
+
+        res = get_current_session_id (connection, &session_id);
+        if (res) {
+                res = get_seat_id_for_session (connection, session_id, &seat_id);
+        }
+        g_free (session_id);
+
+        return seat_id;
+}
+
+gboolean
+activate_session_id_for_ck (GDBusConnection *connection,
                             const char      *seat_id,
                             const char      *session_id)
 {
@@ -361,6 +453,217 @@ gdm_activate_session_by_id (GDBusConnect
         GVariant *reply;
 
         reply = g_dbus_connection_call_sync (connection,
+                                             CK_NAME,
+                                             seat_id,
+                                             CK_SEAT_INTERFACE,
+                                             "ActivateSession",
+                                             g_variant_new ("(o)", session_id),
+                                             NULL,
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL, &local_error);
+        if (reply == NULL) {
+                g_warning ("Unable to activate session: %s", local_error->message);
+                g_error_free (local_error);
+                return FALSE;
+        }
+
+        g_variant_unref (reply);
+
+        return TRUE;
+}
+
+static gboolean
+session_is_login_window (GDBusConnection *connection,
+                         const char      *session_id)
+{
+        GError *local_error = NULL;
+        GVariant *reply;
+        const char *value;
+        gboolean ret;
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             CK_NAME,
+                                             session_id,
+                                             CK_SESSION_INTERFACE,
+                                             "GetSessionType",
+                                             NULL,
+                                             G_VARIANT_TYPE ("(s)"),
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL, &local_error);
+        if (reply == NULL) {
+                g_warning ("Unable to determine session type: %s", local_error->message);
+                g_error_free (local_error);
+                return FALSE;
+        }
+
+        g_variant_get (reply, "(&s)", &value);
+
+        if (value == NULL || value[0] == '\0' || strcmp (value, "LoginWindow") != 0) {
+                ret = FALSE;
+        } else {
+                ret = TRUE;
+        }
+
+        g_variant_unref (reply);
+
+        return ret;
+}
+
+static gboolean
+seat_can_activate_sessions (GDBusConnection *connection,
+                            const char      *seat_id)
+{
+        GError *local_error = NULL;
+        GVariant *reply;
+        gboolean ret;
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             CK_NAME,
+                                             seat_id,
+                                             CK_SEAT_INTERFACE,
+                                             "CanActivateSessions",
+                                             NULL,
+                                             G_VARIANT_TYPE ("(b)"),
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL, &local_error);
+        if (reply == NULL) {
+                g_warning ("Unable to determine if can activate sessions: %s", local_error->message);
+                g_error_free (local_error);
+                return FALSE;
+        }
+
+        g_variant_get (reply, "(b)", &ret);
+        g_variant_unref (reply);
+
+        return ret;
+}
+
+static const char **
+seat_get_sessions (GDBusConnection *connection,
+                   const char      *seat_id)
+{
+        GError *local_error = NULL;
+        GVariant *reply;
+        const char **value;
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             CK_NAME,
+                                             seat_id,
+                                             CK_SEAT_INTERFACE,
+                                             "GetSessions",
+                                             NULL,
+                                             G_VARIANT_TYPE ("(ao)"),
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL, &local_error);
+        if (reply == NULL) {
+                g_warning ("Unable to list sessions: %s", local_error->message);
+                g_error_free (local_error);
+                return FALSE;
+        }
+
+        g_variant_get (reply, "(^ao)", &value);
+        g_variant_unref (reply);
+
+        return value;
+}
+
+static gboolean
+get_login_window_session_id_for_ck (GDBusConnection  *connection,
+                                    const char       *seat_id,
+                                    char            **session_id)
+{
+       gboolean     can_activate_sessions;
+        const char **sessions;
+        int          i;
+
+        *session_id = NULL;
+        sessions = NULL;
+
+        g_debug ("checking if seat can activate sessions");
+
+        can_activate_sessions = seat_can_activate_sessions (connection, seat_id);
+        if (! can_activate_sessions) {
+                g_debug ("seat is unable to activate sessions");
+                return FALSE;
+        }
+
+        sessions = seat_get_sessions (connection, seat_id);
+        for (i = 0; sessions [i] != NULL; i++) {
+                const char *ssid;
+
+                ssid = sessions [i];
+
+                if (session_is_login_window (connection, ssid)) {
+                        *session_id = g_strdup (ssid);
+                        break;
+                }
+        }
+        g_free (sessions);
+
+        return TRUE;
+}
+
+static gboolean
+goto_login_session_for_ck (GDBusConnection  *connection,
+                           GError          **error)
+{
+        gboolean        ret;
+        gboolean        res;
+        char           *session_id;
+        char           *seat_id;
+
+        ret = FALSE;
+
+        /* First look for any existing LoginWindow sessions on the seat.
+           If none are found, create a new one. */
+
+        seat_id = get_current_seat_id (connection);
+        if (seat_id == NULL || seat_id[0] == '\0') {
+                g_debug ("seat id is not set; can't switch sessions");
+                g_set_error (error, GDM_COMMON_ERROR, 0, _("Could not identify the current session."));
+
+                return FALSE;
+        }
+
+        res = get_login_window_session_id_for_ck (connection, seat_id, &session_id);
+        if (! res) {
+                g_set_error (error, GDM_COMMON_ERROR, 1, _("User unable to switch sessions."));
+                return FALSE;
+        }
+
+        if (session_id != NULL) {
+                res = activate_session_id_for_ck (connection, seat_id, session_id);
+                if (res) {
+                        ret = TRUE;
+                }
+        }
+
+        if (! ret && g_strcmp0 (seat_id, "/org/freedesktop/ConsoleKit/Seat1") == 0) {
+                res = create_transient_display (connection, error);
+                if (res) {
+                        ret = TRUE;
+                }
+        }
+
+        return ret;
+}
+#endif
+
+#ifdef WITH_SYSTEMD
+
+gboolean
+activate_session_id_for_systemd (GDBusConnection *connection,
+                                 const char      *seat_id,
+                                 const char      *session_id)
+{
+        GError *local_error = NULL;
+        GVariant *reply;
+
+        reply = g_dbus_connection_call_sync (connection,
                                              "org.freedesktop.login1",
                                              "/org/freedesktop/login1",
                                              "org.freedesktop.login1.Manager",
@@ -382,8 +685,8 @@ gdm_activate_session_by_id (GDBusConnect
 }
 
 gboolean
-gdm_get_login_window_session_id (const char  *seat_id,
-                                 char       **session_id)
+get_login_window_session_id_for_systemd (const char  *seat_id,
+                                         char       **session_id)
 {
         gboolean   ret;
         int        res, i;
@@ -476,15 +779,14 @@ out:
 }
 
 static gboolean
-goto_login_session (GDBusConnection  *connection,
-                    GError          **error)
+goto_login_session_for_systemd (GDBusConnection  *connection,
+                                GError          **error)
 {
         gboolean        ret;
         int             res;
         char           *our_session;
         char           *session_id;
         char           *seat_id;
-        GError         *local_error = NULL;
 
         ret = FALSE;
         session_id = NULL;
@@ -497,8 +799,10 @@ goto_login_session (GDBusConnection  *co
          * since the data allocated is from libsystemd-logind, which
          * does not use GLib's g_malloc (). */
 
-        if (!gdm_find_display_session (0, getuid (), &our_session, &local_error)) {
-                g_propagate_prefixed_error (error, local_error, _("Could not identify the current session: "));
+        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."));
 
                 return FALSE;
         }
@@ -530,9 +834,9 @@ goto_login_session (GDBusConnection  *co
                 return FALSE;
         }
 
-        res = gdm_get_login_window_session_id (seat_id, &session_id);
+        res = get_login_window_session_id_for_systemd (seat_id, &session_id);
         if (res && session_id != NULL) {
-                res = gdm_activate_session_by_id (connection, seat_id, session_id);
+                res = activate_session_id_for_systemd (connection, seat_id, session_id);
 
                 if (res) {
                         ret = TRUE;
@@ -551,6 +855,7 @@ goto_login_session (GDBusConnection  *co
 
         return ret;
 }
+#endif
 
 gboolean
 gdm_goto_login_session (GError **error)
@@ -566,7 +871,17 @@ gdm_goto_login_session (GError **error)
                 return FALSE;
         }
 
-        return goto_login_session (connection, error);
+#ifdef WITH_SYSTEMD
+        if (LOGIND_RUNNING()) {
+                return goto_login_session_for_systemd (connection, error);
+        }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+        return goto_login_session_for_ck (connection, error);
+#else
+        return FALSE;
+#endif
 }
 
 static void
@@ -842,135 +1157,3 @@ 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 (GPid        pid,
-                          const uid_t uid,
-                          char      **out_session_id,
-                          GError    **error)
-{
-        char *local_session_id = NULL;
-        g_auto(GStrv) sessions = NULL;
-        int n_sessions;
-        int res;
-
-        g_return_val_if_fail (out_session_id != NULL, FALSE);
-
-        /* First try to look up the session using the pid. We need this
-         * at least for the greeter, because it currently runs multiple
-         * sessions under the same user.
-         * See also commit 2b52d8933c8ab38e7ee83318da2363d00d8c5581
-         * which added an explicit dbus-run-session for all but seat0.
-         */
-        res = sd_pid_get_session (pid, &local_session_id);
-        if (res >= 0) {
-                g_debug ("GdmCommon: Found session %s for PID %d, using", local_session_id, pid);
-
-                *out_session_id = g_strdup (local_session_id);
-                free (local_session_id);
-
-                return TRUE;
-        } else {
-                if (res != -ENODATA)
-                        g_warning ("GdmCommon: Failed to retrieve session information for pid %d: %s",
-                                   pid, strerror (-res));
-        }
-
-        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;
-}
