[gdm] manager: support just-in-time reauthentication for non-GDM sessions



commit b994e9478eb301f9344f376ead56060586d20a03
Author: Ray Strode <rstrode redhat com>
Date:   Tue Mar 11 15:25:29 2014 -0400

    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.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=726283

 daemon/gdm-manager.c |  205 +++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 188 insertions(+), 17 deletions(-)
---
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index f75e473..f7c33c6 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -918,7 +918,8 @@ gdm_manager_handle_open_session (GdmDBusManager        *manager,
         GdmSession       *session;
         const char       *address;
         GPid              pid = 0;
-        uid_t             uid = 0, allowed_user;
+        uid_t             uid = (uid_t) -1;
+        uid_t             allowed_user;
 
         g_debug ("GdmManager: trying to open new session");
 
@@ -967,6 +968,169 @@ gdm_manager_handle_open_session (GdmDBusManager        *manager,
         return TRUE;
 }
 
+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);
+        session_unlock (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 void
+add_session_weak_refs (GdmManager *self,
+                       GdmSession *session)
+{
+        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);
+}
+
+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;
+        const 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);
+
+        add_session_weak_refs (self, session);
+
+        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 g_strdup (address);
+}
+
 static gboolean
 gdm_manager_handle_open_reauthentication_channel (GdmDBusManager        *manager,
                                                   GDBusMethodInvocation *invocation,
@@ -977,15 +1141,18 @@ gdm_manager_handle_open_reauthentication_channel (GdmDBusManager        *manager
         GdmDisplay       *display = NULL;
         GdmSession       *session;
         GDBusConnection  *connection;
+        char             *seat_id = NULL;
+        char             *session_id = NULL;
         GPid              pid = 0;
-        uid_t             uid = 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,
@@ -995,7 +1162,7 @@ gdm_manager_handle_open_reauthentication_channel (GdmDBusManager        *manager
                 return TRUE;
         }
 
-        if (display == NULL) {
+        if (seat_id == NULL || 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,
@@ -1006,21 +1173,25 @@ gdm_manager_handle_open_reauthentication_channel (GdmDBusManager        *manager
 
         session = get_seed_session_for_display (display);
 
-        if (!gdm_session_is_running (session)) {
-                g_dbus_method_invocation_return_error_literal (invocation,
-                                                               G_DBUS_ERROR,
-                                                               G_DBUS_ERROR_ACCESS_DENIED,
-                                                               _("No session available"));
-
-                return TRUE;
+        if (session != NULL && gdm_session_is_running (session)) {
+                gdm_session_start_reauthentication (session, pid, uid);
+                g_hash_table_insert (self->priv->open_reauthentication_requests,
+                                     GINT_TO_POINTER (pid),
+                                     invocation);
+        } else {
+                char *address;
+                address = open_temporary_reauthentication_channel (self,
+                                                                   seat_id,
+                                                                   session_id,
+                                                                   pid,
+                                                                   uid,
+                                                                   is_remote);
+                gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager),
+                                                                         invocation,
+                                                                         address);
+                g_free (address);
         }
 
-        gdm_session_start_reauthentication (session, pid, uid);
-
-        g_hash_table_insert (self->priv->open_reauthentication_requests,
-                             GINT_TO_POINTER (pid),
-                             invocation);
-
         return TRUE;
 }
 


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