summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2014-03-11 15:25:29 -0400
committerRay Strode <rstrode@redhat.com>2014-03-19 14:48:56 -0400
commitb994e9478eb301f9344f376ead56060586d20a03 (patch)
tree00d651f0b281676ed85ec484a64b1d73d9547eb7
parentafc73ea1d5e283135314abeb9c301cc55d917a03 (diff)
downloadgdm-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.c205
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;
}