[gdm/wip/slave-connection: 29/32] wip: Start to hammer out reauthentication support



commit f5e6f741cc9185c18871d4907c1a00b3181e0aec
Author: Ray Strode <rstrode redhat com>
Date:   Tue Jul 10 02:11:24 2012 -0400

    wip: Start to hammer out reauthentication support
    
    This commit starts to flesh out reauthentication support for
    screensavers.
    
    1) It adds a "verification mode" argument to the GdmSession constructor that
    will eventually get propagated down to the worker process so the worker knows how
    to act (there are minor behaviorial differences between how the pam
    conversation should be treated between login and unlock).
    
    2) It adds a GdmSession object into the worker process that has
    REAUTHENTICATE as the the verification mode.  The address of this
    session object will eventually bubble back up to the screensaver.
    
    3) It adds an "allowed user" property to the gdm session object, so we
    can allow only the user from the session access.
    
    I need to rework gdm_slave_open_session to be asynchronous so it can
    wait for ReauthenticationStarted method call from worker, and I need
    to make the session-worker changes for the actually starting as a
    reauthorization client.

 daemon/Makefile.am                 |   22 +++++
 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               |  105 ++++++++++++++++++++++-
 daemon/gdm-session-enum-types.c.in |   42 +++++++++
 daemon/gdm-session-enum-types.h.in |   24 +++++
 daemon/gdm-session-worker.c        |  165 ++++++++++++++++++++++++++++++++++++
 daemon/gdm-session.c               |  137 ++++++++++++++++++++++++++----
 daemon/gdm-session.h               |   16 +++-
 daemon/gdm-session.xml             |   10 ++
 daemon/gdm-simple-slave.c          |   55 ++++++++++--
 daemon/gdm-slave.c                 |    4 +
 daemon/gdm-slave.h                 |    2 +
 daemon/gdm-slave.xml               |    2 +
 daemon/gdm-welcome-session.c       |   14 +++-
 daemon/gdm-xdmcp-chooser-slave.c   |    4 +
 daemon/test-session.c              |    4 +-
 19 files changed, 623 insertions(+), 32 deletions(-)
---
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 3a23a35..a362d8d 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -39,8 +39,15 @@ BUILT_SOURCES =					\
 	gdm-local-display-factory-glue.h	\
 	gdm-greeter-glue.h			\
 	gdm-session-glue.h			\
+	gdm-session-enum-types.h		\
 	$(NULL)
 
+gdm-session-enum-types.h: gdm-session-enum-types.h.in gdm-session.h
+	$(AM_V_GEN) glib-mkenums --template $^ > $@
+
+gdm-session-enum-types.c: gdm-session-enum-types.c.in gdm-session.h
+	$(AM_V_GEN) glib-mkenums --template $^ > $@
+
 gdm-display-glue.c gdm-display-glue.h: gdm-display.xml Makefile.am
 	$(AM_V_GEN)gdbus-codegen 					\
 		--c-namespace=GdmDBus					\
@@ -120,6 +127,8 @@ test_session_SOURCES = 		\
 	$(NULL)
 
 nodist_test_session_SOURCES = 	\
+	gdm-session-enum-types.c\
+	gdm-session-enum-types.h\
 	gdm-session-glue.c	\
 	gdm-session-glue.h	\
 	$(NULL)
@@ -169,6 +178,8 @@ gdm_simple_slave_SOURCES = 		\
 	$(NULL)
 
 nodist_gdm_simple_slave_SOURCES = 	\
+	gdm-session-enum-types.c	\
+	gdm-session-enum-types.h	\
 	gdm-greeter-glue.c		\
 	gdm-greeter-glue.h		\
 	gdm-session-glue.c		\
@@ -217,6 +228,8 @@ gdm_xdmcp_chooser_slave_SOURCES = 		\
 nodist_gdm_xdmcp_chooser_slave_SOURCES = 	\
 	gdm-session-glue.c			\
 	gdm-session-glue.h			\
+	gdm-session-enum-types.c		\
+	gdm-session-enum-types.h		\
 	gdm-display-glue.c			\
 	gdm-display-glue.h			\
 	gdm-slave-glue.c			\
@@ -236,17 +249,26 @@ 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 =		\
 	gdm-session-glue.h			\
 	gdm-session-glue.c			\
+	gdm-session-enum-types.c		\
+	gdm-session-enum-types.h		\
 	$(NULL)
 
 if HAVE_LIBAUDIT
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 6141aca..8ae7e41 100644
--- a/daemon/gdm-display.c
+++ b/daemon/gdm-display.c
@@ -1250,6 +1250,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)
 {
@@ -1266,6 +1268,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 931b3b8..8901083 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -176,6 +176,82 @@ 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)
+{
+        char *session, *gsession;
+        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_CONSOLEKIT
+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",
+                                             g_variant_new ("(s)", session_id),
+                                             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_CONSOLEKIT
+        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,
@@ -207,6 +283,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;
@@ -217,7 +294,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);
@@ -229,6 +314,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);
@@ -243,7 +346,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-enum-types.c.in b/daemon/gdm-session-enum-types.c.in
new file mode 100644
index 0000000..c028690
--- /dev/null
+++ b/daemon/gdm-session-enum-types.c.in
@@ -0,0 +1,42 @@
+/*** BEGIN file-header ***/
+
+#include <glib-object.h>
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+#include "@filename@"
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name _get_type (void) G_GNUC_CONST;
+
+GType
+ enum_name@_get_type (void)
+{
+        static GType etype = 0;
+
+        if (G_UNLIKELY(etype == 0)) {
+                static const G Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+                { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+                { 0, NULL, NULL }
+        };
+
+        etype = g_ type@_register_static (g_intern_static_string ("@EnumName@"), values);
+    }
+
+    return etype;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+ /**/
+/*** END file-tail ***/
diff --git a/daemon/gdm-session-enum-types.h.in b/daemon/gdm-session-enum-types.h.in
new file mode 100644
index 0000000..b6934c1
--- /dev/null
+++ b/daemon/gdm-session-enum-types.h.in
@@ -0,0 +1,24 @@
+/*** BEGIN file-header ***/
+#ifndef GDM_SESSION_ENUM_TYPES_H
+#define GDM_SESSION_ENUM_TYPES_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name _get_type (void) G_GNUC_CONST;
+#define @ENUMPREFIX _TYPE_@ENUMSHORT@ (@enum_name _get_type ())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* GDM_SESSION_ENUM_TYPES_H */
+/*** END file-tail ***/
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 3b51c2e..a5cfc8f 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;
@@ -140,6 +150,8 @@ struct GdmSessionWorkerPrivate
         GDBusConnection      *connection;
         GdmDBusWorkerManager *manager;
 
+        GHashTable         *reauthentication_requests;
+
         GdmSessionAuditor  *auditor;
         GdmSessionSettings *user_settings;
 };
@@ -2406,6 +2418,141 @@ 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)
+{
+        g_debug ("GdmSessionWorker: client disconnected from reauthentication server");
+
+        g_hash_table_remove (worker->priv->reauthentication_requests,
+                             pid_of_caller);
+}
+
+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 (session);
+        gdm_dbus_worker_manager_call_reauthentication_started (worker->priv->manager,
+                                                               pid_of_caller,
+                                                               address);
+        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,
+                              pid_of_caller,
+                              request);
+}
+
+static void
 on_setup (GdmDBusWorkerManager *proxy,
           const char           *service,
           const char           *x11_display_name,
@@ -2652,6 +2799,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.
@@ -2685,12 +2836,24 @@ gdm_session_worker_class_init (GdmSessionWorkerClass *klass)
 }
 
 static void
+reauthentication_request_free (ReauthenticationRequest *request)
+{
+        g_clear_object (&request->session);
+        g_slice_free (ReauthenticationRequest, request);
+}
+
+static void
 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
@@ -2729,6 +2892,8 @@ 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);
 }
 
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index e7b7d48..e200aca 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -52,6 +52,7 @@
 #include "gdm-dbus-util.h"
 
 #include "gdm-session.h"
+#include "gdm-session-enum-types.h"
 #include "gdm-session-record.h"
 #include "gdm-session-worker-job.h"
 #include "gdm-common.h"
@@ -107,6 +108,9 @@ struct _GdmSessionPrivate
         char                *display_x11_authority_file;
         gboolean             display_is_local;
 
+        GdmSessionVerificationMode verification_mode;
+        uid_t                allowed_user;
+
         char                *fallback_session_name;
 
         GDBusServer         *worker_server;
@@ -116,6 +120,8 @@ struct _GdmSessionPrivate
 
 enum {
         PROP_0,
+        PROP_VERIFICATION_MODE,
+        PROP_ALLOWED_USER,
         PROP_DISPLAY_NAME,
         PROP_DISPLAY_HOSTNAME,
         PROP_DISPLAY_IS_LOCAL,
@@ -135,13 +141,12 @@ enum {
         CLIENT_DISCONNECTED,
         CLIENT_READY_FOR_SESSION_TO_START,
         DISCONNECTED,
-        AUTHORIZED,
-        AUTHORIZATION_FAILED,
         SESSION_OPENED,
         SESSION_STARTED,
         SESSION_START_FAILED,
         SESSION_EXITED,
         SESSION_DIED,
+        REAUTHENTICATION_STARTED,
         LAST_SIGNAL
 };
 
@@ -896,6 +901,23 @@ 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,
+                                             GdmSession            *self)
+{
+        GdmSessionConversation *conversation;
+
+        gdm_dbus_worker_manager_complete_reauthentication_started (worker_manager_interface,
+                                                                   invocation);
+
+        g_debug ("GdmSession: Emitting 'reauthentication-started' signal for caller pid '%d'", pid);
+        g_signal_emit (self, signals[REAUTHENTICATION_STARTED], 0, pid);
+
+        return TRUE;
+}
+
+static gboolean
 gdm_session_handle_saved_language_name_read (GdmDBusWorkerManager  *worker_manager_interface,
                                              GDBusMethodInvocation *invocation,
                                              const char            *language_name,
@@ -969,9 +991,10 @@ 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) {
+        if (g_credentials_get_unix_user (credentials, NULL) == self->priv->allowed_user) {
                 return TRUE;
         }
 
@@ -1158,6 +1181,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,
@@ -1477,14 +1504,20 @@ on_outside_connection_closed (GDBusConnection *connection,
                               GError          *error,
                               GdmSession      *self)
 {
+        GCredentials *credentials;
+
         self->priv->outside_connections =
             g_list_remove (self->priv->outside_connections,
                             connection);
-        g_object_unref (connection);
+
+        credentials = g_dbus_connection_get_peer_credentials (connection);
 
         g_signal_emit (G_OBJECT (self),
                        signals [CLIENT_DISCONNECTED],
-                       0);
+                       0,
+                       credentials);
+
+        g_object_unref (connection);
 }
 
 static gboolean
@@ -1492,6 +1525,8 @@ handle_connection_from_outside (GDBusServer      *server,
                                 GDBusConnection  *connection,
                                 GdmSession       *self)
 {
+        GCredentials *credentials;
+
         g_debug ("GdmSession: Handling new connection from outside");
 
         self->priv->outside_connections =
@@ -1507,9 +1542,12 @@ handle_connection_from_outside (GDBusServer      *server,
         export_greeter_session_interface (self, connection);
         export_chooser_session_interface (self, connection);
 
+        credentials = g_dbus_connection_get_peer_credentials (connection);
+
         g_signal_emit (G_OBJECT (self),
                        signals [CLIENT_CONNECTED],
-                       0);
+                       0,
+                       credentials);
 
         return TRUE;
 }
@@ -1527,7 +1565,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);
@@ -2458,6 +2496,22 @@ 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)
+{
+        gdm_dbus_worker_manager_emit_start_reauthentication (conversation->worker_manager_interface,
+                                                             (int) pid_of_caller,
+                                                             (int) uid_of_caller);
+}
+
 char *
 gdm_session_get_server_address (GdmSession *self)
 {
@@ -2693,6 +2747,20 @@ set_display_is_local (GdmSession *self,
 }
 
 static void
+set_verification_mode (GdmSession                 *self,
+                       GdmSessionVerificationMode  verification_mode)
+{
+        self->priv->verification_mode = verification_mode;
+}
+
+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,
@@ -2724,6 +2792,12 @@ gdm_session_set_property (GObject      *object,
         case PROP_DISPLAY_IS_LOCAL:
                 set_display_is_local (self, g_value_get_boolean (value));
                 break;
+        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;
@@ -2762,6 +2836,12 @@ gdm_session_get_property (GObject    *object,
         case PROP_DISPLAY_IS_LOCAL:
                 g_value_set_boolean (value, self->priv->display_is_local);
                 break;
+        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;
@@ -2945,6 +3025,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_INT);
         signals [CANCELLED] =
                 g_signal_new ("cancelled",
                               GDM_TYPE_SESSION,
@@ -2963,9 +3056,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",
@@ -2974,9 +3069,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,
@@ -3055,16 +3152,20 @@ gdm_session_class_init (GdmSessionClass *session_class)
 }
 
 GdmSession *
-gdm_session_new (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)
+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)
 {
         GdmSession *self;
 
         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 22e8c35..2e6ea79 100644
--- a/daemon/gdm-session.h
+++ b/daemon/gdm-session.h
@@ -34,6 +34,12 @@ G_BEGIN_DECLS
 
 typedef struct _GdmSessionPrivate GdmSessionPrivate;
 
+typedef enum
+{
+        GDM_SESSION_VERIFICATION_MODE_LOGIN,
+        GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE
+} GdmSessionVerificationMode;
+
 typedef struct
 {
         GObject            parent;
@@ -67,6 +73,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,
@@ -77,12 +85,18 @@ typedef struct
 
 GType            gdm_session_get_type                 (void);
 
-GdmSession      *gdm_session_new                      (const char *display_name,
+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 0aee75a..072ff56 100644
--- a/daemon/gdm-session.xml
+++ b/daemon/gdm-session.xml
@@ -67,6 +67,9 @@
       <arg name="service_name" direction="in" type="s"/>
       <arg name="problem" direction="in" type="s"/>
     </method>
+    <signal name="ReauthenticationStarted">
+      <arg name="pid_of_caller" type="i"/>
+    </signal>
     <method name="Opened">
       <arg name="service_name" direction="in" type="s"/>
       <arg name="session_id" direction="in" type="s"/>
@@ -143,6 +146,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" />
@@ -242,6 +249,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.ChooserSession">
     <method name="SelectHostname">
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index 9668ac5..3ebda3c 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -544,6 +544,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 +564,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 +599,15 @@ create_new_session (GdmSimpleSlave  *slave)
         char          *display_device;
         char          *display_seat_id;
         char          *display_x11_authority_file;
+        struct passwd *passwd_entry;
+        GdmSession    *greeter_session;
+        char          *greeter_uid;
 
         g_debug ("GdmSimpleSlave: Creating new session");
 
+        greeter_session = gdm_welcome_session_get_session (GDM_WELCOME_SESSION (greeter));
+        greeter_uid = gdm_session_get_allowed_user (greeter_session);
+
         g_object_get (slave,
                       "display-id", &display_id,
                       "display-name", &display_name,
@@ -612,7 +622,9 @@ create_new_session (GdmSimpleSlave  *slave)
                 display_device = gdm_server_get_display_device (slave->priv->server);
         }
 
-        slave->priv->session = gdm_session_new (display_name,
+        slave->priv->session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_LOGIN,
+                                                greeter_uid,
+                                                display_name,
                                                 display_hostname,
                                                 display_device,
                                                 display_seat_id,
@@ -1121,12 +1133,44 @@ gdm_simple_slave_run (GdmSimpleSlave *slave)
 
 static gboolean
 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;
 
+        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_set_error (error,
+                                     G_DBUS_ERROR,
+                                     G_DBUS_ERROR_ACCESS_DENIED,
+                                     _("Caller not GDM"));
+                        return FALSE;
+                }
+
+                if (gdm_session_client_is_connected (session)) {
+                        g_set_error (error,
+                                     G_DBUS_ERROR,
+                                     G_DBUS_ERROR_ACCESS_DENIED,
+                                     _("The client can only connect once"));
+                        return FALSE;
+                }
+
+                g_debug ("GdmSimpleSlave: Opening session for greeter");
+
+                *address = gdm_session_get_server_address (session);
+
+                return TRUE;
+
+        }
+
+#pragma FIXME need to make open session asynchronous, have it call gdm_session_start_reauthentication and wait for the reauthentication-started signal which it then returns to the caller.
         if (self->priv->session_is_running) {
                 g_set_error (error,
                              G_DBUS_ERROR,
@@ -1137,15 +1181,6 @@ gdm_simple_slave_open_session (GdmSlave   *slave,
 
         session = self->priv->session;
 
-        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;
-        }
-
-        *address = gdm_session_get_server_address (session);
 
         return TRUE;
 }
diff --git a/daemon/gdm-slave.c b/daemon/gdm-slave.c
index db77dbf..462e77f 100644
--- a/daemon/gdm-slave.c
+++ b/daemon/gdm-slave.c
@@ -1853,6 +1853,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;
@@ -1870,6 +1872,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);
diff --git a/daemon/gdm-slave.h b/daemon/gdm-slave.h
index a937593..ea643b2 100644
--- a/daemon/gdm-slave.h
+++ b/daemon/gdm-slave.h
@@ -51,6 +51,8 @@ typedef struct
         gboolean (*stop)  (GdmSlave *slave);
 
         gboolean (*open_session) (GdmSlave    *slave,
+                                  GPid         pid_of_caller,
+                                  uid_t        uid_of_caller,
                                   char       **address,
                                   GError     **error);
         gboolean (*get_private_connection) (GdmSlave    *slave,
diff --git a/daemon/gdm-slave.xml b/daemon/gdm-slave.xml
index dbe5930..57371f0 100644
--- a/daemon/gdm-slave.xml
+++ b/daemon/gdm-slave.xml
@@ -7,6 +7,8 @@
     </method>
 
     <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 e488409..78fd178 100644
--- a/daemon/gdm-welcome-session.c
+++ b/daemon/gdm-welcome-session.c
@@ -779,6 +779,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);
@@ -787,7 +789,17 @@ gdm_welcome_session_start (GdmWelcomeSession *welcome_session)
                 return FALSE;
         }
 
-        welcome_session->priv->session = gdm_session_new (welcome_session->priv->x11_display_name,
+        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 (GDM_SESSION_VERIFICATION_MODE_LOGIN,
+                                                          uid,
+                                                          welcome_session->priv->x11_display_name,
                                                           welcome_session->priv->x11_display_hostname,
                                                           welcome_session->priv->x11_display_device,
                                                           welcome_session->priv->x11_display_seat_id,
diff --git a/daemon/gdm-xdmcp-chooser-slave.c b/daemon/gdm-xdmcp-chooser-slave.c
index 0fc3815..e673bc0 100644
--- a/daemon/gdm-xdmcp-chooser-slave.c
+++ b/daemon/gdm-xdmcp-chooser-slave.c
@@ -145,6 +145,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");
@@ -319,6 +321,8 @@ gdm_xdmcp_chooser_slave_stop (GdmSlave *slave)
 
 static gboolean
 gdm_xdmcp_chooser_slave_open_session (GdmSlave   *slave,
+                                      GPid        pid_of_caller,
+                                      uid_t       uid_of_caller,
                                       char      **address,
                                       GError    **error)
 {
diff --git a/daemon/test-session.c b/daemon/test-session.c
index b907bb1..32b54e7 100644
--- a/daemon/test-session.c
+++ b/daemon/test-session.c
@@ -247,7 +247,9 @@ main (int   argc,
 
         do {
                 g_debug ("creating instance of GdmSession object...");
-                session = gdm_session_new (":0",
+                session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_LOGIN,
+                                           getuid (),
+                                           ":0",
                                            g_get_host_name (),
                                            ttyname (STDIN_FILENO),
                                            "",



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]