From b994e9478eb301f9344f376ead56060586d20a03 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 11 Mar 2014 15:25:29 -0400 Subject: 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 file changed, 188 insertions(+), 17 deletions(-) diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c index f75e4733..f7c33c62 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; } -- cgit v1.2.1