diff options
author | Ray Strode <rstrode@redhat.com> | 2014-03-11 15:25:29 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2014-03-19 14:48:56 -0400 |
commit | b994e9478eb301f9344f376ead56060586d20a03 (patch) | |
tree | 00d651f0b281676ed85ec484a64b1d73d9547eb7 | |
parent | afc73ea1d5e283135314abeb9c301cc55d917a03 (diff) | |
download | gdm-b994e9478eb301f9344f376ead56060586d20a03.tar.gz |
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
-rw-r--r-- | 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 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; } |