[gdm/wip/slave-connection: 32/38] worker: add reauthentication support
- From: Ray Strode <halfline src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gdm/wip/slave-connection: 32/38] worker: add reauthentication support
- Date: Fri, 13 Jul 2012 17:08:40 +0000 (UTC)
commit 37bde00a189a732ac9f9badfe7ce2a02d033c8c5
Author: Ray Strode <rstrode redhat com>
Date: Mon Jul 9 21:33:10 2012 -0400
worker: add reauthentication support
This commit starts to flesh out reauthentication support for
screensavers to use.
1) It adds a "verification mode" argument to the GdmSession constructor
that tweaks the behavior of how the session worker acts to fit login or
unlock scenarios better.
2) It makes it so that when programs running within an existing session
attempt to open a communication channel for user verification, they are
granted access to a session object that's managed by the already running
worker process (so reauthentication happens in the context of the
session).
3) It adds an "allowed user" property to the gdm session object, so the
only user given access to a particular session is the owner of that
session.
daemon/Makefile.am | 7 +
daemon/gdm-dbus-util.c | 40 +++++++
daemon/gdm-dbus-util.h | 3 +
daemon/gdm-display.c | 4 +
daemon/gdm-display.h | 2 +
daemon/gdm-manager.c | 109 ++++++++++++++++++-
daemon/gdm-session-worker-job.c | 28 +++++
daemon/gdm-session-worker-job.h | 2 +
daemon/gdm-session-worker.c | 229 +++++++++++++++++++++++++++++++++++++-
daemon/gdm-session-worker.h | 3 +-
daemon/gdm-session.c | 195 ++++++++++++++++++++++++--------
daemon/gdm-session.h | 10 ++-
daemon/gdm-session.xml | 14 +++
daemon/gdm-simple-slave.c | 154 ++++++++++++++++++++++----
daemon/gdm-slave.c | 50 ++++++---
daemon/gdm-slave.h | 12 ++-
daemon/gdm-slave.xml | 2 +
daemon/gdm-welcome-session.c | 11 ++
daemon/gdm-xdmcp-chooser-slave.c | 61 ++++++++--
daemon/session-worker-main.c | 5 +-
data/gdm.conf.in | 4 +-
21 files changed, 833 insertions(+), 112 deletions(-)
---
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index cd5e122..061b5a2 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -220,12 +220,19 @@ gdm_xdmcp_chooser_slave_LDADD = \
gdm_session_worker_SOURCES = \
session-worker-main.c \
+ gdm-session.c \
+ gdm-session.h \
gdm-session-settings.h \
gdm-session-settings.c \
gdm-session-auditor.h \
gdm-session-auditor.c \
+ gdm-session-record.c \
+ gdm-session-record.h \
gdm-session-worker.h \
gdm-session-worker.c \
+ gdm-session-worker-job.c \
+ gdm-dbus-util.c \
+ gdm-dbus-util.h \
$(NULL)
nodist_gdm_session_worker_SOURCES = \
diff --git a/daemon/gdm-dbus-util.c b/daemon/gdm-dbus-util.c
index ebaa43f..5f177ba 100644
--- a/daemon/gdm-dbus-util.c
+++ b/daemon/gdm-dbus-util.c
@@ -161,3 +161,43 @@ gdm_dbus_get_pid_for_name (const char *system_bus_name,
return retval;
}
+
+gboolean
+gdm_dbus_get_uid_for_name (const char *system_bus_name,
+ uid_t *out_uid,
+ GError **error)
+{
+ GDBusConnection *bus;
+ GVariant *reply;
+ gboolean retval = FALSE;
+ unsigned int v;
+
+ bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
+ if (bus == NULL) {
+ return FALSE;
+ }
+
+ reply = g_dbus_connection_call_sync (bus,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "GetConnectionUnixUser",
+ g_variant_new ("(s)", system_bus_name),
+ G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, error);
+ if (reply == NULL) {
+ goto out;
+ }
+
+ g_variant_get (reply, "(u)", &v);
+ *out_uid = v;
+ g_variant_unref (reply);
+
+ retval = TRUE;
+ out:
+ g_object_unref (bus);
+
+ return retval;
+}
diff --git a/daemon/gdm-dbus-util.h b/daemon/gdm-dbus-util.h
index d83dea7..8bcaea0 100644
--- a/daemon/gdm-dbus-util.h
+++ b/daemon/gdm-dbus-util.h
@@ -32,4 +32,7 @@ gboolean gdm_dbus_get_pid_for_name (const char *system_bus_name,
pid_t *out_pid,
GError **error);
+gboolean gdm_dbus_get_uid_for_name (const char *system_bus_name,
+ uid_t *out_uid,
+ GError **error);
#endif
diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
index f1877ab..6ef724c 100644
--- a/daemon/gdm-display.c
+++ b/daemon/gdm-display.c
@@ -1254,6 +1254,8 @@ register_display (GdmDisplay *display)
char *
gdm_display_open_session_sync (GdmDisplay *display,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
GCancellable *cancellable,
GError **error)
{
@@ -1270,6 +1272,8 @@ gdm_display_open_session_sync (GdmDisplay *display,
address = NULL;
ret = gdm_dbus_slave_call_open_session_sync (display->priv->slave_bus_proxy,
+ (int) pid_of_caller,
+ (int) uid_of_caller,
&address,
cancellable,
error);
diff --git a/daemon/gdm-display.h b/daemon/gdm-display.h
index 1f4d3db..a66003a 100644
--- a/daemon/gdm-display.h
+++ b/daemon/gdm-display.h
@@ -91,6 +91,8 @@ GType gdm_display_get_type (void);
int gdm_display_get_status (GdmDisplay *display);
time_t gdm_display_get_creation_time (GdmDisplay *display);
char * gdm_display_open_session_sync (GdmDisplay *display,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
GCancellable *cancellable,
GError **error);
char * gdm_display_get_session_id (GdmDisplay *display);
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index aed036c..16a0cc9 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -130,7 +130,7 @@ get_session_id_for_pid_systemd (pid_t pid,
}
#endif
-#ifdef WITH_CONSOLEKIT
+#ifdef WITH_CONSOLE_KIT
static char *
get_session_id_for_pid_consolekit (GDBusConnection *connection,
pid_t pid,
@@ -171,13 +171,89 @@ get_session_id_for_pid (GDBusConnection *connection,
}
#endif
-#ifdef WITH_CONSOLEKIT
+#ifdef WITH_CONSOLE_KIT
return get_session_id_for_pid_consolekit (connection, pid, error);
#endif
return NULL;
}
+#ifdef WITH_SYSTEMD
+static gboolean
+get_uid_for_systemd_session_id (const char *session_id,
+ uid_t *uid,
+ GError **error)
+{
+ int ret;
+
+ ret = sd_session_get_uid (session_id, uid);
+ 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));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+static gboolean
+get_uid_for_consolekit_session_id (GDBusConnection *connection,
+ const char *session_id,
+ uid_t *out_uid,
+ GError **error)
+{
+ GVariant *reply;
+ guint32 uid;
+
+ reply = g_dbus_connection_call_sync (connection,
+ "org.freedesktop.ConsoleKit",
+ session_id,
+ "org.freedesktop.ConsoleKit.Session",
+ "GetUnixUser",
+ NULL,
+ G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+ if (reply == NULL) {
+ return FALSE;
+ }
+
+ g_variant_get (reply, "(u)", &uid);
+ g_variant_unref (reply);
+
+ *out_uid = (uid_t) uid;
+
+ return TRUE;
+}
+#endif
+
+static gboolean
+get_uid_for_session_id (GDBusConnection *connection,
+ const char *session_id,
+ uid_t *uid,
+ GError **error)
+{
+#ifdef WITH_SYSTEMD
+ if (sd_booted () > 0) {
+ 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,
@@ -209,6 +285,7 @@ gdm_manager_handle_open_session (GdmDBusManager *manager,
char *address;
int ret;
GPid pid;
+ uid_t caller_uid, session_uid;
sender = g_dbus_method_invocation_get_sender (invocation);
error = NULL;
@@ -219,7 +296,15 @@ gdm_manager_handle_open_session (GdmDBusManager *manager,
g_dbus_method_invocation_return_gerror (invocation, error);
g_error_free (error);
return TRUE;
+ }
+
+ ret = gdm_dbus_get_uid_for_name (sender, &caller_uid, &error);
+ if (!ret) {
+ g_prefix_error (&error, "Error while retrieving caller session id: ");
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ return TRUE;
}
connection = g_dbus_method_invocation_get_connection (invocation);
@@ -231,6 +316,24 @@ gdm_manager_handle_open_session (GdmDBusManager *manager,
return TRUE;
}
+ if (!get_uid_for_session_id (connection, session_id, &session_uid, &error)) {
+ g_prefix_error (&error, "Error while retrieving caller session id: ");
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ return TRUE;
+ }
+
+ if (caller_uid != session_uid) {
+ g_dbus_method_invocation_return_error_literal (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ _("User doesn't own session"));
+ g_prefix_error (&error, "Error while retrieving caller session id: ");
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ return TRUE;
+ }
+
display = gdm_display_store_find (self->priv->display_store,
lookup_by_session_id,
(gpointer) session_id);
@@ -245,7 +348,7 @@ gdm_manager_handle_open_session (GdmDBusManager *manager,
return TRUE;
}
- address = gdm_display_open_session_sync (display, NULL, &error);
+ address = gdm_display_open_session_sync (display, pid, session_uid, NULL, &error);
if (address == NULL) {
g_dbus_method_invocation_return_gerror (invocation, error);
diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c
index 35a506a..1aa6787 100644
--- a/daemon/gdm-session-worker-job.c
+++ b/daemon/gdm-session-worker-job.c
@@ -52,6 +52,7 @@ struct GdmSessionWorkerJobPrivate
{
char *command;
GPid pid;
+ gboolean for_reauth;
guint child_watch_id;
@@ -61,6 +62,7 @@ struct GdmSessionWorkerJobPrivate
enum {
PROP_0,
PROP_SERVER_ADDRESS,
+ PROP_FOR_REAUTH,
};
enum {
@@ -194,6 +196,10 @@ get_job_environment (GdmSessionWorkerJob *job)
g_hash_table_insert (hash, g_strdup ("GDM_SESSION_DBUS_ADDRESS"), g_strdup (job->priv->server_address));
+ if (job->priv->for_reauth) {
+ g_hash_table_insert (hash, g_strdup ("GDM_SESSION_FOR_REAUTH"), g_strdup ("1"));
+ }
+
g_hash_table_foreach (hash, (GHFunc)listify_hash, env);
g_hash_table_destroy (hash);
@@ -349,6 +355,15 @@ gdm_session_worker_job_set_server_address (GdmSessionWorkerJob *session_worker_j
session_worker_job->priv->server_address = g_strdup (address);
}
+void
+gdm_session_worker_job_set_for_reauth (GdmSessionWorkerJob *session_worker_job,
+ gboolean for_reauth)
+{
+ g_return_if_fail (GDM_IS_SESSION_WORKER_JOB (session_worker_job));
+
+ session_worker_job->priv->for_reauth = for_reauth;
+}
+
static void
gdm_session_worker_job_set_property (GObject *object,
guint prop_id,
@@ -363,6 +378,9 @@ gdm_session_worker_job_set_property (GObject *object,
case PROP_SERVER_ADDRESS:
gdm_session_worker_job_set_server_address (self, g_value_get_string (value));
break;
+ case PROP_FOR_REAUTH:
+ gdm_session_worker_job_set_for_reauth (self, g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -383,6 +401,9 @@ gdm_session_worker_job_get_property (GObject *object,
case PROP_SERVER_ADDRESS:
g_value_set_string (value, self->priv->server_address);
break;
+ case PROP_FOR_REAUTH:
+ g_value_set_boolean (value, self->priv->for_reauth);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -422,6 +443,13 @@ gdm_session_worker_job_class_init (GdmSessionWorkerJobClass *klass)
"server address",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_FOR_REAUTH,
+ g_param_spec_boolean ("for-reauth",
+ "for reauth",
+ "for reauth",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
signals [STARTED] =
g_signal_new ("started",
G_OBJECT_CLASS_TYPE (object_class),
diff --git a/daemon/gdm-session-worker-job.h b/daemon/gdm-session-worker-job.h
index ab102a9..7b256de 100644
--- a/daemon/gdm-session-worker-job.h
+++ b/daemon/gdm-session-worker-job.h
@@ -57,6 +57,8 @@ GType gdm_session_worker_job_get_type (void);
GdmSessionWorkerJob * gdm_session_worker_job_new (void);
void gdm_session_worker_job_set_server_address (GdmSessionWorkerJob *session_worker_job,
const char *server_address);
+void gdm_session_worker_job_set_for_reauth (GdmSessionWorkerJob *session_worker_job,
+ gboolean for_reauth);
gboolean gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job,
const char *name);
void gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job);
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 45c24c9..9545814 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -50,6 +50,7 @@
#include "gdm-log.h"
#include "gdm-session-worker.h"
#include "gdm-session-glue.h"
+#include "gdm-session.h"
#if defined (HAVE_ADT)
#include "gdm-session-solaris-auditor.h"
@@ -97,6 +98,15 @@ enum {
GDM_SESSION_WORKER_STATE_SESSION_STARTED
};
+typedef struct
+{
+ GdmSessionWorker *worker;
+ GdmSession *session;
+ GPid pid_of_caller;
+ uid_t uid_of_caller;
+
+} ReauthenticationRequest;
+
struct GdmSessionWorkerPrivate
{
int state;
@@ -133,6 +143,7 @@ struct GdmSessionWorkerPrivate
guint32 cancelled : 1;
guint32 timed_out : 1;
guint32 is_program_session : 1;
+ guint32 is_reauth_session : 1;
guint32 display_is_local : 1;
guint state_change_idle_id;
@@ -140,6 +151,8 @@ struct GdmSessionWorkerPrivate
GDBusConnection *connection;
GdmDBusWorkerManager *manager;
+ GHashTable *reauthentication_requests;
+
GdmSessionAuditor *auditor;
GdmSessionSettings *user_settings;
};
@@ -147,6 +160,7 @@ struct GdmSessionWorkerPrivate
enum {
PROP_0,
PROP_SERVER_ADDRESS,
+ PROP_IS_REAUTH_SESSION,
};
static void gdm_session_worker_class_init (GdmSessionWorkerClass *klass);
@@ -1213,6 +1227,13 @@ gdm_session_worker_authorize_user (GdmSessionWorker *worker,
}
}
+ /* If the user is reauthenticating, then authorization isn't required to
+ * proceed, the user is already logged in after all.
+ */
+ if (worker->priv->is_reauth_session) {
+ error_code = PAM_SUCCESS;
+ }
+
if (error_code != PAM_SUCCESS) {
g_debug ("GdmSessionWorker: user is not authorized to log in: %s",
pam_strerror (worker->priv->pam_handle, error_code));
@@ -1474,6 +1495,15 @@ gdm_session_worker_accredit_user (GdmSessionWorker *worker,
error_code = pam_setcred (worker->priv->pam_handle, worker->priv->cred_flags);
+ /* If the user is reauthenticating and they've made it this far, then there
+ * is no reason we should lock them out of their session. They've already
+ * proved they are they same person who logged in, and that's all we care
+ * about.
+ */
+ if (worker->priv->is_reauth_session) {
+ error_code = PAM_SUCCESS;
+ }
+
if (error_code != PAM_SUCCESS) {
g_set_error (error,
GDM_SESSION_WORKER_ERROR,
@@ -1917,6 +1947,13 @@ gdm_session_worker_set_server_address (GdmSessionWorker *worker,
}
static void
+gdm_session_worker_set_is_reauth_session (GdmSessionWorker *worker,
+ gboolean is_reauth_session)
+{
+ worker->priv->is_reauth_session = is_reauth_session;
+}
+
+static void
gdm_session_worker_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -1930,6 +1967,9 @@ gdm_session_worker_set_property (GObject *object,
case PROP_SERVER_ADDRESS:
gdm_session_worker_set_server_address (self, g_value_get_string (value));
break;
+ case PROP_IS_REAUTH_SESSION:
+ gdm_session_worker_set_is_reauth_session (self, g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1950,6 +1990,9 @@ gdm_session_worker_get_property (GObject *object,
case PROP_SERVER_ADDRESS:
g_value_set_string (value, self->priv->server_address);
break;
+ case PROP_IS_REAUTH_SESSION:
+ g_value_set_boolean (value, self->priv->is_reauth_session);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2395,6 +2438,11 @@ on_start_program (GdmDBusWorkerManager *proxy,
return;
}
+ if (worker->priv->is_reauth_session) {
+ g_debug ("GdmSessionWorker: ignoring start program request in reauthentication session");
+ return;
+ }
+
g_debug ("GdmSessionWorker: start program: %s", text);
g_clear_pointer (&worker->priv->arguments, (GDestroyNotify) g_strfreev);
@@ -2408,6 +2456,146 @@ on_start_program (GdmDBusWorkerManager *proxy,
}
static void
+on_reauthentication_client_connected (GdmSession *session,
+ GCredentials *credentials,
+ GPid pid_of_client,
+ ReauthenticationRequest *request)
+{
+ g_debug ("GdmSessionWorker: client connected to reauthentication server");
+}
+
+static void
+on_reauthentication_client_disconnected (GdmSession *session,
+ GCredentials *credentials,
+ GPid pid_of_client,
+ ReauthenticationRequest *request)
+{
+ GdmSessionWorker *worker;
+
+ g_debug ("GdmSessionWorker: client disconnected from reauthentication server");
+
+ worker = request->worker;
+ g_hash_table_remove (worker->priv->reauthentication_requests,
+ GINT_TO_POINTER (pid_of_client));
+}
+
+static void
+on_reauthentication_cancelled (GdmSession *session,
+ ReauthenticationRequest *request)
+{
+ g_debug ("GdmSessionWorker: client cancelled reauthentication request");
+ gdm_session_reset (session);
+}
+
+static void
+on_reauthentication_conversation_started (GdmSession *session,
+ const char *service_name,
+ ReauthenticationRequest *request)
+{
+ g_debug ("GdmSessionWorker: reauthentication service '%s' stopped",
+ service_name);
+}
+
+static void
+on_reauthentication_conversation_stopped (GdmSession *session,
+ const char *service_name,
+ ReauthenticationRequest *request)
+{
+ g_debug ("GdmSessionWorker: reauthentication service '%s' started",
+ service_name);
+}
+
+static void
+on_reauthenticated (GdmSession *session,
+ const char *service_name,
+ ReauthenticationRequest *request)
+{
+ g_debug ("GdmSessionWorker: pid %d reauthenticated user %d with service '%s'",
+ (int) request->pid_of_caller,
+ (int) request->uid_of_caller,
+ service_name);
+}
+
+static ReauthenticationRequest *
+reauthentication_request_new (GdmSessionWorker *worker,
+ GPid pid_of_caller,
+ uid_t uid_of_caller)
+{
+ ReauthenticationRequest *request;
+ char *address;
+
+ request = g_slice_new (ReauthenticationRequest);
+
+ request->worker = worker;
+ request->pid_of_caller = pid_of_caller;
+ request->uid_of_caller = uid_of_caller;
+ request->session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE,
+ uid_of_caller,
+ worker->priv->x11_display_name,
+ worker->priv->hostname,
+ worker->priv->display_device,
+ worker->priv->display_seat_id,
+ worker->priv->x11_authority_file,
+ worker->priv->display_is_local);
+
+ g_signal_connect (request->session,
+ "client-connected",
+ G_CALLBACK (on_reauthentication_client_connected),
+ request);
+ g_signal_connect (request->session,
+ "client-disconnected",
+ G_CALLBACK (on_reauthentication_client_disconnected),
+ request);
+ g_signal_connect (request->session,
+ "cancelled",
+ G_CALLBACK (on_reauthentication_cancelled),
+ request);
+ g_signal_connect (request->session,
+ "conversation-started",
+ G_CALLBACK (on_reauthentication_conversation_started),
+ request);
+ g_signal_connect (request->session,
+ "conversation-stopped",
+ G_CALLBACK (on_reauthentication_conversation_stopped),
+ request);
+ g_signal_connect (request->session,
+ "reauthenticated",
+ G_CALLBACK (on_reauthenticated),
+ request);
+
+ address = gdm_session_get_server_address (request->session);
+ gdm_dbus_worker_manager_call_reauthentication_started_sync (worker->priv->manager,
+ pid_of_caller,
+ address,
+ NULL,
+ NULL);
+ g_free (address);
+
+ return request;
+}
+
+static void
+on_start_reauthentication (GdmDBusWorkerManager *proxy,
+ int pid_of_caller,
+ int uid_of_caller,
+ GdmSessionWorker *worker)
+{
+ ReauthenticationRequest *request;
+
+ if (worker->priv->state != GDM_SESSION_WORKER_STATE_SESSION_STARTED) {
+ g_debug ("GdmSessionWorker: ignoring spurious start reauthentication while in state %s", get_state_name (worker->priv->state));
+ return;
+ }
+
+ g_debug ("GdmSessionWorker: start reauthentication");
+
+ request = reauthentication_request_new (worker, pid_of_caller, uid_of_caller);
+ g_hash_table_replace (worker->priv->reauthentication_requests,
+ GINT_TO_POINTER (pid_of_caller),
+ request);
+}
+
+static void
on_setup (GdmDBusWorkerManager *proxy,
const char *service,
const char *x11_display_name,
@@ -2552,7 +2740,11 @@ on_establish_credentials (GdmDBusWorkerManager *manager,
return;
}
- worker->priv->cred_flags = PAM_ESTABLISH_CRED;
+ if (!worker->priv->is_reauth_session) {
+ worker->priv->cred_flags = PAM_ESTABLISH_CRED;
+ } else {
+ worker->priv->cred_flags = PAM_REINITIALIZE_CRED;
+ }
queue_state_change (worker);
}
@@ -2567,6 +2759,11 @@ on_open_session (GdmDBusWorkerManager *manager,
return;
}
+ if (worker->priv->is_reauth_session) {
+ g_debug ("GdmSessionWorker: ignoring open session request in reauthentication session");
+ return;
+ }
+
queue_state_change (worker);
}
@@ -2658,6 +2855,10 @@ gdm_session_worker_constructor (GType type,
"start-program",
G_CALLBACK (on_start_program),
worker);
+ g_signal_connect (worker->priv->manager,
+ "start-reauthentication",
+ G_CALLBACK (on_start_reauthentication),
+ worker);
/* Send an initial Hello message so that the session can associate
* the conversation we manage with our pid.
@@ -2688,6 +2889,21 @@ gdm_session_worker_class_init (GdmSessionWorkerClass *klass)
"server address",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class,
+ PROP_IS_REAUTH_SESSION,
+ g_param_spec_boolean ("is-reauth-session",
+ "is reauth session",
+ "is reauth session",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+}
+
+static void
+reauthentication_request_free (ReauthenticationRequest *request)
+{
+ g_clear_object (&request->session);
+ g_slice_free (ReauthenticationRequest, request);
}
static void
@@ -2697,6 +2913,11 @@ gdm_session_worker_init (GdmSessionWorker *worker)
worker->priv = GDM_SESSION_WORKER_GET_PRIVATE (worker);
worker->priv->user_settings = gdm_session_settings_new ();
+ worker->priv->reauthentication_requests = g_hash_table_new_full (NULL,
+ NULL,
+ NULL,
+ (GDestroyNotify)
+ reauthentication_request_free);
}
static void
@@ -2735,16 +2956,20 @@ gdm_session_worker_finalize (GObject *object)
g_free (worker->priv->server_address);
g_strfreev (worker->priv->arguments);
+ g_hash_table_unref (worker->priv->reauthentication_requests);
+
G_OBJECT_CLASS (gdm_session_worker_parent_class)->finalize (object);
}
GdmSessionWorker *
-gdm_session_worker_new (const char *address)
+gdm_session_worker_new (const char *address,
+ gboolean is_reauth_session)
{
GObject *object;
object = g_object_new (GDM_TYPE_SESSION_WORKER,
"server-address", address,
+ "is-reauth-session", is_reauth_session,
NULL);
return GDM_SESSION_WORKER (object);
diff --git a/daemon/gdm-session-worker.h b/daemon/gdm-session-worker.h
index b1c8285..da5ec3f 100644
--- a/daemon/gdm-session-worker.h
+++ b/daemon/gdm-session-worker.h
@@ -65,7 +65,8 @@ typedef struct
GType gdm_session_worker_get_type (void);
GQuark gdm_session_worker_error_quark (void);
-GdmSessionWorker * gdm_session_worker_new (const char *server_address) G_GNUC_MALLOC;
+GdmSessionWorker * gdm_session_worker_new (const char *server_address,
+ gboolean is_for_reauth) G_GNUC_MALLOC;
G_END_DECLS
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index 6b69530..861462c 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -113,6 +113,8 @@ struct _GdmSessionPrivate
GdmSessionVerificationMode verification_mode;
+ uid_t allowed_user;
+
char *fallback_session_name;
GDBusServer *worker_server;
@@ -123,6 +125,7 @@ struct _GdmSessionPrivate
enum {
PROP_0,
PROP_VERIFICATION_MODE,
+ PROP_ALLOWED_USER,
PROP_DISPLAY_NAME,
PROP_DISPLAY_HOSTNAME,
PROP_DISPLAY_IS_LOCAL,
@@ -147,6 +150,7 @@ enum {
SESSION_START_FAILED,
SESSION_EXITED,
SESSION_DIED,
+ REAUTHENTICATION_STARTED,
LAST_SIGNAL
};
@@ -360,7 +364,22 @@ gdm_session_handle_accredited (GdmDBusWorkerManager *worker_manager_interface,
gdm_dbus_worker_manager_complete_accredited (worker_manager_interface,
invocation);
- gdm_session_open_session (self, service_name);
+
+ switch (self->priv->verification_mode) {
+ case GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE:
+ if (self->priv->user_verifier_interface != NULL) {
+ gdm_dbus_user_verifier_emit_verification_complete (self->priv->user_verifier_interface,
+ service_name);
+ }
+ break;
+
+ case GDM_SESSION_VERIFICATION_MODE_LOGIN:
+ case GDM_SESSION_VERIFICATION_MODE_CHOOSER:
+ gdm_session_open_session (self, service_name);
+ break;
+ default:
+ break;
+ }
return TRUE;
}
@@ -922,6 +941,22 @@ gdm_session_handle_session_exited_or_died (GdmDBusWorkerManager *worker_manager
}
static gboolean
+gdm_session_handle_reauthentication_started (GdmDBusWorkerManager *worker_manager_interface,
+ GDBusMethodInvocation *invocation,
+ int pid_of_caller,
+ const char *address,
+ GdmSession *self)
+{
+ gdm_dbus_worker_manager_complete_reauthentication_started (worker_manager_interface,
+ invocation);
+
+ g_debug ("GdmSession: Emitting 'reauthentication-started' signal for caller pid '%d'", pid_of_caller);
+ g_signal_emit (self, signals[REAUTHENTICATION_STARTED], 0, pid_of_caller, address);
+
+ return TRUE;
+}
+
+static gboolean
gdm_session_handle_saved_language_name_read (GdmDBusWorkerManager *worker_manager_interface,
GDBusMethodInvocation *invocation,
const char *language_name,
@@ -999,9 +1034,18 @@ find_conversation_by_pid (GdmSession *self,
static gboolean
allow_worker_function (GDBusAuthObserver *observer,
GIOStream *stream,
- GCredentials *credentials)
+ GCredentials *credentials,
+ GdmSession *self)
{
- if (g_credentials_get_unix_user (credentials, NULL) == 0) {
+ uid_t connecting_user;
+
+ connecting_user = g_credentials_get_unix_user (credentials, NULL);
+
+ if (connecting_user == 0) {
+ return TRUE;
+ }
+
+ if (connecting_user == self->priv->allowed_user) {
return TRUE;
}
@@ -1188,6 +1232,10 @@ export_worker_manager_interface (GdmSession *self,
"handle-session-exited",
G_CALLBACK (gdm_session_handle_session_exited_or_died),
self);
+ g_signal_connect (worker_manager_interface,
+ "handle-reauthentication-started",
+ G_CALLBACK (gdm_session_handle_reauthentication_started),
+ self);
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (worker_manager_interface),
connection,
@@ -1541,16 +1589,26 @@ on_outside_connection_closed (GDBusConnection *connection,
GError *error,
GdmSession *self)
{
+ GCredentials *credentials;
+ GPid pid_of_client;
+
g_debug ("GdmSession: external connection closed");
self->priv->outside_connections =
g_list_remove (self->priv->outside_connections,
connection);
- g_object_unref (connection);
+
+ credentials = g_dbus_connection_get_peer_credentials (connection);
+ pid_of_client = credentials_get_unix_pid (credentials);
g_signal_emit (G_OBJECT (self),
signals [CLIENT_DISCONNECTED],
- 0);
+ 0,
+ credentials,
+ (guint)
+ pid_of_client);
+
+ g_object_unref (connection);
}
static gboolean
@@ -1558,6 +1616,9 @@ handle_connection_from_outside (GDBusServer *server,
GDBusConnection *connection,
GdmSession *self)
{
+ GCredentials *credentials;
+ GPid pid_of_client;
+
g_debug ("GdmSession: Handling new connection from outside");
self->priv->outside_connections =
@@ -1579,15 +1640,24 @@ handle_connection_from_outside (GDBusServer *server,
case GDM_SESSION_VERIFICATION_MODE_CHOOSER:
export_chooser_interface (self, connection);
break;
+
+ default:
+ break;
}
if (!self->priv->display_is_local) {
export_remote_greeter_interface (self, connection);
}
+ credentials = g_dbus_connection_get_peer_credentials (connection);
+ pid_of_client = credentials_get_unix_pid (credentials);
+
g_signal_emit (G_OBJECT (self),
signals [CLIENT_CONNECTED],
- 0);
+ 0,
+ credentials,
+ (guint)
+ pid_of_client);
return TRUE;
}
@@ -1605,7 +1675,7 @@ setup_worker_server (GdmSession *self)
g_signal_connect (observer,
"authorize-authenticated-peer",
G_CALLBACK (allow_worker_function),
- NULL);
+ self);
server = gdm_dbus_setup_private_server (observer, &error);
g_object_unref (observer);
@@ -1629,48 +1699,15 @@ setup_worker_server (GdmSession *self)
}
static gboolean
-_get_uid_and_gid_for_user (const char *username,
- uid_t *uid,
- gid_t *gid)
-{
- struct passwd *passwd_entry;
-
- g_assert (username != NULL);
-
- errno = 0;
- gdm_get_pwent_for_name (username, &passwd_entry);
-
- if (passwd_entry == NULL) {
- return FALSE;
- }
-
- if (uid != NULL) {
- *uid = passwd_entry->pw_uid;
- }
-
- if (gid != NULL) {
- *gid = passwd_entry->pw_gid;
- }
-
- return TRUE;
-}
-
-static gboolean
allow_user_function (GDBusAuthObserver *observer,
GIOStream *stream,
- GCredentials *credentials)
+ GCredentials *credentials,
+ GdmSession *self)
{
- uid_t uid;
- gid_t gid;
uid_t client_uid;
- if (!_get_uid_and_gid_for_user (GDM_USERNAME, &uid, &gid)) {
- g_debug ("GdmSession: Unable to determine uid for gdm user");
- return FALSE;
- }
-
client_uid = g_credentials_get_unix_user (credentials, NULL);
- if (uid == client_uid) {
+ if (client_uid == self->priv->allowed_user) {
return TRUE;
}
@@ -1692,7 +1729,7 @@ setup_outside_server (GdmSession *self)
g_signal_connect (observer,
"authorize-authenticated-peer",
G_CALLBACK (allow_user_function),
- NULL);
+ self);
server = gdm_dbus_setup_private_server (observer, &error);
g_object_unref (observer);
@@ -2540,6 +2577,24 @@ gdm_session_client_is_connected (GdmSession *self)
return self->priv->outside_connections != NULL;
}
+uid_t
+gdm_session_get_allowed_user (GdmSession *self)
+{
+ return self->priv->allowed_user;
+}
+
+void
+gdm_session_start_reauthentication (GdmSession *session,
+ GPid pid_of_caller,
+ uid_t uid_of_caller)
+{
+ g_return_if_fail (session->priv->session_conversation != NULL);
+
+ gdm_dbus_worker_manager_emit_start_reauthentication (session->priv->session_conversation->worker_manager_interface,
+ (int) pid_of_caller,
+ (int) uid_of_caller);
+}
+
char *
gdm_session_get_server_address (GdmSession *self)
{
@@ -2774,7 +2829,7 @@ set_display_is_local (GdmSession *self,
self->priv->display_is_local = is_local;
}
- static void
+static void
set_verification_mode (GdmSession *self,
GdmSessionVerificationMode verification_mode)
{
@@ -2782,6 +2837,13 @@ set_verification_mode (GdmSession *self,
}
static void
+set_allowed_user (GdmSession *self,
+ uid_t allowed_user)
+{
+ self->priv->allowed_user = allowed_user;
+}
+
+static void
gdm_session_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -2816,6 +2878,9 @@ gdm_session_set_property (GObject *object,
case PROP_VERIFICATION_MODE:
set_verification_mode (self, g_value_get_enum (value));
break;
+ case PROP_ALLOWED_USER:
+ set_allowed_user (self, g_value_get_uint (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2857,6 +2922,9 @@ gdm_session_get_property (GObject *object,
case PROP_VERIFICATION_MODE:
g_value_set_enum (value, self->priv->verification_mode);
break;
+ case PROP_ALLOWED_USER:
+ g_value_set_uint (value, self->priv->allowed_user);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -3040,6 +3108,19 @@ gdm_session_class_init (GdmSessionClass *session_class)
G_TYPE_NONE,
1,
G_TYPE_INT);
+
+ signals [REAUTHENTICATION_STARTED] =
+ g_signal_new ("reauthentication-started",
+ GDM_TYPE_SESSION,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmSessionClass, reauthentication_started),
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_INT,
+ G_TYPE_STRING);
signals [CANCELLED] =
g_signal_new ("cancelled",
GDM_TYPE_SESSION,
@@ -3058,9 +3139,11 @@ gdm_session_class_init (GdmSessionClass *session_class)
G_STRUCT_OFFSET (GdmSessionClass, client_connected),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ NULL,
G_TYPE_NONE,
- 0);
+ 2,
+ G_TYPE_CREDENTIALS,
+ G_TYPE_UINT);
signals [CLIENT_DISCONNECTED] =
g_signal_new ("client-disconnected",
@@ -3069,9 +3152,11 @@ gdm_session_class_init (GdmSessionClass *session_class)
G_STRUCT_OFFSET (GdmSessionClass, client_disconnected),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ NULL,
G_TYPE_NONE,
- 0);
+ 2,
+ G_TYPE_CREDENTIALS,
+ G_TYPE_UINT);
signals [CLIENT_READY_FOR_SESSION_TO_START] =
g_signal_new ("client-ready-for-session-to-start",
GDM_TYPE_SESSION,
@@ -3116,6 +3201,16 @@ gdm_session_class_init (GdmSessionClass *session_class)
GDM_SESSION_VERIFICATION_MODE_LOGIN,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
+ PROP_ALLOWED_USER,
+ g_param_spec_uint ("allowed-user",
+ "allowed user",
+ "allowed user ",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
PROP_DISPLAY_NAME,
g_param_spec_string ("display-name",
"display name",
@@ -3170,6 +3265,7 @@ gdm_session_class_init (GdmSessionClass *session_class)
GdmSession *
gdm_session_new (GdmSessionVerificationMode verification_mode,
+ uid_t allowed_user,
const char *display_name,
const char *display_hostname,
const char *display_device,
@@ -3181,6 +3277,7 @@ gdm_session_new (GdmSessionVerificationMode verification_mode,
self = g_object_new (GDM_TYPE_SESSION,
"verification-mode", verification_mode,
+ "allowed-user", (guint) allowed_user,
"display-name", display_name,
"display-hostname", display_hostname,
"display-device", display_device,
diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h
index ad5f885..b16d981 100644
--- a/daemon/gdm-session.h
+++ b/daemon/gdm-session.h
@@ -37,7 +37,8 @@ typedef struct _GdmSessionPrivate GdmSessionPrivate;
typedef enum
{
GDM_SESSION_VERIFICATION_MODE_LOGIN,
- GDM_SESSION_VERIFICATION_MODE_CHOOSER
+ GDM_SESSION_VERIFICATION_MODE_CHOOSER,
+ GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE
} GdmSessionVerificationMode;
typedef struct
@@ -73,6 +74,8 @@ typedef struct
int exit_code);
void (* session_died) (GdmSession *session,
int signal_number);
+ void (* reauthentication_started) (GdmSession *session,
+ GPid pid_of_caller);
void (* conversation_started) (GdmSession *session,
const char *service_name);
void (* conversation_stopped) (GdmSession *session,
@@ -84,12 +87,17 @@ typedef struct
GType gdm_session_get_type (void);
GdmSession *gdm_session_new (GdmSessionVerificationMode verification_mode,
+ uid_t allowed_user,
const char *display_name,
const char *display_hostname,
const char *display_device,
const char *display_seat_id,
const char *display_x11_authority_file,
gboolean display_is_local);
+uid_t gdm_session_get_allowed_user (GdmSession *session);
+void gdm_session_start_reauthentication (GdmSession *session,
+ GPid pid_of_caller,
+ uid_t uid_of_caller);
char *gdm_session_get_server_address (GdmSession *session);
char *gdm_session_get_username (GdmSession *session);
diff --git a/daemon/gdm-session.xml b/daemon/gdm-session.xml
index 2ef1ff8..ca597d2 100644
--- a/daemon/gdm-session.xml
+++ b/daemon/gdm-session.xml
@@ -67,6 +67,10 @@
<arg name="service_name" direction="in" type="s"/>
<arg name="problem" direction="in" type="s"/>
</method>
+ <method name="ReauthenticationStarted">
+ <arg name="pid_of_caller" direction="in" type="i"/>
+ <arg name="address" direction="in" type="s"/>
+ </method>
<method name="Opened">
<arg name="service_name" direction="in" type="s"/>
<arg name="session_id" direction="in" type="s"/>
@@ -143,6 +147,10 @@
<signal name="StartSession">
<arg name="service_name" type="s"/>
</signal>
+ <signal name="StartReauthentication">
+ <arg name="pid_of_caller" type="i"/>
+ <arg name="uid_of_caller" type="i"/>
+ </signal>
<signal name="SetEnvironmentVariable">
<arg name="name" type="s" />
<arg name="value" type="s" />
@@ -177,6 +185,9 @@
</method>
<method name="Cancel">
</method>
+ <signal name="ReauthenticationStarted">
+ <arg name="pid_of_caller" type="i"/>
+ </signal>
<signal name="Info">
<arg name="service_name" type="s"/>
<arg name="info" type="s"/>
@@ -242,6 +253,9 @@
<signal name="SessionOpened">
<arg name="service_name" type="s"/>
</signal>
+ <signal name="Reauthenticated">
+ <arg name="service_name" type="s"/>
+ </signal>
</interface>
<interface name="org.gnome.DisplayManager.RemoteGreeter">
<method name="Disconnect" />
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index 54a7bcb..41b6f04 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -79,6 +79,8 @@ struct GdmSimpleSlavePrivate
GdmSession *session;
GdmGreeterSession *greeter;
+ GHashTable *open_session_requests;
+
guint start_session_when_ready : 1;
guint waiting_to_start_session : 1;
guint session_is_running : 1;
@@ -520,12 +522,34 @@ start_autologin_conversation_if_necessary (GdmSimpleSlave *slave)
}
static void
+on_session_reauthentication_started (GdmSession *session,
+ int pid_of_caller,
+ const char *address,
+ GdmSimpleSlave *slave)
+{
+ GSimpleAsyncResult *result;
+ gpointer source_tag;
+
+ source_tag = GINT_TO_POINTER (pid_of_caller);
+
+ result = g_hash_table_lookup (slave->priv->open_session_requests,
+ source_tag);
+
+ if (result != NULL) {
+ g_simple_async_result_set_op_res_gpointer (result,
+ g_strdup (address),
+ (GDestroyNotify)
+ g_free);
+ g_simple_async_result_complete_in_idle (result);
+ }
+}
+
+static void
on_session_client_ready_for_session_to_start (GdmSession *session,
const char *service_name,
gboolean client_is_ready,
GdmSimpleSlave *slave)
{
-
if (client_is_ready) {
g_debug ("GdmSimpleSlave: Will start session when ready");
} else {
@@ -544,6 +568,8 @@ on_session_client_ready_for_session_to_start (GdmSession *session,
}
static void
on_session_client_connected (GdmSession *session,
+ GCredentials *credentials,
+ GPid pid_of_client,
GdmSimpleSlave *slave)
{
gboolean display_is_local;
@@ -562,6 +588,8 @@ on_session_client_connected (GdmSession *session,
static void
on_session_client_disconnected (GdmSession *session,
+ GCredentials *credentials,
+ GPid pid_of_client,
GdmSimpleSlave *slave)
{
gboolean display_is_local;
@@ -595,9 +623,14 @@ create_new_session (GdmSimpleSlave *slave)
char *display_device;
char *display_seat_id;
char *display_x11_authority_file;
+ GdmSession *greeter_session;
+ uid_t greeter_uid;
g_debug ("GdmSimpleSlave: Creating new session");
+ greeter_session = gdm_welcome_session_get_session (GDM_WELCOME_SESSION (slave->priv->greeter));
+ greeter_uid = gdm_session_get_allowed_user (greeter_session);
+
g_object_get (slave,
"display-id", &display_id,
"display-name", &display_name,
@@ -613,6 +646,7 @@ create_new_session (GdmSimpleSlave *slave)
}
slave->priv->session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_LOGIN,
+ greeter_uid,
display_name,
display_hostname,
display_device,
@@ -626,6 +660,10 @@ create_new_session (GdmSimpleSlave *slave)
g_free (display_hostname);
g_signal_connect (slave->priv->session,
+ "reauthentication-started",
+ G_CALLBACK (on_session_reauthentication_started),
+ slave);
+ g_signal_connect (slave->priv->session,
"client-ready-for-session-to-start",
G_CALLBACK (on_session_client_ready_for_session_to_start),
slave);
@@ -1117,35 +1155,98 @@ gdm_simple_slave_run (GdmSimpleSlave *slave)
return TRUE;
}
-static gboolean
-gdm_simple_slave_open_session (GdmSlave *slave,
- char **address,
- GError **error)
+static char *
+gdm_simple_slave_open_session_finish (GdmSlave *slave,
+ GAsyncResult *result,
+ GError **error)
{
GdmSimpleSlave *self = GDM_SIMPLE_SLAVE (slave);
- GdmSession *session;
+ const char *address;
+ gpointer source_tag;
- if (self->priv->session_is_running) {
- g_set_error (error,
- G_DBUS_ERROR,
- G_DBUS_ERROR_ACCESS_DENIED,
- _("Greeter access only currently supported"));
- return FALSE;
+ source_tag = g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result));
+ g_hash_table_remove (self->priv->open_session_requests,
+ source_tag);
+
+ address = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) {
+ return NULL;
}
- session = self->priv->session;
+ return g_strdup (address);
+}
- if (gdm_session_client_is_connected (session)) {
- g_set_error (error,
- G_DBUS_ERROR,
- G_DBUS_ERROR_ACCESS_DENIED,
- _("Currently, only one client can be connected at once"));
- return FALSE;
+static void
+gdm_simple_slave_open_session (GdmSlave *slave,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ GCancellable *cancellable)
+{
+ GdmSimpleSlave *self = GDM_SIMPLE_SLAVE (slave);
+ GSimpleAsyncResult *result;
+ gpointer source_tag;
+
+ source_tag = GINT_TO_POINTER (pid_of_caller);
+
+ result = g_hash_table_lookup (self->priv->open_session_requests,
+ source_tag);
+
+ if (result != NULL) {
+ g_simple_async_result_set_error (result,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ _("The client can only connect once"));
+ g_simple_async_result_complete_in_idle (result);
+ return;
}
- *address = gdm_session_get_server_address (session);
+ result = g_simple_async_result_new (G_OBJECT (slave),
+ callback,
+ user_data,
+ source_tag);
- return TRUE;
+ g_simple_async_result_set_check_cancellable (result, cancellable);
+
+ g_hash_table_insert (self->priv->open_session_requests,
+ source_tag,
+ result);
+
+ if (!self->priv->session_is_running) {
+ uid_t allowed_user;
+
+ allowed_user = gdm_session_get_allowed_user (self->priv->session);
+
+ if (uid_of_caller != allowed_user) {
+ g_simple_async_result_set_error (result,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ _("Caller not GDM"));
+ } else if (gdm_session_client_is_connected (self->priv->session)) {
+ g_simple_async_result_set_error (result,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ _("Only one client can connect before session is started"));
+ } else {
+ char *address;
+
+ address = gdm_session_get_server_address (self->priv->session);
+
+ g_simple_async_result_set_op_res_gpointer (result,
+ address,
+ (GDestroyNotify)
+ g_free);
+ }
+
+ g_simple_async_result_complete_in_idle (result);
+
+ } else {
+ gdm_session_start_reauthentication (self->priv->session,
+ pid_of_caller,
+ uid_of_caller);
+ }
}
static gboolean
@@ -1253,6 +1354,7 @@ gdm_simple_slave_class_init (GdmSimpleSlaveClass *klass)
slave_class->start = gdm_simple_slave_start;
slave_class->stop = gdm_simple_slave_stop;
slave_class->open_session = gdm_simple_slave_open_session;
+ slave_class->open_session_finish = gdm_simple_slave_open_session_finish;
g_type_class_add_private (klass, sizeof (GdmSimpleSlavePrivate));
}
@@ -1264,6 +1366,14 @@ gdm_simple_slave_init (GdmSimpleSlave *slave)
#ifdef HAVE_LOGINDEVPERM
slave->priv->use_logindevperm = FALSE;
#endif
+
+ slave->priv->open_session_requests = g_hash_table_new_full (NULL,
+ NULL,
+ (GDestroyNotify)
+ NULL,
+ (GDestroyNotify)
+ g_object_unref);
+
}
static void
@@ -1280,6 +1390,8 @@ gdm_simple_slave_finalize (GObject *object)
gdm_simple_slave_stop (GDM_SLAVE (slave));
+ g_hash_table_unref (slave->priv->open_session_requests);
+
if (slave->priv->greeter_reset_id > 0) {
g_source_remove (slave->priv->greeter_reset_id);
slave->priv->greeter_reset_id = 0;
diff --git a/daemon/gdm-slave.c b/daemon/gdm-slave.c
index fbee296..0739953 100644
--- a/daemon/gdm-slave.c
+++ b/daemon/gdm-slave.c
@@ -1867,14 +1867,39 @@ gdm_slave_get_property (GObject *object,
}
}
+static void
+on_session_opened (GdmSlave *slave,
+ GAsyncResult *result,
+ GDBusMethodInvocation *invocation)
+{
+ GdmSlaveClass *slave_class;
+ GError *error;
+ char *address;
+
+ slave_class = GDM_SLAVE_GET_CLASS (slave);
+
+ g_assert (slave_class->open_session_finish != NULL);
+
+ error = NULL;
+ address = slave_class->open_session_finish (slave, result, &error);
+
+ if (address == NULL) {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ } else {
+ gdm_dbus_slave_complete_open_session (slave->priv->skeleton,
+ invocation,
+ address);
+ }
+}
+
static gboolean
handle_open_session (GdmDBusSlave *skeleton,
GDBusMethodInvocation *invocation,
+ int pid_of_caller,
+ int uid_of_caller,
GdmSlave *slave)
{
- GError *error;
GdmSlaveClass *slave_class;
- char *address;
slave_class = GDM_SLAVE_GET_CLASS (slave);
if (slave_class->open_session == NULL) {
@@ -1884,20 +1909,13 @@ handle_open_session (GdmDBusSlave *skeleton,
return TRUE;
}
- error = NULL;
- address = NULL;
- if (!slave_class->open_session (slave,
- &address,
- &error)) {
- g_dbus_method_invocation_return_gerror (invocation, error);
- g_error_free (error);
- return TRUE;
- }
-
- gdm_dbus_slave_complete_open_session (skeleton, invocation, address);
-
- g_free (address);
-
+ slave_class->open_session (slave,
+ (GPid) pid_of_caller,
+ (uid_t) uid_of_caller,
+ (GAsyncReadyCallback)
+ on_session_opened,
+ invocation,
+ NULL);
return TRUE;
}
diff --git a/daemon/gdm-slave.h b/daemon/gdm-slave.h
index ee3dcbc..c84c47a 100644
--- a/daemon/gdm-slave.h
+++ b/daemon/gdm-slave.h
@@ -50,9 +50,15 @@ typedef struct
gboolean (*start) (GdmSlave *slave);
gboolean (*stop) (GdmSlave *slave);
- gboolean (*open_session) (GdmSlave *slave,
- char **address,
- GError **error);
+ void (*open_session) (GdmSlave *slave,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ GCancellable *cancellable);
+ char * (*open_session_finish) (GdmSlave *slave,
+ GAsyncResult *result,
+ GError **error);
/* signals */
void (*stopped) (GdmSlave *slave);
diff --git a/daemon/gdm-slave.xml b/daemon/gdm-slave.xml
index b6e57cf..f8b7086 100644
--- a/daemon/gdm-slave.xml
+++ b/daemon/gdm-slave.xml
@@ -2,6 +2,8 @@
<node>
<interface name="org.gnome.DisplayManager.Slave">
<method name="OpenSession">
+ <arg name="pid_of_caller" type="i" direction="in" />
+ <arg name="uid_of_caller" type="i" direction="in" />
<arg name="address" type="s" direction="out" />
</method>
diff --git a/daemon/gdm-welcome-session.c b/daemon/gdm-welcome-session.c
index e8947b5..3f3cd66 100644
--- a/daemon/gdm-welcome-session.c
+++ b/daemon/gdm-welcome-session.c
@@ -785,6 +785,8 @@ gboolean
gdm_welcome_session_start (GdmWelcomeSession *welcome_session)
{
gboolean res;
+ struct passwd *passwd_entry;
+ uid_t uid;
g_debug ("GdmWelcomeSession: Starting welcome...");
res = start_dbus_daemon (welcome_session);
@@ -793,7 +795,16 @@ gdm_welcome_session_start (GdmWelcomeSession *welcome_session)
return FALSE;
}
+ res = gdm_get_pwent_for_name (welcome_session->priv->user_name,
+ &passwd_entry);
+
+ if (!res) {
+ return FALSE;
+ }
+
+ uid = passwd_entry->pw_uid;
welcome_session->priv->session = gdm_session_new (welcome_session->priv->verification_mode,
+ uid,
welcome_session->priv->x11_display_name,
welcome_session->priv->x11_display_hostname,
welcome_session->priv->x11_display_device,
diff --git a/daemon/gdm-xdmcp-chooser-slave.c b/daemon/gdm-xdmcp-chooser-slave.c
index c8bc586..982192c 100644
--- a/daemon/gdm-xdmcp-chooser-slave.c
+++ b/daemon/gdm-xdmcp-chooser-slave.c
@@ -155,6 +155,8 @@ on_chooser_disconnected (GdmSession *session,
static void
on_chooser_connected (GdmSession *session,
+ GCredentials *credentials,
+ GPid pid_of_client,
GdmXdmcpChooserSlave *slave)
{
g_debug ("GdmXdmcpChooserSlave: Chooser connected");
@@ -331,27 +333,59 @@ gdm_xdmcp_chooser_slave_stop (GdmSlave *slave)
return TRUE;
}
-static gboolean
-gdm_xdmcp_chooser_slave_open_session (GdmSlave *slave,
- char **address,
- GError **error)
+static char *
+gdm_xdmcp_chooser_slave_open_session_finish (GdmSlave *slave,
+ GAsyncResult *result,
+ GError **error)
+{
+ const char *address;
+
+ address = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) {
+ return NULL;
+ }
+
+ return g_strdup (address);
+}
+
+static void
+gdm_xdmcp_chooser_slave_open_session (GdmSlave *slave,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ GCancellable *cancellable)
{
GdmXdmcpChooserSlave *self = GDM_XDMCP_CHOOSER_SLAVE (slave);
- GdmSession *session;
+ GdmSession *session;
+ GSimpleAsyncResult *result;
+
+ result = g_simple_async_result_new (G_OBJECT (slave),
+ callback,
+ user_data,
+ GINT_TO_POINTER (pid_of_caller));
+ g_simple_async_result_set_check_cancellable (result, cancellable);
session = gdm_welcome_session_get_session (GDM_WELCOME_SESSION (self->priv->chooser));
if (gdm_session_client_is_connected (session)) {
- g_set_error (error,
- G_DBUS_ERROR,
- G_DBUS_ERROR_ACCESS_DENIED,
- _("Currently, only one client can be connected at once"));
- return FALSE;
- }
+ g_simple_async_result_set_error (result,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ _("Currently, only one client can be connected at once"));
+ } else {
+ char *address;
- *address = gdm_session_get_server_address (session);
+ address = gdm_session_get_server_address (session);
- return TRUE;
+ g_simple_async_result_set_op_res_gpointer (result,
+ address,
+ (GDestroyNotify)
+ g_free);
+ }
+
+ g_simple_async_result_complete_in_idle (result);
}
static GObject *
@@ -384,6 +418,7 @@ gdm_xdmcp_chooser_slave_class_init (GdmXdmcpChooserSlaveClass *klass)
slave_class->start = gdm_xdmcp_chooser_slave_start;
slave_class->stop = gdm_xdmcp_chooser_slave_stop;
slave_class->open_session = gdm_xdmcp_chooser_slave_open_session;
+ slave_class->open_session_finish = gdm_xdmcp_chooser_slave_open_session_finish;
g_type_class_add_private (klass, sizeof (GdmXdmcpChooserSlavePrivate));
}
diff --git a/daemon/session-worker-main.c b/daemon/session-worker-main.c
index 94496b5..7a385ed 100644
--- a/daemon/session-worker-main.c
+++ b/daemon/session-worker-main.c
@@ -137,6 +137,7 @@ main (int argc,
GdmSessionWorker *worker;
GdmSignalHandler *signal_handler;
const char *address;
+ gboolean is_for_reauth;
static GOptionEntry entries [] = {
{ NULL }
};
@@ -176,7 +177,9 @@ main (int argc,
exit (1);
}
- worker = gdm_session_worker_new (address);
+ is_for_reauth = g_getenv ("GDM_SESSION_FOR_REAUTH") != NULL;
+
+ worker = gdm_session_worker_new (address, is_for_reauth);
main_loop = g_main_loop_new (NULL, FALSE);
diff --git a/data/gdm.conf.in b/data/gdm.conf.in
index b455971..ec20260 100644
--- a/data/gdm.conf.in
+++ b/data/gdm.conf.in
@@ -24,8 +24,6 @@
<policy context="default">
<deny send_destination="org.gnome.DisplayManager"
- send_interface="org.gnome.DisplayManager.Manager"/>
- <deny send_destination="org.gnome.DisplayManager"
send_interface="org.gnome.DisplayManager.Display"/>
<deny send_destination="org.gnome.DisplayManager"
send_interface="org.gnome.DisplayManager.LocalDisplayFactory"/>
@@ -40,6 +38,8 @@
<allow send_destination="org.gnome.DisplayManager"
send_interface="org.freedesktop.DBus.ObjectManager"/>
<allow send_destination="org.gnome.DisplayManager"
+ send_interface="org.gnome.DisplayManager.Manager"/>
+ <allow send_destination="org.gnome.DisplayManager"
send_interface="org.gnome.DisplayManager.Display"
send_member="GetId"/>
<allow send_destination="org.gnome.DisplayManager"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]