Blob Blame History Raw
From 16adbf262b641ec722794a30a91097767d13fc16 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 12 Feb 2014 14:22:31 -0500
Subject: [PATCH 1/4] manager: explicitly disallow login screen from opening
 reauth channel

It doesn't make sense for it to do, and right now the shell does it
up front, waits for the failure, and then does the "right" thing
(opens a new auth session) after.

This commit makes the failure explicit, so we can subsequently make
other cases where a reauth channel is requested work even if there is
no session to channel to by implicitly creating a transient one just
in time.  That will come later.
---
 daemon/gdm-manager.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 116 insertions(+), 6 deletions(-)

diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 6c0fe1d..6ce37e8 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -244,192 +244,302 @@ get_uid_for_session_id (GDBusConnection  *connection,
         if (LOGIND_RUNNING()) {
                 return get_uid_for_systemd_session_id (session_id, uid, error);
         }
 #endif
 
 #ifdef WITH_CONSOLE_KIT
         return get_uid_for_consolekit_session_id (connection, session_id, uid, error);
 #endif
 
         return FALSE;
 }
 
 static gboolean
 lookup_by_session_id (const char *id,
                       GdmDisplay *display,
                       gpointer    user_data)
 {
         const char *looking_for = user_data;
         char *current;
         gboolean res;
 
         current = gdm_display_get_session_id (display);
 
         res = g_strcmp0 (current, looking_for) == 0;
 
         g_free (current);
 
         return res;
 }
 
+#ifdef WITH_CONSOLE_KIT
+static gboolean
+is_consolekit_login_session (GdmManager       *self,
+                             GDBusConnection  *connection,
+                             const char       *session_id,
+                             GError          **error)
+{
+        GVariant *reply;
+        char *session_type = NULL;
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             "org.freedesktop.ConsoleKit",
+                                             session_id,
+                                             "org.freedesktop.ConsoleKit.Session",
+                                             "GetSessionType",
+                                             NULL,
+                                             G_VARIANT_TYPE ("(s)"),
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL,
+                                             error);
+        if (reply == NULL) {
+                return FALSE;
+        }
+
+        g_variant_get (reply, "(s)", &session_type);
+        g_variant_unref (reply);
+
+        if (g_strcmp0 (session_type, "LoginWindow") != 0) {
+                g_free (session_type);
+
+                return FALSE;
+        }
+
+        g_free (session_type);
+        return TRUE;
+}
+#endif
+
+#ifdef WITH_SYSTEMD
+static gboolean
+is_systemd_login_session (GdmManager  *self,
+                          const char  *session_id,
+                          GError     **error)
+{
+        char *session_class = NULL;
+        int ret;
+
+        ret = sd_session_get_class (session_id, &session_class);
+
+        if (ret < 0) {
+                g_set_error (error,
+                             GDM_DISPLAY_ERROR,
+                             GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
+                             "Error getting class for session id %s from systemd: %s",
+                             session_id,
+                             g_strerror (-ret));
+                return FALSE;
+        }
+
+        if (g_strcmp0 (session_class, "greeter") != 0) {
+                g_free (session_class);
+                return FALSE;
+        }
+
+        g_free (session_class);
+        return TRUE;
+}
+#endif
+
+static gboolean
+is_login_session (GdmManager       *self,
+                  GDBusConnection  *connection,
+                  const char       *session_id,
+                  GError          **error)
+{
+#ifdef WITH_SYSTEMD
+        if (LOGIND_RUNNING()) {
+                return is_systemd_login_session (self, session_id, error);
+        }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+        return is_consolekit_login_session (self, connection, session_id, error);
+#endif
+
+        return FALSE;
+}
+
 static GdmDisplay *
 get_display_and_details_for_bus_sender (GdmManager       *self,
-                            GDBusConnection  *connection,
-                            const char       *sender,
-                            GPid             *out_pid,
-                            uid_t            *out_uid)
+                                        GDBusConnection  *connection,
+                                        const char       *sender,
+                                        GPid             *out_pid,
+                                        uid_t            *out_uid,
+                                        gboolean         *out_is_login_screen)
 {
         GdmDisplay *display = NULL;
         char       *session_id = NULL;
         GError     *error = NULL;
         int         ret;
         GPid        pid;
         uid_t       caller_uid, session_uid;
 
         ret = gdm_dbus_get_pid_for_name (sender, &pid, &error);
 
         if (!ret) {
                 g_debug ("GdmManager: Error while retrieving pid for sender: %s",
                          error->message);
                 g_error_free (error);
                 goto out;
         }
 
         ret = gdm_dbus_get_uid_for_name (sender, &caller_uid, &error);
 
         if (!ret) {
                 g_debug ("GdmManager: Error while retrieving uid for sender: %s",
                          error->message);
                 g_error_free (error);
                 goto out;
         }
 
         session_id = get_session_id_for_pid (connection, pid, &error);
 
         if (session_id == NULL) {
                 g_debug ("GdmManager: Error while retrieving session id for sender: %s",
                          error->message);
                 g_error_free (error);
                 goto out;
         }
 
+        if (out_is_login_screen != NULL) {
+                *out_is_login_screen = is_login_session (self, connection, session_id, &error);
+
+                if (error != NULL) {
+                        g_debug ("GdmManager: Error while checking if sender is login screen: %s",
+                                 error->message);
+                        g_error_free (error);
+                        goto out;
+                }
+        }
+
         if (!get_uid_for_session_id (connection, session_id, &session_uid, &error)) {
                 g_debug ("GdmManager: Error while retrieving uid for session: %s",
                          error->message);
                 g_error_free (error);
                 goto out;
         }
 
         if (caller_uid != session_uid) {
                 g_debug ("GdmManager: uid for sender and uid for session don't match");
                 goto out;
         }
 
         display = gdm_display_store_find (self->priv->display_store,
                                           lookup_by_session_id,
                                           (gpointer) session_id);
 out:
         g_free (session_id);
 
         if (display != NULL) {
             if (out_pid != NULL)
                 *out_pid = pid;
 
             if (out_uid != NULL)
                 *out_uid = session_uid;
         }
         return display;
 }
 
 static gboolean
 gdm_manager_handle_open_session (GdmDBusManager        *manager,
                                  GDBusMethodInvocation *invocation)
 {
         GdmManager       *self = GDM_MANAGER (manager);
         const char       *sender = NULL;
         GError           *error = NULL;
         GDBusConnection  *connection;
         GdmDisplay       *display;
         char             *address;
         GPid              pid;
         uid_t             uid;
 
         g_debug ("GdmManager: trying to open new session");
 
         sender = g_dbus_method_invocation_get_sender (invocation);
         connection = g_dbus_method_invocation_get_connection (invocation);
-        display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid);
+        display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid, NULL);
 
         if (display == NULL) {
                 g_dbus_method_invocation_return_error_literal (invocation,
                                                                G_DBUS_ERROR,
                                                                G_DBUS_ERROR_ACCESS_DENIED,
                                                                _("No session available"));
 
                 return TRUE;
         }
 
         address = gdm_display_open_session_sync (display, pid, uid, NULL, &error);
 
         if (address == NULL) {
                 g_dbus_method_invocation_return_gerror (invocation, error);
                 g_error_free (error);
                 return TRUE;
         }
 
         gdm_dbus_manager_complete_open_session (GDM_DBUS_MANAGER (manager),
                                                 invocation,
                                                 address);
         g_free (address);
 
         return TRUE;
 }
 
 static gboolean
 gdm_manager_handle_open_reauthentication_channel (GdmDBusManager        *manager,
                                                   GDBusMethodInvocation *invocation,
                                                   const char            *username)
 {
         GdmManager       *self = GDM_MANAGER (manager);
         const char       *sender = NULL;
         GError           *error = NULL;
         GDBusConnection  *connection;
         GdmDisplay       *display;
         char             *address;
         GPid              pid;
         uid_t             uid;
+        gboolean          is_login_screen = FALSE;
 
         g_debug ("GdmManager: trying to open reauthentication channel for user %s", username);
 
         sender = g_dbus_method_invocation_get_sender (invocation);
         connection = g_dbus_method_invocation_get_connection (invocation);
-        display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid);
+        display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid, &is_login_screen);
+
+        if (is_login_screen) {
+                g_dbus_method_invocation_return_error_literal (invocation,
+                                                               G_DBUS_ERROR,
+                                                               G_DBUS_ERROR_ACCESS_DENIED,
+                                                               _("Login screen not allow to open reauthentication channel"));
+                return TRUE;
+        }
 
         if (display == NULL) {
                 g_dbus_method_invocation_return_error_literal (invocation,
                                                                G_DBUS_ERROR,
                                                                G_DBUS_ERROR_ACCESS_DENIED,
                                                                _("No session available"));
 
                 return TRUE;
         }
 
         address = gdm_display_open_reauthentication_channel_sync (display,
                                                                   username,
                                                                   pid,
                                                                   uid,
                                                                   NULL,
                                                                   &error);
 
         if (address == NULL) {
                 g_dbus_method_invocation_return_gerror (invocation, error);
                 g_error_free (error);
                 return TRUE;
         }
 
         gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager),
                                                                  invocation,
                                                                  address);
         g_free (address);
 
         return TRUE;
 }
-- 
1.8.4.2


From 3a1330c93213a060c51b2d3021360e80a779814c Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 11 Mar 2014 23:46:35 -0400
Subject: [PATCH 2/4] worker: support authentication without X11 display

At the moment we unconditionally set PAM_XDISPLAY
and PAM_XAUTHDATA based on values passed to the worker.

In a future commit, those values are going to become
stubs, so as a first step, this commit makes PAM_XDISPLAY
and PAM_XAUTHDATA optional.
---
 daemon/gdm-session-worker.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 79cf202..eb81450 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -1073,76 +1073,81 @@ gdm_session_worker_initialize_pam (GdmSessionWorker *worker,
 
         /* set TTY */
         pam_tty = _get_tty_for_pam (x11_display_name, display_device);
         if (pam_tty != NULL && pam_tty[0] != '\0') {
                 error_code = pam_set_item (worker->priv->pam_handle, PAM_TTY, pam_tty);
         }
         g_free (pam_tty);
 
         if (error_code != PAM_SUCCESS) {
                 g_set_error (error,
                              GDM_SESSION_WORKER_ERROR,
                              GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
                              _("error informing authentication system of user's console: %s"),
                              pam_strerror (worker->priv->pam_handle, error_code));
                 goto out;
         }
 
 #ifdef WITH_SYSTEMD
         /* set seat ID */
         if (seat_id != NULL && seat_id[0] != '\0' && LOGIND_RUNNING()) {
                 gdm_session_worker_set_environment_variable (worker, "XDG_SEAT", seat_id);
         }
 #endif
 
         if (strcmp (service, "gdm-launch-environment") == 0) {
                 gdm_session_worker_set_environment_variable (worker, "XDG_SESSION_CLASS", "greeter");
         }
 
 #ifdef PAM_XDISPLAY
         /* set XDISPLAY */
-        error_code = pam_set_item (worker->priv->pam_handle, PAM_XDISPLAY, x11_display_name);
+        if (x11_display_name != NULL && x11_display_name[0] != '\0') {
+                error_code = pam_set_item (worker->priv->pam_handle, PAM_XDISPLAY, x11_display_name);
+        }
 
         if (error_code != PAM_SUCCESS) {
                 g_set_error (error,
                              GDM_SESSION_WORKER_ERROR,
                              GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
                              _("error informing authentication system of display string: %s"),
                              pam_strerror (worker->priv->pam_handle, error_code));
                 goto out;
         }
 #endif
 #ifdef PAM_XAUTHDATA
         /* set XAUTHDATA */
         pam_xauth = _get_xauth_for_pam (x11_authority_file);
-        error_code = pam_set_item (worker->priv->pam_handle, PAM_XAUTHDATA, pam_xauth);
-        g_free (pam_xauth);
+
+        if (pam_xauth != NULL) {
+                error_code = pam_set_item (worker->priv->pam_handle, PAM_XAUTHDATA, pam_xauth);
+                g_free (pam_xauth);
+        }
 
         if (error_code != PAM_SUCCESS) {
                 g_set_error (error,
                              GDM_SESSION_WORKER_ERROR,
                              GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
                              _("error informing authentication system of display xauth credentials: %s"),
                              pam_strerror (worker->priv->pam_handle, error_code));
                 goto out;
         }
 #endif
 
         g_debug ("GdmSessionWorker: state SETUP_COMPLETE");
         worker->priv->state = GDM_SESSION_WORKER_STATE_SETUP_COMPLETE;
 
  out:
         if (error_code != PAM_SUCCESS) {
                 gdm_session_worker_uninitialize_pam (worker, error_code);
                 return FALSE;
         }
 
         return TRUE;
 }
 
 static gboolean
 gdm_session_worker_authenticate_user (GdmSessionWorker *worker,
                                       gboolean          password_is_required,
                                       GError          **error)
 {
         int error_code;
         int authentication_flags;
-- 
1.8.4.2


From e8c249d57b744d61c3c119f55e26f1ff1c14a598 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 19 Feb 2014 10:54:56 -0500
Subject: [PATCH 3/4] manager: collect more details about bus sender

In the future we're going to need to know more details about the
sender to know how to move forward (such as seat id, session id,
if it's remote, etc) in order to create a transient session soley
for reauthentication.

To prepare for that future, this commit adds the necessary
functionality to get_display_and_details_for_bus_sender.
---
 daemon/gdm-manager.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 209 insertions(+), 19 deletions(-)

diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 6ce37e8..4c47045 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -333,205 +333,395 @@ is_systemd_login_session (GdmManager  *self,
 
         if (g_strcmp0 (session_class, "greeter") != 0) {
                 g_free (session_class);
                 return FALSE;
         }
 
         g_free (session_class);
         return TRUE;
 }
 #endif
 
 static gboolean
 is_login_session (GdmManager       *self,
                   GDBusConnection  *connection,
                   const char       *session_id,
                   GError          **error)
 {
 #ifdef WITH_SYSTEMD
         if (LOGIND_RUNNING()) {
                 return is_systemd_login_session (self, session_id, error);
         }
 #endif
 
 #ifdef WITH_CONSOLE_KIT
         return is_consolekit_login_session (self, connection, session_id, error);
 #endif
 
         return FALSE;
 }
 
-static GdmDisplay *
+#ifdef WITH_CONSOLE_KIT
+static gboolean
+is_consolekit_remote_session (GdmManager       *self,
+                             GDBusConnection  *connection,
+                             const char       *session_id,
+                             GError          **error)
+{
+        GVariant *reply;
+        gboolean is_remote;
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             "org.freedesktop.ConsoleKit",
+                                             session_id,
+                                             "org.freedesktop.ConsoleKit.Session",
+                                             "IsLocal",
+                                             NULL,
+                                             G_VARIANT_TYPE ("(b)"),
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL,
+                                             error);
+        if (reply == NULL) {
+                return FALSE;
+        }
+
+        g_variant_get (reply, "(b)", &is_remote);
+        g_variant_unref (reply);
+
+        return is_remote;
+}
+#endif
+
+#ifdef WITH_SYSTEMD
+static gboolean
+is_systemd_remote_session (GdmManager  *self,
+                           const char  *session_id,
+                           GError     **error)
+{
+        char *seat;
+        int ret;
+        gboolean is_remote;
+
+        /* FIXME: The next release of logind is going to have explicit api for
+         * checking remoteness.
+         */
+        seat = NULL;
+        ret = sd_session_get_seat (session_id, &seat);
+
+        if (ret < 0 && ret != -ENOENT) {
+                g_debug ("GdmManager: Error while retrieving seat for session %s: %s",
+                         session_id, strerror (-ret));
+        }
+
+        if (seat != NULL) {
+                is_remote = FALSE;
+                free (seat);
+        } else {
+                is_remote = TRUE;
+        }
+
+        return is_remote;
+}
+#endif
+
+static gboolean
+is_remote_session (GdmManager       *self,
+                  GDBusConnection  *connection,
+                  const char       *session_id,
+                  GError          **error)
+{
+#ifdef WITH_SYSTEMD
+        if (LOGIND_RUNNING()) {
+                return is_systemd_remote_session (self, session_id, error);
+        }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+        return is_consolekit_remote_session (self, connection, session_id, error);
+#endif
+
+        return FALSE;
+}
+
+#ifdef WITH_SYSTEMD
+static char *
+get_seat_id_for_systemd_session_id (const char  *session_id,
+                                    GError     **error)
+{
+        int ret;
+        char *seat, *out_seat;
+
+        seat = NULL;
+        ret = sd_session_get_seat (session_id, &seat);
+
+        if (ret == -ENOENT) {
+                out_seat = NULL;
+        } else if (ret < 0) {
+                g_set_error (error,
+                             GDM_DISPLAY_ERROR,
+                             GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
+                             "Error getting uid for session id %s from systemd: %s",
+                             session_id,
+                             g_strerror (-ret));
+                out_seat = NULL;
+        } else {
+                out_seat = g_strdup (seat);
+                free (seat);
+        }
+
+        return out_seat;
+}
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+static char *
+get_seat_id_for_consolekit_session_id (GDBusConnection  *connection,
+                                       const char       *session_id,
+                                       GError          **error)
+{
+        GVariant *reply;
+        char *retval;
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             "org.freedesktop.ConsoleKit",
+                                             session_id,
+                                             "org.freedesktop.ConsoleKit.Session",
+                                             "GetSeatId",
+                                             NULL,
+                                             G_VARIANT_TYPE ("(o)"),
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL,
+                                             error);
+        if (reply == NULL) {
+                return NULL;
+        }
+
+        g_variant_get (reply, "(o)", &retval);
+        g_variant_unref (reply);
+
+        return retval;
+}
+#endif
+
+static char *
+get_seat_id_for_session_id (GDBusConnection  *connection,
+                            const char       *session_id,
+                            GError          **error)
+{
+#ifdef WITH_SYSTEMD
+        if (LOGIND_RUNNING()) {
+                return get_seat_id_for_systemd_session_id (session_id, error);
+        }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+        return get_seat_id_for_consolekit_session_id (connection, session_id, error);
+#endif
+
+        return NULL;
+}
+
+static void
 get_display_and_details_for_bus_sender (GdmManager       *self,
                                         GDBusConnection  *connection,
                                         const char       *sender,
+                                        GdmDisplay      **out_display,
+                                        char            **out_seat_id,
+                                        char            **out_session_id,
                                         GPid             *out_pid,
                                         uid_t            *out_uid,
-                                        gboolean         *out_is_login_screen)
+                                        gboolean         *out_is_login_screen,
+                                        gboolean         *out_is_remote)
 {
         GdmDisplay *display = NULL;
         char       *session_id = NULL;
         GError     *error = NULL;
         int         ret;
         GPid        pid;
         uid_t       caller_uid, session_uid;
 
         ret = gdm_dbus_get_pid_for_name (sender, &pid, &error);
 
         if (!ret) {
                 g_debug ("GdmManager: Error while retrieving pid for sender: %s",
                          error->message);
                 g_error_free (error);
                 goto out;
         }
 
+        if (out_pid != NULL)
+            *out_pid = pid;
+
         ret = gdm_dbus_get_uid_for_name (sender, &caller_uid, &error);
 
         if (!ret) {
                 g_debug ("GdmManager: Error while retrieving uid for sender: %s",
                          error->message);
                 g_error_free (error);
                 goto out;
         }
 
         session_id = get_session_id_for_pid (connection, pid, &error);
 
         if (session_id == NULL) {
                 g_debug ("GdmManager: Error while retrieving session id for sender: %s",
                          error->message);
                 g_error_free (error);
                 goto out;
         }
 
+        if (out_session_id != NULL) {
+                *out_session_id = g_strdup (session_id);
+        }
+
         if (out_is_login_screen != NULL) {
                 *out_is_login_screen = is_login_session (self, connection, session_id, &error);
 
                 if (error != NULL) {
                         g_debug ("GdmManager: Error while checking if sender is login screen: %s",
                                  error->message);
                         g_error_free (error);
                         goto out;
                 }
         }
 
         if (!get_uid_for_session_id (connection, session_id, &session_uid, &error)) {
                 g_debug ("GdmManager: Error while retrieving uid for session: %s",
                          error->message);
                 g_error_free (error);
                 goto out;
         }
 
+        if (out_uid != NULL)
+            *out_uid = session_uid;
+
         if (caller_uid != session_uid) {
                 g_debug ("GdmManager: uid for sender and uid for session don't match");
                 goto out;
         }
 
+        if (out_seat_id != NULL) {
+                *out_seat_id = get_seat_id_for_session_id (connection, session_id, &error);
+
+                if (error != NULL) {
+                        g_debug ("GdmManager: Error while retrieving seat id for session: %s",
+                                 error->message);
+                        g_clear_error (&error);
+                }
+        }
+
+        if (out_is_remote != NULL) {
+                *out_is_remote = is_remote_session (self, connection, session_id, &error);
+
+                if (error != NULL) {
+                        g_debug ("GdmManager: Error while retrieving remoteness for session: %s",
+                                 error->message);
+                        g_clear_error (&error);
+                }
+        }
+
         display = gdm_display_store_find (self->priv->display_store,
                                           lookup_by_session_id,
                                           (gpointer) session_id);
+        if (out_display != NULL)
+            *out_display = display;
+
 out:
         g_free (session_id);
-
-        if (display != NULL) {
-            if (out_pid != NULL)
-                *out_pid = pid;
-
-            if (out_uid != NULL)
-                *out_uid = session_uid;
-        }
-        return display;
 }
 
 static gboolean
 gdm_manager_handle_open_session (GdmDBusManager        *manager,
                                  GDBusMethodInvocation *invocation)
 {
         GdmManager       *self = GDM_MANAGER (manager);
         const char       *sender = NULL;
         GError           *error = NULL;
         GDBusConnection  *connection;
-        GdmDisplay       *display;
+        GdmDisplay       *display = NULL;
         char             *address;
-        GPid              pid;
-        uid_t             uid;
+        GPid              pid = 0;
+        uid_t             uid = (uid_t) -1;
 
         g_debug ("GdmManager: trying to open new session");
 
         sender = g_dbus_method_invocation_get_sender (invocation);
         connection = g_dbus_method_invocation_get_connection (invocation);
-        display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid, NULL);
+        get_display_and_details_for_bus_sender (self, connection, sender, &display, NULL, NULL, &pid, &uid, NULL, NULL);
 
         if (display == NULL) {
                 g_dbus_method_invocation_return_error_literal (invocation,
                                                                G_DBUS_ERROR,
                                                                G_DBUS_ERROR_ACCESS_DENIED,
                                                                _("No session available"));
 
                 return TRUE;
         }
 
         address = gdm_display_open_session_sync (display, pid, uid, NULL, &error);
 
         if (address == NULL) {
                 g_dbus_method_invocation_return_gerror (invocation, error);
                 g_error_free (error);
                 return TRUE;
         }
 
         gdm_dbus_manager_complete_open_session (GDM_DBUS_MANAGER (manager),
                                                 invocation,
                                                 address);
         g_free (address);
 
         return TRUE;
 }
 
 static gboolean
 gdm_manager_handle_open_reauthentication_channel (GdmDBusManager        *manager,
                                                   GDBusMethodInvocation *invocation,
                                                   const char            *username)
 {
         GdmManager       *self = GDM_MANAGER (manager);
         const char       *sender = NULL;
         GError           *error = NULL;
         GDBusConnection  *connection;
-        GdmDisplay       *display;
+        GdmDisplay       *display = NULL;
         char             *address;
-        GPid              pid;
-        uid_t             uid;
+        GPid              pid = 0;
+        uid_t             uid = (uid_t) -1;
         gboolean          is_login_screen = FALSE;
 
         g_debug ("GdmManager: trying to open reauthentication channel for user %s", username);
 
         sender = g_dbus_method_invocation_get_sender (invocation);
         connection = g_dbus_method_invocation_get_connection (invocation);
-        display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid, &is_login_screen);
+        get_display_and_details_for_bus_sender (self, connection, sender, &display, NULL, NULL, &pid, &uid, &is_login_screen, NULL);
 
         if (is_login_screen) {
                 g_dbus_method_invocation_return_error_literal (invocation,
                                                                G_DBUS_ERROR,
                                                                G_DBUS_ERROR_ACCESS_DENIED,
                                                                _("Login screen not allow to open reauthentication channel"));
                 return TRUE;
         }
 
         if (display == NULL) {
                 g_dbus_method_invocation_return_error_literal (invocation,
                                                                G_DBUS_ERROR,
                                                                G_DBUS_ERROR_ACCESS_DENIED,
                                                                _("No session available"));
 
                 return TRUE;
         }
 
         address = gdm_display_open_reauthentication_channel_sync (display,
                                                                   username,
                                                                   pid,
                                                                   uid,
                                                                   NULL,
                                                                   &error);
 
         if (address == NULL) {
                 g_dbus_method_invocation_return_gerror (invocation, error);
                 g_error_free (error);
                 return TRUE;
         }
-- 
1.8.4.2


From 8fe36a032eb5ce681c91d5ccc8b0719f8e360b53 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 11 Mar 2014 15:25:29 -0400
Subject: [PATCH 4/4] manager: support just-in-time reauthentication for
 non-GDM sessions

Right now, gnome-shell can't unlock screens running on an X server that
isn't managed by GDM (say Xvnc or startx).  This is because GDM handles
the backend processing for unlocking, and it handles that backend
processing from the worker associated with the session.  If there is no
worker associated with the session (as is the case with Xvnc and startx),
then there's no process to handle reauthentication.

This commit notices that case, and creates a transient worker on the fly
just to perform one off authentication for unlock of non-GDM managed
sessions.
---
 daemon/Makefile.am   |  13 +++
 daemon/gdm-manager.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 271 insertions(+), 10 deletions(-)

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index ead9096..750735a 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -289,83 +289,96 @@ endif
 
 gdm_session_worker_LDFLAGS =			\
 	$(XLIB_LIBS)				\
 	$(PAM_LIBS)				\
 	$(NULL)
 
 gdm_session_worker_LDADD = 			\
 	$(top_builddir)/common/libgdmcommon.la	\
 	$(DAEMON_LIBS)				\
 	$(SYSTEMD_LIBS) 			\
 	$(JOURNALD_LIBS) 			\
 	$(LIBSELINUX_LIBS) 			\
 	$(NULL)
 
 sbin_PROGRAMS = 			\
 	gdm				\
 	$(NULL)
 
 gdm_SOURCES = 			\
 	main.c				\
 	gdm-display-access-file.c	\
 	gdm-display-access-file.h	\
 	gdm-display-store.c		\
 	gdm-display-store.h		\
 	gdm-display-factory.c		\
 	gdm-display-factory.h		\
 	gdm-local-display-factory.c	\
 	gdm-local-display-factory.h	\
 	gdm-display.c			\
 	gdm-display.h			\
+	gdm-session.c			\
+	gdm-session.h			\
+	gdm-session-record.c		\
+	gdm-session-record.h		\
+	gdm-session-worker-common.c	\
+	gdm-session-worker-common.h	\
+	gdm-session-worker-job.c	\
 	gdm-static-display.c		\
 	gdm-static-display.h		\
 	gdm-transient-display.c		\
 	gdm-transient-display.h		\
 	gdm-manager.c			\
 	gdm-manager.h			\
 	gdm-slave-proxy.c		\
 	gdm-slave-proxy.h		\
 	gdm-dbus-util.c			\
 	gdm-dbus-util.h			\
 	$(NULL)
 
 nodist_gdm_SOURCES = 			\
 	gdm-display-glue.h			\
 	gdm-display-glue.c			\
 	gdm-local-display-factory-glue.h	\
 	gdm-local-display-factory-glue.c	\
 	gdm-manager-glue.h			\
 	gdm-manager-glue.c			\
 	gdm-transient-display-glue.h		\
 	gdm-transient-display-glue.c		\
 	gdm-static-display-glue.h		\
 	gdm-static-display-glue.c		\
+	gdm-session-enum-types.c		\
+	gdm-session-enum-types.h		\
+	gdm-session-glue.c			\
+	gdm-session-glue.h			\
+	gdm-session-worker-glue.c		\
+	gdm-session-worker-glue.h		\
 	gdm-slave-glue.h			\
 	gdm-slave-glue.c			\
 	$(NULL)
 
 XDMCP_SOURCES =				\
 	gdm-xdmcp-display-factory.c	\
 	gdm-xdmcp-display-factory.h	\
 	gdm-xdmcp-display.c		\
 	gdm-xdmcp-display.h		\
 	gdm-xdmcp-greeter-display.c	\
 	gdm-xdmcp-greeter-display.h	\
 	gdm-xdmcp-chooser-display.c	\
 	gdm-xdmcp-chooser-display.h	\
 	$(NULL)
 
 XDMCP_nodist_SOURCES = 			\
 	gdm-xdmcp-display-glue.c	\
 	gdm-xdmcp-display-glue.h	\
 	gdm-xdmcp-chooser-slave-glue.c	\
 	gdm-xdmcp-chooser-slave-glue.h	\
 	$(NULL)
 
 if XDMCP_SUPPORT
 gdm_SOURCES += $(XDMCP_SOURCES)
 nodist_gdm_SOURCES += $(XDMCP_nodist_SOURCES)
 endif
 
 EXTRA_gdm_SOURCES = 	\
 	$(XDMCP_SOURCES)	\
 	$(NULL)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 4c47045..7eb2172 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -16,60 +16,61 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  */
 
 #include "config.h"
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
 #include <signal.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <glib/gstdio.h>
 #include <glib-object.h>
 
 #ifdef WITH_SYSTEMD
 #include <systemd/sd-login.h>
 #endif
 
 #include "gdm-common.h"
 
 #include "gdm-dbus-util.h"
 #include "gdm-manager.h"
 #include "gdm-manager-glue.h"
+#include "gdm-session.h"
 #include "gdm-display-store.h"
 #include "gdm-display-factory.h"
 #include "gdm-local-display-factory.h"
 #include "gdm-xdmcp-display-factory.h"
 
 #define GDM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_MANAGER, GdmManagerPrivate))
 
 #define GDM_DBUS_PATH             "/org/gnome/DisplayManager"
 #define GDM_MANAGER_PATH          GDM_DBUS_PATH "/Manager"
 #define GDM_MANAGER_DISPLAYS_PATH GDM_DBUS_PATH "/Displays"
 
 struct GdmManagerPrivate
 {
         GdmDisplayStore        *display_store;
         GdmLocalDisplayFactory *local_factory;
 #ifdef HAVE_LIBXDMCP
         GdmXdmcpDisplayFactory *xdmcp_factory;
 #endif
         gboolean                xdmcp_enabled;
 
         gboolean                started;
         gboolean                wait_for_go;
         gboolean                no_console;
 
         GDBusProxy               *bus_proxy;
         GDBusConnection          *connection;
         GDBusObjectManagerServer *object_manager;
 };
 
 enum {
@@ -648,104 +649,351 @@ gdm_manager_handle_open_session (GdmDBusManager        *manager,
 
         sender = g_dbus_method_invocation_get_sender (invocation);
         connection = g_dbus_method_invocation_get_connection (invocation);
         get_display_and_details_for_bus_sender (self, connection, sender, &display, NULL, NULL, &pid, &uid, NULL, NULL);
 
         if (display == NULL) {
                 g_dbus_method_invocation_return_error_literal (invocation,
                                                                G_DBUS_ERROR,
                                                                G_DBUS_ERROR_ACCESS_DENIED,
                                                                _("No session available"));
 
                 return TRUE;
         }
 
         address = gdm_display_open_session_sync (display, pid, uid, NULL, &error);
 
         if (address == NULL) {
                 g_dbus_method_invocation_return_gerror (invocation, error);
                 g_error_free (error);
                 return TRUE;
         }
 
         gdm_dbus_manager_complete_open_session (GDM_DBUS_MANAGER (manager),
                                                 invocation,
                                                 address);
         g_free (address);
 
         return TRUE;
 }
 
+#ifdef WITH_SYSTEMD
+static gboolean
+unlock_systemd_session (GdmManager *manager,
+                        const char *ssid)
+{
+        GError *error = NULL;
+        GVariant *reply;
+
+        reply = g_dbus_connection_call_sync (manager->priv->connection,
+                                             "org.freedesktop.login1",
+                                             "/org/freedesktop/login1",
+                                             "org.freedesktop.login1.Manager",
+                                             "UnlockSession",
+                                             g_variant_new ("(s)", ssid),
+                                             NULL, /* expected reply */
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL,
+                                             &error);
+        if (reply == NULL) {
+                g_debug ("GdmManager: logind 'UnlockSession' %s raised:\n %s\n\n",
+                         g_dbus_error_get_remote_error (error), error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+
+        g_variant_unref (reply);
+
+        return TRUE;
+}
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+static gboolean
+unlock_consolekit_session (GdmManager *manager,
+                           const char *ssid)
+{
+        GError *error = NULL;
+        GVariant *reply;
+
+        reply = g_dbus_connection_call_sync (manager->priv->connection,
+                                             "org.freedesktop.ConsoleKit",
+                                             ssid,
+                                             "org.freedesktop.ConsoleKit.Manager",
+                                             "Unlock",
+                                             NULL, /* parameters */
+                                             NULL, /* expected reply */
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL,
+                                             &error);
+        if (reply == NULL) {
+                g_debug ("GdmSlave: ConsoleKit %s raised:\n %s\n\n",
+                         g_dbus_error_get_remote_error (error), error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+
+        g_variant_unref (reply);
+
+        return TRUE;
+}
+#endif
+
+static void
+unlock_session (GdmManager *manager,
+                const char *ssid)
+{
+
+        g_debug ("GdmManager: Unlocking session %s", ssid);
+
+#ifdef WITH_SYSTEMD
+        if (LOGIND_RUNNING()) {
+                unlock_systemd_session (manager, ssid);
+                return;
+        }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+        unlock_consolekit_session (manager, ssid);
+#endif
+}
+static void
+on_reauthentication_client_connected (GdmSession              *session,
+                                      GCredentials            *credentials,
+                                      GPid                     pid_of_client,
+                                      GdmManager              *self)
+{
+        g_debug ("GdmManager: client connected to reauthentication server");
+}
+
+static void
+on_reauthentication_client_disconnected (GdmSession              *session,
+                                         GCredentials            *credentials,
+                                         GPid                     pid_of_client,
+                                         GdmManager              *self)
+{
+        g_debug ("GdmManger: client disconnected from reauthentication server");
+        gdm_session_close (session);
+        g_object_unref (session);
+}
+
+static void
+on_reauthentication_cancelled (GdmSession *session,
+                               GdmManager *self)
+{
+        g_debug ("GdmManager: client cancelled reauthentication request");
+        gdm_session_close (session);
+        g_object_unref (session);
+}
+
+static void
+on_reauthentication_conversation_started (GdmSession *session,
+                                          const char *service_name,
+                                          GdmManager *self)
+{
+        g_debug ("GdmManager: reauthentication service '%s' started",
+                 service_name);
+}
+
+static void
+on_reauthentication_conversation_stopped (GdmSession *session,
+                                          const char *service_name,
+                                          GdmManager *self)
+{
+        g_debug ("GdmManager: reauthentication service '%s' stopped",
+                 service_name);
+}
+
+static void
+on_reauthentication_verification_complete (GdmSession *session,
+                                           const char *service_name,
+                                           GdmManager *self)
+{
+        const char *session_id;
+        session_id = g_object_get_data (G_OBJECT (session), "caller-session-id");
+        g_debug ("GdmManager: reauthenticated user in unmanaged session '%s' with service '%s'",
+                 session_id, service_name);
+        unlock_session (self, session_id);
+        gdm_session_close (session);
+        g_object_unref (session);
+}
+
+static void
+remove_session_weak_refs (GdmManager *self,
+                          GdmSession *session)
+{
+        g_object_weak_unref (G_OBJECT (self),
+                             (GWeakNotify)
+                             gdm_session_close,
+                             session);
+        g_object_weak_unref (G_OBJECT (self),
+                             (GWeakNotify)
+                             g_object_unref,
+                             session);
+}
+
+static char *
+open_temporary_reauthentication_channel (GdmManager            *self,
+                                         char                  *seat_id,
+                                         char                  *session_id,
+                                         GPid                   pid,
+                                         uid_t                  uid,
+                                         gboolean               is_remote)
+{
+        GdmSession *session;
+        char **environment;
+        const char *display, *auth_file;
+        char *address;
+
+        /* Note we're just using a minimal environment here rather than the
+         * session's environment because the caller is unprivileged and the
+         * associated worker will be privileged */
+        environment = g_get_environ ();
+        display = "";
+        auth_file = "/dev/null";
+
+        session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE,
+                                   uid,
+                                   display,
+                                   NULL,
+                                   NULL,
+                                   seat_id,
+                                   auth_file,
+                                   is_remote == FALSE,
+                                   (const char * const *)
+                                   environment);
+        g_strfreev (environment);
+
+        g_object_set_data_full (G_OBJECT (session),
+                                "caller-session-id",
+                                g_strdup (session_id),
+                                (GDestroyNotify)
+                                g_free);
+        g_object_weak_ref (G_OBJECT (self),
+                           (GWeakNotify)
+                           gdm_session_close,
+                           session);
+        g_object_weak_ref (G_OBJECT (self),
+                           (GWeakNotify)
+                           g_object_unref,
+                           session);
+        g_object_weak_ref (G_OBJECT (session),
+                           (GWeakNotify)
+                           remove_session_weak_refs,
+                           self);
+
+        g_signal_connect (session,
+                          "client-connected",
+                          G_CALLBACK (on_reauthentication_client_connected),
+                          self);
+        g_signal_connect (session,
+                          "client-disconnected",
+                          G_CALLBACK (on_reauthentication_client_disconnected),
+                          self);
+        g_signal_connect (session,
+                          "cancelled",
+                          G_CALLBACK (on_reauthentication_cancelled),
+                          self);
+        g_signal_connect (session,
+                          "conversation-started",
+                          G_CALLBACK (on_reauthentication_conversation_started),
+                          self);
+        g_signal_connect (session,
+                          "conversation-stopped",
+                          G_CALLBACK (on_reauthentication_conversation_stopped),
+                          self);
+        g_signal_connect (session,
+                          "verification-complete",
+                          G_CALLBACK (on_reauthentication_verification_complete),
+                          self);
+
+        address = gdm_session_get_server_address (session);
+        return address;
+}
+
 static gboolean
 gdm_manager_handle_open_reauthentication_channel (GdmDBusManager        *manager,
                                                   GDBusMethodInvocation *invocation,
                                                   const char            *username)
 {
         GdmManager       *self = GDM_MANAGER (manager);
         const char       *sender = NULL;
         GError           *error = NULL;
         GDBusConnection  *connection;
         GdmDisplay       *display = NULL;
         char             *address;
+        char             *seat_id = NULL;
+        char             *session_id = NULL;
         GPid              pid = 0;
         uid_t             uid = (uid_t) -1;
         gboolean          is_login_screen = FALSE;
+        gboolean          is_remote = FALSE;
 
         g_debug ("GdmManager: trying to open reauthentication channel for user %s", username);
 
         sender = g_dbus_method_invocation_get_sender (invocation);
         connection = g_dbus_method_invocation_get_connection (invocation);
-        get_display_and_details_for_bus_sender (self, connection, sender, &display, NULL, NULL, &pid, &uid, &is_login_screen, NULL);
+        get_display_and_details_for_bus_sender (self, connection, sender, &display, &seat_id, &session_id, &pid, &uid, &is_login_screen, &is_remote);
 
         if (is_login_screen) {
                 g_dbus_method_invocation_return_error_literal (invocation,
                                                                G_DBUS_ERROR,
                                                                G_DBUS_ERROR_ACCESS_DENIED,
                                                                _("Login screen not allow to open reauthentication channel"));
                 return TRUE;
         }
 
-        if (display == NULL) {
+        if (session_id == NULL || pid == 0 || uid == (uid_t) -1) {
                 g_dbus_method_invocation_return_error_literal (invocation,
                                                                G_DBUS_ERROR,
                                                                G_DBUS_ERROR_ACCESS_DENIED,
-                                                               _("No session available"));
-
+                                                               _("Could not retrieve details about caller"));
                 return TRUE;
         }
 
-        address = gdm_display_open_reauthentication_channel_sync (display,
-                                                                  username,
-                                                                  pid,
-                                                                  uid,
-                                                                  NULL,
-                                                                  &error);
+        if (display == NULL) {
+                address = open_temporary_reauthentication_channel (self,
+                                                                   seat_id,
+                                                                   session_id,
+                                                                   pid,
+                                                                   uid,
+                                                                   is_remote);
+        } else {
+                address = gdm_display_open_reauthentication_channel_sync (display,
+                                                                          username,
+                                                                          pid,
+                                                                          uid,
+                                                                          NULL,
+                                                                          &error);
+        }
 
         if (address == NULL) {
                 g_dbus_method_invocation_return_gerror (invocation, error);
                 g_error_free (error);
                 return TRUE;
         }
 
         gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager),
                                                                  invocation,
                                                                  address);
         g_free (address);
 
         return TRUE;
 }
 
 static void
 manager_interface_init (GdmDBusManagerIface *interface)
 {
         interface->handle_open_session = gdm_manager_handle_open_session;
         interface->handle_open_reauthentication_channel = gdm_manager_handle_open_reauthentication_channel;
 }
 
 static void
 on_display_removed (GdmDisplayStore *display_store,
                     const char      *id,
                     GdmManager      *manager)
 {
         GdmDisplay *display;
 
         display = gdm_display_store_lookup (display_store, id);
-- 
1.8.4.2