summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2012-07-09 21:33:10 -0400
committerRay Strode <rstrode@redhat.com>2012-07-17 04:14:56 -0400
commit2853ce5812aa8f03f677516e64d5dcff1e6e01ab (patch)
tree9287b11efc20a033ca2d57a99d7046c607163e18
parent4f86de30a115a77cf61b4652fef53f9f0517fc0b (diff)
downloadgdm-2853ce5812aa8f03f677516e64d5dcff1e6e01ab.tar.gz
worker: add reauthentication support
This commit adds reauthentication support for screensavers and user switching 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 adds a way for programs to open a communication channel for user verification to already runnings sessions (so reauthentication happens in the context of the session).
-rw-r--r--daemon/Makefile.am7
-rw-r--r--daemon/gdm-dbus-util.c40
-rw-r--r--daemon/gdm-dbus-util.h3
-rw-r--r--daemon/gdm-display.c39
-rw-r--r--daemon/gdm-display.h9
-rw-r--r--daemon/gdm-manager.c525
-rw-r--r--daemon/gdm-manager.xml4
-rw-r--r--daemon/gdm-session-worker-job.c28
-rw-r--r--daemon/gdm-session-worker-job.h2
-rw-r--r--daemon/gdm-session-worker.c239
-rw-r--r--daemon/gdm-session-worker.h3
-rw-r--r--daemon/gdm-session.c321
-rw-r--r--daemon/gdm-session.h14
-rw-r--r--daemon/gdm-session.xml26
-rw-r--r--daemon/gdm-simple-slave.c147
-rw-r--r--daemon/gdm-slave.c64
-rw-r--r--daemon/gdm-slave.h19
-rw-r--r--daemon/gdm-slave.xml9
-rw-r--r--daemon/gdm-welcome-session.c11
-rw-r--r--daemon/gdm-xdmcp-chooser-slave.c14
-rw-r--r--daemon/session-worker-main.c5
-rw-r--r--data/gdm.conf.in4
22 files changed, 1438 insertions, 95 deletions
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index cd5e122f..061b5a22 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 e57f0a0b..94361c66 100644
--- a/daemon/gdm-dbus-util.c
+++ b/daemon/gdm-dbus-util.c
@@ -163,3 +163,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 b3210b4d..a9a42acb 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 0c6e7564..25fff698 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);
@@ -1281,6 +1285,41 @@ gdm_display_open_session_sync (GdmDisplay *display,
return address;
}
+char *
+gdm_display_open_reauthentication_channel_sync (GdmDisplay *display,
+ const char *username,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
+ GCancellable *cancellable,
+ GError **error)
+{
+ char *address;
+ int ret;
+
+ if (display->priv->slave_bus_proxy == NULL) {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ _("No session available yet"));
+ return NULL;
+ }
+
+ address = NULL;
+ ret = gdm_dbus_slave_call_open_reauthentication_channel_sync (display->priv->slave_bus_proxy,
+ username,
+ pid_of_caller,
+ uid_of_caller,
+ &address,
+ cancellable,
+ error);
+
+ if (!ret) {
+ return NULL;
+ }
+
+ return address;
+}
+
/*
dbus-send --system --print-reply --dest=org.gnome.DisplayManager /org/gnome/DisplayManager/Displays/1 org.freedesktop.DBus.Introspectable.Introspect
*/
diff --git a/daemon/gdm-display.h b/daemon/gdm-display.h
index 1f4d3dbe..5050eecd 100644
--- a/daemon/gdm-display.h
+++ b/daemon/gdm-display.h
@@ -91,8 +91,17 @@ 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_open_reauthentication_channel_sync (GdmDisplay *display,
+ const char *username,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
+ GCancellable *cancellable,
+ GError **error);
char * gdm_display_get_session_id (GdmDisplay *display);
gboolean gdm_display_create_authority (GdmDisplay *display);
gboolean gdm_display_prepare (GdmDisplay *display);
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 1da7ef83..bb43c0f2 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -178,6 +178,319 @@ get_session_id_for_pid (GDBusConnection *connection,
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;
+}
+
+#ifdef WITH_SYSTEMD
+static char *
+get_session_id_for_user_on_seat_systemd (const char *username,
+ const char *seat,
+ GError **error)
+{
+ struct passwd *pwent;
+ uid_t uid;
+ int i;
+ char **sessions;
+ char *session = NULL;
+ int ret;
+
+ pwent = NULL;
+ gdm_get_pwent_for_name (username, &pwent);
+
+ if (pwent == NULL) {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ _("Unable to look up UID of user %s"),
+ username);
+ return NULL;
+ }
+
+ uid = pwent->pw_uid;
+
+ session = NULL;
+ ret = sd_seat_get_sessions (seat, &sessions, NULL, NULL);
+ if (ret < 0 || sessions == NULL) {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ "Error getting session ids from systemd: %s",
+ ret < 0? g_strerror (-ret) : _("no sessions available"));
+ return NULL;
+ }
+
+ for (i = 0; sessions[i] != NULL; i++) {
+ char *type;
+ char *state;
+ gboolean is_closing;
+ gboolean is_x11;
+ uid_t session_uid;
+
+ ret = sd_session_get_uid (sessions[i], &session_uid);
+
+ if (ret < 0) {
+ g_warning ("GdmManager: could not fetch uid of session '%s': %s",
+ sessions[i], strerror (-ret));
+ continue;
+ }
+
+ if (uid != session_uid) {
+ continue;
+ }
+
+ ret = sd_session_get_type (sessions[i], &type);
+
+ if (ret < 0) {
+ g_warning ("GdmManager: could not fetch type of session '%s': %s",
+ sessions[i], strerror (-ret));
+ continue;
+ }
+
+ is_x11 = g_strcmp0 (type, "x11") == 0;
+ free (type);
+
+ if (!is_x11) {
+ continue;
+ }
+
+ ret = sd_session_get_state (sessions[i], &state);
+ if (ret < 0) {
+ g_warning ("GdmManager: could not fetch state of session '%s': %s",
+ sessions[i], strerror (-ret));
+ continue;
+ }
+
+ is_closing = g_strcmp0 (state, "closing") == 0;
+
+ if (is_closing) {
+ continue;
+ }
+
+ session = g_strdup (sessions[i]);
+ break;
+
+ }
+
+ if (session == NULL) {
+ g_debug ("GdmManager: There are no applicable sessions (%d looked at)", i);
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ _("No sessions for %s available for reauthentication"),
+ username);
+ return NULL;
+ }
+
+ g_debug ("GdmManager: session %s is available for reauthentication", session);
+
+ return session;
+}
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+static char *
+get_session_id_for_user_on_seat_consolekit (GDBusConnection *connection,
+ const char *username,
+ const char *seat,
+ GError **error)
+{
+ GVariant *reply;
+ GVariant *array;
+ const gchar **sessions;
+ char *session = NULL;
+ struct passwd *pwent;
+ uid_t uid;
+ int i;
+
+ pwent = NULL;
+ gdm_get_pwent_for_name (username, &pwent);
+
+ if (pwent == NULL) {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ _("Unable to look up UID of user %s"),
+ username);
+ return NULL;
+ }
+
+ uid = pwent->pw_uid;
+
+ reply = g_dbus_connection_call_sync (connection,
+ "org.freedesktop.ConsoleKit",
+ "/org/freedesktop/ConsoleKit/Manager",
+ "org.freedesktop.ConsoleKit.Manager",
+ "GetSessionsForUnixUser",
+ g_variant_new ("(u)", (guint32) uid),
+ G_VARIANT_TYPE ("(ao)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+ if (reply == NULL) {
+ return NULL;
+ }
+
+ g_variant_get (reply, "(ao)", &array);
+
+ sessions = g_variant_get_objv (array, NULL);
+
+ for (i = 0; sessions[i] != NULL; i++) {
+ GVariant *reply2;
+ GError *error2 = NULL;
+ gchar *display;
+ gchar *session_seat_id;
+
+ reply2 = g_dbus_connection_call_sync (connection,
+ "org.freedesktop.ConsoleKit",
+ sessions[i],
+ "org.freedesktop.ConsoleKit.Session",
+ "GetSeatId",
+ NULL,
+ G_VARIANT_TYPE ("(o)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error2);
+ if (reply2 == NULL) {
+ continue;
+ }
+
+ g_variant_get (reply, "(o)", &session_seat_id);
+ g_variant_unref (reply2);
+
+ if (g_strcmp0 (seat, session_seat_id) != 0) {
+ g_free (session_seat_id);
+ continue;
+ }
+ g_free (session_seat_id);
+
+ reply2 = g_dbus_connection_call_sync (connection,
+ "org.freedesktop.ConsoleKit",
+ sessions[i],
+ "org.freedesktop.ConsoleKit.Session",
+ "GetX11DisplayDevice",
+ NULL,
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error2);
+ if (reply2 == NULL) {
+ continue;
+ }
+
+ g_variant_get (reply2, "(s)", &display);
+ g_variant_unref (reply2);
+
+ if (display[0] == '\0') {
+ g_free (display);
+ continue;
+ }
+
+ session = g_strdup (sessions[i]);
+ break;
+
+ }
+ g_free (sessions);
+ g_variant_unref (reply);
+
+ return session;
+}
+#endif
+
+static char *
+get_session_id_for_user_on_seat (GDBusConnection *connection,
+ const char *username,
+ const char *seat,
+ GError **error)
+{
+#ifdef WITH_SYSTEMD
+ if (sd_booted () > 0) {
+ return get_session_id_for_user_on_seat_systemd (username, seat, error);
+ }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+ return get_session_id_for_user_on_seat_consolekit (connection, username, seat, error);
+#endif
+
+ return NULL;
+}
+
static gboolean
lookup_by_session_id (const char *id,
GdmDisplay *display,
@@ -196,6 +509,102 @@ lookup_by_session_id (const char *id,
return res;
}
+#ifdef WITH_SYSTEMD
+static char *
+get_seat_id_for_pid_systemd (pid_t pid,
+ GError **error)
+{
+ char *session;
+ char *seat, *gseat;
+ int ret;
+
+ session = get_session_id_for_pid_systemd (pid, error);
+
+ if (session == NULL) {
+ return NULL;
+ }
+
+ seat = NULL;
+ ret = sd_session_get_seat (session, &seat);
+ free (session);
+
+ if (ret < 0) {
+ g_set_error (error,
+ GDM_DISPLAY_ERROR,
+ GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
+ "Error getting seat id from systemd: %s",
+ g_strerror (-ret));
+ return NULL;
+ }
+
+ if (seat != NULL) {
+ gseat = g_strdup (seat);
+ free (seat);
+
+ return gseat;
+ } else {
+ return NULL;
+ }
+}
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+static char *
+get_seat_id_for_pid_consolekit (GDBusConnection *connection,
+ pid_t pid,
+ GError **error)
+{
+ char *session;
+ GVariant *reply;
+ char *retval;
+
+ session = get_session_id_for_pid_consolekit (connection, pid, error);
+
+ if (session == NULL) {
+ return NULL;
+ }
+
+ reply = g_dbus_connection_call_sync (connection,
+ "org.freedesktop.ConsoleKit",
+ session,
+ "org.freedesktop.ConsoleKit.Session",
+ "GetSeatId",
+ NULL,
+ G_VARIANT_TYPE ("(o)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, error);
+ g_free (session);
+
+ if (reply == NULL) {
+ return NULL;
+ }
+
+ g_variant_get (reply, "(o)", &retval);
+ g_variant_unref (reply);
+
+ return retval;
+}
+#endif
+
+static char *
+get_seat_id_for_pid (GDBusConnection *connection,
+ pid_t pid,
+ GError **error)
+{
+#ifdef WITH_SYSTEMD
+ if (sd_booted () > 0) {
+ return get_seat_id_for_pid_systemd (pid, error);
+ }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+ return get_seat_id_for_pid_consolekit (connection, pid, error);
+#endif
+
+ return NULL;
+}
+
static gboolean
gdm_manager_handle_open_session (GdmDBusManager *manager,
GDBusMethodInvocation *invocation)
@@ -209,6 +618,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 +629,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 +649,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 +681,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);
@@ -261,10 +697,97 @@ gdm_manager_handle_open_session (GdmDBusManager *manager,
return TRUE;
}
+static gboolean
+gdm_manager_handle_open_reauthentication_channel (GdmDBusManager *manager,
+ GDBusMethodInvocation *invocation,
+ const char *username)
+{
+ GdmManager *self = GDM_MANAGER (manager);
+ GDBusConnection *connection;
+ GdmDisplay *display;
+ const char *sender;
+ char *seat_id;
+ char *session_id = NULL;
+ GError *error;
+ char *address;
+ int ret;
+ GPid pid;
+ uid_t caller_uid;
+
+ g_debug ("GdmManager: trying to open reauthentication channel for user %s", username);
+
+ sender = g_dbus_method_invocation_get_sender (invocation);
+ error = NULL;
+ ret = gdm_dbus_get_pid_for_name (sender, &pid, &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;
+
+ }
+
+ 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);
+
+ seat_id = get_seat_id_for_pid (connection, pid, &error);
+
+ session_id = get_session_id_for_user_on_seat (connection, username, seat_id, &error);
+ if (session_id == NULL) {
+ 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);
+ g_free (session_id);
+
+ if (display == NULL) {
+ g_dbus_method_invocation_return_error_literal (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ _("No session available"));
+
+ return TRUE;
+ }
+
+ address = gdm_display_open_reauthentication_channel_sync (display,
+ username,
+ pid,
+ caller_uid,
+ NULL,
+ &error);
+
+ if (address == NULL) {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ return TRUE;
+ }
+
+ gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager),
+ invocation,
+ address);
+ g_free (address);
+
+ return TRUE;
+}
+
static void
manager_interface_init (GdmDBusManagerIface *interface)
{
interface->handle_open_session = gdm_manager_handle_open_session;
+ interface->handle_open_reauthentication_channel = gdm_manager_handle_open_reauthentication_channel;
}
static void
diff --git a/daemon/gdm-manager.xml b/daemon/gdm-manager.xml
index 8c1a94e9..db35b38a 100644
--- a/daemon/gdm-manager.xml
+++ b/daemon/gdm-manager.xml
@@ -4,5 +4,9 @@
<method name="OpenSession">
<arg name="address" direction="out" type="s"/>
</method>
+ <method name="OpenReauthenticationChannel">
+ <arg name="username" direction="in" type="s"/>
+ <arg name="address" direction="out" type="s"/>
+ </method>
</interface>
</node>
diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c
index 35a506af..1aa67876 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 ab102a91..7b256de1 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 f7516066..190ca4f7 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,156 @@ 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_verification_complete (GdmSession *session,
+ const char *service_name,
+ ReauthenticationRequest *request)
+{
+ GdmSessionWorker *worker;
+
+ worker = request->worker;
+
+ g_debug ("GdmSessionWorker: pid %d reauthenticated user %d with service '%s'",
+ (int) request->pid_of_caller,
+ (int) request->uid_of_caller,
+ service_name);
+ gdm_session_reset (session);
+
+ gdm_dbus_worker_manager_call_reauthenticated_sync (worker->priv->manager,
+ service_name,
+ NULL,
+ NULL);
+}
+
+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,
+ "verification-complete",
+ G_CALLBACK (on_verification_complete),
+ 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 +2750,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 +2769,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);
}
@@ -2660,6 +2867,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.
@@ -2690,6 +2901,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
@@ -2699,6 +2925,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
@@ -2737,16 +2968,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 b1c8285c..da5ec3ff 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 aab06b6e..0e389fa0 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -73,6 +73,7 @@ typedef struct
char *service_name;
GDBusConnection *worker_connection;
GDBusMethodInvocation *starting_invocation;
+ char *starting_username;
GDBusMethodInvocation *pending_invocation;
GdmDBusWorkerManager *worker_manager_interface;
char *session_id;
@@ -114,6 +115,8 @@ struct _GdmSessionPrivate
GdmSessionVerificationMode verification_mode;
+ uid_t allowed_user;
+
char *fallback_session_name;
GDBusServer *worker_server;
@@ -124,6 +127,7 @@ struct _GdmSessionPrivate
enum {
PROP_0,
PROP_VERIFICATION_MODE,
+ PROP_ALLOWED_USER,
PROP_DISPLAY_NAME,
PROP_DISPLAY_HOSTNAME,
PROP_DISPLAY_IS_LOCAL,
@@ -143,11 +147,14 @@ enum {
CLIENT_DISCONNECTED,
CLIENT_READY_FOR_SESSION_TO_START,
DISCONNECTED,
+ VERIFICATION_COMPLETE,
SESSION_OPENED,
SESSION_STARTED,
SESSION_START_FAILED,
SESSION_EXITED,
SESSION_DIED,
+ REAUTHENTICATION_STARTED,
+ REAUTHENTICATED,
LAST_SIGNAL
};
@@ -226,6 +233,8 @@ report_problem_and_stop_conversation (GdmSession *self,
gdm_dbus_user_verifier_emit_problem (self->priv->user_verifier_interface,
service_name,
message);
+ gdm_dbus_user_verifier_emit_verification_failed (self->priv->user_verifier_interface,
+ service_name);
}
gdm_session_stop_conversation (self, service_name);
@@ -245,6 +254,8 @@ gdm_session_handle_service_unavailable (GdmDBusWorkerManager *worker_manager_in
gdm_dbus_user_verifier_emit_service_unavailable (self->priv->user_verifier_interface,
service_name,
message);
+ gdm_dbus_user_verifier_emit_verification_failed (self->priv->user_verifier_interface,
+ service_name);
}
gdm_session_stop_conversation (self, service_name);
@@ -258,6 +269,16 @@ gdm_session_handle_setup_complete (GdmDBusWorkerManager *worker_manager_interfa
const char *service_name,
GdmSession *self)
{
+ GdmSessionConversation *conversation;
+
+ conversation = find_conversation_by_name (self, service_name);
+ if (conversation != NULL) {
+ if (conversation->starting_invocation != NULL) {
+ g_dbus_method_invocation_return_value (conversation->starting_invocation,
+ NULL);
+ g_clear_object (&conversation->starting_invocation);
+ }
+ }
gdm_dbus_worker_manager_complete_setup_complete (worker_manager_interface,
invocation);
@@ -278,6 +299,19 @@ gdm_session_handle_setup_failed (GdmDBusWorkerManager *worker_manager_interface
const char *message,
GdmSession *self)
{
+ GdmSessionConversation *conversation;
+
+ conversation = find_conversation_by_name (self, service_name);
+ if (conversation != NULL) {
+ if (conversation->starting_invocation != NULL) {
+ g_dbus_method_invocation_return_dbus_error (conversation->starting_invocation,
+ "org.gnome.DisplayManager.Session.Error.SetupFailed",
+ message);
+
+ g_clear_object (&conversation->starting_invocation);
+ }
+ }
+
gdm_dbus_worker_manager_complete_setup_failed (worker_manager_interface,
invocation);
@@ -361,7 +395,23 @@ 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) {
+ g_signal_emit (self, signals[VERIFICATION_COMPLETE], 0, service_name);
+ 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;
}
@@ -376,8 +426,6 @@ gdm_session_handle_accreditation_failed (GdmDBusWorkerManager *worker_manager_i
gdm_dbus_worker_manager_complete_accreditation_failed (worker_manager_interface,
invocation);
-#warning emit TRY_TO_MIGRATE or something like that. The idea is, we don't care if accreditation fails if the user is already logged in. though maybe we should rethink how user switching is done so that its done in the same way unlock will be done, then we won't even try to accredit in the first place.
-
report_problem_and_stop_conversation (self, service_name, message);
return TRUE;
}
@@ -831,14 +879,15 @@ gdm_session_handle_opened (GdmDBusWorkerManager *worker_manager_interface,
service_name);
}
- g_debug ("GdmSession: Emitting 'session-opened' signal");
- g_signal_emit (self, signals[SESSION_OPENED], 0, service_name, session_id);
-
if (self->priv->user_verifier_interface != NULL) {
+ g_signal_emit (self, signals[VERIFICATION_COMPLETE], 0, service_name);
gdm_dbus_user_verifier_emit_verification_complete (self->priv->user_verifier_interface,
service_name);
}
+ g_debug ("GdmSession: Emitting 'session-opened' signal");
+ g_signal_emit (self, signals[SESSION_OPENED], 0, service_name, session_id);
+
return TRUE;
}
@@ -923,6 +972,35 @@ 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_reauthenticated (GdmDBusWorkerManager *worker_manager_interface,
+ GDBusMethodInvocation *invocation,
+ const char *service_name,
+ GdmSession *self)
+{
+ gdm_dbus_worker_manager_complete_reauthentication_started (worker_manager_interface,
+ invocation);
+
+ g_debug ("GdmSession: Emitting 'reauthenticated' signal ");
+ g_signal_emit (self, signals[REAUTHENTICATED], 0, service_name);
+ return TRUE;
+}
+
+static gboolean
gdm_session_handle_saved_language_name_read (GdmDBusWorkerManager *worker_manager_interface,
GDBusMethodInvocation *invocation,
const char *language_name,
@@ -1000,9 +1078,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;
}
@@ -1085,6 +1172,23 @@ register_worker (GdmDBusWorkerManager *worker_manager_interface,
g_debug ("GdmSession: Emitting conversation-started signal");
g_signal_emit (self, signals[CONVERSATION_STARTED], 0, conversation->service_name);
+ if (self->priv->user_verifier_interface != NULL) {
+ gdm_dbus_user_verifier_emit_conversation_started (self->priv->user_verifier_interface,
+ conversation->service_name);
+ }
+
+ if (conversation->starting_invocation != NULL) {
+ if (conversation->starting_username != NULL) {
+ gdm_session_setup_for_user (self, conversation->service_name, conversation->starting_username);
+
+ g_clear_pointer (&conversation->starting_username,
+ (GDestroyNotify)
+ g_free);
+ } else {
+ gdm_session_setup (self, conversation->service_name);
+ }
+ }
+
g_debug ("GdmSession: Conversation started");
return TRUE;
@@ -1189,6 +1293,14 @@ 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_signal_connect (worker_manager_interface,
+ "handle-reauthenticated",
+ G_CALLBACK (gdm_session_handle_reauthenticated),
+ self);
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (worker_manager_interface),
connection,
@@ -1249,8 +1361,7 @@ gdm_session_handle_client_begin_verification (GdmDBusUserVerifier *user_verif
if (conversation != NULL) {
conversation->starting_invocation = g_object_ref (invocation);
-
- gdm_session_setup (self, service_name);
+ conversation->starting_username = NULL;
} else {
g_dbus_method_invocation_return_error (conversation->starting_invocation,
G_DBUS_ERROR,
@@ -1276,8 +1387,7 @@ gdm_session_handle_client_begin_verification_for_user (GdmDBusUserVerifier *u
if (conversation != NULL) {
conversation->starting_invocation = g_object_ref (invocation);
-
- gdm_session_setup_for_user (self, service_name, username);
+ conversation->starting_username = g_strdup (username);
} else {
g_dbus_method_invocation_return_error (conversation->starting_invocation,
G_DBUS_ERROR,
@@ -1534,16 +1644,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
@@ -1551,6 +1671,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 =
@@ -1573,15 +1696,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;
}
@@ -1599,7 +1731,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);
@@ -1623,48 +1755,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;
}
@@ -1686,7 +1785,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);
@@ -1717,6 +1816,7 @@ free_conversation (GdmSessionConversation *conversation)
}
g_free (conversation->service_name);
+ g_clear_object (&conversation->session);
g_free (conversation);
}
@@ -1760,11 +1860,6 @@ worker_started (GdmSessionWorkerJob *job,
{
g_debug ("GdmSession: Worker job started");
- if (conversation->starting_invocation != NULL) {
- g_dbus_method_invocation_return_value (conversation->starting_invocation,
- NULL);
- g_clear_object (&conversation->starting_invocation);
- }
}
static void
@@ -1785,6 +1880,10 @@ worker_exited (GdmSessionWorkerJob *job,
g_debug ("GdmSession: Emitting conversation-stopped signal");
g_signal_emit (self, signals[CONVERSATION_STOPPED], 0, conversation->service_name);
+ if (self->priv->user_verifier_interface != NULL) {
+ gdm_dbus_user_verifier_emit_conversation_stopped (self->priv->user_verifier_interface,
+ conversation->service_name);
+ }
g_object_unref (conversation->job);
if (conversation->is_stopping) {
@@ -1813,6 +1912,10 @@ worker_died (GdmSessionWorkerJob *job,
g_debug ("GdmSession: Emitting conversation-stopped signal");
g_signal_emit (self, signals[CONVERSATION_STOPPED], 0, conversation->service_name);
+ if (self->priv->user_verifier_interface != NULL) {
+ gdm_dbus_user_verifier_emit_conversation_stopped (self->priv->user_verifier_interface,
+ conversation->service_name);
+ }
g_object_unref (conversation->job);
if (conversation->is_stopping) {
@@ -1831,7 +1934,7 @@ start_conversation (GdmSession *self,
char *job_name;
conversation = g_new0 (GdmSessionConversation, 1);
- conversation->session = self;
+ conversation->session = g_object_ref (self);
conversation->service_name = g_strdup (service_name);
conversation->worker_pid = -1;
conversation->job = gdm_session_worker_job_new ();
@@ -2463,10 +2566,6 @@ gdm_session_close (GdmSession *self)
g_list_free_full (self->priv->pending_worker_connections, g_object_unref);
self->priv->pending_worker_connections = NULL;
- g_clear_object (&self->priv->user_verifier_interface);
- g_clear_object (&self->priv->greeter_interface);
- g_clear_object (&self->priv->chooser_interface);
-
g_free (self->priv->selected_user);
self->priv->selected_user = NULL;
@@ -2543,6 +2642,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)
{
@@ -2777,7 +2894,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)
{
@@ -2785,6 +2902,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,
@@ -2819,6 +2943,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;
@@ -2860,6 +2987,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;
@@ -2877,6 +3007,10 @@ gdm_session_dispose (GObject *object)
gdm_session_close (self);
+ g_clear_object (&self->priv->user_verifier_interface);
+ g_clear_object (&self->priv->greeter_interface);
+ g_clear_object (&self->priv->chooser_interface);
+
g_free (self->priv->display_name);
self->priv->display_name = NULL;
@@ -2986,6 +3120,17 @@ gdm_session_class_init (GdmSessionClass *session_class)
G_TYPE_NONE,
1,
G_TYPE_STRING);
+ signals [VERIFICATION_COMPLETE] =
+ g_signal_new ("verification-complete",
+ GDM_TYPE_SESSION,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmSessionClass, verification_complete),
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
signals [SESSION_OPENED] =
g_signal_new ("session-opened",
GDM_TYPE_SESSION,
@@ -3043,6 +3188,30 @@ 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 [REAUTHENTICATED] =
+ g_signal_new ("reauthenticated",
+ GDM_TYPE_SESSION,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmSessionClass, reauthenticated),
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
signals [CANCELLED] =
g_signal_new ("cancelled",
GDM_TYPE_SESSION,
@@ -3061,9 +3230,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",
@@ -3072,9 +3243,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,
@@ -3119,6 +3292,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",
@@ -3173,6 +3356,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,
@@ -3184,6 +3368,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 ad5f8852..3a1d0fdd 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
@@ -59,6 +60,8 @@ typedef struct
void (* client_connected) (GdmSession *session);
void (* client_disconnected) (GdmSession *session);
void (* disconnected) (GdmSession *session);
+ void (* verification_complete) (GdmSession *session,
+ const char *service_name);
void (* session_opened) (GdmSession *session,
const char *service_name,
const char *session_id);
@@ -73,6 +76,10 @@ typedef struct
int exit_code);
void (* session_died) (GdmSession *session,
int signal_number);
+ void (* reauthentication_started) (GdmSession *session,
+ GPid pid_of_caller);
+ void (* reauthenticated) (GdmSession *session,
+ const char *service_name);
void (* conversation_started) (GdmSession *session,
const char *service_name);
void (* conversation_stopped) (GdmSession *session,
@@ -84,12 +91,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 ad20adf6..15f83f9f 100644
--- a/daemon/gdm-session.xml
+++ b/daemon/gdm-session.xml
@@ -67,6 +67,13 @@
<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="Reauthenticated">
+ <arg name="service_name" 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 +150,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" />
@@ -171,6 +182,15 @@
</method>
<method name="Cancel">
</method>
+ <signal name="ConversationStarted">
+ <arg name="service_name" type="s"/>
+ </signal>
+ <signal name="ConversationStopped">
+ <arg name="service_name" type="s"/>
+ </signal>
+ <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"/>
@@ -193,6 +213,9 @@
<arg name="service_name" type="s"/>
<arg name="message" type="s"/>
</signal>
+ <signal name="VerificationFailed">
+ <arg name="service_name" type="s"/>
+ </signal>
<signal name="VerificationComplete">
<arg name="service_name" type="s"/>
</signal>
@@ -230,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 be6aa276..4dc5009f 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_reauthentication_requests;
+
guint start_session_when_ready : 1;
guint waiting_to_start_session : 1;
guint session_is_running : 1;
@@ -411,6 +413,14 @@ queue_start_session (GdmSimpleSlave *slave,
}
static void
+on_session_reauthenticated (GdmSession *session,
+ const char *service_name,
+ GdmSimpleSlave *slave)
+{
+ try_migrate_session (slave);
+}
+
+static void
on_session_opened (GdmSession *session,
const char *service_name,
const char *session_id,
@@ -484,12 +494,36 @@ 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;
+
+ g_debug ("GdmSimpleSlave: reauthentication started");
+
+ source_tag = GINT_TO_POINTER (pid_of_caller);
+
+ result = g_hash_table_lookup (slave->priv->open_reauthentication_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 {
@@ -508,6 +542,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;
@@ -526,6 +562,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;
@@ -559,9 +597,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,
@@ -577,6 +620,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,
@@ -590,6 +634,14 @@ 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,
+ "reauthenticated",
+ G_CALLBACK (on_session_reauthenticated),
+ slave);
+ g_signal_connect (slave->priv->session,
"client-ready-for-session-to-start",
G_CALLBACK (on_session_client_ready_for_session_to_start),
slave);
@@ -1040,36 +1092,98 @@ gdm_simple_slave_run (GdmSimpleSlave *slave)
}
static gboolean
-gdm_simple_slave_open_session (GdmSlave *slave,
- char **address,
- GError **error)
+gdm_simple_slave_open_session (GdmSlave *slave,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
+ char **address,
+ GError **error)
{
- GdmSimpleSlave *self = GDM_SIMPLE_SLAVE (slave);
- GdmSession *session;
+ GdmSimpleSlave *self = GDM_SIMPLE_SLAVE (slave);
+ uid_t allowed_user;
if (self->priv->session_is_running) {
g_set_error (error,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
- _("Greeter access only currently supported"));
+ _("Can only be called before user is logged in"));
return FALSE;
}
- session = self->priv->session;
+ allowed_user = gdm_session_get_allowed_user (self->priv->session);
- if (gdm_session_client_is_connected (session)) {
+ if (uid_of_caller != allowed_user) {
g_set_error (error,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
- _("Currently, only one client can be connected at once"));
+ _("Caller not GDM"));
return FALSE;
}
- *address = gdm_session_get_server_address (session);
+ *address = gdm_session_get_server_address (self->priv->session);
return TRUE;
}
+static char *
+gdm_simple_slave_open_reauthentication_channel_finish (GdmSlave *slave,
+ GAsyncResult *result,
+ GError **error)
+{
+ GdmSimpleSlave *self = GDM_SIMPLE_SLAVE (slave);
+ const char *address;
+ GPid pid_of_caller;
+
+ pid_of_caller = GPOINTER_TO_INT (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result)));
+
+ g_hash_table_remove (self->priv->open_reauthentication_requests,
+ GINT_TO_POINTER (pid_of_caller));
+
+ 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_simple_slave_open_reauthentication_channel (GdmSlave *slave,
+ const char *username,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ GCancellable *cancellable)
+{
+ GdmSimpleSlave *self = GDM_SIMPLE_SLAVE (slave);
+ 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);
+
+ g_hash_table_insert (self->priv->open_reauthentication_requests,
+ GINT_TO_POINTER (pid_of_caller),
+ g_object_ref (result));
+
+ if (!self->priv->session_is_running) {
+ g_simple_async_result_set_error (result,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ _("User not logged in"));
+ g_simple_async_result_complete_in_idle (result);
+
+ } else {
+ gdm_session_start_reauthentication (self->priv->session,
+ pid_of_caller,
+ uid_of_caller);
+ }
+}
+
static gboolean
gdm_simple_slave_start (GdmSlave *slave)
{
@@ -1175,6 +1289,8 @@ 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_reauthentication_channel = gdm_simple_slave_open_reauthentication_channel;
+ slave_class->open_reauthentication_channel_finish = gdm_simple_slave_open_reauthentication_channel_finish;
g_type_class_add_private (klass, sizeof (GdmSimpleSlavePrivate));
}
@@ -1186,6 +1302,13 @@ gdm_simple_slave_init (GdmSimpleSlave *slave)
#ifdef HAVE_LOGINDEVPERM
slave->priv->use_logindevperm = FALSE;
#endif
+
+ slave->priv->open_reauthentication_requests = g_hash_table_new_full (NULL,
+ NULL,
+ (GDestroyNotify)
+ NULL,
+ (GDestroyNotify)
+ g_object_unref);
}
static void
@@ -1202,6 +1325,8 @@ gdm_simple_slave_finalize (GObject *object)
gdm_simple_slave_stop (GDM_SLAVE (slave));
+ g_hash_table_unref (slave->priv->open_reauthentication_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 fbee296d..0869097f 100644
--- a/daemon/gdm-slave.c
+++ b/daemon/gdm-slave.c
@@ -1870,6 +1870,8 @@ gdm_slave_get_property (GObject *object,
static gboolean
handle_open_session (GdmDBusSlave *skeleton,
GDBusMethodInvocation *invocation,
+ int pid_of_caller,
+ int uid_of_caller,
GdmSlave *slave)
{
GError *error;
@@ -1887,6 +1889,8 @@ handle_open_session (GdmDBusSlave *skeleton,
error = NULL;
address = NULL;
if (!slave_class->open_session (slave,
+ (GPid) pid_of_caller,
+ (uid_t) uid_of_caller,
&address,
&error)) {
g_dbus_method_invocation_return_gerror (invocation, error);
@@ -1897,6 +1901,62 @@ handle_open_session (GdmDBusSlave *skeleton,
gdm_dbus_slave_complete_open_session (skeleton, invocation, address);
g_free (address);
+ return TRUE;
+}
+
+static void
+on_reauthentication_channel_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_reauthentication_channel_finish != NULL);
+
+ error = NULL;
+ address = slave_class->open_reauthentication_channel_finish (slave, result, &error);
+
+ if (address == NULL) {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ } else {
+ gdm_dbus_slave_complete_open_reauthentication_channel (slave->priv->skeleton,
+ invocation,
+ address);
+ }
+
+ g_object_unref (invocation);
+}
+
+static gboolean
+handle_open_reauthentication_channel (GdmDBusSlave *skeleton,
+ GDBusMethodInvocation *invocation,
+ const char *username,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
+ GdmSlave *slave)
+{
+ GdmSlaveClass *slave_class;
+
+ slave_class = GDM_SLAVE_GET_CLASS (slave);
+ if (slave_class->open_reauthentication_channel == NULL) {
+ g_dbus_method_invocation_return_dbus_error (invocation,
+ "org.gnome.DisplayManager.Slave.Unsupported",
+ "Connections to the slave are not supported by this slave");
+ return TRUE;
+ }
+
+ slave_class->open_reauthentication_channel (slave,
+ username,
+ pid_of_caller,
+ uid_of_caller,
+ (GAsyncReadyCallback)
+ on_reauthentication_channel_opened,
+ g_object_ref (invocation),
+ NULL);
return TRUE;
}
@@ -1922,6 +1982,10 @@ register_slave (GdmSlave *slave)
"handle-open-session",
G_CALLBACK (handle_open_session),
slave);
+ g_signal_connect (slave->priv->skeleton,
+ "handle-open-reauthentication-channel",
+ G_CALLBACK (handle_open_reauthentication_channel),
+ slave);
g_object_bind_property (G_OBJECT (slave),
"session-id",
diff --git a/daemon/gdm-slave.h b/daemon/gdm-slave.h
index ee3dcbc0..dc046775 100644
--- a/daemon/gdm-slave.h
+++ b/daemon/gdm-slave.h
@@ -50,9 +50,22 @@ typedef struct
gboolean (*start) (GdmSlave *slave);
gboolean (*stop) (GdmSlave *slave);
- gboolean (*open_session) (GdmSlave *slave,
- char **address,
- GError **error);
+ gboolean (*open_session) (GdmSlave *slave,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
+ char **address,
+ GError **error);
+
+ void (*open_reauthentication_channel) (GdmSlave *slave,
+ const char *username,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ GCancellable *cancellable);
+ char * (*open_reauthentication_channel_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 b6e57cf5..547c44e9 100644
--- a/daemon/gdm-slave.xml
+++ b/daemon/gdm-slave.xml
@@ -2,6 +2,15 @@
<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>
+
+ <method name="OpenReauthenticationChannel">
+ <arg name="username" type="s" direction="in" />
+ <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 e8947b5b..3f3cd661 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 c8bc5865..17ce057c 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");
@@ -332,12 +334,14 @@ gdm_xdmcp_chooser_slave_stop (GdmSlave *slave)
}
static gboolean
-gdm_xdmcp_chooser_slave_open_session (GdmSlave *slave,
- char **address,
- GError **error)
+gdm_xdmcp_chooser_slave_open_session (GdmSlave *slave,
+ GPid pid_of_caller,
+ uid_t uid_of_caller,
+ char **address,
+ GError **error)
{
GdmXdmcpChooserSlave *self = GDM_XDMCP_CHOOSER_SLAVE (slave);
- GdmSession *session;
+ GdmSession *session;
session = gdm_welcome_session_get_session (GDM_WELCOME_SESSION (self->priv->chooser));
@@ -346,11 +350,11 @@ gdm_xdmcp_chooser_slave_open_session (GdmSlave *slave,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
_("Currently, only one client can be connected at once"));
+
return FALSE;
}
*address = gdm_session_get_server_address (session);
-
return TRUE;
}
diff --git a/daemon/session-worker-main.c b/daemon/session-worker-main.c
index 94496b5d..7a385edd 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 0ee28d05..cd7fb36b 100644
--- a/data/gdm.conf.in
+++ b/data/gdm.conf.in
@@ -25,8 +25,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"/>
@@ -41,6 +39,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"