[gdm/wip/slave-connection: 16/24] daemon: Add an interface for communicating with GDM via D-Bus



commit 44f40ffc9288867d05b0d98595098b0eac6d31e7
Author: Ray Strode <rstrode redhat com>
Date:   Fri May 18 21:04:21 2012 +0200

    daemon: Add an interface for communicating with GDM via D-Bus
    
    One goal for GNOME 3.6, is to replace the screen locking functionality
    provided by gnome-screensaver with redesigned functionality provided
    by gnome-shell.
    
    At the same time, it makes sense to consolidate the yucky PAM
    authentication code to one place (GDM).
    
    Right now only greeters can talk to GDM.  At the time the greeter is
    started, the slave sets up a private communication channel which the
    greeter then connects to for initiating communication.
    
    This commit adds a new method to the org.gnome.DisplayManager.Manager
    interface that allows opening a private connection to the slave that
    is associated with the currently running session.  That slave exports
    the session object over the bus that greeters can interact with the
    session as appropriate.  This interface replaces the
    GDM_GREETER_DBUS_ADDRESS environment variable that used to to be used
    for connecting the greeter to the slave.
    
    This commit also drops gdm-greeter-server and gdm-chooser-server which
    don't fit the new model, and are really just thin middle men that don't do
    anything important.
    
    Furthermore, this commit splits GdmSession interfaces 3 orthogonal parts
    up into 3 separate interfaces on the session object.
    
    A future commit will make this interface work for screensavers/reauthentication.
    
    Based on work by Giovanni Campagna <gcampagna src gnome org>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=676381

 daemon/Makefile.am                 |   66 +-
 daemon/gdm-chooser-server.c        |  419 -----------
 daemon/gdm-chooser-server.h        |   63 --
 daemon/gdm-chooser-session.c       |    5 +-
 daemon/gdm-dbus-util.c             |   40 +
 daemon/gdm-dbus-util.h             |    6 +
 daemon/gdm-display.c               |  102 ++-
 daemon/gdm-display.h               |    9 +-
 daemon/gdm-greeter-server.c        |  932 -----------------------
 daemon/gdm-greeter-server.h        |  118 ---
 daemon/gdm-greeter-server.xml      |   92 ---
 daemon/gdm-greeter-session.c       |    3 -
 daemon/gdm-manager.c               |  228 ++++++-
 daemon/gdm-manager.h               |    8 +-
 daemon/gdm-manager.xml             |    8 +
 daemon/gdm-session-enum-types.c.in |   42 +
 daemon/gdm-session-enum-types.h.in |   24 +
 daemon/gdm-session-worker.c        |  416 +++++++----
 daemon/gdm-session.c               | 1437 ++++++++++++++++++++++++------------
 daemon/gdm-session.h               |   77 +--
 daemon/gdm-session.xml             |  113 +++-
 daemon/gdm-simple-slave.c          |  819 +++++----------------
 daemon/gdm-slave.c                 |   86 +++
 daemon/gdm-slave.h                 |   17 +-
 daemon/gdm-slave.xml               |    7 +-
 daemon/gdm-welcome-session.c       |  143 ++---
 daemon/gdm-welcome-session.h       |    6 +-
 daemon/gdm-xdmcp-chooser-display.c |    2 +-
 daemon/gdm-xdmcp-chooser-slave.c   |  123 ++--
 daemon/gdm-xdmcp-chooser-slave.h   |    2 -
 daemon/test-session.c              |  343 ---------
 31 files changed, 2203 insertions(+), 3553 deletions(-)
---
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index e72479a..cd5e122 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -33,13 +33,20 @@ BUILT_SOURCES =					\
 	gdm-xdmcp-chooser-slave-glue.h		\
 	gdm-display-glue.h			\
 	gdm-xdmcp-display-glue.h		\
+	gdm-manager-glue.h			\
 	gdm-static-display-glue.h		\
 	gdm-transient-display-glue.h		\
 	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					\
@@ -75,19 +82,19 @@ gdm-local-display-factory-glue.c gdm-local-display-factory-glue.h : gdm-local-di
 		--generate-c-code=gdm-local-display-factory-glue	\
 		$(srcdir)/gdm-local-display-factory.xml
 
-gdm-session-glue.c gdm-session-glue.h : gdm-session.xml Makefile.am
+gdm-manager-glue.c gdm-manager-glue.h : gdm-manager.xml Makefile.am
 	$(AM_V_GEN)gdbus-codegen 					\
 		--c-namespace=GdmDBus					\
 		--interface-prefix=org.gnome.DisplayManager		\
-		--generate-c-code=gdm-session-glue			\
-		$(srcdir)/gdm-session.xml
+		--generate-c-code=gdm-manager-glue			\
+		$(srcdir)/gdm-manager.xml
 
-gdm-greeter-glue.c gdm-greeter-glue.h : gdm-greeter-server.xml Makefile.am
+gdm-session-glue.c gdm-session-glue.h : gdm-session.xml Makefile.am
 	$(AM_V_GEN)gdbus-codegen 					\
 		--c-namespace=GdmDBus					\
 		--interface-prefix=org.gnome.DisplayManager		\
-		--generate-c-code=gdm-greeter-glue			\
-		$(srcdir)/gdm-greeter-server.xml
+		--generate-c-code=gdm-session-glue			\
+		$(srcdir)/gdm-session.xml
 
 gdm-slave-glue.c gdm-slave-glue.h: gdm-slave.xml Makefile.am
 	$(AM_V_GEN)gdbus-codegen 					\
@@ -104,32 +111,6 @@ gdm-xdmcp-chooser-slave-glue.c gdm-xdmcp-chooser-slave-glue.h: gdm-xdmcp-chooser
 		$(srcdir)/gdm-xdmcp-chooser-slave.xml
 
 noinst_PROGRAMS = 		\
-	test-session		\
-	$(NULL)
-
-test_session_SOURCES = 		\
-	test-session.c	 	\
-	gdm-session.c		\
-	gdm-session.h		\
-	gdm-session-record.c	\
-	gdm-session-record.h	\
-	gdm-session-worker-job.c\
-	gdm-dbus-util.c		\
-	gdm-dbus-util.h		\
-	$(NULL)
-
-nodist_test_session_SOURCES = 	\
-	gdm-session-glue.c	\
-	gdm-session-glue.h	\
-	$(NULL)
-
-test_session_LDADD =		\
-	$(top_builddir)/common/libgdmcommon.la	\
-	$(XLIB_LIBS)		\
-	$(EXTRA_DAEMON_LIBS)	\
-	$(DAEMON_LIBS)		\
-	$(PAM_LIBS)		\
-	$(LIBXKLAVIER_LIBS)	\
 	$(NULL)
 
 libexec_PROGRAMS = 			\
@@ -145,8 +126,6 @@ endif
 
 gdm_simple_slave_SOURCES = 		\
 	simple-slave-main.c 		\
-	gdm-greeter-server.c		\
-	gdm-greeter-server.h		\
 	gdm-welcome-session.c		\
 	gdm-welcome-session.h		\
 	gdm-greeter-session.c		\
@@ -174,6 +153,8 @@ nodist_gdm_simple_slave_SOURCES = 	\
 	gdm-greeter-glue.h		\
 	gdm-display-glue.c		\
 	gdm-display-glue.h		\
+	gdm-session-enum-types.c	\
+	gdm-session-enum-types.h	\
 	gdm-session-glue.c		\
 	gdm-session-glue.h		\
 	gdm-slave-glue.c		\
@@ -195,8 +176,6 @@ gdm_simple_slave_LDADD = 			\
 
 gdm_xdmcp_chooser_slave_SOURCES = 		\
 	xdmcp-chooser-slave-main.c 		\
-	gdm-chooser-server.c			\
-	gdm-chooser-server.h			\
 	gdm-session.c				\
 	gdm-session.h				\
 	gdm-session-record.c			\
@@ -220,6 +199,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			\
@@ -250,6 +231,8 @@ gdm_session_worker_SOURCES = 			\
 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
@@ -297,6 +280,8 @@ gdm_binary_SOURCES = 			\
 	gdm-manager.h			\
 	gdm-slave-proxy.c		\
 	gdm-slave-proxy.h		\
+	gdm-dbus-util.c			\
+	gdm-dbus-util.h			\
 	$(NULL)
 
 nodist_gdm_binary_SOURCES = 			\
@@ -304,10 +289,14 @@ nodist_gdm_binary_SOURCES = 			\
 	gdm-display-glue.c			\
 	gdm-local-display-factory-glue.h	\
 	gdm-local-display-factory-glue.c	\
+	gdm-manager-glue.h			\
+	gdm-manager-glue.c			\
 	gdm-transient-display-glue.h		\
 	gdm-transient-display-glue.c		\
 	gdm-static-display-glue.h		\
 	gdm-static-display-glue.c		\
+	gdm-slave-glue.h			\
+	gdm-slave-glue.c			\
 	$(NULL)
 
 XDMCP_SOURCES =				\
@@ -371,8 +360,8 @@ gdm: $(srcdir)/gdm.in
 CLEANFILES =					\
 	gdm					\
 	gdm-display-glue.c			\
-	gdm-greeter-glue.c			\
 	gdm-local-display-factory-glue.c	\
+	gdm-manager-glue.c			\
 	gdm-session-glue.c			\
 	gdm-slave-glue.c			\
 	gdm-static-display-glue.c		\
@@ -384,7 +373,6 @@ CLEANFILES =					\
 
 EXTRA_DIST = 				\
 	gdm.in				\
-	gdm-greeter-server.xml		\
 	gdm-slave.xml			\
 	gdm-simple-slave.xml		\
 	gdm-xdmcp-chooser-slave.xml	\
diff --git a/daemon/gdm-chooser-session.c b/daemon/gdm-chooser-session.c
index 6aa60a6..2e6c252 100644
--- a/daemon/gdm-chooser-session.c
+++ b/daemon/gdm-chooser-session.c
@@ -39,6 +39,7 @@
 
 #include "gdm-common.h"
 
+#include "gdm-session.h"
 #include "gdm-welcome-session.h"
 #include "gdm-chooser-session.h"
 
@@ -78,9 +79,7 @@ gdm_chooser_session_new (const char *display_name,
 
         object = g_object_new (GDM_TYPE_CHOOSER_SESSION,
                                "command", LIBEXECDIR "/gdm-simple-chooser",
-                               "server-dbus-path", GDM_CHOOSER_SERVER_DBUS_PATH,
-                               "server-dbus-interface", GDM_CHOOSER_SERVER_DBUS_INTERFACE,
-                               "server-env-var-name", "GDM_CHOOSER_DBUS_ADDRESS",
+                               "verification-mode", GDM_SESSION_VERIFICATION_MODE_CHOOSER,
                                "x11-display-name", display_name,
                                "x11-display-device", display_device,
                                "x11-display-hostname", display_hostname,
diff --git a/daemon/gdm-dbus-util.c b/daemon/gdm-dbus-util.c
index f77bc92..e57f0a0 100644
--- a/daemon/gdm-dbus-util.c
+++ b/daemon/gdm-dbus-util.c
@@ -123,3 +123,43 @@ gdm_dbus_setup_private_server (GDBusAuthObserver  *observer,
 
         return server;
 }
+
+gboolean
+gdm_dbus_get_pid_for_name (const char  *system_bus_name,
+                           pid_t       *out_pid,
+                           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",
+                                             "GetConnectionUnixProcessID",
+                                             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_pid = 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 75fa62b..b3210b4 100644
--- a/daemon/gdm-dbus-util.h
+++ b/daemon/gdm-dbus-util.h
@@ -22,8 +22,14 @@
 #define __GDM_DBUS_UTIL_H
 
 #include <gio/gio.h>
+#include <unistd.h>
+#include <sys/types.h>
 
 GDBusServer *gdm_dbus_setup_private_server (GDBusAuthObserver  *observer,
                                             GError            **error);
 
+gboolean gdm_dbus_get_pid_for_name (const char  *system_bus_name,
+                                    pid_t       *out_pid,
+                                    GError     **error);
+
 #endif
diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
index 4e45379..0c6e756 100644
--- a/daemon/gdm-display.c
+++ b/daemon/gdm-display.c
@@ -41,17 +41,19 @@
 #include "gdm-settings-keys.h"
 
 #include "gdm-slave-proxy.h"
-
-static guint32 display_serial = 1;
+#include "gdm-slave-glue.h"
+#include "gdm-dbus-util.h"
 
 #define GDM_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DISPLAY, GdmDisplayPrivate))
 
+#define GDM_SLAVE_PATH "/org/gnome/DisplayManager/Slave"
 #define DEFAULT_SLAVE_COMMAND LIBEXECDIR "/gdm-simple-slave"
 
 struct GdmDisplayPrivate
 {
         char                 *id;
         char                 *seat_id;
+        char                 *session_id;
 
         char                 *remote_hostname;
         int                   x11_display_number;
@@ -70,6 +72,7 @@ struct GdmDisplayPrivate
 
         GdmSlaveProxy        *slave_proxy;
         char                 *slave_bus_name;
+        GdmDBusSlave         *slave_bus_proxy;
         int                   slave_name_id;
         GDBusConnection      *connection;
         GdmDisplayAccessFile *user_access_file;
@@ -83,6 +86,7 @@ enum {
         PROP_ID,
         PROP_STATUS,
         PROP_SEAT_ID,
+        PROP_SESSION_ID,
         PROP_REMOTE_HOSTNAME,
         PROP_X11_DISPLAY_NUMBER,
         PROP_X11_DISPLAY_NAME,
@@ -110,20 +114,6 @@ gdm_display_error_quark (void)
         return ret;
 }
 
-static guint32
-get_next_display_serial (void)
-{
-        guint32 serial;
-
-        serial = display_serial++;
-
-        if ((gint32)display_serial < 0) {
-                display_serial = 1;
-        }
-
-        return serial;
-}
-
 time_t
 gdm_display_get_creation_time (GdmDisplay *display)
 {
@@ -140,6 +130,12 @@ gdm_display_get_status (GdmDisplay *display)
         return display->priv->status;
 }
 
+char *
+gdm_display_get_session_id (GdmDisplay *display)
+{
+        return g_strdup (display->priv->session_id);
+}
+
 static GdmDisplayAccessFile *
 _create_access_file_for_user (GdmDisplay  *display,
                               const char  *username,
@@ -308,6 +304,19 @@ gdm_display_real_set_slave_bus_name (GdmDisplay *display,
                                         on_name_vanished,
                                         g_object_ref (display),
                                         NULL);
+
+        g_clear_object (&display->priv->slave_bus_proxy);
+        display->priv->slave_bus_proxy = GDM_DBUS_SLAVE (gdm_dbus_slave_proxy_new_sync (display->priv->connection,
+                                                                                        G_DBUS_PROXY_FLAGS_NONE,
+                                                                                        name,
+                                                                                        GDM_SLAVE_PATH,
+                                                                                        NULL, NULL));
+        g_object_bind_property (G_OBJECT (display->priv->slave_bus_proxy),
+                                "session-id",
+                                G_OBJECT (display),
+                                "session-id",
+                                G_BINDING_DEFAULT);
+
         return TRUE;
 }
 
@@ -823,6 +832,14 @@ _gdm_display_set_seat_id (GdmDisplay     *display,
 }
 
 static void
+_gdm_display_set_session_id (GdmDisplay     *display,
+                             const char     *session_id)
+{
+        g_free (display->priv->session_id);
+        display->priv->session_id = g_strdup (session_id);
+}
+
+static void
 _gdm_display_set_remote_hostname (GdmDisplay     *display,
                                   const char     *hostname)
 {
@@ -888,6 +905,9 @@ gdm_display_set_property (GObject        *object,
         case PROP_SEAT_ID:
                 _gdm_display_set_seat_id (self, g_value_get_string (value));
                 break;
+        case PROP_SESSION_ID:
+                _gdm_display_set_session_id (self, g_value_get_string (value));
+                break;
         case PROP_REMOTE_HOSTNAME:
                 _gdm_display_set_remote_hostname (self, g_value_get_string (value));
                 break;
@@ -932,6 +952,9 @@ gdm_display_get_property (GObject        *object,
         case PROP_SEAT_ID:
                 g_value_set_string (value, self->priv->seat_id);
                 break;
+        case PROP_SESSION_ID:
+                g_value_set_string (value, self->priv->session_id);
+                break;
         case PROP_REMOTE_HOSTNAME:
                 g_value_set_string (value, self->priv->remote_hostname);
                 break;
@@ -1180,8 +1203,6 @@ handle_remove_user_authorization (GdmDBusDisplay        *skeleton,
         return TRUE;
 }
 
-
-
 static gboolean
 register_display (GdmDisplay *display)
 {
@@ -1231,6 +1252,35 @@ register_display (GdmDisplay *display)
         return TRUE;
 }
 
+char *
+gdm_display_open_session_sync (GdmDisplay    *display,
+                               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_session_sync (display->priv->slave_bus_proxy,
+                                                     &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
 */
@@ -1241,14 +1291,21 @@ gdm_display_constructor (GType                  type,
                          GObjectConstructParam *construct_properties)
 {
         GdmDisplay      *display;
+        char            *canonical_display_name;
         gboolean         res;
 
         display = GDM_DISPLAY (G_OBJECT_CLASS (gdm_display_parent_class)->constructor (type,
                                                                                        n_construct_properties,
                                                                                        construct_properties));
 
+        canonical_display_name = g_strdelimit (g_strdup (display->priv->x11_display_name),
+                                               ":" G_STR_DELIMITERS, '_');
+
         g_free (display->priv->id);
-        display->priv->id = g_strdup_printf ("/org/gnome/DisplayManager/Displays/%u", get_next_display_serial ());
+        display->priv->id = g_strdup_printf ("/org/gnome/DisplayManager/Displays/%s",
+                                             canonical_display_name);
+
+        g_free (canonical_display_name);
 
         res = register_display (display);
         if (! res) {
@@ -1358,6 +1415,13 @@ gdm_display_class_init (GdmDisplayClass *klass)
                                                               NULL,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
         g_object_class_install_property (object_class,
+                                         PROP_SESSION_ID,
+                                         g_param_spec_string ("session-id",
+                                                              "session id",
+                                                              "session id",
+                                                              NULL,
+                                                              G_PARAM_READWRITE));
+        g_object_class_install_property (object_class,
                                          PROP_X11_COOKIE,
                                          g_param_spec_string ("x11-cookie",
                                                               "cookie",
diff --git a/daemon/gdm-display.h b/daemon/gdm-display.h
index 6cbcca2..1f4d3db 100644
--- a/daemon/gdm-display.h
+++ b/daemon/gdm-display.h
@@ -79,7 +79,8 @@ typedef struct
 typedef enum
 {
          GDM_DISPLAY_ERROR_GENERAL,
-         GDM_DISPLAY_ERROR_GETTING_USER_INFO
+         GDM_DISPLAY_ERROR_GETTING_USER_INFO,
+         GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
 } GdmDisplayError;
 
 #define GDM_DISPLAY_ERROR gdm_display_error_quark ()
@@ -89,8 +90,10 @@ 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_get_user_auth                  (GdmDisplay *display);
-
+char *              gdm_display_open_session_sync              (GdmDisplay    *display,
+                                                                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);
 gboolean            gdm_display_manage                         (GdmDisplay *display);
diff --git a/daemon/gdm-greeter-session.c b/daemon/gdm-greeter-session.c
index 464b16b..f9f16e3 100644
--- a/daemon/gdm-greeter-session.c
+++ b/daemon/gdm-greeter-session.c
@@ -89,9 +89,6 @@ gdm_greeter_session_new (const char *display_name,
 
         object = g_object_new (GDM_TYPE_GREETER_SESSION,
                                "command", command,
-                               "server-dbus-path", GDM_GREETER_SERVER_DBUS_PATH,
-                               "server-dbus-interface", GDM_GREETER_SERVER_DBUS_INTERFACE,
-                               "server-env-var-name", "GDM_GREETER_DBUS_ADDRESS",
                                "x11-display-name", display_name,
                                "x11-display-seat-id", seat_id,
                                "x11-display-device", display_device,
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index c0bdc5c..2ae06b8 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -34,9 +34,16 @@
 #include <glib/gstdio.h>
 #include <glib-object.h>
 
+#ifdef WITH_SYSTEMD
+#include <systemd/sd-daemon.h>
+#include <systemd/sd-login.h>
+#endif
+
 #include "gdm-common.h"
 
+#include "gdm-dbus-util.h"
 #include "gdm-manager.h"
+#include "gdm-manager-glue.h"
 #include "gdm-display-store.h"
 #include "gdm-display-factory.h"
 #include "gdm-local-display-factory.h"
@@ -44,9 +51,9 @@
 
 #define GDM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_MANAGER, GdmManagerPrivate))
 
-#define GDM_DBUS_PATH         "/org/gnome/DisplayManager"
-#define GDM_MANAGER_DBUS_PATH GDM_DBUS_PATH "/Displays"
-#define GDM_MANAGER_DBUS_NAME "org.gnome.DisplayManager.Manager"
+#define GDM_DBUS_PATH             "/org/gnome/DisplayManager"
+#define GDM_MANAGER_PATH          GDM_DBUS_PATH "/Manager"
+#define GDM_MANAGER_DISPLAYS_PATH GDM_DBUS_PATH "/Displays"
 
 struct GdmManagerPrivate
 {
@@ -85,7 +92,180 @@ static void     gdm_manager_finalize    (GObject         *object);
 
 static gpointer manager_object = NULL;
 
-G_DEFINE_TYPE (GdmManager, gdm_manager, G_TYPE_OBJECT)
+static void manager_interface_init (GdmDBusManagerIface *interface);
+
+G_DEFINE_TYPE_WITH_CODE (GdmManager,
+                         gdm_manager,
+                         GDM_DBUS_TYPE_MANAGER_SKELETON,
+                         G_IMPLEMENT_INTERFACE (GDM_DBUS_TYPE_MANAGER,
+                                                manager_interface_init));
+
+#ifdef WITH_SYSTEMD
+static char *
+get_session_id_for_pid_systemd (pid_t    pid,
+                                GError **error)
+{
+        char *session, *gsession;
+        int ret;
+
+        session = NULL;
+        ret = sd_pid_get_session (pid, &session);
+        if (ret < 0) {
+                g_set_error (error,
+                             GDM_DISPLAY_ERROR,
+                             GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
+                             "Error getting session id from systemd: %s",
+                             g_strerror (-ret));
+                return NULL;
+        }
+
+        if (session != NULL) {
+                gsession = g_strdup (session);
+                free (session);
+
+                return gsession;
+        } else {
+                return NULL;
+        }
+}
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+static char *
+get_session_id_for_pid_consolekit (GDBusConnection  *connection,
+                                   pid_t             pid,
+                                   GError          **error)
+{
+        GVariant *reply;
+        char *retval;
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             "org.freedesktop.ConsoleKit",
+                                             "/org/freedesktop/ConsoleKit/Manager",
+                                             "org.freedesktop.ConsoleKit.Manager",
+                                             "GetSessionForUnixProcess",
+                                             g_variant_new ("(u)", pid),
+                                             G_VARIANT_TYPE ("(o)"),
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL, error);
+        if (reply == NULL) {
+                return NULL;
+        }
+
+        g_variant_get (reply, "(o)", &retval);
+        g_variant_unref (reply);
+
+        return retval;
+}
+#endif
+
+static char *
+get_session_id_for_pid (GDBusConnection  *connection,
+                        pid_t             pid,
+                        GError          **error)
+{
+#ifdef WITH_SYSTEMD
+        if (sd_booted () > 0) {
+                return get_session_id_for_pid_systemd (pid, error);
+        }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+        return get_session_id_for_pid_consolekit (connection, pid, error);
+#endif
+
+        return NULL;
+}
+
+static gboolean
+lookup_by_session_id (const char *id,
+                      GdmDisplay *display,
+                      gpointer    user_data)
+{
+        const char *looking_for = user_data;
+        char *current;
+        gboolean res;
+
+        current = gdm_display_get_session_id (display);
+
+        res = g_strcmp0 (current, looking_for) == 0;
+
+        g_free (current);
+
+        return res;
+}
+
+static gboolean
+gdm_manager_handle_open_session (GdmDBusManager        *manager,
+                                 GDBusMethodInvocation *invocation)
+{
+        GdmManager       *self = GDM_MANAGER (manager);
+        GDBusConnection  *connection;
+        GdmDisplay       *display;
+        const char       *sender;
+        char             *session_id;
+        GError           *error;
+        char             *address;
+        int               ret;
+        GPid              pid;
+
+        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;
+
+        }
+
+        connection = g_dbus_method_invocation_get_connection (invocation);
+        session_id = get_session_id_for_pid (connection, pid, &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_session_sync (display, NULL, &error);
+
+        if (address == NULL) {
+                g_dbus_method_invocation_return_gerror (invocation, error);
+                g_error_free (error);
+                return TRUE;
+        }
+
+        gdm_dbus_manager_complete_open_session (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;
+}
 
 static void
 on_display_removed (GdmDisplayStore *display_store,
@@ -235,17 +415,30 @@ register_manager (GdmManager *manager)
         GDBusObjectManagerServer *object_server;
 
         error = NULL;
-        manager->priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+        manager->priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM,
+                                                    NULL,
+                                                    &error);
         if (manager->priv->connection == NULL) {
                 g_critical ("error getting system bus: %s", error->message);
                 g_error_free (error);
                 exit (1);
         }
 
-        object_server = g_dbus_object_manager_server_new (GDM_MANAGER_DBUS_PATH);
+        object_server = g_dbus_object_manager_server_new (GDM_MANAGER_DISPLAYS_PATH);
         g_dbus_object_manager_server_set_connection (object_server, manager->priv->connection);
         manager->priv->object_manager = object_server;
 
+        if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (manager),
+                                               manager->priv->connection,
+                                               GDM_MANAGER_PATH,
+                                               &error)) {
+                g_critical ("error exporting interface to %s: %s",
+                            GDM_MANAGER_PATH,
+                            error->message);
+                g_error_free (error);
+                exit (1);
+        }
+
         return TRUE;
 }
 
@@ -400,6 +593,14 @@ gdm_manager_init (GdmManager *manager)
 }
 
 static void
+unexport_display (const char *id,
+                  GdmDisplay *display,
+                  GdmManager *manager)
+{
+    g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);
+}
+
+static void
 gdm_manager_finalize (GObject *object)
 {
         GdmManager *manager;
@@ -415,10 +616,6 @@ gdm_manager_finalize (GObject *object)
         g_clear_object (&manager->priv->xdmcp_factory);
 #endif
         g_clear_object (&manager->priv->local_factory);
-        g_clear_object (&manager->priv->connection);
-        g_clear_object (&manager->priv->object_manager);
-
-        gdm_display_store_clear (manager->priv->display_store);
 
         g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store),
                                               G_CALLBACK (on_display_added),
@@ -426,6 +623,17 @@ gdm_manager_finalize (GObject *object)
         g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store),
                                               G_CALLBACK (on_display_removed),
                                               manager);
+
+        gdm_display_store_foreach (manager->priv->display_store,
+                                   (GdmDisplayStoreFunc)unexport_display,
+                                   manager);
+        gdm_display_store_clear (manager->priv->display_store);
+
+        g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (manager));
+
+        g_clear_object (&manager->priv->connection);
+        g_clear_object (&manager->priv->object_manager);
+
         g_object_unref (manager->priv->display_store);
 
         G_OBJECT_CLASS (gdm_manager_parent_class)->finalize (object);
diff --git a/daemon/gdm-manager.h b/daemon/gdm-manager.h
index c479d93..f0355f2 100644
--- a/daemon/gdm-manager.h
+++ b/daemon/gdm-manager.h
@@ -24,6 +24,8 @@
 
 #include <glib-object.h>
 
+#include "gdm-manager-glue.h"
+
 G_BEGIN_DECLS
 
 #define GDM_TYPE_MANAGER         (gdm_manager_get_type ())
@@ -37,13 +39,13 @@ typedef struct GdmManagerPrivate GdmManagerPrivate;
 
 typedef struct
 {
-        GObject           parent;
-        GdmManagerPrivate *priv;
+        GDBusInterfaceSkeleton  parent;
+        GdmManagerPrivate      *priv;
 } GdmManager;
 
 typedef struct
 {
-        GObjectClass   parent_class;
+        GDBusInterfaceSkeletonClass parent_class;
 
         void          (* display_added)    (GdmManager      *manager,
                                             const char      *id);
diff --git a/daemon/gdm-manager.xml b/daemon/gdm-manager.xml
new file mode 100644
index 0000000..8c1a94e
--- /dev/null
+++ b/daemon/gdm-manager.xml
@@ -0,0 +1,8 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd";>
+<node name="/org/gnome/DisplayManager/Manager">
+  <interface name="org.gnome.DisplayManager.Manager">
+    <method name="OpenSession">
+      <arg name="address" direction="out" type="s"/>
+    </method>
+  </interface>
+</node>
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 ddd91e1..bbe7807 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -122,6 +122,7 @@ struct GdmSessionWorkerPrivate
         char             *username;
         char             *log_file;
         char             *session_type;
+        char             *session_id;
         uid_t             uid;
         gid_t             gid;
         gboolean          password_is_required;
@@ -134,9 +135,9 @@ struct GdmSessionWorkerPrivate
         guint32           is_program_session : 1;
         guint             state_change_idle_id;
 
-        char             *server_address;
-        GDBusConnection  *connection;
-        GdmDBusSession   *session_proxy;
+        char                 *server_address;
+        GDBusConnection      *connection;
+        GdmDBusWorkerManager *manager;
 
         GdmSessionAuditor  *auditor;
         GdmSessionSettings *user_settings;
@@ -337,6 +338,51 @@ out:
         g_clear_pointer (&worker->priv->session_cookie,
                          (GDestroyNotify) g_free);
 }
+
+static char *
+get_ck_session_id (GdmSessionWorker *worker)
+{
+        GDBusConnection  *system_bus;
+        GVariant         *reply;
+        GError           *error = NULL;
+        char             *session_id = NULL;
+
+        error = NULL;
+        system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+
+        if (system_bus == NULL) {
+                g_warning ("Couldn't create connection to system bus: %s",
+                           error->message);
+
+                g_error_free (error);
+                goto out;
+        }
+
+        reply = g_dbus_connection_call_sync (system_bus,
+                                             "org.freedesktop.ConsoleKit",
+                                             "/org/freedesktop/ConsoleKit/Manager",
+                                             "org.freedesktop.ConsoleKit.Manager",
+                                             "GetCurrentSession",
+                                             NULL,
+                                             G_VARIANT_TYPE ("(o)"),
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL,
+                                             &error);
+
+        if (reply == NULL) {
+                g_warning ("%s", error->message);
+                g_clear_error (&error);
+                goto out;
+        }
+
+        g_variant_get (reply, "(o)", &session_id);
+
+        g_variant_unref (reply);
+
+out:
+        return session_id;
+}
 #endif
 
 /* adapted from glib script_execute */
@@ -584,10 +630,11 @@ gdm_session_worker_update_username (GdmSessionWorker *worker)
                 worker->priv->username = username;
                 username = NULL;
 
-                gdm_dbus_session_call_username_changed_sync (worker->priv->session_proxy,
-                                                             worker->priv->service,
-                                                             worker->priv->username,
-                                                             NULL, NULL);
+                gdm_dbus_worker_manager_call_username_changed_sync (worker->priv->manager,
+                                                                    worker->priv->service,
+                                                                    worker->priv->username,
+                                                                    NULL,
+                                                                    NULL);
 
                 /* We have a new username to try. If we haven't been able to
                  * read user settings up until now, then give it a go now
@@ -609,11 +656,12 @@ gdm_session_worker_ask_question (GdmSessionWorker *worker,
                                  const char       *question,
                                  char            **answerp)
 {
-        return gdm_dbus_session_call_info_query_sync (worker->priv->session_proxy,
-                                                      worker->priv->service,
-                                                      question,
-                                                      answerp,
-                                                      NULL, NULL);
+        return gdm_dbus_worker_manager_call_info_query_sync (worker->priv->manager,
+                                                             worker->priv->service,
+                                                             question,
+                                                             answerp,
+                                                             NULL,
+                                                             NULL);
 }
 
 static gboolean
@@ -621,31 +669,34 @@ gdm_session_worker_ask_for_secret (GdmSessionWorker *worker,
                                    const char       *question,
                                    char            **answerp)
 {
-        return gdm_dbus_session_call_secret_info_query_sync (worker->priv->session_proxy,
-                                                             worker->priv->service,
-                                                             question,
-                                                             answerp,
-                                                             NULL, NULL);
+        return gdm_dbus_worker_manager_call_secret_info_query_sync (worker->priv->manager,
+                                                                    worker->priv->service,
+                                                                    question,
+                                                                    answerp,
+                                                                    NULL,
+                                                                    NULL);
 }
 
 static gboolean
 gdm_session_worker_report_info (GdmSessionWorker *worker,
                                 const char       *info)
 {
-        return gdm_dbus_session_call_info_sync (worker->priv->session_proxy,
-                                                worker->priv->service,
-                                                info,
-                                                NULL, NULL);
+        return gdm_dbus_worker_manager_call_info_sync (worker->priv->manager,
+                                                       worker->priv->service,
+                                                       info,
+                                                       NULL,
+                                                       NULL);
 }
 
 static gboolean
 gdm_session_worker_report_problem (GdmSessionWorker *worker,
                                    const char       *problem)
 {
-        return gdm_dbus_session_call_problem_sync (worker->priv->session_proxy,
-                                                   worker->priv->service,
-                                                   problem,
-                                                   NULL, NULL);
+        return gdm_dbus_worker_manager_call_problem_sync (worker->priv->manager,
+                                                          worker->priv->service,
+                                                          problem,
+                                                          NULL,
+                                                          NULL);
 }
 
 static char *
@@ -720,9 +771,10 @@ gdm_session_worker_process_pam_message (GdmSessionWorker          *worker,
         }
 
         if (worker->priv->timed_out) {
-                gdm_dbus_session_call_cancel_pending_query_sync (worker->priv->session_proxy,
-                                                                 worker->priv->service,
-                                                                 NULL, NULL);
+                gdm_dbus_worker_manager_call_cancel_pending_query_sync (worker->priv->manager,
+                                                                        worker->priv->service,
+                                                                        NULL,
+                                                                        NULL);
                 worker->priv->timed_out = FALSE;
         }
 
@@ -1504,10 +1556,11 @@ session_worker_child_watch (GPid              pid,
 
         gdm_session_worker_uninitialize_pam (worker, PAM_SUCCESS);
 
-        gdm_dbus_session_call_session_exited_sync (worker->priv->session_proxy,
-                                                   worker->priv->service,
-                                                   status,
-                                                   NULL, NULL);
+        gdm_dbus_worker_manager_call_session_exited_sync (worker->priv->manager,
+                                                          worker->priv->service,
+                                                          status,
+                                                          NULL,
+                                                          NULL);
 
         worker->priv->child_pid = -1;
 }
@@ -1812,6 +1865,7 @@ gdm_session_worker_open_session (GdmSessionWorker  *worker,
 {
         int error_code;
         int flags;
+        char *session_id;
 
         g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED);
         g_assert (geteuid () == 0);
@@ -1835,6 +1889,21 @@ gdm_session_worker_open_session (GdmSessionWorker  *worker,
         g_debug ("GdmSessionWorker: state SESSION_OPENED");
         worker->priv->state = GDM_SESSION_WORKER_STATE_SESSION_OPENED;
 
+#ifdef WITH_SYSTEMD
+        session_id = gdm_session_worker_get_environment_variable (worker, "XDG_SESSION_ID");
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+        if (session_id == NULL) {
+                session_id = get_ck_session_id (worker);
+        }
+#endif
+
+        if (session_id != NULL) {
+                g_free (worker->priv->session_id);
+                worker->priv->session_id = session_id;
+        }
+
  out:
         if (error_code != PAM_SUCCESS) {
                 gdm_session_worker_uninitialize_pam (worker, error_code);
@@ -1896,19 +1965,19 @@ gdm_session_worker_get_property (GObject    *object,
 }
 
 static void
-on_set_environment_variable (GdmDBusSession   *proxy,
-                             const char       *key,
-                             const char       *value,
-                             GdmSessionWorker *worker)
+on_set_environment_variable (GdmDBusWorkerManager *proxy,
+                             const char           *key,
+                             const char           *value,
+                             GdmSessionWorker     *worker)
 {
         g_debug ("GdmSessionWorker: set env: %s = %s", key, value);
         gdm_session_worker_set_environment_variable (worker, key, value);
 }
 
 static void
-on_set_session_name (GdmDBusSession   *proxy,
-                     const char       *session_name,
-                     GdmSessionWorker *worker)
+on_set_session_name (GdmDBusWorkerManager *proxy,
+                     const char           *session_name,
+                     GdmSessionWorker     *worker)
 {
         g_debug ("GdmSessionWorker: session name set to %s", session_name);
         gdm_session_settings_set_session_name (worker->priv->user_settings,
@@ -1916,9 +1985,9 @@ on_set_session_name (GdmDBusSession   *proxy,
 }
 
 static void
-on_set_session_type (GdmDBusSession   *proxy,
-                     const char       *session_type,
-                     GdmSessionWorker *worker)
+on_set_session_type (GdmDBusWorkerManager *proxy,
+                     const char           *session_type,
+                     GdmSessionWorker     *worker)
 {
         g_debug ("GdmSessionWorker: session type set to %s", session_type);
         g_free (worker->priv->session_type);
@@ -1926,9 +1995,9 @@ on_set_session_type (GdmDBusSession   *proxy,
 }
 
 static void
-on_set_language_name (GdmDBusSession   *proxy,
-                      const char       *language_name,
-                      GdmSessionWorker *worker)
+on_set_language_name (GdmDBusWorkerManager *proxy,
+                      const char           *language_name,
+                      GdmSessionWorker     *worker)
 {
         g_debug ("GdmSessionWorker: language name set to %s", language_name);
         gdm_session_settings_set_language_name (worker->priv->user_settings,
@@ -1943,9 +2012,10 @@ on_saved_language_name_read (GdmSessionWorker *worker)
         language_name = gdm_session_settings_get_language_name (worker->priv->user_settings);
 
         g_debug ("GdmSessionWorker: Saved language is %s", language_name);
-        gdm_dbus_session_call_saved_language_name_read_sync (worker->priv->session_proxy,
-                                                             language_name,
-                                                             NULL, NULL);
+        gdm_dbus_worker_manager_call_saved_language_name_read_sync (worker->priv->manager,
+                                                                    language_name,
+                                                                    NULL,
+                                                                    NULL);
         g_free (language_name);
 }
 
@@ -1957,9 +2027,10 @@ on_saved_session_name_read (GdmSessionWorker *worker)
         session_name = gdm_session_settings_get_session_name (worker->priv->user_settings);
 
         g_debug ("GdmSessionWorker: Saved session is %s", session_name);
-        gdm_dbus_session_call_saved_session_name_read_sync (worker->priv->session_proxy,
-                                                            session_name,
-                                                            NULL, NULL);
+        gdm_dbus_worker_manager_call_saved_session_name_read_sync (worker->priv->manager,
+                                                                   session_name,
+                                                                   NULL,
+                                                                   NULL);
         g_free (session_name);
 }
 
@@ -1983,15 +2054,17 @@ do_setup (GdmSessionWorker *worker)
                 if (g_error_matches (error,
                                      GDM_SESSION_WORKER_ERROR,
                                      GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE)) {
-                        gdm_dbus_session_call_service_unavailable_sync (worker->priv->session_proxy,
+                        gdm_dbus_worker_manager_call_service_unavailable_sync (worker->priv->manager,
+                                                                               worker->priv->service,
+                                                                               error->message,
+                                                                               NULL,
+                                                                               NULL);
+                } else {
+                        gdm_dbus_worker_manager_call_setup_failed_sync (worker->priv->manager,
                                                                         worker->priv->service,
                                                                         error->message,
-                                                                        NULL, NULL);
-                } else {
-                        gdm_dbus_session_call_setup_failed_sync (worker->priv->session_proxy,
-                                                                 worker->priv->service,
-                                                                 error->message,
-                                                                 NULL, NULL);
+                                                                        NULL,
+                                                                        NULL);
                 }
                 g_error_free (error);
                 return;
@@ -2009,9 +2082,10 @@ do_setup (GdmSessionWorker *worker)
                                               G_CALLBACK (on_saved_language_name_read),
                                               worker);
 
-        gdm_dbus_session_call_setup_complete_sync (worker->priv->session_proxy,
-                                                   worker->priv->service,
-                                                   NULL, NULL);
+        gdm_dbus_worker_manager_call_setup_complete_sync (worker->priv->manager,
+                                                          worker->priv->service,
+                                                          NULL,
+                                                          NULL);
 }
 
 static void
@@ -2031,16 +2105,18 @@ do_authenticate (GdmSessionWorker *worker)
                                      GDM_SESSION_WORKER_ERROR,
                                      GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE)) {
                         g_debug ("GdmSessionWorker: Unable to use authentication service");
-                        gdm_dbus_session_call_service_unavailable_sync (worker->priv->session_proxy,
-                                                                        worker->priv->service,
-                                                                        error->message,
-                                                                        NULL, NULL);
+                        gdm_dbus_worker_manager_call_service_unavailable_sync (worker->priv->manager,
+                                                                               worker->priv->service,
+                                                                               error->message,
+                                                                               NULL,
+                                                                               NULL);
                 } else {
                         g_debug ("GdmSessionWorker: Unable to verify user");
-                        gdm_dbus_session_call_authentication_failed_sync (worker->priv->session_proxy,
-                                                                          worker->priv->service,
-                                                                          error->message,
-                                                                          NULL, NULL);
+                        gdm_dbus_worker_manager_call_authentication_failed_sync (worker->priv->manager,
+                                                                                 worker->priv->service,
+                                                                                 error->message,
+                                                                                 NULL,
+                                                                                 NULL);
                 }
                 g_error_free (error);
                 return;
@@ -2054,9 +2130,10 @@ do_authenticate (GdmSessionWorker *worker)
                 gdm_session_worker_update_username (worker);
         }
 
-        gdm_dbus_session_call_authenticated_sync (worker->priv->session_proxy,
-                                                  worker->priv->service,
-                                                  NULL, NULL);
+        gdm_dbus_worker_manager_call_authenticated_sync (worker->priv->manager,
+                                                         worker->priv->service,
+                                                         NULL,
+                                                         NULL);
 }
 
 static void
@@ -2072,17 +2149,19 @@ do_authorize (GdmSessionWorker *worker)
                                                  worker->priv->password_is_required,
                                                  &error);
         if (! res) {
-                gdm_dbus_session_call_authorization_failed_sync (worker->priv->session_proxy,
-                                                                 worker->priv->service,
-                                                                 error->message,
-                                                                 NULL, NULL);
+                gdm_dbus_worker_manager_call_authorization_failed_sync (worker->priv->manager,
+                                                                        worker->priv->service,
+                                                                        error->message,
+                                                                        NULL,
+                                                                        NULL);
                 g_error_free (error);
                 return;
         }
 
-        gdm_dbus_session_call_authorized_sync (worker->priv->session_proxy,
-                                               worker->priv->service,
-                                               NULL, NULL);
+        gdm_dbus_worker_manager_call_authorized_sync (worker->priv->manager,
+                                                      worker->priv->service,
+                                                      NULL,
+                                                      NULL);
 }
 
 static void
@@ -2097,17 +2176,19 @@ do_accredit (GdmSessionWorker *worker)
         res = gdm_session_worker_accredit_user (worker, &error);
 
         if (! res) {
-                gdm_dbus_session_call_accreditation_failed_sync (worker->priv->session_proxy,
-                                                                 worker->priv->service,
-                                                                 error->message,
-                                                                 NULL, NULL);
+                gdm_dbus_worker_manager_call_accreditation_failed_sync (worker->priv->manager,
+                                                                        worker->priv->service,
+                                                                        error->message,
+                                                                        NULL,
+                                                                        NULL);
                 g_error_free (error);
                 return;
         }
 
-        gdm_dbus_session_call_accredited_sync (worker->priv->session_proxy,
-                                               worker->priv->service,
-                                               NULL, NULL);
+        gdm_dbus_worker_manager_call_accredited_sync (worker->priv->manager,
+                                                      worker->priv->service,
+                                                      NULL,
+                                                      NULL);
 }
 
 static void
@@ -2177,17 +2258,21 @@ do_open_session (GdmSessionWorker *worker)
         error = NULL;
         res = gdm_session_worker_open_session (worker, &error);
         if (! res) {
-                gdm_dbus_session_call_open_failed_sync (worker->priv->session_proxy,
-                                                        worker->priv->service,
-                                                        error->message,
-                                                        NULL, NULL);
+                gdm_dbus_worker_manager_call_open_failed_sync (worker->priv->manager,
+                                                               worker->priv->service,
+                                                               error->message,
+                                                               NULL,
+                                                               NULL);
                 g_error_free (error);
                 return;
         }
 
-        gdm_dbus_session_call_opened_sync (worker->priv->session_proxy,
-                                           worker->priv->service,
-                                           NULL, NULL);
+        gdm_dbus_worker_manager_call_opened_sync (worker->priv->manager,
+                                                  worker->priv->service,
+                                                  worker->priv->session_id ?
+                                                  worker->priv->session_id : "",
+                                                  NULL,
+                                                  NULL);
 }
 
 static void
@@ -2199,18 +2284,20 @@ do_start_session (GdmSessionWorker *worker)
         error = NULL;
         res = gdm_session_worker_start_session (worker, &error);
         if (! res) {
-                gdm_dbus_session_call_session_start_failed_sync (worker->priv->session_proxy,
-                                                                 worker->priv->service,
-                                                                 error->message,
-                                                                 NULL, NULL);
+                gdm_dbus_worker_manager_call_session_start_failed_sync (worker->priv->manager,
+                                                                        worker->priv->service,
+                                                                        error->message,
+                                                                        NULL,
+                                                                        NULL);
                 g_error_free (error);
                 return;
         }
 
-        gdm_dbus_session_call_session_started_sync (worker->priv->session_proxy,
-                                                    worker->priv->service,
-                                                    worker->priv->child_pid,
-                                                    NULL, NULL);
+        gdm_dbus_worker_manager_call_session_started_sync (worker->priv->manager,
+                                                           worker->priv->service,
+                                                           worker->priv->child_pid,
+                                                           NULL,
+                                                           NULL);
 }
 
 static const char *
@@ -2304,9 +2391,9 @@ queue_state_change (GdmSessionWorker *worker)
 }
 
 static void
-on_start_program (GdmDBusSession   *proxy,
-                  const char       *text,
-                  GdmSessionWorker *worker)
+on_start_program (GdmDBusWorkerManager *proxy,
+                  const char           *text,
+                  GdmSessionWorker     *worker)
 {
         GError *parse_error = NULL;
 
@@ -2328,14 +2415,14 @@ on_start_program (GdmDBusSession   *proxy,
 }
 
 static void
-on_setup (GdmDBusSession   *proxy,
-          const char       *service,
-          const char       *x11_display_name,
-          const char       *x11_authority_file,
-          const char       *console,
-          const char       *seat_id,
-          const char       *hostname,
-          GdmSessionWorker *worker)
+on_setup (GdmDBusWorkerManager *proxy,
+          const char           *service,
+          const char           *x11_display_name,
+          const char           *x11_authority_file,
+          const char           *console,
+          const char           *seat_id,
+          const char           *hostname,
+          GdmSessionWorker     *worker)
 {
         if (worker->priv->state != GDM_SESSION_WORKER_STATE_NONE) {
                 g_debug ("GdmSessionWorker: ignoring spurious setup while in state %s", get_state_name (worker->priv->state));
@@ -2355,15 +2442,15 @@ on_setup (GdmDBusSession   *proxy,
 }
 
 static void
-on_setup_for_user (GdmDBusSession   *proxy,
-                   const char       *service,
-                   const char       *username,
-                   const char       *x11_display_name,
-                   const char       *x11_authority_file,
-                   const char       *console,
-                   const char       *seat_id,
-                   const char       *hostname,
-                   GdmSessionWorker *worker)
+on_setup_for_user (GdmDBusWorkerManager *proxy,
+                   const char           *service,
+                   const char           *username,
+                   const char           *x11_display_name,
+                   const char           *x11_authority_file,
+                   const char           *console,
+                   const char           *seat_id,
+                   const char           *hostname,
+                   GdmSessionWorker     *worker)
 {
         if (worker->priv->state != GDM_SESSION_WORKER_STATE_NONE) {
                 g_debug ("GdmSessionWorker: ignoring spurious setup while in state %s", get_state_name (worker->priv->state));
@@ -2402,15 +2489,15 @@ on_setup_for_user (GdmDBusSession   *proxy,
 }
 
 static void
-on_setup_for_program (GdmDBusSession   *proxy,
-                      const char       *service,
-                      const char       *x11_display_name,
-                      const char       *x11_authority_file,
-                      const char       *console,
-                      const char       *seat_id,
-                      const char       *hostname,
-                      const char       *log_file,
-                      GdmSessionWorker *worker)
+on_setup_for_program (GdmDBusWorkerManager *proxy,
+                      const char           *service,
+                      const char           *x11_display_name,
+                      const char           *x11_authority_file,
+                      const char           *console,
+                      const char           *seat_id,
+                      const char           *hostname,
+                      const char           *log_file,
+                      GdmSessionWorker     *worker)
 {
         if (worker->priv->state != GDM_SESSION_WORKER_STATE_NONE) {
                 g_debug ("GdmSessionWorker: ignoring spurious setup while in state %s", get_state_name (worker->priv->state));
@@ -2431,9 +2518,9 @@ on_setup_for_program (GdmDBusSession   *proxy,
 }
 
 static void
-on_authenticate (GdmDBusSession   *session,
-                 const char       *service_name,
-                 GdmSessionWorker *worker)
+on_authenticate (GdmDBusWorkerManager *manager,
+                 const char           *service_name,
+                 GdmSessionWorker     *worker)
 {
         if (worker->priv->state != GDM_SESSION_WORKER_STATE_SETUP_COMPLETE) {
                 g_debug ("GdmSessionWorker: ignoring spurious authenticate for user while in state %s", get_state_name (worker->priv->state));
@@ -2444,9 +2531,9 @@ on_authenticate (GdmDBusSession   *session,
 }
 
 static void
-on_authorize (GdmDBusSession   *session,
-              const char       *service_name,
-              GdmSessionWorker *worker)
+on_authorize (GdmDBusWorkerManager *manager,
+              const char           *service_name,
+              GdmSessionWorker     *worker)
 {
         if (worker->priv->state != GDM_SESSION_WORKER_STATE_AUTHENTICATED) {
                 g_debug ("GdmSessionWorker: ignoring spurious authorize for user while in state %s", get_state_name (worker->priv->state));
@@ -2457,9 +2544,9 @@ on_authorize (GdmDBusSession   *session,
 }
 
 static void
-on_establish_credentials (GdmDBusSession   *session,
-                          const char       *service_name,
-                          GdmSessionWorker *worker)
+on_establish_credentials (GdmDBusWorkerManager *manager,
+                          const char           *service_name,
+                          GdmSessionWorker     *worker)
 {
         if (worker->priv->state != GDM_SESSION_WORKER_STATE_AUTHORIZED) {
                 g_debug ("GdmSessionWorker: ignoring spurious establish credentials for user while in state %s", get_state_name (worker->priv->state));
@@ -2472,9 +2559,9 @@ on_establish_credentials (GdmDBusSession   *session,
 }
 
 static void
-on_open_session (GdmDBusSession   *session,
-                 const char       *service_name,
-                 GdmSessionWorker *worker)
+on_open_session (GdmDBusWorkerManager *manager,
+                 const char           *service_name,
+                 GdmSessionWorker     *worker)
 {
         if (worker->priv->state != GDM_SESSION_WORKER_STATE_ACCREDITED) {
                 g_debug ("GdmSessionWorker: ignoring spurious open session for user while in state %s", get_state_name (worker->priv->state));
@@ -2511,66 +2598,66 @@ gdm_session_worker_constructor (GType                  type,
                 exit (1);
         }
 
-        worker->priv->session_proxy = GDM_DBUS_SESSION (gdm_dbus_session_proxy_new_sync (worker->priv->connection,
-                                                                                         G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
-                                                                                         NULL, /* dbus name */
-                                                                                         GDM_SESSION_DBUS_PATH,
-                                                                                         NULL,
-                                                                                         &error));
-        if (worker->priv->session_proxy == NULL) {
+        worker->priv->manager = GDM_DBUS_WORKER_MANAGER (gdm_dbus_worker_manager_proxy_new_sync (worker->priv->connection,
+                                                                                                 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+                                                                                                 NULL, /* dbus name */
+                                                                                                 GDM_SESSION_DBUS_PATH,
+                                                                                                 NULL,
+                                                                                                 &error));
+        if (worker->priv->manager == NULL) {
                 g_warning ("error creating session proxy: %s", error->message);
                 g_clear_error (&error);
 
                 exit (1);
         }
 
-        g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (worker->priv->session_proxy), -1);
+        g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (worker->priv->manager), -1);
 
-        g_signal_connect (worker->priv->session_proxy,
+        g_signal_connect (worker->priv->manager,
                           "authenticate",
                           G_CALLBACK (on_authenticate),
                           worker);
-        g_signal_connect (worker->priv->session_proxy,
+        g_signal_connect (worker->priv->manager,
                           "authorize",
                           G_CALLBACK (on_authorize),
                           worker);
-        g_signal_connect (worker->priv->session_proxy,
+        g_signal_connect (worker->priv->manager,
                           "establish-credentials",
                           G_CALLBACK (on_establish_credentials),
                           worker);
-        g_signal_connect (worker->priv->session_proxy,
+        g_signal_connect (worker->priv->manager,
                           "open-session",
                           G_CALLBACK (on_open_session),
                           worker);
-        g_signal_connect (worker->priv->session_proxy,
+        g_signal_connect (worker->priv->manager,
                           "set-environment-variable",
                           G_CALLBACK (on_set_environment_variable),
                           worker);
-        g_signal_connect (worker->priv->session_proxy,
+        g_signal_connect (worker->priv->manager,
                           "set-session-name",
                           G_CALLBACK (on_set_session_name),
                           worker);
-        g_signal_connect (worker->priv->session_proxy,
+        g_signal_connect (worker->priv->manager,
                           "set-language-name",
                           G_CALLBACK (on_set_language_name),
                           worker);
-        g_signal_connect (worker->priv->session_proxy,
+        g_signal_connect (worker->priv->manager,
                           "set-session-type",
                           G_CALLBACK (on_set_session_type),
                           worker);
-        g_signal_connect (worker->priv->session_proxy,
+        g_signal_connect (worker->priv->manager,
                           "setup",
                           G_CALLBACK (on_setup),
                           worker);
-        g_signal_connect (worker->priv->session_proxy,
+        g_signal_connect (worker->priv->manager,
                           "setup-for-user",
                           G_CALLBACK (on_setup_for_user),
                           worker);
-        g_signal_connect (worker->priv->session_proxy,
+        g_signal_connect (worker->priv->manager,
                           "setup-for-program",
                           G_CALLBACK (on_setup_for_program),
                           worker);
-        g_signal_connect (worker->priv->session_proxy,
+        g_signal_connect (worker->priv->manager,
                           "start-program",
                           G_CALLBACK (on_start_program),
                           worker);
@@ -2578,8 +2665,9 @@ gdm_session_worker_constructor (GType                  type,
         /* Send an initial Hello message so that the session can associate
          * the conversation we manage with our pid.
          */
-        gdm_dbus_session_call_hello_sync (worker->priv->session_proxy,
-                                          NULL, NULL);
+        gdm_dbus_worker_manager_call_hello_sync (worker->priv->manager,
+                                                 NULL,
+                                                 NULL);
 
         return G_OBJECT (worker);
 }
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index 47ec470..8d337b2 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -53,13 +53,13 @@
 #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"
 
-#define GDM_SESSION_DBUS_PATH         "/org/gnome/DisplayManager/Session"
-#define GDM_SESSION_DBUS_INTERFACE    "org.gnome.DisplayManager.Session"
 #define GDM_SESSION_DBUS_ERROR_CANCEL "org.gnome.DisplayManager.Session.Error.Cancel"
+#define GDM_SESSION_DBUS_OBJECT_PATH "/org/gnome/DisplayManager/Session"
 
 #ifndef GDM_SESSION_DEFAULT_PATH
 #define GDM_SESSION_DEFAULT_PATH "/usr/local/bin:/usr/bin:/bin"
@@ -72,8 +72,9 @@ typedef struct
         GPid                   worker_pid;
         char                  *service_name;
         GDBusConnection       *worker_connection;
+        GDBusMethodInvocation *starting_invocation;
         GDBusMethodInvocation *pending_invocation;
-        GdmDBusSession        *worker_skeleton;
+        GdmDBusWorkerManager  *worker_manager_interface;
         char                  *session_id;
         guint32                is_stopping : 1;
 } GdmSessionConversation;
@@ -93,12 +94,17 @@ struct _GdmSessionPrivate
 
         GdmSessionConversation *session_conversation;
 
-        GList               *pending_connections;
+        GdmDBusUserVerifier   *user_verifier_interface;
+        GdmDBusGreeter        *greeter_interface;
+        GdmDBusRemoteGreeter  *remote_greeter_interface;
+        GdmDBusChooser        *chooser_interface;
+
+        GList               *pending_worker_connections;
+        GList               *outside_connections;
 
         GPid                 session_pid;
 
         /* object lifetime scope */
-        char                *display_id;
         char                *display_name;
         char                *display_hostname;
         char                *display_device;
@@ -106,14 +112,18 @@ struct _GdmSessionPrivate
         char                *display_x11_authority_file;
         gboolean             display_is_local;
 
+        GdmSessionVerificationMode verification_mode;
+
         char                *fallback_session_name;
 
-        GDBusServer         *server;
+        GDBusServer         *worker_server;
+        GDBusServer         *outside_server;
         GHashTable          *environment;
 };
 
 enum {
         PROP_0,
+        PROP_VERIFICATION_MODE,
         PROP_DISPLAY_NAME,
         PROP_DISPLAY_HOSTNAME,
         PROP_DISPLAY_IS_LOCAL,
@@ -126,28 +136,18 @@ enum {
 enum {
         CONVERSATION_STARTED = 0,
         CONVERSATION_STOPPED,
-        SERVICE_UNAVAILABLE,
         SETUP_COMPLETE,
-        SETUP_FAILED,
-        AUTHENTICATED,
-        AUTHENTICATION_FAILED,
-        AUTHORIZED,
-        AUTHORIZATION_FAILED,
-        ACCREDITED,
-        ACCREDITATION_FAILED,
-        INFO,
-        PROBLEM,
-        INFO_QUERY,
-        SECRET_INFO_QUERY,
+        CANCELLED,
+        HOSTNAME_SELECTED,
+        CLIENT_CONNECTED,
+        CLIENT_DISCONNECTED,
+        CLIENT_READY_FOR_SESSION_TO_START,
+        DISCONNECTED,
         SESSION_OPENED,
-        SESSION_OPEN_FAILED,
         SESSION_STARTED,
         SESSION_START_FAILED,
         SESSION_EXITED,
         SESSION_DIED,
-        SELECTED_USER_CHANGED,
-        DEFAULT_LANGUAGE_NAME_CHANGED,
-        DEFAULT_SESSION_NAME_CHANGED,
         LAST_SIGNAL
 };
 
@@ -173,23 +173,6 @@ find_conversation_by_name (GdmSession *self,
 }
 
 static void
-on_authentication_failed (GdmSession *self,
-                          const char *service_name,
-                          const char *message)
-{
-        GdmSessionConversation *conversation;
-
-        conversation = find_conversation_by_name (self, service_name);
-        if (conversation != NULL) {
-                gdm_session_record_failed (conversation->worker_pid,
-                                           self->priv->selected_user,
-                                           self->priv->display_hostname,
-                                           self->priv->display_name,
-                                           self->priv->display_device);
-        }
-}
-
-static void
 on_session_started (GdmSession *self,
                     const char *service_name)
 {
@@ -234,133 +217,168 @@ on_session_exited (GdmSession *self,
                                    self->priv->display_device);
 }
 
+static void
+report_problem_and_stop_conversation (GdmSession *self,
+                                      const char *service_name,
+                                      const char *message)
+{
+        if (self->priv->user_verifier_interface != NULL) {
+                gdm_dbus_user_verifier_emit_problem (self->priv->user_verifier_interface,
+                                                     service_name,
+                                                     message);
+        }
+
+        gdm_session_stop_conversation (self, service_name);
+}
+
 static gboolean
-gdm_session_handle_service_unavailable (GdmDBusSession        *skeleton,
+gdm_session_handle_service_unavailable (GdmDBusWorkerManager  *worker_manager_interface,
                                         GDBusMethodInvocation *invocation,
                                         const char            *service_name,
                                         const char            *message,
                                         GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_service_unavailable (worker_manager_interface,
+                                                              invocation);
 
-        g_debug ("GdmSession: Emitting 'service-unavailable' signal");
-        g_signal_emit (self, signals[SERVICE_UNAVAILABLE], 0, service_name);
+        if (self->priv->user_verifier_interface != NULL) {
+                gdm_dbus_user_verifier_emit_service_unavailable (self->priv->user_verifier_interface,
+                                                                 service_name,
+                                                                 message);
+        }
+
+        gdm_session_stop_conversation (self, service_name);
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_setup_complete (GdmDBusSession        *skeleton,
+gdm_session_handle_setup_complete (GdmDBusWorkerManager  *worker_manager_interface,
                                    GDBusMethodInvocation *invocation,
                                    const char            *service_name,
                                    GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_setup_complete (worker_manager_interface,
+                                                         invocation);
 
-        g_debug ("GdmSession: Emitting 'setup-complete' signal");
-        g_signal_emit (self, signals[SETUP_COMPLETE], 0, service_name);
+        g_signal_emit (G_OBJECT (self),
+                       signals [SETUP_COMPLETE],
+                       0,
+                       service_name);
+
+        gdm_session_authenticate (self, service_name);
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_setup_failed (GdmDBusSession        *skeleton,
+gdm_session_handle_setup_failed (GdmDBusWorkerManager  *worker_manager_interface,
                                  GDBusMethodInvocation *invocation,
                                  const char            *service_name,
                                  const char            *message,
                                  GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_setup_failed (worker_manager_interface,
+                                                       invocation);
 
-        g_debug ("GdmSession: Emitting 'setup-failed' signal");
-        g_signal_emit (self, signals[SETUP_FAILED], 0, service_name, message);
+        report_problem_and_stop_conversation (self, service_name, message);
 
         return TRUE;
 }
 
-
 static gboolean
-gdm_session_handle_authenticated (GdmDBusSession        *skeleton,
+gdm_session_handle_authenticated (GdmDBusWorkerManager  *worker_manager_interface,
                                   GDBusMethodInvocation *invocation,
                                   const char            *service_name,
                                   GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
-
-        g_debug ("GdmSession: Emitting 'authenticated' signal");
-        g_signal_emit (self, signals[AUTHENTICATED], 0, service_name);
+        gdm_dbus_worker_manager_complete_authenticated (worker_manager_interface,
+                                                        invocation);
+        gdm_session_authorize (self, service_name);
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_authentication_failed (GdmDBusSession        *skeleton,
+gdm_session_handle_authentication_failed (GdmDBusWorkerManager  *worker_manager_interface,
                                           GDBusMethodInvocation *invocation,
                                           const char            *service_name,
                                           const char            *message,
                                           GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        GdmSessionConversation *conversation;
 
-        g_debug ("GdmSession: Emitting 'authentication-failed' signal");
-        g_signal_emit (self, signals[AUTHENTICATION_FAILED], 0, service_name, message);
+        gdm_dbus_worker_manager_complete_authentication_failed (worker_manager_interface,
+                                                                invocation);
+
+        conversation = find_conversation_by_name (self, service_name);
+        if (conversation != NULL) {
+                gdm_session_record_failed (conversation->worker_pid,
+                                           self->priv->selected_user,
+                                           self->priv->display_hostname,
+                                           self->priv->display_name,
+                                           self->priv->display_device);
+        }
+
+        report_problem_and_stop_conversation (self, service_name, message);
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_authorized (GdmDBusSession        *skeleton,
+gdm_session_handle_authorized (GdmDBusWorkerManager  *worker_manager_interface,
                                GDBusMethodInvocation *invocation,
                                const char            *service_name,
                                GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
-
-        g_debug ("GdmSession: Emitting 'authorized' signal");
-        g_signal_emit (self, signals[AUTHORIZED], 0, service_name);
+        gdm_dbus_worker_manager_complete_authorized (worker_manager_interface,
+                                                     invocation);
+        gdm_session_accredit (self, service_name);
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_authorization_failed (GdmDBusSession        *skeleton,
+gdm_session_handle_authorization_failed (GdmDBusWorkerManager  *worker_manager_interface,
                                          GDBusMethodInvocation *invocation,
                                          const char            *service_name,
                                          const char            *message,
                                          GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_authorization_failed (worker_manager_interface,
+                                                               invocation);
 
-        g_debug ("GdmSession: Emitting 'authorization-failed' signal");
-        g_signal_emit (self, signals[AUTHORIZATION_FAILED], 0, service_name, message);
+        report_problem_and_stop_conversation (self, service_name, message);
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_accredited (GdmDBusSession        *skeleton,
+gdm_session_handle_accredited (GdmDBusWorkerManager  *worker_manager_interface,
                                GDBusMethodInvocation *invocation,
                                const char            *service_name,
                                GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_accredited (worker_manager_interface,
+                                                     invocation);
 
-        g_debug ("GdmSession: Emitting 'accredited' signal");
-        g_signal_emit (self, signals[ACCREDITED], 0, service_name);
+        gdm_session_open_session (self, service_name);
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_accreditation_failed (GdmDBusSession        *skeleton,
+gdm_session_handle_accreditation_failed (GdmDBusWorkerManager  *worker_manager_interface,
                                          GDBusMethodInvocation *invocation,
                                          const char            *service_name,
                                          const char            *message,
                                          GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        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.
 
-        g_debug ("GdmSession: Emitting 'accreditation-failed' signal");
-        g_signal_emit (self, signals[ACCREDITATION_FAILED], 0, service_name, message);
+        report_problem_and_stop_conversation (self, service_name, message);
         return TRUE;
 }
 
@@ -609,15 +627,13 @@ get_default_session_name (GdmSession *self)
 static void
 gdm_session_defaults_changed (GdmSession *self)
 {
-        g_signal_emit (self,
-                       signals[DEFAULT_LANGUAGE_NAME_CHANGED],
-                       0,
-                       get_default_language_name (self));
 
-        g_signal_emit (self,
-                       signals[DEFAULT_SESSION_NAME_CHANGED],
-                       0,
-                       get_default_session_name (self));
+        if (self->priv->greeter_interface != NULL) {
+                gdm_dbus_greeter_emit_default_language_name_changed (self->priv->greeter_interface,
+                                                                     get_default_language_name (self));
+                gdm_dbus_greeter_emit_default_session_name_changed (self->priv->greeter_interface,
+                                                                    get_default_session_name (self));
+        }
 }
 
 void
@@ -638,21 +654,20 @@ gdm_session_select_user (GdmSession *self,
 }
 
 static gboolean
-gdm_session_handle_username_changed (GdmDBusSession        *skeleton,
+gdm_session_handle_username_changed (GdmDBusWorkerManager  *worker_manager_interface,
                                      GDBusMethodInvocation *invocation,
                                      const char            *service_name,
-                                     const char            *text,
+                                     const char            *username,
                                      GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_username_changed (worker_manager_interface,
+                                                           invocation);
 
         g_debug ("GdmSession: changing username from '%s' to '%s'",
                  self->priv->selected_user != NULL ? self->priv->selected_user : "<unset>",
-                 (strlen (text)) ? text : "<unset>");
-
-        gdm_session_select_user (self, (strlen (text) > 0) ? g_strdup (text) : NULL);
-        g_signal_emit (self, signals[SELECTED_USER_CHANGED], 0, self->priv->selected_user);
+                 (strlen (username)) ? username : "<unset>");
 
+        gdm_session_select_user (self, (strlen (username) > 0) ? g_strdup (username) : NULL);
         gdm_session_defaults_changed (self);
 
         return TRUE;
@@ -692,58 +707,69 @@ set_pending_query (GdmSessionConversation *conversation,
 }
 
 static gboolean
-gdm_session_handle_info_query (GdmDBusSession        *skeleton,
+gdm_session_handle_info_query (GdmDBusWorkerManager  *worker_manager_interface,
                                GDBusMethodInvocation *invocation,
                                const char            *service_name,
-                               const char            *text,
+                               const char            *query,
                                GdmSession            *self)
 {
         GdmSessionConversation *conversation;
 
+        g_return_val_if_fail (self->priv->user_verifier_interface != NULL, FALSE);
+
         conversation = find_conversation_by_name (self, service_name);
         set_pending_query (conversation, invocation);
 
-        g_debug ("GdmSession: Emitting 'info-query' signal");
-        g_signal_emit (self, signals[INFO_QUERY], 0, service_name, text);
+        gdm_dbus_user_verifier_emit_info_query (self->priv->user_verifier_interface,
+                                                service_name,
+                                                query);
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_secret_info_query (GdmDBusSession        *skeleton,
+gdm_session_handle_secret_info_query (GdmDBusWorkerManager  *worker_manager_interface,
                                       GDBusMethodInvocation *invocation,
                                       const char            *service_name,
-                                      const char            *text,
+                                      const char            *query,
                                       GdmSession            *self)
 {
         GdmSessionConversation *conversation;
 
+        g_return_val_if_fail (self->priv->user_verifier_interface != NULL, FALSE);
+
         conversation = find_conversation_by_name (self, service_name);
         set_pending_query (conversation, invocation);
 
-        g_debug ("GdmSession: Emitting 'secret-info-query' signal");
-        g_signal_emit (self, signals[SECRET_INFO_QUERY], 0, service_name, text);
+        gdm_dbus_user_verifier_emit_secret_info_query (self->priv->user_verifier_interface,
+                                                       service_name,
+                                                       query);
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_info (GdmDBusSession        *skeleton,
+gdm_session_handle_info (GdmDBusWorkerManager  *worker_manager_interface,
                          GDBusMethodInvocation *invocation,
                          const char            *service_name,
-                         const char            *text,
+                         const char            *info,
                          GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
 
-        g_debug ("GdmSession: Emitting 'info' signal");
-        g_signal_emit (self, signals[INFO], 0, service_name, text);
+        g_return_val_if_fail (self->priv->user_verifier_interface != NULL, FALSE);
+
+        gdm_dbus_worker_manager_complete_info (worker_manager_interface,
+                                               invocation);
+
+        gdm_dbus_user_verifier_emit_info (self->priv->user_verifier_interface,
+                                          service_name,
+                                          info);
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_cancel_pending_query (GdmDBusSession        *skeleton,
+gdm_session_handle_cancel_pending_query (GdmDBusWorkerManager  *worker_manager_interface,
                                          GDBusMethodInvocation *invocation,
                                          const char            *service_name,
                                          GdmSession            *self)
@@ -753,79 +779,101 @@ gdm_session_handle_cancel_pending_query (GdmDBusSession        *skeleton,
         conversation = find_conversation_by_name (self, service_name);
         cancel_pending_query (conversation);
 
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_cancel_pending_query (worker_manager_interface,
+                                                               invocation);
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_problem (GdmDBusSession        *skeleton,
+gdm_session_handle_problem (GdmDBusWorkerManager  *worker_manager_interface,
                             GDBusMethodInvocation *invocation,
                             const char            *service_name,
-                            const char            *text,
+                            const char            *problem,
                             GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
-
-        g_debug ("GdmSession: Emitting 'problem' signal");
-        g_signal_emit (self, signals[PROBLEM], 0, service_name, text);
+        gdm_dbus_worker_manager_complete_problem (worker_manager_interface,
+                                                  invocation);
 
+        if (self->priv->user_verifier_interface != NULL) {
+                gdm_dbus_user_verifier_emit_problem (self->priv->user_verifier_interface,
+                                                     service_name,
+                                                     problem);
+        }
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_opened (GdmDBusSession        *skeleton,
+gdm_session_handle_opened (GdmDBusWorkerManager  *worker_manager_interface,
                            GDBusMethodInvocation *invocation,
                            const char            *service_name,
+                           const char            *session_id,
                            GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        GdmSessionConversation *conversation;
+
+        gdm_dbus_worker_manager_complete_opened (worker_manager_interface,
+                                                 invocation);
+
+        conversation = find_conversation_by_name (self, service_name);
+
+        if (conversation == NULL) {
+                return TRUE;
+        }
+
+        g_clear_pointer (&conversation->session_id,
+                         (GDestroyNotify) g_free);
+
+        conversation->session_id = g_strdup (session_id);
+
+        if (self->priv->greeter_interface != NULL) {
+                gdm_dbus_greeter_emit_session_opened (self->priv->greeter_interface,
+                                                      service_name);
+        }
 
         g_debug ("GdmSession: Emitting 'session-opened' signal");
-        g_signal_emit (self, signals[SESSION_OPENED], 0, service_name);
+        g_signal_emit (self, signals[SESSION_OPENED], 0, service_name, session_id);
+
+        if (self->priv->user_verifier_interface != NULL) {
+                gdm_dbus_user_verifier_emit_verification_complete (self->priv->user_verifier_interface,
+                                                                   service_name);
+        }
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_open_failed (GdmDBusSession        *skeleton,
+gdm_session_handle_open_failed (GdmDBusWorkerManager  *worker_manager_interface,
                                 GDBusMethodInvocation *invocation,
                                 const char            *service_name,
                                 const char            *message,
                                 GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_open_failed (worker_manager_interface,
+                                                      invocation);
 
-        g_debug ("GdmSession: Emitting 'session-open-failed' signal");
-        g_signal_emit (self, signals[SESSION_OPEN_FAILED], 0, service_name, message);
+        report_problem_and_stop_conversation (self, service_name, message);
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_session_started (GdmDBusSession        *skeleton,
+gdm_session_handle_session_started (GdmDBusWorkerManager  *worker_manager_interface,
                                     GDBusMethodInvocation *invocation,
                                     const char            *service_name,
-                                    const char            *session_id,
                                     int                    pid,
                                     GdmSession            *self)
 {
         GdmSessionConversation *conversation;
 
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_session_started (worker_manager_interface,
+                                                          invocation);
 
         conversation = find_conversation_by_name (self, service_name);
 
         self->priv->session_pid = pid;
         self->priv->session_conversation = conversation;
 
-        g_clear_pointer (&conversation->session_id,
-                         (GDestroyNotify) g_free);
-
-        if (session_id != NULL && session_id[0] != '\0') {
-                conversation->session_id = g_strdup (session_id);
-        }
-
         g_debug ("GdmSession: Emitting 'session-started' signal with pid '%d'", pid);
         g_signal_emit (self, signals[SESSION_STARTED], 0, service_name, pid);
 
@@ -833,13 +881,15 @@ gdm_session_handle_session_started (GdmDBusSession        *skeleton,
 }
 
 static gboolean
-gdm_session_handle_session_start_failed (GdmDBusSession        *skeleton,
+gdm_session_handle_session_start_failed (GdmDBusWorkerManager  *worker_manager_interface,
                                          GDBusMethodInvocation *invocation,
                                          const char            *service_name,
                                          const char            *message,
                                          GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_session_start_failed (worker_manager_interface,
+                                                               invocation);
+        gdm_session_stop_conversation (self, service_name);
 
         g_debug ("GdmSession: Emitting 'session-start-failed' signal");
         g_signal_emit (self, signals[SESSION_START_FAILED], 0, service_name, message);
@@ -848,13 +898,14 @@ gdm_session_handle_session_start_failed (GdmDBusSession        *skeleton,
 }
 
 static gboolean
-gdm_session_handle_session_exited_or_died (GdmDBusSession        *skeleton,
+gdm_session_handle_session_exited_or_died (GdmDBusWorkerManager  *worker_manager_interface,
                                            GDBusMethodInvocation *invocation,
                                            const char            *service_name,
                                            int                    status,
                                            GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_session_exited (worker_manager_interface,
+                                                         invocation);
 
         self->priv->session_conversation = NULL;
 
@@ -872,31 +923,36 @@ gdm_session_handle_session_exited_or_died (GdmDBusSession        *skeleton,
 }
 
 static gboolean
-gdm_session_handle_saved_language_name_read (GdmDBusSession        *skeleton,
+gdm_session_handle_saved_language_name_read (GdmDBusWorkerManager  *worker_manager_interface,
                                              GDBusMethodInvocation *invocation,
                                              const char            *language_name,
                                              GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_saved_language_name_read (worker_manager_interface,
+                                                                   invocation);
 
         if (strcmp (language_name,
                     get_default_language_name (self)) != 0) {
                 g_free (self->priv->saved_language);
                 self->priv->saved_language = g_strdup (language_name);
 
-                g_signal_emit (self, signals[DEFAULT_LANGUAGE_NAME_CHANGED], 0, language_name);
+                if (self->priv->greeter_interface != NULL) {
+                        gdm_dbus_greeter_emit_default_language_name_changed (self->priv->greeter_interface,
+                                                                             language_name);
+                }
         }
 
         return TRUE;
 }
 
 static gboolean
-gdm_session_handle_saved_session_name_read (GdmDBusSession        *skeleton,
+gdm_session_handle_saved_session_name_read (GdmDBusWorkerManager  *worker_manager_interface,
                                             GDBusMethodInvocation *invocation,
                                             const char            *session_name,
                                             GdmSession            *self)
 {
-        g_dbus_method_invocation_return_value (invocation, NULL);
+        gdm_dbus_worker_manager_complete_saved_session_name_read (worker_manager_interface,
+                                                                   invocation);
 
         if (! get_session_command_for_name (session_name, NULL)) {
                 /* ignore sessions that don't exist */
@@ -911,7 +967,10 @@ gdm_session_handle_saved_session_name_read (GdmDBusSession        *skeleton,
                 g_free (self->priv->saved_session);
                 self->priv->saved_session = g_strdup (session_name);
 
-                g_signal_emit (self, signals[DEFAULT_SESSION_NAME_CHANGED], 0, session_name);
+                if (self->priv->greeter_interface != NULL) {
+                        gdm_dbus_greeter_emit_default_session_name_changed (self->priv->greeter_interface,
+                                                                            session_name);
+                }
         }
  out:
         return TRUE;
@@ -939,12 +998,13 @@ find_conversation_by_pid (GdmSession *self,
 }
 
 static gboolean
-allow_user_function (GDBusAuthObserver *observer,
-                     GIOStream         *stream,
-                     GCredentials      *credentials)
+allow_worker_function (GDBusAuthObserver *observer,
+                       GIOStream         *stream,
+                       GCredentials      *credentials)
 {
-        if (g_credentials_get_unix_user (credentials, NULL) == 0)
+        if (g_credentials_get_unix_user (credentials, NULL) == 0) {
                 return TRUE;
+        }
 
         g_debug ("GdmSession: User not allowed");
 
@@ -974,7 +1034,7 @@ credentials_get_unix_pid (GCredentials *credentials)
 }
 
 static gboolean
-register_worker (GdmDBusSession        *skeleton,
+register_worker (GdmDBusWorkerManager  *worker_manager_interface,
                  GDBusMethodInvocation *invocation,
                  GdmSession            *self)
 {
@@ -987,15 +1047,18 @@ register_worker (GdmDBusSession        *skeleton,
         g_debug ("GdmSession: Authenticating new connection");
 
         connection = g_dbus_method_invocation_get_connection (invocation);
-        connection_node = g_list_find (self->priv->pending_connections, connection);
+        connection_node = g_list_find (self->priv->pending_worker_connections, connection);
 
         if (connection_node == NULL) {
                 g_debug ("GdmSession: Ignoring connection that we aren't tracking");
                 return FALSE;
         }
 
-        self->priv->pending_connections =
-                g_list_delete_link (self->priv->pending_connections,
+        /* connection was ref'd when it was added to list, we're taking that
+         * reference over and removing it from the list
+         */
+        self->priv->pending_worker_connections =
+                g_list_delete_link (self->priv->pending_worker_connections,
                                     connection_node);
 
         credentials = g_dbus_connection_get_peer_credentials (connection);
@@ -1015,8 +1078,8 @@ register_worker (GdmDBusSession        *skeleton,
 
         g_dbus_method_invocation_return_value (invocation, NULL);
 
-        conversation->worker_connection = g_object_ref (connection);
-        conversation->worker_skeleton = g_object_ref (skeleton);
+        conversation->worker_connection = connection;
+        conversation->worker_manager_interface = g_object_ref (worker_manager_interface);
         g_debug ("GdmSession: worker connection is %p", connection);
 
         g_debug ("GdmSession: Emitting conversation-started signal");
@@ -1027,133 +1090,597 @@ register_worker (GdmDBusSession        *skeleton,
         return TRUE;
 }
 
-static gboolean
-handle_connection (GDBusServer      *server,
-                   GDBusConnection  *connection,
-                   GdmSession       *self)
+static void
+export_worker_manager_interface (GdmSession      *self,
+                                 GDBusConnection *connection)
 {
-        GdmDBusSession *skeleton;
-
-        g_debug ("GdmSession: Handing new connection");
-
-        /* add to the list of pending connections.  We won't be able to
-         * associate it with a specific worker conversation until we have
-         * authenticated the connection (from the Hello handler).
-         */
-        self->priv->pending_connections =
-                g_list_prepend (self->priv->pending_connections,
-                                g_object_ref (connection));
+        GdmDBusWorkerManager *worker_manager_interface;
 
-        skeleton = GDM_DBUS_SESSION (gdm_dbus_session_skeleton_new ());
-        g_signal_connect (skeleton,
+        worker_manager_interface = GDM_DBUS_WORKER_MANAGER (gdm_dbus_worker_manager_skeleton_new ());
+        g_signal_connect (worker_manager_interface,
                           "handle-hello",
                           G_CALLBACK (register_worker),
                           self);
-        g_signal_connect (skeleton,
-                          "handle-info-query",
-                          G_CALLBACK (gdm_session_handle_info_query),
-                          self);
-        g_signal_connect (skeleton,
-                          "handle-secret-info-query",
-                          G_CALLBACK (gdm_session_handle_secret_info_query),
+        g_signal_connect (worker_manager_interface,
+                          "handle-cancel-pending-query",
+                          G_CALLBACK (gdm_session_handle_cancel_pending_query),
                           self);
-        g_signal_connect (skeleton,
-                          "handle-info",
-                          G_CALLBACK (gdm_session_handle_info),
+        g_signal_connect (worker_manager_interface,
+                          "handle-username-changed",
+                          G_CALLBACK (gdm_session_handle_username_changed),
                           self);
-        g_signal_connect (skeleton,
-                          "handle-problem",
-                          G_CALLBACK (gdm_session_handle_problem),
+        g_signal_connect (worker_manager_interface,
+                          "handle-saved-language-name-read",
+                          G_CALLBACK (gdm_session_handle_saved_language_name_read),
                           self);
-        g_signal_connect (skeleton,
-                          "handle-cancel-pending-query",
-                          G_CALLBACK (gdm_session_handle_cancel_pending_query),
+        g_signal_connect (worker_manager_interface,
+                          "handle-saved-session-name-read",
+                          G_CALLBACK (gdm_session_handle_saved_session_name_read),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-service-unavailable",
                           G_CALLBACK (gdm_session_handle_service_unavailable),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-setup-complete",
                           G_CALLBACK (gdm_session_handle_setup_complete),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-setup-failed",
                           G_CALLBACK (gdm_session_handle_setup_failed),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-authenticated",
                           G_CALLBACK (gdm_session_handle_authenticated),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-authentication-failed",
                           G_CALLBACK (gdm_session_handle_authentication_failed),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-authorized",
                           G_CALLBACK (gdm_session_handle_authorized),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-authorization-failed",
                           G_CALLBACK (gdm_session_handle_authorization_failed),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-accredited",
                           G_CALLBACK (gdm_session_handle_accredited),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-accreditation-failed",
                           G_CALLBACK (gdm_session_handle_accreditation_failed),
                           self);
-        g_signal_connect (skeleton,
-                          "handle-username-changed",
-                          G_CALLBACK (gdm_session_handle_username_changed),
+        g_signal_connect (worker_manager_interface,
+                          "handle-info-query",
+                          G_CALLBACK (gdm_session_handle_info_query),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
+                          "handle-secret-info-query",
+                          G_CALLBACK (gdm_session_handle_secret_info_query),
+                          self);
+        g_signal_connect (worker_manager_interface,
+                          "handle-info",
+                          G_CALLBACK (gdm_session_handle_info),
+                          self);
+        g_signal_connect (worker_manager_interface,
+                          "handle-problem",
+                          G_CALLBACK (gdm_session_handle_problem),
+                          self);
+        g_signal_connect (worker_manager_interface,
                           "handle-opened",
                           G_CALLBACK (gdm_session_handle_opened),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-open-failed",
                           G_CALLBACK (gdm_session_handle_open_failed),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-session-started",
                           G_CALLBACK (gdm_session_handle_session_started),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-session-start-failed",
                           G_CALLBACK (gdm_session_handle_session_start_failed),
                           self);
-        g_signal_connect (skeleton,
+        g_signal_connect (worker_manager_interface,
                           "handle-session-exited",
                           G_CALLBACK (gdm_session_handle_session_exited_or_died),
                           self);
-        g_signal_connect (skeleton,
-                          "handle-saved-language-name-read",
-                          G_CALLBACK (gdm_session_handle_saved_language_name_read),
+
+        g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (worker_manager_interface),
+                                          connection,
+                                          GDM_SESSION_DBUS_OBJECT_PATH,
+                                          NULL);
+}
+
+static void
+on_worker_connection_closed (GDBusConnection *connection,
+                             gboolean         remote_peer_vanished,
+                             GError          *error,
+                             GdmSession      *self)
+{
+        self->priv->pending_worker_connections =
+            g_list_remove (self->priv->pending_worker_connections,
+                           connection);
+        g_object_unref (connection);
+}
+
+static gboolean
+handle_connection_from_worker (GDBusServer      *server,
+                               GDBusConnection  *connection,
+                               GdmSession       *self)
+{
+
+        g_debug ("GdmSession: Handling new connection from worker");
+
+        /* add to the list of pending connections.  We won't be able to
+         * associate it with a specific worker conversation until we have
+         * authenticated the connection (from the Hello handler).
+         */
+        self->priv->pending_worker_connections =
+                g_list_prepend (self->priv->pending_worker_connections,
+                                g_object_ref (connection));
+
+        g_signal_connect_object (connection,
+                                 "closed",
+                                 G_CALLBACK (on_worker_connection_closed),
+                                 self,
+                                 0);
+
+        export_worker_manager_interface (self, connection);
+
+        return TRUE;
+}
+
+static gboolean
+gdm_session_handle_client_begin_verification (GdmDBusUserVerifier    *user_verifier_interface,
+                                              GDBusMethodInvocation  *invocation,
+                                              const char             *service_name,
+                                              GdmSession             *self)
+{
+        GdmSessionConversation *conversation;
+
+        gdm_session_start_conversation (self, service_name);
+
+        conversation = find_conversation_by_name (self, service_name);
+
+        if (conversation != NULL) {
+                conversation->starting_invocation = g_object_ref (invocation);
+
+                gdm_session_setup (self, service_name);
+        } else {
+                g_dbus_method_invocation_return_error (conversation->starting_invocation,
+                                                       G_DBUS_ERROR,
+                                                       G_DBUS_ERROR_SPAWN_FAILED,
+                                                       _("Could not create authentication helper process"));
+        }
+
+        return TRUE;
+}
+
+static gboolean
+gdm_session_handle_client_begin_verification_for_user (GdmDBusUserVerifier    *user_verifier_interface,
+                                                       GDBusMethodInvocation  *invocation,
+                                                       const char             *service_name,
+                                                       const char             *username,
+                                                       GdmSession             *self)
+{
+        GdmSessionConversation *conversation;
+
+        gdm_session_start_conversation (self, service_name);
+
+        conversation = find_conversation_by_name (self, service_name);
+
+        if (conversation != NULL) {
+                conversation->starting_invocation = g_object_ref (invocation);
+
+                gdm_session_setup_for_user (self, service_name, username);
+        } else {
+                g_dbus_method_invocation_return_error (conversation->starting_invocation,
+                                                       G_DBUS_ERROR,
+                                                       G_DBUS_ERROR_SPAWN_FAILED,
+                                                       _("Could not create authentication helper process"));
+        }
+
+        return TRUE;
+}
+
+static gboolean
+gdm_session_handle_client_answer_query (GdmDBusUserVerifier    *user_verifier_interface,
+                                        GDBusMethodInvocation  *invocation,
+                                        const char             *service_name,
+                                        const char             *answer,
+                                        GdmSession             *self)
+{
+        gdm_dbus_user_verifier_complete_answer_query (user_verifier_interface,
+                                                      invocation);
+        gdm_session_answer_query (self, service_name, answer);
+        return TRUE;
+}
+
+static gboolean
+gdm_session_handle_client_cancel (GdmDBusUserVerifier    *user_verifier_interface,
+                                  GDBusMethodInvocation  *invocation,
+                                  GdmSession             *self)
+{
+        gdm_dbus_user_verifier_complete_cancel (user_verifier_interface,
+                                                invocation);
+        gdm_session_cancel (self);
+        return TRUE;
+}
+
+static gboolean
+gdm_session_handle_client_select_session (GdmDBusGreeter         *greeter_interface,
+                                          GDBusMethodInvocation  *invocation,
+                                          const char             *session,
+                                          GdmSession             *self)
+{
+        if (self->priv->greeter_interface != NULL) {
+                gdm_dbus_greeter_complete_select_session (greeter_interface,
+                                                          invocation);
+        }
+        gdm_session_select_session (self, session);
+        return TRUE;
+}
+
+static gboolean
+gdm_session_handle_client_select_language (GdmDBusGreeter         *greeter_interface,
+                                           GDBusMethodInvocation  *invocation,
+                                           const char             *language,
+                                           GdmSession             *self)
+{
+        if (self->priv->greeter_interface != NULL) {
+                gdm_dbus_greeter_complete_select_language (greeter_interface,
+                                                           invocation);
+        }
+        gdm_session_select_language (self, language);
+        return TRUE;
+}
+
+static gboolean
+gdm_session_handle_client_select_user (GdmDBusGreeter        *greeter_interface,
+                                       GDBusMethodInvocation *invocation,
+                                       const char            *username,
+                                       GdmSession            *self)
+{
+        if (self->priv->greeter_interface != NULL) {
+                gdm_dbus_greeter_complete_select_user (greeter_interface,
+                                                       invocation);
+        }
+        gdm_session_select_user (self, username);
+        return TRUE;
+}
+
+static gboolean
+gdm_session_handle_client_start_session_when_ready (GdmDBusGreeter        *greeter_interface,
+                                                    GDBusMethodInvocation *invocation,
+                                                    const char            *service_name,
+                                                    gboolean               client_is_ready,
+                                                    GdmSession            *self)
+{
+
+        if (self->priv->greeter_interface != NULL) {
+                gdm_dbus_greeter_complete_start_session_when_ready (greeter_interface,
+                                                                    invocation);
+        }
+        g_signal_emit (G_OBJECT (self),
+                       signals [CLIENT_READY_FOR_SESSION_TO_START],
+                       0,
+                       service_name,
+                       client_is_ready);
+        return TRUE;
+}
+
+static gboolean
+gdm_session_handle_client_begin_auto_login (GdmDBusGreeter        *greeter_interface,
+                                            GDBusMethodInvocation *invocation,
+                                            const char            *username,
+                                            GdmSession            *self)
+{
+        if (self->priv->greeter_interface != NULL) {
+                gdm_dbus_greeter_complete_begin_auto_login (greeter_interface,
+                                                            invocation);
+        }
+
+        g_debug ("GdmSession: begin auto login for user '%s'", username);
+
+        gdm_session_setup_for_user (self, "gdm-autologin", username);
+
+        return TRUE;
+}
+
+static void
+export_user_verifier_interface (GdmSession      *self,
+                                GDBusConnection *connection)
+{
+        GdmDBusUserVerifier   *user_verifier_interface;
+        user_verifier_interface = GDM_DBUS_USER_VERIFIER (gdm_dbus_user_verifier_skeleton_new ());
+        g_signal_connect (user_verifier_interface,
+                          "handle-begin-verification",
+                          G_CALLBACK (gdm_session_handle_client_begin_verification),
                           self);
-        g_signal_connect (skeleton,
-                          "handle-saved-session-name-read",
-                          G_CALLBACK (gdm_session_handle_saved_session_name_read),
+        g_signal_connect (user_verifier_interface,
+                          "handle-begin-verification-for-user",
+                          G_CALLBACK (gdm_session_handle_client_begin_verification_for_user),
+                          self);
+        g_signal_connect (user_verifier_interface,
+                          "handle-answer-query",
+                          G_CALLBACK (gdm_session_handle_client_answer_query),
+                          self);
+        g_signal_connect (user_verifier_interface,
+                          "handle-cancel",
+                          G_CALLBACK (gdm_session_handle_client_cancel),
+                          self);
+
+        g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (user_verifier_interface),
+                                          connection,
+                                          GDM_SESSION_DBUS_OBJECT_PATH,
+                                          NULL);
+
+        self->priv->user_verifier_interface = user_verifier_interface;
+}
+
+static void
+export_greeter_interface (GdmSession      *self,
+                          GDBusConnection *connection)
+{
+        GdmDBusGreeter *greeter_interface;
+
+        greeter_interface = GDM_DBUS_GREETER (gdm_dbus_greeter_skeleton_new ());
+
+        g_signal_connect (greeter_interface,
+                          "handle-begin-auto-login",
+                          G_CALLBACK (gdm_session_handle_client_begin_auto_login),
+                          self);
+        g_signal_connect (greeter_interface,
+                          "handle-select-session",
+                          G_CALLBACK (gdm_session_handle_client_select_session),
+                          self);
+        g_signal_connect (greeter_interface,
+                          "handle-select-language",
+                          G_CALLBACK (gdm_session_handle_client_select_language),
+                          self);
+        g_signal_connect (greeter_interface,
+                          "handle-select-user",
+                          G_CALLBACK (gdm_session_handle_client_select_user),
+                          self);
+        g_signal_connect (greeter_interface,
+                          "handle-start-session-when-ready",
+                          G_CALLBACK (gdm_session_handle_client_start_session_when_ready),
+                          self);
+
+        g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (greeter_interface),
+                                          connection,
+                                          GDM_SESSION_DBUS_OBJECT_PATH,
+                                          NULL);
+
+        self->priv->greeter_interface = greeter_interface;
+
+}
+
+static gboolean
+gdm_session_handle_client_disconnect (GdmDBusChooser        *chooser_interface,
+                                      GDBusMethodInvocation *invocation,
+                                      GdmSession            *self)
+{
+        gdm_dbus_chooser_complete_disconnect (chooser_interface,
+                                              invocation);
+        g_signal_emit (self, signals[DISCONNECTED], 0);
+        return TRUE;
+}
+
+static void
+export_remote_greeter_interface (GdmSession      *self,
+                                 GDBusConnection *connection)
+{
+        GdmDBusRemoteGreeter *remote_greeter_interface;
+
+        remote_greeter_interface = GDM_DBUS_REMOTE_GREETER (gdm_dbus_remote_greeter_skeleton_new ());
+
+        g_signal_connect (remote_greeter_interface,
+                          "handle-disconnect",
+                          G_CALLBACK (gdm_session_handle_client_disconnect),
+                          self);
+
+        g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (remote_greeter_interface),
+                                          connection,
+                                          GDM_SESSION_DBUS_OBJECT_PATH,
+                                          NULL);
+
+        self->priv->remote_greeter_interface = remote_greeter_interface;
+
+}
+
+static gboolean
+gdm_session_handle_client_select_hostname (GdmDBusChooser        *chooser_interface,
+                                           GDBusMethodInvocation *invocation,
+                                           const char            *hostname,
+                                           GdmSession            *self)
+{
+
+        gdm_dbus_chooser_complete_select_hostname (chooser_interface,
+                                                   invocation);
+        g_signal_emit (self, signals[HOSTNAME_SELECTED], 0, hostname);
+        return TRUE;
+}
+
+static void
+export_chooser_interface (GdmSession      *self,
+                          GDBusConnection *connection)
+{
+        GdmDBusChooser *chooser_interface;
+
+        chooser_interface = GDM_DBUS_CHOOSER (gdm_dbus_chooser_skeleton_new ());
+
+        g_signal_connect (chooser_interface,
+                          "handle-select-hostname",
+                          G_CALLBACK (gdm_session_handle_client_select_hostname),
+                          self);
+
+        g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (chooser_interface),
+                                          connection,
+                                          GDM_SESSION_DBUS_OBJECT_PATH,
+                                          NULL);
+
+        self->priv->chooser_interface = chooser_interface;
+}
+
+static void
+on_outside_connection_closed (GDBusConnection *connection,
+                              gboolean         remote_peer_vanished,
+                              GError          *error,
+                              GdmSession      *self)
+{
+        g_debug ("GdmSession: external connection closed");
+
+        self->priv->outside_connections =
+            g_list_remove (self->priv->outside_connections,
+                            connection);
+        g_object_unref (connection);
+
+        g_signal_emit (G_OBJECT (self),
+                       signals [CLIENT_DISCONNECTED],
+                       0);
+}
+
+static gboolean
+handle_connection_from_outside (GDBusServer      *server,
+                                GDBusConnection  *connection,
+                                GdmSession       *self)
+{
+        g_debug ("GdmSession: Handling new connection from outside");
+
+        self->priv->outside_connections =
+            g_list_prepend (self->priv->outside_connections,
+                            g_object_ref (connection));
+
+        g_signal_connect_object (connection,
+                                 "closed",
+                                 G_CALLBACK (on_outside_connection_closed),
+                                 self,
+                                 0);
+
+        export_user_verifier_interface (self, connection);
+
+        switch (self->priv->verification_mode) {
+                case GDM_SESSION_VERIFICATION_MODE_LOGIN:
+                        export_greeter_interface (self, connection);
+                break;
+
+                case GDM_SESSION_VERIFICATION_MODE_CHOOSER:
+                        export_chooser_interface (self, connection);
+                break;
+        }
+
+        if (!self->priv->display_is_local) {
+                export_remote_greeter_interface (self, connection);
+        }
+
+        g_signal_emit (G_OBJECT (self),
+                       signals [CLIENT_CONNECTED],
+                       0);
+
+        return TRUE;
+}
+
+static void
+setup_worker_server (GdmSession *self)
+{
+        GDBusAuthObserver *observer;
+        GDBusServer *server;
+        GError *error = NULL;
+
+        g_debug ("GdmSession: Creating D-Bus server for worker for session");
+
+        observer = g_dbus_auth_observer_new ();
+        g_signal_connect (observer,
+                          "authorize-authenticated-peer",
+                          G_CALLBACK (allow_worker_function),
+                          NULL);
+
+        server = gdm_dbus_setup_private_server (observer, &error);
+        g_object_unref (observer);
+
+        if (server == NULL) {
+                g_warning ("Cannot create worker D-Bus server for the session: %s",
+                           error->message);
+                return;
+        }
+
+        g_signal_connect (server,
+                          "new-connection",
+                          G_CALLBACK (handle_connection_from_worker),
                           self);
+        self->priv->worker_server = server;
 
-        g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (skeleton),
-                                          connection,
-                                          "/org/gnome/DisplayManager/Session",
-                                          NULL);
+        g_dbus_server_start (server);
+
+        g_debug ("GdmSession: D-Bus server for workers listening on %s",
+        g_dbus_server_get_client_address (self->priv->worker_server));
+}
+
+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)
+{
+        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) {
+                return TRUE;
+        }
+
+        g_debug ("GdmSession: User not allowed");
+
+        return FALSE;
+}
+
 static void
-setup_server (GdmSession *self)
+setup_outside_server (GdmSession *self)
 {
         GDBusAuthObserver *observer;
         GDBusServer *server;
         GError *error = NULL;
 
-        g_debug ("GdmSession: Creating D-Bus server for session");
+        g_debug ("GdmSession: Creating D-Bus server for greeters and such");
 
         observer = g_dbus_auth_observer_new ();
         g_signal_connect (observer,
@@ -1165,21 +1692,21 @@ setup_server (GdmSession *self)
         g_object_unref (observer);
 
         if (server == NULL) {
-                g_warning ("Cannot create D-BUS server for the session: %s", error->message);
-                /* FIXME: should probably fail if we can't create the socket */
+                g_warning ("Cannot create greeter D-Bus server for the session: %s",
+                           error->message);
                 return;
         }
 
         g_signal_connect (server,
                           "new-connection",
-                          G_CALLBACK (handle_connection),
+                          G_CALLBACK (handle_connection_from_outside),
                           self);
-        self->priv->server = server;
+        self->priv->outside_server = server;
 
         g_dbus_server_start (server);
 
-        g_debug ("GdmSession: D-Bus server listening on %s",
-        g_dbus_server_get_client_address (self->priv->server));
+        g_debug ("GdmSession: D-Bus server for greeters listening on %s",
+        g_dbus_server_get_client_address (self->priv->outside_server));
 }
 
 static void
@@ -1201,10 +1728,6 @@ gdm_session_init (GdmSession *self)
                                                   GdmSessionPrivate);
 
         g_signal_connect (self,
-                          "authentication-failed",
-                          G_CALLBACK (on_authentication_failed),
-                          NULL);
-        g_signal_connect (self,
                           "session-started",
                           G_CALLBACK (on_session_started),
                           NULL);
@@ -1227,7 +1750,8 @@ gdm_session_init (GdmSession *self)
                                                          (GDestroyNotify) g_free,
                                                          (GDestroyNotify) g_free);
 
-        setup_server (self);
+        setup_worker_server (self);
+        setup_outside_server (self);
 }
 
 static void
@@ -1235,6 +1759,12 @@ worker_started (GdmSessionWorkerJob    *job,
                 GdmSessionConversation *conversation)
 {
         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
@@ -1306,7 +1836,7 @@ start_conversation (GdmSession *self,
         conversation->worker_pid = -1;
         conversation->job = gdm_session_worker_job_new ();
         gdm_session_worker_job_set_server_address (conversation->job,
-                                                   g_dbus_server_get_client_address (self->priv->server));
+                                                   g_dbus_server_get_client_address (self->priv->worker_server));
         g_signal_connect (conversation->job,
                           "started",
                           G_CALLBACK (worker_started),
@@ -1351,7 +1881,7 @@ stop_conversation (GdmSessionConversation *conversation)
 static void
 stop_conversation_now (GdmSessionConversation *conversation)
 {
-        g_clear_object (&conversation->worker_skeleton);
+        g_clear_object (&conversation->worker_manager_interface);
 
         if (conversation->worker_connection != NULL) {
                 g_dbus_connection_close_sync (conversation->worker_connection, NULL, NULL);
@@ -1452,13 +1982,13 @@ send_setup (GdmSession *self,
 
         conversation = find_conversation_by_name (self, service_name);
         if (conversation != NULL) {
-                gdm_dbus_session_emit_setup (conversation->worker_skeleton,
-                                             service_name,
-                                             display_name,
-                                             display_x11_authority_file,
-                                             display_device,
-                                             display_seat_id,
-                                             display_hostname);
+                gdm_dbus_worker_manager_emit_setup (conversation->worker_manager_interface,
+                                                    service_name,
+                                                    display_name,
+                                                    display_x11_authority_file,
+                                                    display_device,
+                                                    display_seat_id,
+                                                    display_hostname);
         }
 }
 
@@ -1512,14 +2042,14 @@ send_setup_for_user (GdmSession *self,
         g_debug ("GdmSession: Beginning setup for user %s", self->priv->selected_user);
 
         if (conversation != NULL) {
-                gdm_dbus_session_emit_setup_for_user (conversation->worker_skeleton,
-                                                      service_name,
-                                                      selected_user,
-                                                      display_name,
-                                                      display_x11_authority_file,
-                                                      display_device,
-                                                      display_seat_id,
-                                                      display_hostname);
+                gdm_dbus_worker_manager_emit_setup_for_user (conversation->worker_manager_interface,
+                                                             service_name,
+                                                             selected_user,
+                                                             display_name,
+                                                             display_x11_authority_file,
+                                                             display_device,
+                                                             display_seat_id,
+                                                             display_hostname);
         }
 }
 
@@ -1567,14 +2097,14 @@ send_setup_for_program (GdmSession *self,
 
         conversation = find_conversation_by_name (self, service_name);
         if (conversation != NULL) {
-                gdm_dbus_session_emit_setup_for_program (conversation->worker_skeleton,
-                                                         service_name,
-                                                         display_name,
-                                                         display_x11_authority_file,
-                                                         display_device,
-                                                         display_seat_id,
-                                                         display_hostname,
-                                                         log_file);
+                gdm_dbus_worker_manager_emit_setup_for_program (conversation->worker_manager_interface,
+                                                                service_name,
+                                                                display_name,
+                                                                display_x11_authority_file,
+                                                                display_device,
+                                                                display_seat_id,
+                                                                display_hostname,
+                                                                log_file);
         }
 }
 
@@ -1589,25 +2119,6 @@ gdm_session_setup (GdmSession *self,
         gdm_session_defaults_changed (self);
 }
 
-typedef struct {
-        GdmSession *instance;
-        char       *service_name;
-} SetupForUserClosure;
-
-static gboolean
-emit_setup_complete (gpointer data)
-{
-        SetupForUserClosure *closure = data;
-
-        g_signal_emit (closure->instance, signals[SETUP_COMPLETE], 0, closure->service_name);
-
-        g_free (closure->service_name);
-        g_object_unref (closure->instance);
-
-        g_slice_free (SetupForUserClosure, data);
-
-        return G_SOURCE_REMOVE;
-}
 
 void
 gdm_session_setup_for_user (GdmSession *self,
@@ -1618,23 +2129,10 @@ gdm_session_setup_for_user (GdmSession *self,
         g_return_if_fail (GDM_IS_SESSION (self));
         g_return_if_fail (username != NULL);
 
-        if (self->priv->session_conversation != NULL &&
-            g_strcmp0 (self->priv->session_conversation->service_name, service_name) == 0) {
-                SetupForUserClosure *closure;
-
-                g_warn_if_fail (g_strcmp0 (self->priv->selected_user, username) == 0);
+        gdm_session_select_user (self, username);
 
-                closure = g_slice_new (SetupForUserClosure);
-                closure->instance = g_object_ref (self);
-                closure->service_name = g_strdup (service_name);
-
-                g_idle_add (emit_setup_complete, closure);
-        } else {
-                gdm_session_select_user (self, username);
-
-                send_setup_for_user (self, service_name);
-                gdm_session_defaults_changed (self);
-        }
+        send_setup_for_user (self, service_name);
+        gdm_session_defaults_changed (self);
 }
 
 void
@@ -1658,8 +2156,8 @@ gdm_session_authenticate (GdmSession *self,
 
         conversation = find_conversation_by_name (self, service_name);
         if (conversation != NULL) {
-                gdm_dbus_session_emit_authenticate (conversation->worker_skeleton,
-                                                    service_name);
+                gdm_dbus_worker_manager_emit_authenticate (conversation->worker_manager_interface,
+                                                           service_name);
         }
 }
 
@@ -1673,15 +2171,14 @@ gdm_session_authorize (GdmSession *self,
 
         conversation = find_conversation_by_name (self, service_name);
         if (conversation != NULL) {
-                gdm_dbus_session_emit_authorize (conversation->worker_skeleton,
-                                                 service_name);
+                gdm_dbus_worker_manager_emit_authorize (conversation->worker_manager_interface,
+                                                        service_name);
         }
 }
 
 void
 gdm_session_accredit (GdmSession *self,
-                      const char *service_name,
-                      gboolean    refresh)
+                      const char *service_name)
 {
         GdmSessionConversation *conversation;
 
@@ -1692,15 +2189,8 @@ gdm_session_accredit (GdmSession *self,
                 return;
         }
 
-        if (refresh) {
-                /* FIXME: need to support refresh
-                 */
-                gdm_dbus_session_emit_establish_credentials (conversation->worker_skeleton,
-                                                             service_name);
-        } else {
-                gdm_dbus_session_emit_establish_credentials (conversation->worker_skeleton,
-                                                             service_name);
-        }
+        gdm_dbus_worker_manager_emit_establish_credentials (conversation->worker_manager_interface,
+                                                            service_name);
 }
 
 static void
@@ -1708,9 +2198,9 @@ send_environment_variable (const char             *key,
                            const char             *value,
                            GdmSessionConversation *conversation)
 {
-        gdm_dbus_session_emit_set_environment_variable (conversation->worker_skeleton,
-                                                        key,
-                                                        value);
+        gdm_dbus_worker_manager_emit_set_environment_variable (conversation->worker_manager_interface,
+                                                               key,
+                                                               value);
 }
 
 static void
@@ -1838,8 +2328,8 @@ gdm_session_open_session (GdmSession *self,
 
         conversation = find_conversation_by_name (self, service_name);
 
-        gdm_dbus_session_emit_open_session (conversation->worker_skeleton,
-                                            service_name);
+        gdm_dbus_worker_manager_emit_open_session (conversation->worker_manager_interface,
+                                                   service_name);
 }
 
 static void
@@ -1935,8 +2425,8 @@ gdm_session_start_session (GdmSession *self,
         setup_session_environment (self);
         send_environment (self, conversation);
 
-        gdm_dbus_session_emit_start_program (conversation->worker_skeleton,
-                                             program);
+        gdm_dbus_worker_manager_emit_start_program (conversation->worker_manager_interface,
+                                                    program);
         g_free (program);
 }
 
@@ -1964,8 +2454,15 @@ gdm_session_close (GdmSession *self)
 
         stop_all_conversations (self);
 
-        g_list_free_full (self->priv->pending_connections, g_object_unref);
-        self->priv->pending_connections = NULL;
+        g_list_free_full (self->priv->outside_connections, g_object_unref);
+        self->priv->outside_connections = NULL;
+
+        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;
@@ -2010,7 +2507,45 @@ gdm_session_cancel  (GdmSession *self)
 {
         g_return_if_fail (GDM_IS_SESSION (self));
 
-        stop_all_conversations (self);
+        g_signal_emit (G_OBJECT (self), signals [CANCELLED], 0);
+}
+
+void
+gdm_session_reset (GdmSession *self)
+{
+        if (self->priv->user_verifier_interface != NULL) {
+                gdm_dbus_user_verifier_emit_reset (self->priv->user_verifier_interface);
+        }
+
+        gdm_session_close (self);
+}
+
+void
+gdm_session_request_timed_login (GdmSession *self,
+                                 const char *username,
+                                 int         delay)
+{
+        if (self->priv->greeter_interface != NULL) {
+                gdm_dbus_greeter_emit_timed_login_requested (self->priv->greeter_interface,
+                                                             username,
+                                                             delay);
+        }
+}
+
+gboolean
+gdm_session_client_is_connected (GdmSession *self)
+{
+        g_return_val_if_fail (GDM_IS_SESSION (self), FALSE);
+
+        return self->priv->outside_connections != NULL;
+}
+
+char *
+gdm_session_get_server_address (GdmSession *self)
+{
+        g_return_val_if_fail (GDM_IS_SESSION (self), NULL);
+
+        return g_strdup (g_dbus_server_get_client_address (self->priv->outside_server));
 }
 
 char *
@@ -2037,6 +2572,22 @@ gdm_session_get_display_seat_id (GdmSession *self)
         return g_strdup (self->priv->display_seat_id);
 }
 
+char *
+gdm_session_get_session_id (GdmSession *self)
+{
+        GdmSessionConversation *conversation;
+
+        g_return_val_if_fail (GDM_IS_SESSION (self), NULL);
+
+        conversation = self->priv->session_conversation;
+
+        if (conversation == NULL) {
+                return NULL;
+        }
+
+        return g_strdup (conversation->session_id);
+}
+
 gboolean
 gdm_session_bypasses_xsession (GdmSession *self)
 {
@@ -2108,8 +2659,8 @@ gdm_session_select_session_type (GdmSession *self,
 
                 conversation = (GdmSessionConversation *) value;
 
-                gdm_dbus_session_emit_set_session_type (conversation->worker_skeleton,
-                                                        text);
+                gdm_dbus_worker_manager_emit_set_session_type (conversation->worker_manager_interface,
+                                                               text);
         }
 }
 
@@ -2134,8 +2685,8 @@ gdm_session_select_session (GdmSession *self,
 
                 conversation = (GdmSessionConversation *) value;
 
-                gdm_dbus_session_emit_set_session_name (conversation->worker_skeleton,
-                                                        get_session_name (self));
+                gdm_dbus_worker_manager_emit_set_session_name (conversation->worker_manager_interface,
+                                                               get_session_name (self));
         }
 }
 
@@ -2160,8 +2711,8 @@ gdm_session_select_language (GdmSession *self,
 
                 conversation = (GdmSessionConversation *) value;
 
-                gdm_dbus_session_emit_set_language_name (conversation->worker_skeleton,
-                                                         get_language_name (self));
+                gdm_dbus_worker_manager_emit_set_language_name (conversation->worker_manager_interface,
+                                                                get_language_name (self));
         }
 }
 
@@ -2223,6 +2774,13 @@ set_display_is_local (GdmSession *self,
         self->priv->display_is_local = is_local;
 }
 
+ static void
+set_verification_mode (GdmSession                 *self,
+                       GdmSessionVerificationMode  verification_mode)
+{
+        self->priv->verification_mode = verification_mode;
+}
+
 static void
 gdm_session_set_property (GObject      *object,
                           guint         prop_id,
@@ -2255,6 +2813,9 @@ 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;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -2293,6 +2854,9 @@ 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;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -2310,9 +2874,6 @@ gdm_session_dispose (GObject *object)
 
         gdm_session_close (self);
 
-        g_free (self->priv->display_id);
-        self->priv->display_id = NULL;
-
         g_free (self->priv->display_name);
         self->priv->display_name = NULL;
 
@@ -2328,9 +2889,9 @@ gdm_session_dispose (GObject *object)
         g_free (self->priv->display_x11_authority_file);
         self->priv->display_x11_authority_file = NULL;
 
-        if (self->priv->server != NULL) {
-                g_dbus_server_stop (self->priv->server);
-                g_clear_object (&self->priv->server);
+        if (self->priv->worker_server != NULL) {
+                g_dbus_server_stop (self->priv->worker_server);
+                g_clear_object (&self->priv->worker_server);
         }
 
         if (self->priv->environment != NULL) {
@@ -2411,17 +2972,6 @@ gdm_session_class_init (GdmSessionClass *session_class)
                               g_cclosure_marshal_VOID__STRING,
                               G_TYPE_NONE,
                               1, G_TYPE_STRING);
-        signals [SERVICE_UNAVAILABLE] =
-                g_signal_new ("service-unavailable",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, service_unavailable),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_VOID__STRING,
-                              G_TYPE_NONE,
-                              1,
-                              G_TYPE_STRING);
         signals [SETUP_COMPLETE] =
                 g_signal_new ("setup-complete",
                               GDM_TYPE_SESSION,
@@ -2433,125 +2983,6 @@ gdm_session_class_init (GdmSessionClass *session_class)
                               G_TYPE_NONE,
                               1,
                               G_TYPE_STRING);
-        signals [SETUP_FAILED] =
-                g_signal_new ("setup-failed",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, setup_failed),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_generic,
-                              G_TYPE_NONE,
-                              2,
-                              G_TYPE_STRING, G_TYPE_STRING);
-        signals [AUTHENTICATED] =
-                g_signal_new ("authenticated",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, authenticated),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_VOID__STRING,
-                              G_TYPE_NONE,
-                              1, G_TYPE_STRING);
-        signals [AUTHENTICATION_FAILED] =
-                g_signal_new ("authentication-failed",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, authentication_failed),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_generic,
-                              G_TYPE_NONE,
-                              2,
-                              G_TYPE_STRING, G_TYPE_STRING);
-        signals [AUTHORIZED] =
-                g_signal_new ("authorized",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, authorized),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_VOID__STRING,
-                              G_TYPE_NONE,
-                              1, G_TYPE_STRING);
-        signals [AUTHORIZATION_FAILED] =
-                g_signal_new ("authorization-failed",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, authorization_failed),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_generic,
-                              G_TYPE_NONE,
-                              2,
-                              G_TYPE_STRING, G_TYPE_STRING);
-        signals [ACCREDITED] =
-                g_signal_new ("accredited",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, accredited),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_VOID__STRING,
-                              G_TYPE_NONE,
-                              1, G_TYPE_STRING);
-        signals [ACCREDITATION_FAILED] =
-                g_signal_new ("accreditation-failed",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, accreditation_failed),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_generic,
-                              G_TYPE_NONE,
-                              2,
-                              G_TYPE_STRING, G_TYPE_STRING);
-
-         signals [INFO_QUERY] =
-                g_signal_new ("info-query",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, info_query),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_generic,
-                              G_TYPE_NONE,
-                              2,
-                              G_TYPE_STRING, G_TYPE_STRING);
-        signals [SECRET_INFO_QUERY] =
-                g_signal_new ("secret-info-query",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, secret_info_query),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_generic,
-                              G_TYPE_NONE,
-                              2,
-                              G_TYPE_STRING, G_TYPE_STRING);
-        signals [INFO] =
-                g_signal_new ("info",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, info),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_generic,
-                              G_TYPE_NONE,
-                              2,
-                              G_TYPE_STRING, G_TYPE_STRING);
-        signals [PROBLEM] =
-                g_signal_new ("problem",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, problem),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_generic,
-                              G_TYPE_NONE,
-                              2,
-                              G_TYPE_STRING, G_TYPE_STRING);
         signals [SESSION_OPENED] =
                 g_signal_new ("session-opened",
                               GDM_TYPE_SESSION,
@@ -2559,21 +2990,11 @@ gdm_session_class_init (GdmSessionClass *session_class)
                               G_STRUCT_OFFSET (GdmSessionClass, session_opened),
                               NULL,
                               NULL,
-                              g_cclosure_marshal_VOID__STRING,
-                              G_TYPE_NONE,
-                              1,
-                              G_TYPE_STRING);
-        signals [SESSION_OPEN_FAILED] =
-                g_signal_new ("session-open-failed",
-                              GDM_TYPE_SESSION,
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, session_open_failed),
                               NULL,
-                              NULL,
-                              g_cclosure_marshal_generic,
                               G_TYPE_NONE,
                               2,
-                              G_TYPE_STRING, G_TYPE_STRING);
+                              G_TYPE_STRING,
+                              G_TYPE_STRING);
         signals [SESSION_STARTED] =
                 g_signal_new ("session-started",
                               GDM_TYPE_SESSION,
@@ -2584,7 +3005,8 @@ gdm_session_class_init (GdmSessionClass *session_class)
                               g_cclosure_marshal_generic,
                               G_TYPE_NONE,
                               2,
-                              G_TYPE_STRING, G_TYPE_INT);
+                              G_TYPE_STRING,
+                              G_TYPE_INT);
         signals [SESSION_START_FAILED] =
                 g_signal_new ("session-start-failed",
                               GDM_TYPE_SESSION,
@@ -2618,41 +3040,82 @@ gdm_session_class_init (GdmSessionClass *session_class)
                               G_TYPE_NONE,
                               1,
                               G_TYPE_INT);
-        signals [SELECTED_USER_CHANGED] =
-                g_signal_new ("selected-user-changed",
+        signals [CANCELLED] =
+                g_signal_new ("cancelled",
                               GDM_TYPE_SESSION,
                               G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, selected_user_changed),
+                              G_STRUCT_OFFSET (GdmSessionClass, cancelled),
                               NULL,
                               NULL,
-                              g_cclosure_marshal_VOID__STRING,
+                              g_cclosure_marshal_VOID__VOID,
                               G_TYPE_NONE,
-                              1,
-                              G_TYPE_STRING);
-        signals [DEFAULT_LANGUAGE_NAME_CHANGED] =
-                g_signal_new ("default-language-name-changed",
+                              0);
+
+        signals [CLIENT_CONNECTED] =
+                g_signal_new ("client-connected",
                               GDM_TYPE_SESSION,
                               G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, default_language_name_changed),
+                              G_STRUCT_OFFSET (GdmSessionClass, client_connected),
                               NULL,
                               NULL,
-                              g_cclosure_marshal_VOID__STRING,
+                              g_cclosure_marshal_VOID__VOID,
                               G_TYPE_NONE,
-                              1,
-                              G_TYPE_STRING);
-        signals [DEFAULT_SESSION_NAME_CHANGED] =
-                g_signal_new ("default-session-name-changed",
+                              0);
+
+        signals [CLIENT_DISCONNECTED] =
+                g_signal_new ("client-disconnected",
                               GDM_TYPE_SESSION,
                               G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmSessionClass, default_session_name_changed),
+                              G_STRUCT_OFFSET (GdmSessionClass, client_disconnected),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE,
+                              0);
+        signals [CLIENT_READY_FOR_SESSION_TO_START] =
+                g_signal_new ("client-ready-for-session-to-start",
+                              GDM_TYPE_SESSION,
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmSessionClass, client_ready_for_session_to_start),
+                              NULL,
+                              NULL,
+                              NULL,
+                              G_TYPE_NONE,
+                              2,
+                              G_TYPE_STRING,
+                              G_TYPE_BOOLEAN);
+
+        signals [HOSTNAME_SELECTED] =
+                g_signal_new ("hostname-selected",
+                              GDM_TYPE_SESSION,
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmSessionClass, disconnected),
+                              NULL,
                               NULL,
                               NULL,
-                              g_cclosure_marshal_VOID__STRING,
                               G_TYPE_NONE,
                               1,
                               G_TYPE_STRING);
+        signals [DISCONNECTED] =
+                g_signal_new ("disconnected",
+                              GDM_TYPE_SESSION,
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmSessionClass, disconnected),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE,
+                              0);
 
         g_object_class_install_property (object_class,
+                                         PROP_VERIFICATION_MODE,
+                                         g_param_spec_enum ("verification-mode",
+                                                            "verification mode",
+                                                            "verification mode",
+                                                            GDM_TYPE_SESSION_VERIFICATION_MODE,
+                                                            GDM_SESSION_VERIFICATION_MODE_LOGIN,
+                                                            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",
@@ -2706,16 +3169,18 @@ 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,
+                 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,
                              "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 2810c89..ad5f885 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_CHOOSER
+} GdmSessionVerificationMode;
+
 typedef struct
 {
         GObject            parent;
@@ -45,49 +51,20 @@ typedef struct
         GObjectClass parent_class;
 
         /* Signals */
-        void (* setup_complete)              (GdmSession   *session,
-                                              const char   *service_name);
-        void (* setup_failed)                (GdmSession   *session,
-                                              const char   *service_name,
-                                              const char   *message);
-        void (* reset_complete)              (GdmSession   *session);
-        void (* reset_failed)                (GdmSession   *session,
-                                              const char   *message);
-        void (* authenticated)               (GdmSession   *session,
-                                              const char   *service_name);
-        void (* authentication_failed)       (GdmSession   *session,
-                                              const char   *service_name,
-                                              const char   *message);
-        void (* authorized)                  (GdmSession   *session,
-                                              const char   *service_name);
-        void (* authorization_failed)        (GdmSession   *session,
-                                              const char   *service_name,
-                                              const char   *message);
-        void (* accredited)                  (GdmSession   *session,
-                                              const char   *service_name);
-        void (* accreditation_failed)        (GdmSession   *session,
-                                              const char   *service_name,
-                                              const char   *message);
-
-        void (* info_query)                  (GdmSession   *session,
-                                              const char   *service_name,
-                                              const char   *query_text);
-        void (* secret_info_query)           (GdmSession   *session,
-                                              const char   *service_name,
-                                              const char   *query_text);
-        void (* info)                        (GdmSession   *session,
-                                              const char   *service_name,
-                                              const char   *info);
-        void (* problem)                     (GdmSession   *session,
-                                              const char   *service_name,
-                                              const char   *problem);
+        void (* client_ready_for_session_to_start) (GdmSession   *session,
+                                                    const char   *service_name,
+                                                    gboolean      client_is_ready);
+
+        void (* cancelled)                   (GdmSession   *session);
+        void (* client_connected)            (GdmSession   *session);
+        void (* client_disconnected)         (GdmSession   *session);
+        void (* disconnected)                (GdmSession   *session);
         void (* session_opened)              (GdmSession   *session,
-                                              const char   *service_name);
-        void (* session_open_failed)         (GdmSession   *session,
                                               const char   *service_name,
-                                              const char   *message);
+                                              const char   *session_id);
         void (* session_started)             (GdmSession   *session,
                                               const char   *service_name,
+                                              const char   *session_id,
                                               int           pid);
         void (* session_start_failed)        (GdmSession   *session,
                                               const char   *service_name,
@@ -100,29 +77,25 @@ typedef struct
                                               const char   *service_name);
         void (* conversation_stopped)        (GdmSession   *session,
                                               const char   *service_name);
-        void (* service_unavailable)         (GdmSession   *session,
+        void (* setup_complete)              (GdmSession   *session,
                                               const char   *service_name);
-        void (* selected_user_changed)       (GdmSession   *session,
-                                              const char   *text);
-
-        void (* default_language_name_changed)    (GdmSession   *session,
-                                                   const char   *text);
-        void (* default_session_name_changed)     (GdmSession   *session,
-                                                   const char   *text);
 } GdmSessionClass;
 
 GType            gdm_session_get_type                 (void);
 
-GdmSession      *gdm_session_new                      (const char *display_name,
+GdmSession      *gdm_session_new                      (GdmSessionVerificationMode verification_mode,
+                                                       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);
 
+char             *gdm_session_get_server_address          (GdmSession     *session);
 char             *gdm_session_get_username                (GdmSession     *session);
 char             *gdm_session_get_display_device          (GdmSession     *session);
 char             *gdm_session_get_display_seat_id         (GdmSession     *session);
+char             *gdm_session_get_session_id              (GdmSession     *session);
 gboolean          gdm_session_bypasses_xsession           (GdmSession     *session);
 
 void              gdm_session_start_conversation          (GdmSession *session,
@@ -146,8 +119,7 @@ void              gdm_session_authenticate                (GdmSession *session,
 void              gdm_session_authorize                   (GdmSession *session,
                                                            const char *service_name);
 void              gdm_session_accredit                    (GdmSession *session,
-                                                           const char *service_name,
-                                                           int         cred_flag);
+                                                           const char *service_name);
 void              gdm_session_open_session                (GdmSession *session,
                                                            const char *service_name);
 void              gdm_session_start_session               (GdmSession *session,
@@ -168,6 +140,11 @@ void              gdm_session_select_language             (GdmSession *session,
 void              gdm_session_select_user                 (GdmSession *session,
                                                            const char *username);
 void              gdm_session_cancel                      (GdmSession *session);
+void              gdm_session_reset                       (GdmSession *session);
+void              gdm_session_request_timed_login         (GdmSession *session,
+                                                           const char *username,
+                                                           int         delay);
+gboolean          gdm_session_client_is_connected         (GdmSession *session);
 
 G_END_DECLS
 
diff --git a/daemon/gdm-session.xml b/daemon/gdm-session.xml
index c320c09..292d416 100644
--- a/daemon/gdm-session.xml
+++ b/daemon/gdm-session.xml
@@ -2,15 +2,7 @@
 <node name="/org/gnome/DisplayManager/Session">
   <!-- methods are called by the session worker,
        signals are emitted by the simple slave -->
-  <interface name="org.gnome.DisplayManager.Session">
-    <method name="ConversationStarted">
-      <arg name="service_name" direction="in" type="s"/>
-    </method>
-    <signal name="StartConversation">
-      <arg name="service_name" type="s"/>
-    </signal>
-    <signal name="Close"/>
-    <signal name="Cancelled"/>
+  <interface name="org.gnome.DisplayManager.WorkerManager">
     <method name="Hello" />
     <method name="CancelPendingQuery">
       <arg name="service_name" type="s" direction="in"/>
@@ -25,9 +17,6 @@
     <method name="SavedSessionNameRead">
       <arg name="session_name" type="s" direction="in"/>
     </method>
-    <signal name="StartProgram">
-      <arg name="command" type="s"/>
-    </signal>
     <method name="ServiceUnavailable">
       <arg name="service_name" direction="in" type="s"/>
       <arg name="message" direction="in" type="s"/>
@@ -62,24 +51,25 @@
     </method>
     <method name="InfoQuery">
       <arg name="service_name" direction="in" type="s"/>
-      <arg name="text" direction="in" type="s"/>
+      <arg name="query" direction="in" type="s"/>
       <arg name="answer" direction="out" type="s"/>
     </method>
     <method name="SecretInfoQuery">
       <arg name="service_name" direction="in" type="s"/>
-      <arg name="text" direction="in" type="s"/>
+      <arg name="query" direction="in" type="s"/>
       <arg name="answer" direction="out" type="s"/>
     </method>
     <method name="Info">
       <arg name="service_name" direction="in" type="s"/>
-      <arg name="text" direction="in" type="s"/>
+      <arg name="info" direction="in" type="s"/>
     </method>
     <method name="Problem">
       <arg name="service_name" direction="in" type="s"/>
-      <arg name="text" direction="in" type="s"/>
+      <arg name="problem" direction="in" type="s"/>
     </method>
     <method name="Opened">
       <arg name="service_name" direction="in" type="s"/>
+      <arg name="session_id" direction="in" type="s"/>
     </method>
     <method name="OpenFailed">
       <arg name="service_name" direction="in" type="s"/>
@@ -100,6 +90,14 @@
       <arg name="status" direction="in" type="i"/>
     </method>
 
+    <signal name="StartConversation">
+      <arg name="service_name" type="s"/>
+    </signal>
+    <signal name="StartProgram">
+      <arg name="command" type="s"/>
+    </signal>
+    <signal name="Close"/>
+    <signal name="Cancelled"/>
     <signal name="Reset" />
     <signal name="Setup">
       <arg name="service_name" type="s"/>
@@ -156,4 +154,87 @@
       <arg name="session_type" type="s" />
     </signal>
   </interface>
+  <interface name="org.gnome.DisplayManager.UserVerifier">
+    <method name="BeginVerification">
+      <arg name="service_name" direction="in" type="s"/>
+    </method>
+    <method name="BeginVerificationForUser">
+      <arg name="service_name" direction="in" type="s"/>
+      <arg name="username" direction="in" type="s"/>
+    </method>
+    <method name="AnswerQuery">
+      <arg name="service_name" direction="in" type="s"/>
+      <arg name="answer" direction="in" type="s"/>
+    </method>
+    <method name="Cancel">
+    </method>
+    <signal name="Info">
+      <arg name="service_name" type="s"/>
+      <arg name="info" type="s"/>
+    </signal>
+    <signal name="Problem">
+      <arg name="service_name" type="s"/>
+      <arg name="problem" type="s"/>
+    </signal>
+    <signal name="InfoQuery">
+      <arg name="service_name" type="s"/>
+      <arg name="query" type="s"/>
+    </signal>
+    <signal name="SecretInfoQuery">
+      <arg name="service_name" type="s"/>
+      <arg name="query" type="s"/>
+    </signal>
+    <signal name="Reset">
+    </signal>
+    <signal name="ServiceUnavailable">
+      <arg name="service_name" type="s"/>
+      <arg name="message" type="s"/>
+    </signal>
+    <signal name="VerificationComplete">
+      <arg name="service_name" type="s"/>
+    </signal>
+  </interface>
+  <interface name="org.gnome.DisplayManager.Greeter">
+    <method name="SelectSession">
+      <arg name="session" direction="in" type="s"/>
+    </method>
+    <method name="SelectLanguage">
+      <arg name="language" direction="in" type="s"/>
+    </method>
+    <method name="SelectUser">
+      <arg name="username" direction="in" type="s"/>
+    </method>
+    <method name="BeginAutoLogin">
+      <arg name="username" direction="in" type="s"/>
+    </method>
+    <method name="StartSessionWhenReady">
+      <arg name="service_name" direction="in" type="s"/>
+      <arg name="should_start_session" direction="in" type="b"/>
+    </method>
+    <signal name="SelectedUserChanged">
+      <arg name="username" type="s"/>
+    </signal>
+    <signal name="DefaultLanguageNameChanged">
+      <arg name="language_name" type="s"/>
+    </signal>
+    <signal name="DefaultSessionNameChanged">
+      <arg name="session_name" type="s"/>
+    </signal>
+    <signal name="TimedLoginRequested">
+      <arg name="username" type="s"/>
+      <arg name="delay" type="i"/>
+    </signal>
+    <signal name="SessionOpened">
+      <arg name="service_name" type="s"/>
+    </signal>
+  </interface>
+  <interface name="org.gnome.DisplayManager.RemoteGreeter">
+    <method name="Disconnect" />
+  </interface>
+  <interface name="org.gnome.DisplayManager.Chooser">
+    <method name="SelectHostname">
+      <arg name="hostname" direction="in" type="s"/>
+    </method>
+    <method name="Disconnect" />
+  </interface>
 </node>
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index a9138be..be6aa27 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -49,7 +49,7 @@
 
 #include "gdm-server.h"
 #include "gdm-session.h"
-#include "gdm-greeter-server.h"
+#include "gdm-session-glue.h"
 #include "gdm-greeter-session.h"
 #include "gdm-settings-direct.h"
 #include "gdm-settings-keys.h"
@@ -65,8 +65,7 @@
 struct GdmSimpleSlavePrivate
 {
         GPid               pid;
-
-        guint              greeter_reset_id;
+        gint               greeter_reset_id;
         guint              start_session_id;
 
         char              *start_session_service_name;
@@ -78,12 +77,11 @@ struct GdmSimpleSlavePrivate
 
         GdmServer         *server;
         GdmSession        *session;
-
-        GdmGreeterServer  *greeter_server;
         GdmGreeterSession *greeter;
 
         guint              start_session_when_ready : 1;
         guint              waiting_to_start_session : 1;
+        guint              session_is_running : 1;
 #ifdef  HAVE_LOGINDEVPERM
         gboolean           use_logindevperm;
 #endif
@@ -102,10 +100,9 @@ static void     gdm_simple_slave_finalize       (GObject             *object);
 
 G_DEFINE_TYPE (GdmSimpleSlave, gdm_simple_slave, GDM_TYPE_SLAVE)
 
-static void create_new_session (GdmSimpleSlave *slave);
-static void destroy_session    (GdmSimpleSlave *slave);
+static void create_new_session (GdmSimpleSlave  *slave);
 static void start_greeter      (GdmSimpleSlave *slave);
-static void start_session      (GdmSimpleSlave *slave);
+static void start_session      (GdmSimpleSlave  *slave);
 static void queue_start_session (GdmSimpleSlave *slave,
                                  const char     *service_name);
 
@@ -116,9 +113,16 @@ on_session_started (GdmSession       *session,
                     GdmSimpleSlave   *slave)
 {
         char *username;
+        char *session_id;
 
         g_debug ("GdmSimpleSlave: session started %d", pid);
 
+        slave->priv->session_is_running = TRUE;
+
+        session_id = gdm_session_get_session_id (session);
+        g_object_set (GDM_SLAVE (slave), "session-id", session_id, NULL);
+        g_free (session_id);
+
         /* Run the PreSession script. gdmslave suspends until script has terminated */
         username = gdm_session_get_username (slave->priv->session);
         if (username != NULL) {
@@ -209,6 +213,9 @@ on_session_exited (GdmSession       *session,
                    int               exit_code,
                    GdmSimpleSlave   *slave)
 {
+        slave->priv->session_is_running = FALSE;
+        g_object_set (GDM_SLAVE (slave), "session-id", NULL, NULL);
+
         g_debug ("GdmSimpleSlave: session exited with code %d\n", exit_code);
         if (slave->priv->start_session_service_name == NULL) {
                 gdm_slave_stopped (GDM_SLAVE (slave));
@@ -220,6 +227,9 @@ on_session_died (GdmSession       *session,
                  int               signal_number,
                  GdmSimpleSlave   *slave)
 {
+        slave->priv->session_is_running = FALSE;
+        g_object_set (GDM_SLAVE (slave), "session-id", NULL, NULL);
+
         g_debug ("GdmSimpleSlave: session died with signal %d, (%s)",
                  signal_number,
                  g_strsignal (signal_number));
@@ -246,30 +256,28 @@ add_user_authorization (GdmSimpleSlave *slave,
 }
 
 static void
-reset_session (GdmSimpleSlave *slave)
+reset_session (GdmSimpleSlave  *slave)
 {
-        destroy_session (slave);
-        create_new_session (slave);
+        if (slave->priv->session == NULL) {
+                return;
+        }
+
+        gdm_session_reset (slave->priv->session);
 }
 
 static gboolean
-greeter_reset_timeout (GdmSimpleSlave *slave)
+greeter_reset_timeout (GdmSimpleSlave  *slave)
 {
         g_debug ("GdmSimpleSlave: resetting greeter");
 
-        if (slave->priv->greeter_server != NULL) {
-                gdm_greeter_server_reset (slave->priv->greeter_server);
-                reset_session (slave);
-        } else {
-                start_greeter (slave);
-                create_new_session (slave);
-        }
+        reset_session (slave);
+
         slave->priv->greeter_reset_id = 0;
         return FALSE;
 }
 
 static void
-queue_greeter_reset (GdmSimpleSlave *slave)
+queue_greeter_reset (GdmSimpleSlave  *slave)
 {
         if (slave->priv->greeter_reset_id > 0) {
                 return;
@@ -279,66 +287,6 @@ queue_greeter_reset (GdmSimpleSlave *slave)
 }
 
 static void
-on_session_service_unavailable (GdmSession       *session,
-                                const char       *service_name,
-                                GdmSimpleSlave   *slave)
-{
-        if (slave->priv->greeter_server != NULL) {
-                gdm_greeter_server_service_unavailable (slave->priv->greeter_server,
-                                                        service_name);
-        }
-
-        gdm_session_stop_conversation (session, service_name);
-}
-
-static void
-on_session_setup_complete (GdmSession       *session,
-                           const char       *service_name,
-                           GdmSimpleSlave   *slave)
-{
-        gdm_session_authenticate (session, service_name);
-}
-
-static void
-on_session_setup_failed (GdmSession       *session,
-                         const char       *service_name,
-                         const char       *message,
-                         GdmSimpleSlave   *slave)
-{
-        if (slave->priv->greeter_server != NULL) {
-                gdm_greeter_server_problem (slave->priv->greeter_server,
-                                            service_name,
-                                            message != NULL ? message:  _("Unable to initialize login system"));
-        }
-
-        gdm_session_stop_conversation (session, service_name);
-}
-
-static void
-on_session_authenticated (GdmSession       *session,
-                          const char       *service_name,
-                          GdmSimpleSlave   *slave)
-{
-        gdm_session_authorize (session, service_name);
-}
-
-static void
-on_session_authentication_failed (GdmSession       *session,
-                                  const char       *service_name,
-                                  const char       *message,
-                                  GdmSimpleSlave   *slave)
-{
-        if (slave->priv->greeter_server != NULL) {
-                gdm_greeter_server_problem (slave->priv->greeter_server,
-                                            service_name,
-                                            message != NULL ? message : _("Unable to authenticate user"));
-        }
-
-        g_debug ("GdmSimpleSlave: Authentication failed - may retry");
-        gdm_session_stop_conversation (session, service_name);
-}
-
-static void
 gdm_simple_slave_start_session_when_ready (GdmSimpleSlave *slave,
                                            const char     *service_name)
 {
@@ -350,32 +298,8 @@ gdm_simple_slave_start_session_when_ready (GdmSimpleSlave *slave,
         }
 }
 
-static void
-on_session_authorized (GdmSession       *session,
-                       const char       *service_name,
-                       GdmSimpleSlave   *slave)
-{
-        /* FIXME: we don't yet support refresh */
-        gdm_session_accredit (slave->priv->session, service_name, FALSE);
-}
-
-static void
-on_session_authorization_failed (GdmSession       *session,
-                                 const char       *service_name,
-                                 const char       *message,
-                                 GdmSimpleSlave   *slave)
-{
-        if (slave->priv->greeter_server != NULL) {
-                gdm_greeter_server_problem (slave->priv->greeter_server,
-                                            service_name,
-                                            message != NULL ? message :  _("Unable to authorize user"));
-        }
-
-        gdm_session_stop_conversation (session, service_name);
-}
-
 static gboolean
-try_migrate_session (GdmSimpleSlave *slave)
+try_migrate_session (GdmSimpleSlave  *slave)
 {
         char    *username;
         gboolean res;
@@ -418,9 +342,10 @@ stop_greeter (GdmSimpleSlave *slave)
 }
 
 static void
-start_session (GdmSimpleSlave *slave)
+start_session (GdmSimpleSlave  *slave)
 {
-        char    *auth_file;
+        char           *auth_file;
+
         auth_file = NULL;
         add_user_authorization (slave, &auth_file);
 
@@ -433,7 +358,7 @@ start_session (GdmSimpleSlave *slave)
         g_free (auth_file);
 
         gdm_session_start_session (slave->priv->session,
-                                          slave->priv->start_session_service_name);
+                                   slave->priv->start_session_service_name);
 
         slave->priv->start_session_id = 0;
         g_free (slave->priv->start_session_service_name);
@@ -441,23 +366,21 @@ start_session (GdmSimpleSlave *slave)
 }
 
 static gboolean
-start_session_timeout (GdmSimpleSlave *slave)
+start_session_timeout (GdmSimpleSlave  *slave)
 {
-
         gboolean migrated;
 
+
         g_debug ("GdmSimpleSlave: accredited");
 
         migrated = try_migrate_session (slave);
         g_debug ("GdmSimpleSlave: migrated: %d", migrated);
         if (migrated) {
-                destroy_session (slave);
-
                 /* We don't stop the slave here because
                    when Xorg exits it switches to the VT it was
                    started from.  That interferes with fast
                    user switching. */
-                queue_greeter_reset (slave);
+                gdm_session_reset (slave->priv->session);
 
                 slave->priv->start_session_id = 0;
                 g_free (slave->priv->start_session_service_name);
@@ -488,147 +411,44 @@ queue_start_session (GdmSimpleSlave *slave,
 }
 
 static void
-on_session_accredited (GdmSession       *session,
-                       const char       *service_name,
-                       GdmSimpleSlave   *slave)
-{
-        gdm_session_open_session (session, service_name);
-}
-
-static void
-on_session_accreditation_failed (GdmSession       *session,
-                                 const char       *service_name,
-                                 const char       *message,
-                                 GdmSimpleSlave   *slave)
-{
-        gboolean migrated;
-
-        g_debug ("GdmSimpleSlave: accreditation failed");
-
-        migrated = try_migrate_session (slave);
-
-        /* If we switched to another session we don't care if
-           accreditation fails */
-        if (! migrated) {
-                if (slave->priv->greeter_server != NULL) {
-                        const char *problem;
-                        if (message) {
-                                problem = message;
-                        } else {
-                                problem = _("Unable to establish credentials");
-                        }
-                        gdm_greeter_server_problem (slave->priv->greeter_server,
-                                                    service_name,
-                                                    problem);
-                }
-        }
-
-        gdm_session_stop_conversation (session, service_name);
-}
-
-static void
 on_session_opened (GdmSession       *session,
                    const char       *service_name,
+                   const char       *session_id,
                    GdmSimpleSlave   *slave)
 {
+
 #ifdef  HAVE_LOGINDEVPERM
         gdm_simple_slave_grant_console_permissions (slave);
 #endif  /* HAVE_LOGINDEVPERM */
 
-        if (slave->priv->greeter_server != NULL) {
-                gdm_greeter_server_session_opened (slave->priv->greeter_server, service_name);
+        if (gdm_session_client_is_connected (slave->priv->session)) {
                 gdm_simple_slave_start_session_when_ready (slave, service_name);
         } else {
+                /* Auto login */
                 slave->priv->start_session_when_ready = TRUE;
                 gdm_simple_slave_start_session_when_ready (slave, service_name);
         }
 }
 
 static void
-on_session_open_failed (GdmSession       *session,
-                        const char       *service_name,
-                        const char       *message,
-                        GdmSimpleSlave   *slave)
-{
-        if (slave->priv->greeter_server != NULL) {
-                gdm_greeter_server_problem (slave->priv->greeter_server,
-                                            service_name,
-                                            _("Unable to open session"));
-        }
-
-        gdm_session_stop_conversation (session, service_name);
-}
-
-static void
-on_session_info (GdmSession       *session,
-                 const char       *service_name,
-                 const char       *text,
-                 GdmSimpleSlave   *slave)
-{
-        g_debug ("GdmSimpleSlave: Info: %s", text);
-        if (slave->priv->greeter_server != NULL) {
-                gdm_greeter_server_info (slave->priv->greeter_server, service_name, text);
-        }
-}
-
-static void
-on_session_problem (GdmSession       *session,
-                    const char       *service_name,
-                    const char       *text,
-                    GdmSimpleSlave   *slave)
-{
-        g_debug ("GdmSimpleSlave: Problem: %s", text);
-        gdm_greeter_server_problem (slave->priv->greeter_server, service_name, text);
-}
-
-static void
-on_session_info_query (GdmSession       *session,
-                       const char       *service_name,
-                       const char       *text,
-                       GdmSimpleSlave   *slave)
-{
-
-        g_debug ("GdmSimpleSlave: Info query: %s", text);
-        gdm_greeter_server_info_query (slave->priv->greeter_server, service_name, text);
-}
-
-static void
-on_session_secret_info_query (GdmSession       *session,
-                              const char       *service_name,
-                              const char       *text,
-                              GdmSimpleSlave   *slave)
-{
-        g_debug ("GdmSimpleSlave: Secret info query: %s", text);
-        gdm_greeter_server_secret_info_query (slave->priv->greeter_server, service_name, text);
-}
-
-static void
 on_session_conversation_started (GdmSession       *session,
                                  const char       *service_name,
                                  GdmSimpleSlave   *slave)
 {
-        gboolean res;
         gboolean enabled;
         char    *username;
         int      delay;
 
-        g_debug ("GdmSimpleSlave: session conversation started");
-        if (slave->priv->greeter_server != NULL) {
-                res = gdm_greeter_server_ready (slave->priv->greeter_server,
-                                                service_name);
-                if (! res) {
-                        g_warning ("Unable to send ready");
-                }
-        }
 
+        g_debug ("GdmSimpleSlave: session conversation started");
         enabled = FALSE;
         gdm_slave_get_timed_login_details (GDM_SLAVE (slave), &enabled, &username, &delay);
         if (! enabled) {
                 return;
         }
 
-        if (slave->priv->greeter_server != NULL) {
-                gdm_greeter_server_request_timed_login (slave->priv->greeter_server, username, delay);
+        if (delay > 0) {
+                gdm_session_request_timed_login (session, username, delay);
         } else {
                 g_debug ("GdmSimpleSlave: begin auto login for user '%s'", username);
                 /* service_name will be "gdm-autologin"
@@ -644,70 +464,93 @@ on_session_conversation_stopped (GdmSession       *session,
                                  const char       *service_name,
                                  GdmSimpleSlave   *slave)
 {
-        gboolean res;
         g_debug ("GdmSimpleSlave: conversation stopped");
 
-        if (slave->priv->greeter != NULL) {
-                res = gdm_greeter_server_conversation_stopped (slave->priv->greeter_server,
-                                                               service_name);
-                if (! res) {
-                        g_warning ("Unable to send conversation stopped");
-                }
-        }
 }
 
 static void
-on_session_selected_user_changed (GdmSession       *session,
-                                  const char       *text,
-                                  GdmSimpleSlave   *slave)
+start_autologin_conversation_if_necessary (GdmSimpleSlave  *slave)
 {
-        g_debug ("GdmSimpleSlave: Selected user changed: %s", text);
+        gboolean enabled;
 
-        if (slave->priv->greeter_server != NULL) {
-                gdm_greeter_server_selected_user_changed (slave->priv->greeter_server, text);
+        gdm_slave_get_timed_login_details (GDM_SLAVE (slave), &enabled, NULL, NULL);
+
+        if (!enabled) {
+                return;
         }
+
+        g_debug ("GdmSimpleSlave: Starting automatic login conversation");
+        gdm_session_start_conversation (slave->priv->session, "gdm-autologin");
 }
 
 static void
-on_default_language_name_changed (GdmSession       *session,
-                                  const char       *text,
-                                  GdmSimpleSlave   *slave)
+on_session_client_ready_for_session_to_start (GdmSession      *session,
+                                              const char      *service_name,
+                                              gboolean         client_is_ready,
+                                              GdmSimpleSlave  *slave)
 {
-        g_debug ("GdmSimpleSlave: Default language name changed: %s", text);
 
-        if (slave->priv->greeter_server != NULL) {
-                gdm_greeter_server_default_language_name_changed (slave->priv->greeter_server, text);
+        if (client_is_ready) {
+                g_debug ("GdmSimpleSlave: Will start session when ready");
+        } else {
+                g_debug ("GdmSimpleSlave: Will start session when ready and told");
+        }
+
+        if (slave->priv->greeter_reset_id > 0) {
+                return;
         }
-}
 
+        slave->priv->start_session_when_ready = client_is_ready;
+
+        if (client_is_ready && slave->priv->waiting_to_start_session) {
+                gdm_simple_slave_start_session_when_ready (slave, service_name);
+        }
+}
 static void
-on_default_session_name_changed (GdmSession       *session,
-                                 const char       *text,
-                                 GdmSimpleSlave   *slave)
+on_session_client_connected (GdmSession          *session,
+                             GdmSimpleSlave      *slave)
 {
-        g_debug ("GdmSimpleSlave: Default session name changed: %s", text);
+        gboolean display_is_local;
+
+        g_debug ("GdmSimpleSlave: client connected");
 
-        if (slave->priv->greeter_server != NULL) {
-                gdm_greeter_server_default_session_name_changed (slave->priv->greeter_server, text);
+        g_object_get (slave,
+                      "display-is-local", &display_is_local,
+                      NULL);
+
+        /* If XDMCP stop pinging */
+        if ( ! display_is_local) {
+                alarm (0);
         }
 }
 
 static void
-start_autologin_conversation_if_necessary (GdmSimpleSlave *slave)
+on_session_client_disconnected (GdmSession          *session,
+                                GdmSimpleSlave      *slave)
 {
-        gboolean enabled;
-        gdm_slave_get_timed_login_details (GDM_SLAVE (slave), &enabled, NULL, NULL);
+        gboolean display_is_local;
 
-        if (!enabled) {
-                return;
+        g_debug ("GdmSimpleSlave: client disconnected");
+
+        g_object_get (slave,
+                      "display-is-local", &display_is_local,
+                      NULL);
+
+        if ( ! display_is_local) {
+                gdm_slave_stopped (GDM_SLAVE (slave));
         }
+}
 
-        g_debug ("GdmSimpleSlave: Starting automatic login conversation");
-        gdm_session_start_conversation (slave->priv->session, "gdm-autologin");
+static void
+on_session_cancelled (GdmSession      *session,
+                      GdmSimpleSlave  *slave)
+{
+        g_debug ("GdmSimpleSlave: Session was cancelled");
+        queue_greeter_reset (slave);
 }
 
 static void
-create_new_session (GdmSimpleSlave *slave)
+create_new_session (GdmSimpleSlave  *slave)
 {
         gboolean       display_is_local;
         char          *display_id;
@@ -733,86 +576,48 @@ 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,
+                                                display_name,
                                                 display_hostname,
                                                 display_device,
                                                 display_seat_id,
                                                 display_x11_authority_file,
                                                 display_is_local);
+
         g_free (display_id);
         g_free (display_name);
         g_free (display_device);
         g_free (display_hostname);
 
         g_signal_connect (slave->priv->session,
-                          "conversation-started",
-                          G_CALLBACK (on_session_conversation_started),
-                          slave);
-        g_signal_connect (slave->priv->session,
-                          "conversation-stopped",
-                          G_CALLBACK (on_session_conversation_stopped),
-                          slave);
-        g_signal_connect (slave->priv->session,
-                          "service-unavailable",
-                          G_CALLBACK (on_session_service_unavailable),
-                          slave);
-        g_signal_connect (slave->priv->session,
-                          "setup-complete",
-                          G_CALLBACK (on_session_setup_complete),
-                          slave);
-        g_signal_connect (slave->priv->session,
-                          "setup-failed",
-                          G_CALLBACK (on_session_setup_failed),
+                          "client-ready-for-session-to-start",
+                          G_CALLBACK (on_session_client_ready_for_session_to_start),
                           slave);
         g_signal_connect (slave->priv->session,
-                          "authenticated",
-                          G_CALLBACK (on_session_authenticated),
+                          "client-connected",
+                          G_CALLBACK (on_session_client_connected),
                           slave);
         g_signal_connect (slave->priv->session,
-                          "authentication-failed",
-                          G_CALLBACK (on_session_authentication_failed),
+                          "client-disconnected",
+                          G_CALLBACK (on_session_client_disconnected),
                           slave);
         g_signal_connect (slave->priv->session,
-                          "authorized",
-                          G_CALLBACK (on_session_authorized),
-                          slave);
-        g_signal_connect (slave->priv->session,
-                          "authorization-failed",
-                          G_CALLBACK (on_session_authorization_failed),
+                          "cancelled",
+                          G_CALLBACK (on_session_cancelled),
                           slave);
         g_signal_connect (slave->priv->session,
-                          "accredited",
-                          G_CALLBACK (on_session_accredited),
+                          "conversation-started",
+                          G_CALLBACK (on_session_conversation_started),
                           slave);
         g_signal_connect (slave->priv->session,
-                          "accreditation-failed",
-                          G_CALLBACK (on_session_accreditation_failed),
+                          "conversation-stopped",
+                          G_CALLBACK (on_session_conversation_stopped),
                           slave);
         g_signal_connect (slave->priv->session,
                           "session-opened",
                           G_CALLBACK (on_session_opened),
                           slave);
         g_signal_connect (slave->priv->session,
-                          "session-open-failed",
-                          G_CALLBACK (on_session_open_failed),
-                          slave);
-        g_signal_connect (slave->priv->session,
-                          "info",
-                          G_CALLBACK (on_session_info),
-                          slave);
-        g_signal_connect (slave->priv->session,
-                          "problem",
-                          G_CALLBACK (on_session_problem),
-                          slave);
-        g_signal_connect (slave->priv->session,
-                          "info-query",
-                          G_CALLBACK (on_session_info_query),
-                          slave);
-        g_signal_connect (slave->priv->session,
-                          "secret-info-query",
-                          G_CALLBACK (on_session_secret_info_query),
-                          slave);
-        g_signal_connect (slave->priv->session,
                           "session-started",
                           G_CALLBACK (on_session_started),
                           slave);
@@ -824,123 +629,38 @@ create_new_session (GdmSimpleSlave *slave)
                           "session-died",
                           G_CALLBACK (on_session_died),
                           slave);
-        g_signal_connect (slave->priv->session,
-                          "selected-user-changed",
-                          G_CALLBACK (on_session_selected_user_changed),
-                          slave);
-
-        g_signal_connect (slave->priv->session,
-                          "default-language-name-changed",
-                          G_CALLBACK (on_default_language_name_changed),
-                          slave);
-
-        g_signal_connect (slave->priv->session,
-                          "default-session-name-changed",
-                          G_CALLBACK (on_default_session_name_changed),
-                          slave);
 
         start_autologin_conversation_if_necessary (slave);
 }
 
 static void
-destroy_session (GdmSimpleSlave *slave)
+on_greeter_session_opened (GdmGreeterSession *greeter,
+                           GdmSimpleSlave    *slave)
 {
-        if (slave->priv->session == NULL) {
-                return;
-        }
+        char       *session_id;
 
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_conversation_started),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_conversation_stopped),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_service_unavailable),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_setup_complete),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_setup_failed),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_authenticated),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_authentication_failed),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_authorized),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_authorization_failed),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_accredited),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_accreditation_failed),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_opened),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_open_failed),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_info),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_problem),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_info_query),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_secret_info_query),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_started),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_exited),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_died),
-                                              slave);
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_session_selected_user_changed),
-                                              slave);
-
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_default_language_name_changed),
-                                              slave);
-
-        g_signal_handlers_disconnect_by_func (slave->priv->session,
-                                              G_CALLBACK (on_default_session_name_changed),
-                                              slave);
-
-        gdm_session_close (slave->priv->session);
-        g_clear_object (&slave->priv->session);
+        g_debug ("GdmSimpleSlave: Greeter session opened");
+        session_id = gdm_welcome_session_get_session_id (GDM_WELCOME_SESSION (greeter));
+
+        g_object_set (GDM_SLAVE (slave), "session-id", session_id, NULL);
+        g_free (session_id);
 }
 
 static void
-on_greeter_session_start (GdmGreeterSession *greeter,
-                          GdmSimpleSlave    *slave)
+on_greeter_session_started (GdmGreeterSession *greeter,
+                            GdmSimpleSlave    *slave)
 {
         g_debug ("GdmSimpleSlave: Greeter started");
 }
 
 static void
-on_greeter_session_stop (GdmGreeterSession *greeter,
-                         GdmSimpleSlave    *slave)
+on_greeter_session_stopped (GdmGreeterSession *greeter,
+                            GdmSimpleSlave    *slave)
 {
         g_debug ("GdmSimpleSlave: Greeter stopped");
         if (slave->priv->start_session_service_name == NULL) {
                 gdm_slave_stopped (GDM_SLAVE (slave));
         } else {
-                gdm_greeter_server_stop (slave->priv->greeter_server);
                 start_session (slave);
         }
 
@@ -971,172 +691,6 @@ on_greeter_session_died (GdmGreeterSession    *greeter,
         }
 }
 
-static void
-on_greeter_start_conversation (GdmGreeterServer *greeter_server,
-                               const char       *service_name,
-                               GdmSimpleSlave   *slave)
-{
-        if (slave->priv->greeter_reset_id > 0) {
-                return;
-        }
-
-        g_debug ("GdmSimpleSlave: starting conversation with '%s' pam service'", service_name);
-        gdm_session_start_conversation (slave->priv->session, service_name);
-}
-
-static void
-on_greeter_begin_verification (GdmGreeterServer *greeter_server,
-                               const char       *service_name,
-                               GdmSimpleSlave   *slave)
-{
-        g_debug ("GdmSimpleSlave: begin verification");
-        if (slave->priv->greeter_reset_id > 0) {
-                return;
-        }
-        gdm_session_setup (slave->priv->session, service_name);
-}
-
-static void
-on_greeter_begin_auto_login (GdmGreeterServer *greeter_server,
-                             const char       *username,
-                             GdmSimpleSlave   *slave)
-{
-        g_debug ("GdmSimpleSlave: begin auto login for user '%s'", username);
-        if (slave->priv->greeter_reset_id > 0) {
-                return;
-        }
-        gdm_session_setup_for_user (slave->priv->session, "gdm-autologin", username);
-}
-
-static void
-on_greeter_begin_verification_for_user (GdmGreeterServer *greeter_server,
-                                        const char       *service_name,
-                                        const char       *username,
-                                        GdmSimpleSlave   *slave)
-{
-        g_debug ("GdmSimpleSlave: begin verification");
-        if (slave->priv->greeter_reset_id > 0) {
-                return;
-        }
-        gdm_session_setup_for_user (slave->priv->session, service_name, username);
-}
-
-static void
-on_greeter_answer (GdmGreeterServer *greeter_server,
-                   const char       *service_name,
-                   const char       *text,
-                   GdmSimpleSlave   *slave)
-{
-        if (slave->priv->greeter_reset_id > 0) {
-                return;
-        }
-        gdm_session_answer_query (slave->priv->session, service_name, text);
-}
-
-static void
-on_greeter_session_selected (GdmGreeterServer *greeter_server,
-                             const char       *text,
-                             GdmSimpleSlave   *slave)
-{
-        if (slave->priv->greeter_reset_id > 0) {
-                return;
-        }
-        gdm_session_select_session (slave->priv->session, text);
-}
-
-static void
-on_greeter_language_selected (GdmGreeterServer *greeter_server,
-                              const char       *text,
-                              GdmSimpleSlave   *slave)
-{
-        if (slave->priv->greeter_reset_id > 0) {
-                return;
-        }
-        gdm_session_select_language (slave->priv->session, text);
-}
-
-static void
-on_greeter_user_selected (GdmGreeterServer *greeter_server,
-                          const char       *text,
-                          GdmSimpleSlave   *slave)
-{
-        g_debug ("GdmSimpleSlave: Greeter user selected");
-}
-
-static void
-on_greeter_cancel (GdmGreeterServer *greeter_server,
-                   GdmSimpleSlave   *slave)
-{
-        g_debug ("GdmSimpleSlave: Greeter cancelled");
-        queue_greeter_reset (slave);
-}
-
-static void
-on_greeter_connected (GdmGreeterServer *greeter_server,
-                      GdmSimpleSlave   *slave)
-{
-        gboolean display_is_local;
-
-        g_debug ("GdmSimpleSlave: Greeter connected");
-        if (slave->priv->greeter_reset_id > 0) {
-                return;
-        }
-
-        g_object_get (slave,
-                      "display-is-local", &display_is_local,
-                      NULL);
-
-        /* If XDMCP stop pinging */
-        if ( ! display_is_local) {
-                alarm (0);
-        }
-}
-
-static void
-on_greeter_disconnected (GdmGreeterServer *greeter_server,
-                         GdmSimpleSlave   *slave)
-{
-        gboolean display_is_local;
-
-        g_debug ("GdmSimpleSlave: Greeter disconnected");
-
-        g_object_get (slave,
-                      "display-is-local", &display_is_local,
-                      NULL);
-
-        if ( ! display_is_local) {
-                gdm_slave_stopped (GDM_SLAVE (slave));
-        }
-}
-
-static void
-on_start_session_when_ready (GdmGreeterServer *session,
-                             const char       *service_name,
-                             GdmSimpleSlave   *slave)
-{
-        g_debug ("GdmSimpleSlave: Will start session when ready");
-        if (slave->priv->greeter_reset_id > 0) {
-                return;
-        }
-        slave->priv->start_session_when_ready = TRUE;
-
-        if (slave->priv->waiting_to_start_session) {
-                gdm_simple_slave_start_session_when_ready (slave, service_name);
-        }
-}
-
-static void
-on_start_session_later (GdmGreeterServer *session,
-                        const char       *service_name,
-                        GdmSimpleSlave   *slave)
-{
-        g_debug ("GdmSimpleSlave: Will start session when ready and told");
-        if (slave->priv->greeter_reset_id > 0) {
-                return;
-        }
-        slave->priv->start_session_when_ready = FALSE;
-}
-
 #ifdef  WITH_PLYMOUTH
 static gboolean
 plymouth_is_running (void)
@@ -1242,7 +796,6 @@ start_greeter (GdmSimpleSlave *slave)
         char          *display_device;
         char          *display_hostname;
         char          *auth_file;
-        char          *address;
         gboolean       res;
 
         g_debug ("GdmSimpleSlave: Running greeter");
@@ -1284,63 +837,6 @@ start_greeter (GdmSimpleSlave *slave)
         /* Run the init script. gdmslave suspends until script has terminated */
         gdm_slave_run_script (GDM_SLAVE (slave), GDMCONFDIR "/Init", GDM_USERNAME);
 
-        slave->priv->greeter_server = gdm_greeter_server_new (display_id);
-        g_signal_connect (slave->priv->greeter_server,
-                          "start-conversation",
-                          G_CALLBACK (on_greeter_start_conversation),
-                          slave);
-        g_signal_connect (slave->priv->greeter_server,
-                          "begin-auto-login",
-                          G_CALLBACK (on_greeter_begin_auto_login),
-                          slave);
-        g_signal_connect (slave->priv->greeter_server,
-                          "begin-verification",
-                          G_CALLBACK (on_greeter_begin_verification),
-                          slave);
-        g_signal_connect (slave->priv->greeter_server,
-                          "begin-verification-for-user",
-                          G_CALLBACK (on_greeter_begin_verification_for_user),
-                          slave);
-        g_signal_connect (slave->priv->greeter_server,
-                          "query-answer",
-                          G_CALLBACK (on_greeter_answer),
-                          slave);
-        g_signal_connect (slave->priv->greeter_server,
-                          "session-selected",
-                          G_CALLBACK (on_greeter_session_selected),
-                          slave);
-        g_signal_connect (slave->priv->greeter_server,
-                          "language-selected",
-                          G_CALLBACK (on_greeter_language_selected),
-                          slave);
-        g_signal_connect (slave->priv->greeter_server,
-                          "user-selected",
-                          G_CALLBACK (on_greeter_user_selected),
-                          slave);
-        g_signal_connect (slave->priv->greeter_server,
-                          "connected",
-                          G_CALLBACK (on_greeter_connected),
-                          slave);
-        g_signal_connect (slave->priv->greeter_server,
-                          "disconnected",
-                          G_CALLBACK (on_greeter_disconnected),
-                          slave);
-        g_signal_connect (slave->priv->greeter_server,
-                          "cancelled",
-                          G_CALLBACK (on_greeter_cancel),
-                          slave);
-        g_signal_connect (slave->priv->greeter_server,
-                          "start-session-when-ready",
-                          G_CALLBACK (on_start_session_when_ready),
-                          slave);
-
-        g_signal_connect (slave->priv->greeter_server,
-                          "start-session-later",
-                          G_CALLBACK (on_start_session_later),
-                          slave);
-
-        gdm_greeter_server_start (slave->priv->greeter_server);
-
         g_debug ("GdmSimpleSlave: Creating greeter on %s %s %s", display_name, display_device, display_hostname);
         slave->priv->greeter = gdm_greeter_session_new (display_name,
                                                         seat_id,
@@ -1348,12 +844,16 @@ start_greeter (GdmSimpleSlave *slave)
                                                         display_hostname,
                                                         display_is_local);
         g_signal_connect (slave->priv->greeter,
+                          "opened",
+                          G_CALLBACK (on_greeter_session_opened),
+                          slave);
+        g_signal_connect (slave->priv->greeter,
                           "started",
-                          G_CALLBACK (on_greeter_session_start),
+                          G_CALLBACK (on_greeter_session_started),
                           slave);
         g_signal_connect (slave->priv->greeter,
                           "stopped",
-                          G_CALLBACK (on_greeter_session_stop),
+                          G_CALLBACK (on_greeter_session_stopped),
                           slave);
         g_signal_connect (slave->priv->greeter,
                           "exited",
@@ -1367,9 +867,6 @@ start_greeter (GdmSimpleSlave *slave)
                       "x11-authority-file", auth_file,
                       NULL);
 
-        address = gdm_greeter_server_get_address (slave->priv->greeter_server);
-        gdm_welcome_session_set_server_address (GDM_WELCOME_SESSION (slave->priv->greeter), address);
-        g_free (address);
         gdm_welcome_session_start (GDM_WELCOME_SESSION (slave->priv->greeter));
 
         g_free (display_id);
@@ -1543,6 +1040,37 @@ gdm_simple_slave_run (GdmSimpleSlave *slave)
 }
 
 static gboolean
+gdm_simple_slave_open_session (GdmSlave   *slave,
+                               char      **address,
+                               GError    **error)
+{
+        GdmSimpleSlave  *self = GDM_SIMPLE_SLAVE (slave);
+        GdmSession      *session;
+
+        if (self->priv->session_is_running) {
+                g_set_error (error,
+                             G_DBUS_ERROR,
+                             G_DBUS_ERROR_ACCESS_DENIED,
+                             _("Greeter access only currently supported"));
+                return FALSE;
+        }
+
+        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;
+}
+
+static gboolean
 gdm_simple_slave_start (GdmSlave *slave)
 {
         GDM_SLAVE_CLASS (gdm_simple_slave_parent_class)->start (slave);
@@ -1565,7 +1093,7 @@ gdm_simple_slave_stop (GdmSlave *slave)
                 stop_greeter (self);
         }
 
-        if (self->priv->session != NULL) {
+        if (self->priv->session_is_running) {
                 char *username;
 
                 /* Run the PostSession script. gdmslave suspends until script
@@ -1646,6 +1174,7 @@ gdm_simple_slave_class_init (GdmSimpleSlaveClass *klass)
 
         slave_class->start = gdm_simple_slave_start;
         slave_class->stop = gdm_simple_slave_stop;
+        slave_class->open_session = gdm_simple_slave_open_session;
 
         g_type_class_add_private (klass, sizeof (GdmSimpleSlavePrivate));
 }
@@ -1662,20 +1191,20 @@ gdm_simple_slave_init (GdmSimpleSlave *slave)
 static void
 gdm_simple_slave_finalize (GObject *object)
 {
-        GdmSimpleSlave *simple_slave;
+        GdmSimpleSlave *slave;
 
         g_return_if_fail (object != NULL);
         g_return_if_fail (GDM_IS_SIMPLE_SLAVE (object));
 
-        simple_slave = GDM_SIMPLE_SLAVE (object);
+        slave = GDM_SIMPLE_SLAVE (object);
 
-        g_return_if_fail (simple_slave->priv != NULL);
+        g_return_if_fail (slave->priv != NULL);
 
-        gdm_simple_slave_stop (GDM_SLAVE (simple_slave));
+        gdm_simple_slave_stop (GDM_SLAVE (slave));
 
-        if (simple_slave->priv->greeter_reset_id > 0) {
-                g_source_remove (simple_slave->priv->greeter_reset_id);
-                simple_slave->priv->greeter_reset_id = 0;
+        if (slave->priv->greeter_reset_id > 0) {
+                g_source_remove (slave->priv->greeter_reset_id);
+                slave->priv->greeter_reset_id = 0;
         }
 
         G_OBJECT_CLASS (gdm_simple_slave_parent_class)->finalize (object);
diff --git a/daemon/gdm-slave.c b/daemon/gdm-slave.c
index 97a5544..fbee296 100644
--- a/daemon/gdm-slave.c
+++ b/daemon/gdm-slave.c
@@ -88,6 +88,8 @@ struct GdmSlavePrivate
 
         Display         *server_display;
 
+        char            *session_id;
+
         /* cached display values */
         char            *display_id;
         char            *display_name;
@@ -104,10 +106,12 @@ struct GdmSlavePrivate
 
         GdmDBusDisplay  *display_proxy;
         GDBusConnection *connection;
+        GdmDBusSlave    *skeleton;
 };
 
 enum {
         PROP_0,
+        PROP_SESSION_ID,
         PROP_DISPLAY_ID,
         PROP_DISPLAY_NAME,
         PROP_DISPLAY_NUMBER,
@@ -132,6 +136,17 @@ G_DEFINE_ABSTRACT_TYPE (GdmSlave, gdm_slave, G_TYPE_OBJECT)
 
 #define CURSOR_WATCH XC_watch
 
+GQuark
+gdm_slave_error_quark (void)
+{
+        static GQuark ret = 0;
+        if (ret == 0) {
+                ret = g_quark_from_static_string ("gdm-slave-error-quark");
+        }
+
+        return ret;
+}
+
 static void
 gdm_slave_whack_temp_auth_file (GdmSlave *slave)
 {
@@ -1709,6 +1724,14 @@ gdm_slave_switch_to_user_session (GdmSlave   *slave,
 }
 
 static void
+_gdm_slave_set_session_id (GdmSlave   *slave,
+                           const char *id)
+{
+        g_free (slave->priv->session_id);
+        slave->priv->session_id = g_strdup (id);
+}
+
+static void
 _gdm_slave_set_display_id (GdmSlave   *slave,
                            const char *id)
 {
@@ -1773,6 +1796,9 @@ gdm_slave_set_property (GObject      *object,
         self = GDM_SLAVE (object);
 
         switch (prop_id) {
+        case PROP_SESSION_ID:
+                _gdm_slave_set_session_id (self, g_value_get_string (value));
+                break;
         case PROP_DISPLAY_ID:
                 _gdm_slave_set_display_id (self, g_value_get_string (value));
                 break;
@@ -1811,6 +1837,9 @@ gdm_slave_get_property (GObject    *object,
         self = GDM_SLAVE (object);
 
         switch (prop_id) {
+        case PROP_SESSION_ID:
+                g_value_set_string (value, self->priv->session_id);
+                break;
         case PROP_DISPLAY_ID:
                 g_value_set_string (value, self->priv->display_id);
                 break;
@@ -1839,6 +1868,40 @@ gdm_slave_get_property (GObject    *object,
 }
 
 static gboolean
+handle_open_session (GdmDBusSlave          *skeleton,
+                     GDBusMethodInvocation *invocation,
+                     GdmSlave              *slave)
+{
+        GError        *error;
+        GdmSlaveClass *slave_class;
+        char          *address;
+
+        slave_class = GDM_SLAVE_GET_CLASS (slave);
+        if (slave_class->open_session == 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;
+        }
+
+        error = NULL;
+        address = NULL;
+        if (!slave_class->open_session (slave,
+                                        &address,
+                                        &error)) {
+                g_dbus_method_invocation_return_gerror (invocation, error);
+                g_error_free (error);
+                return TRUE;
+        }
+
+        gdm_dbus_slave_complete_open_session (skeleton, invocation, address);
+
+        g_free (address);
+
+        return TRUE;
+}
+
+static gboolean
 register_slave (GdmSlave *slave)
 {
         GError *error;
@@ -1853,6 +1916,22 @@ register_slave (GdmSlave *slave)
                 exit (1);
         }
 
+        slave->priv->skeleton = GDM_DBUS_SLAVE (gdm_dbus_slave_skeleton_new ());
+
+        g_signal_connect (slave->priv->skeleton,
+                          "handle-open-session",
+                          G_CALLBACK (handle_open_session),
+                          slave);
+
+        g_object_bind_property (G_OBJECT (slave),
+                                "session-id",
+                                G_OBJECT (slave->priv->skeleton),
+                                "session-id",
+                                G_BINDING_DEFAULT);
+
+        gdm_slave_export_interface (slave,
+                                    G_DBUS_INTERFACE_SKELETON (slave->priv->skeleton));
+
         return TRUE;
 }
 
@@ -1893,6 +1972,13 @@ gdm_slave_class_init (GdmSlaveClass *klass)
         g_type_class_add_private (klass, sizeof (GdmSlavePrivate));
 
         g_object_class_install_property (object_class,
+                                         PROP_SESSION_ID,
+                                         g_param_spec_string ("session-id",
+                                                              "Session id",
+                                                              "ID of session",
+                                                              NULL,
+                                                              G_PARAM_READWRITE));
+        g_object_class_install_property (object_class,
                                          PROP_DISPLAY_ID,
                                          g_param_spec_string ("display-id",
                                                               "id",
diff --git a/daemon/gdm-slave.h b/daemon/gdm-slave.h
index 79ef064..ee3dcbc 100644
--- a/daemon/gdm-slave.h
+++ b/daemon/gdm-slave.h
@@ -50,10 +50,25 @@ typedef struct
         gboolean (*start) (GdmSlave *slave);
         gboolean (*stop)  (GdmSlave *slave);
 
+        gboolean (*open_session) (GdmSlave    *slave,
+                                  char       **address,
+                                  GError     **error);
+
         /* signals */
         void (*stopped) (GdmSlave *slave);
 } GdmSlaveClass;
 
+typedef enum
+{
+        GDM_SLAVE_ERROR_GENERIC,
+        GDM_SLAVE_ERROR_UNSUPPORTED,
+        GDM_SLAVE_ERROR_NOT_OPENED,
+        GDM_SLAVE_ERROR_WRONG_SESSION,
+} GdmSlaveError;
+
+#define GDM_SLAVE_ERROR (gdm_slave_error_quark ())
+
+GQuark              gdm_slave_error_quark            (void);
 GType               gdm_slave_get_type               (void);
 gboolean            gdm_slave_start                  (GdmSlave   *slave);
 gboolean            gdm_slave_stop                   (GdmSlave   *slave);
@@ -84,10 +99,8 @@ gboolean            gdm_slave_run_script             (GdmSlave   *slave,
                                                       const char *dir,
                                                       const char *username);
 void                gdm_slave_stopped                (GdmSlave   *slave);
-
 void                gdm_slave_export_interface       (GdmSlave               *slave,
                                                       GDBusInterfaceSkeleton *interface);
-
 G_END_DECLS
 
 #endif /* __GDM_SLAVE_H */
diff --git a/daemon/gdm-slave.xml b/daemon/gdm-slave.xml
index 6566594..b6e57cf 100644
--- a/daemon/gdm-slave.xml
+++ b/daemon/gdm-slave.xml
@@ -1,5 +1,10 @@
 <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd";>
 <node>
   <interface name="org.gnome.DisplayManager.Slave">
-  </interface>
+    <method name="OpenSession">
+      <arg name="address" type="s" direction="out" />
+    </method>
+
+    <property name="session_id" type="s" access="read"/>â
+  </interface>â
 </node>
diff --git a/daemon/gdm-welcome-session.c b/daemon/gdm-welcome-session.c
index 693fbf7..e8947b5 100644
--- a/daemon/gdm-welcome-session.c
+++ b/daemon/gdm-welcome-session.c
@@ -43,7 +43,7 @@
 
 #include "gdm-common.h"
 
-#include "gdm-session.h"
+#include "gdm-session-enum-types.h"
 #include "gdm-welcome-session.h"
 
 #define DBUS_LAUNCH_COMMAND BINDIR "/dbus-launch"
@@ -56,14 +56,17 @@ extern char **environ;
 
 struct GdmWelcomeSessionPrivate
 {
-        GdmSession       *session;
+        GdmSession     *session;
         char           *command;
         GPid            pid;
 
+        GdmSessionVerificationMode verification_mode;
+
         char           *user_name;
         char           *group_name;
         char           *runtime_dir;
 
+        char           *session_id;
         char           *x11_display_name;
         char           *x11_display_seat_id;
         char           *x11_display_device;
@@ -75,13 +78,13 @@ struct GdmWelcomeSessionPrivate
         char           *dbus_bus_address;
         char           *server_dbus_path;
         char           *server_dbus_interface;
-        char           *server_env_var_name;
 
         char           *server_address;
 };
 
 enum {
         PROP_0,
+        PROP_VERIFICATION_MODE,
         PROP_X11_DISPLAY_NAME,
         PROP_X11_DISPLAY_SEAT_ID,
         PROP_X11_DISPLAY_DEVICE,
@@ -91,14 +94,13 @@ enum {
         PROP_USER_NAME,
         PROP_GROUP_NAME,
         PROP_RUNTIME_DIR,
-        PROP_SERVER_ADDRESS,
         PROP_COMMAND,
         PROP_SERVER_DBUS_PATH,
         PROP_SERVER_DBUS_INTERFACE,
-        PROP_SERVER_ENV_VAR_NAME
 };
 
 enum {
+        OPENED,
         STARTED,
         STOPPED,
         EXITED,
@@ -274,11 +276,6 @@ build_welcome_environment (GdmWelcomeSession *welcome_session,
                                      g_strdup ("DBUS_SESSION_BUS_ADDRESS"),
                                      g_strdup (welcome_session->priv->dbus_bus_address));
         }
-        if (welcome_session->priv->server_address != NULL) {
-                g_assert (welcome_session->priv->server_env_var_name != NULL);
-                g_hash_table_insert (hash, g_strdup (welcome_session->priv->server_env_var_name),
-                                     g_strdup (welcome_session->priv->server_address));
-        }
 
         g_hash_table_insert (hash, g_strdup ("XAUTHORITY"), g_strdup (welcome_session->priv->x11_authority_file));
         g_hash_table_insert (hash, g_strdup ("DISPLAY"), g_strdup (welcome_session->priv->x11_display_name));
@@ -695,39 +692,17 @@ on_session_setup_complete (GdmSession        *session,
         g_hash_table_destroy (hash);
 
         gdm_session_select_session_type (welcome_session->priv->session, "LoginWindow");
-
-        gdm_session_authenticate (welcome_session->priv->session, service_name);
-}
-
-static void
-on_session_authenticated (GdmSession        *session,
-                          const char        *service_name,
-                          GdmWelcomeSession *welcome_session)
-{
-        gdm_session_authorize (welcome_session->priv->session, service_name);
-}
-
-static void
-on_session_authorized (GdmSession        *session,
-                       const char        *service_name,
-                       GdmWelcomeSession *welcome_session)
-{
-        gdm_session_accredit (welcome_session->priv->session, service_name, FALSE);
-}
-
-static void
-on_session_accredited (GdmSession        *session,
-                       const char        *service_name,
-                       GdmWelcomeSession *welcome_session)
-{
-        gdm_session_open_session (welcome_session->priv->session, service_name);
 }
 
 static void
 on_session_opened (GdmSession        *session,
                    const char        *service_name,
+                   const char        *session_id,
                    GdmWelcomeSession *welcome_session)
 {
+        welcome_session->priv->session_id = g_strdup (session_id);
+
+        g_signal_emit (G_OBJECT (welcome_session), signals [OPENED], 0);
         gdm_session_start_session (welcome_session->priv->session, service_name);
 }
 
@@ -818,7 +793,8 @@ gdm_welcome_session_start (GdmWelcomeSession *welcome_session)
                 return FALSE;
         }
 
-        welcome_session->priv->session = gdm_session_new (welcome_session->priv->x11_display_name,
+        welcome_session->priv->session = gdm_session_new (welcome_session->priv->verification_mode,
+                                                          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,
@@ -838,18 +814,6 @@ gdm_welcome_session_start (GdmWelcomeSession *welcome_session)
                           G_CALLBACK (on_session_setup_complete),
                           welcome_session);
         g_signal_connect (welcome_session->priv->session,
-                          "authenticated",
-                          G_CALLBACK (on_session_authenticated),
-                          welcome_session);
-        g_signal_connect (welcome_session->priv->session,
-                          "authorized",
-                          G_CALLBACK (on_session_authorized),
-                          welcome_session);
-        g_signal_connect (welcome_session->priv->session,
-                          "accredited",
-                          G_CALLBACK (on_session_accredited),
-                          welcome_session);
-        g_signal_connect (welcome_session->priv->session,
                           "session-opened",
                           G_CALLBACK (on_session_opened),
                           welcome_session);
@@ -892,14 +856,23 @@ gdm_welcome_session_stop (GdmWelcomeSession *welcome_session)
         return TRUE;
 }
 
-void
-gdm_welcome_session_set_server_address (GdmWelcomeSession *welcome_session,
-                                        const char        *address)
+GdmSession *
+gdm_welcome_session_get_session (GdmWelcomeSession *welcome_session)
 {
-        g_return_if_fail (GDM_IS_WELCOME_SESSION (welcome_session));
+        return welcome_session->priv->session;
+}
 
-        g_free (welcome_session->priv->server_address);
-        welcome_session->priv->server_address = g_strdup (address);
+char *
+gdm_welcome_session_get_session_id (GdmWelcomeSession *welcome_session)
+{
+        return g_strdup (welcome_session->priv->session_id);
+}
+
+static void
+_gdm_welcome_session_set_verification_mode (GdmWelcomeSession           *welcome_session,
+                                            GdmSessionVerificationMode   verification_mode)
+{
+        welcome_session->priv->verification_mode = verification_mode;
 }
 
 static void
@@ -998,14 +971,6 @@ _gdm_welcome_session_set_command (GdmWelcomeSession *welcome_session,
 }
 
 static void
-_gdm_welcome_session_set_server_env_var_name (GdmWelcomeSession *welcome_session,
-                                              const char        *name)
-{
-        g_free (welcome_session->priv->server_env_var_name);
-        welcome_session->priv->server_env_var_name = g_strdup (name);
-}
-
-static void
 gdm_welcome_session_set_property (GObject      *object,
                                   guint         prop_id,
                                   const GValue *value,
@@ -1016,6 +981,9 @@ gdm_welcome_session_set_property (GObject      *object,
         self = GDM_WELCOME_SESSION (object);
 
         switch (prop_id) {
+        case PROP_VERIFICATION_MODE:
+                _gdm_welcome_session_set_verification_mode (self, g_value_get_enum (value));
+                break;
         case PROP_X11_DISPLAY_NAME:
                 _gdm_welcome_session_set_x11_display_name (self, g_value_get_string (value));
                 break;
@@ -1043,18 +1011,12 @@ gdm_welcome_session_set_property (GObject      *object,
         case PROP_RUNTIME_DIR:
                 _gdm_welcome_session_set_runtime_dir (self, g_value_get_string (value));
                 break;
-        case PROP_SERVER_ADDRESS:
-                gdm_welcome_session_set_server_address (self, g_value_get_string (value));
-                break;
         case PROP_SERVER_DBUS_PATH:
                 _gdm_welcome_session_set_server_dbus_path (self, g_value_get_string (value));
                 break;
         case PROP_SERVER_DBUS_INTERFACE:
                 _gdm_welcome_session_set_server_dbus_interface (self, g_value_get_string (value));
                 break;
-        case PROP_SERVER_ENV_VAR_NAME:
-                _gdm_welcome_session_set_server_env_var_name (self, g_value_get_string (value));
-                break;
         case PROP_COMMAND:
                 _gdm_welcome_session_set_command (self, g_value_get_string (value));
                 break;
@@ -1075,6 +1037,9 @@ gdm_welcome_session_get_property (GObject    *object,
         self = GDM_WELCOME_SESSION (object);
 
         switch (prop_id) {
+        case PROP_VERIFICATION_MODE:
+                g_value_set_enum (value, self->priv->verification_mode);
+                break;
         case PROP_X11_DISPLAY_NAME:
                 g_value_set_string (value, self->priv->x11_display_name);
                 break;
@@ -1102,18 +1067,12 @@ gdm_welcome_session_get_property (GObject    *object,
         case PROP_RUNTIME_DIR:
                 g_value_set_string (value, self->priv->runtime_dir);
                 break;
-        case PROP_SERVER_ADDRESS:
-                g_value_set_string (value, self->priv->server_address);
-                break;
         case PROP_SERVER_DBUS_PATH:
                 g_value_set_string (value, self->priv->server_dbus_path);
                 break;
         case PROP_SERVER_DBUS_INTERFACE:
                 g_value_set_string (value, self->priv->server_dbus_interface);
                 break;
-        case PROP_SERVER_ENV_VAR_NAME:
-                g_value_set_string (value, self->priv->server_env_var_name);
-                break;
         case PROP_COMMAND:
                 g_value_set_string (value, self->priv->command);
                 break;
@@ -1135,6 +1094,14 @@ gdm_welcome_session_class_init (GdmWelcomeSessionClass *klass)
         g_type_class_add_private (klass, sizeof (GdmWelcomeSessionPrivate));
 
         g_object_class_install_property (object_class,
+                                         PROP_VERIFICATION_MODE,
+                                         g_param_spec_enum ("verification-mode",
+                                                            "verification mode",
+                                                            "verification mode",
+                                                            GDM_TYPE_SESSION_VERIFICATION_MODE,
+                                                            GDM_SESSION_VERIFICATION_MODE_LOGIN,
+                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+        g_object_class_install_property (object_class,
                                          PROP_X11_DISPLAY_NAME,
                                          g_param_spec_string ("x11-display-name",
                                                               "name",
@@ -1198,13 +1165,6 @@ gdm_welcome_session_class_init (GdmWelcomeSessionClass *klass)
                                                               NULL,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
         g_object_class_install_property (object_class,
-                                         PROP_SERVER_ADDRESS,
-                                         g_param_spec_string ("server-address",
-                                                              "server address",
-                                                              "server address",
-                                                              NULL,
-                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-        g_object_class_install_property (object_class,
                                          PROP_SERVER_DBUS_PATH,
                                          g_param_spec_string ("server-dbus-path",
                                                               "server dbus path",
@@ -1219,19 +1179,22 @@ gdm_welcome_session_class_init (GdmWelcomeSessionClass *klass)
                                                               NULL,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
         g_object_class_install_property (object_class,
-                                         PROP_SERVER_ENV_VAR_NAME,
-                                         g_param_spec_string ("server-env-var-name",
-                                                              "server env var name",
-                                                              "server env var name",
-                                                              NULL,
-                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-        g_object_class_install_property (object_class,
                                          PROP_COMMAND,
                                          g_param_spec_string ("command",
                                                               "command",
                                                               "command",
                                                               NULL,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+        signals [OPENED] =
+                g_signal_new ("opened",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmWelcomeSessionClass, opened),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE,
+                              0);
         signals [STARTED] =
                 g_signal_new ("started",
                               G_OBJECT_CLASS_TYPE (object_class),
@@ -1316,8 +1279,8 @@ gdm_welcome_session_finalize (GObject *object)
         g_free (welcome_session->priv->server_address);
         g_free (welcome_session->priv->server_dbus_path);
         g_free (welcome_session->priv->server_dbus_interface);
-        g_free (welcome_session->priv->server_env_var_name);
         g_free (welcome_session->priv->dbus_bus_address);
+        g_free (welcome_session->priv->session_id);
 
         G_OBJECT_CLASS (gdm_welcome_session_parent_class)->finalize (object);
 }
diff --git a/daemon/gdm-welcome-session.h b/daemon/gdm-welcome-session.h
index b6d49d3..6e35d1d 100644
--- a/daemon/gdm-welcome-session.h
+++ b/daemon/gdm-welcome-session.h
@@ -23,6 +23,7 @@
 #define __GDM_WELCOME_SESSION_H
 
 #include <glib-object.h>
+#include "gdm-session.h"
 
 G_BEGIN_DECLS
 
@@ -51,6 +52,7 @@ typedef struct
 
 
         /* signals */
+        void (* opened)            (GdmWelcomeSession  *welcome_session);
         void (* started)           (GdmWelcomeSession  *welcome_session);
         void (* stopped)           (GdmWelcomeSession  *welcome_session);
         void (* exited)            (GdmWelcomeSession  *welcome_session,
@@ -61,10 +63,10 @@ typedef struct
 
 GType                 gdm_welcome_session_get_type           (void);
 
-void                  gdm_welcome_session_set_server_address (GdmWelcomeSession *welcome_session,
-                                                              const char        *server_address);
 gboolean              gdm_welcome_session_start              (GdmWelcomeSession *welcome_session);
 gboolean              gdm_welcome_session_stop               (GdmWelcomeSession *welcome_session);
+GdmSession *          gdm_welcome_session_get_session        (GdmWelcomeSession *welcome_session);
+char *                gdm_welcome_session_get_session_id     (GdmWelcomeSession *welcome_session);
 
 G_END_DECLS
 
diff --git a/daemon/gdm-xdmcp-chooser-display.c b/daemon/gdm-xdmcp-chooser-display.c
index efdcdf1..d9590e6 100644
--- a/daemon/gdm-xdmcp-chooser-display.c
+++ b/daemon/gdm-xdmcp-chooser-display.c
@@ -102,7 +102,7 @@ gdm_xdmcp_chooser_display_set_slave_bus_name (GdmDisplay *display,
 
         chooser_display->priv->slave_proxy = GDM_DBUS_XDMCP_CHOOSER_SLAVE (
                 gdm_dbus_xdmcp_chooser_slave_proxy_new_sync (connection,
-                                                             G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+                                                             G_DBUS_PROXY_FLAGS_NONE,
                                                              name,
                                                              GDM_SLAVE_PATH,
                                                              NULL,
diff --git a/daemon/gdm-xdmcp-chooser-slave.c b/daemon/gdm-xdmcp-chooser-slave.c
index 45d04ad..c8bc586 100644
--- a/daemon/gdm-xdmcp-chooser-slave.c
+++ b/daemon/gdm-xdmcp-chooser-slave.c
@@ -42,10 +42,10 @@
 #include "gdm-xdmcp-chooser-slave-glue.h"
 
 #include "gdm-server.h"
-#include "gdm-chooser-server.h"
 #include "gdm-chooser-session.h"
 #include "gdm-settings-direct.h"
 #include "gdm-settings-keys.h"
+#include "gdm-session.h"
 
 #define GDM_XDMCP_CHOOSER_SLAVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XDMCP_CHOOSER_SLAVE, GdmXdmcpChooserSlavePrivate))
 
@@ -64,19 +64,11 @@ struct GdmXdmcpChooserSlavePrivate
 
         guint              connection_attempts;
 
-        GdmChooserServer  *chooser_server;
         GdmChooserSession *chooser;
 
         GdmDBusXdmcpChooserSlave *skeleton;
 };
 
-enum {
-        HOSTNAME_SELECTED,
-        LAST_SIGNAL
-};
-
-static guint signals [LAST_SIGNAL] = { 0, };
-
 static void     gdm_xdmcp_chooser_slave_class_init     (GdmXdmcpChooserSlaveClass *klass);
 static void     gdm_xdmcp_chooser_slave_init           (GdmXdmcpChooserSlave      *xdmcp_chooser_slave);
 static void     gdm_xdmcp_chooser_slave_finalize       (GObject                   *object);
@@ -85,6 +77,19 @@ G_DEFINE_TYPE (GdmXdmcpChooserSlave, gdm_xdmcp_chooser_slave, GDM_TYPE_SLAVE)
 
 
 static void
+on_chooser_session_opened (GdmChooserSession    *chooser,
+                           GdmXdmcpChooserSlave *slave)
+{
+        char       *session_id;
+
+        g_debug ("GdmSimpleSlave: Chooser session opened");
+        session_id = gdm_welcome_session_get_session_id (GDM_WELCOME_SESSION (chooser));
+
+        g_object_set (GDM_SLAVE (slave), "session-id", session_id, NULL);
+        g_free (session_id);
+}
+
+static void
 on_chooser_session_start (GdmChooserSession    *chooser,
                           GdmXdmcpChooserSlave *slave)
 {
@@ -108,6 +113,9 @@ on_chooser_session_exited (GdmChooserSession    *chooser,
                            GdmXdmcpChooserSlave *slave)
 {
         g_debug ("GdmXdmcpChooserSlave: Chooser exited: %d", code);
+
+        g_object_set (GDM_SLAVE (slave), "session-id", NULL, NULL);
+
         gdm_slave_stopped (GDM_SLAVE (slave));
 }
 
@@ -117,23 +125,24 @@ on_chooser_session_died (GdmChooserSession    *chooser,
                          GdmXdmcpChooserSlave *slave)
 {
         g_debug ("GdmXdmcpChooserSlave: Chooser died: %d", signal);
+
+        g_object_set (GDM_SLAVE (slave), "session-id", NULL, NULL);
+
         gdm_slave_stopped (GDM_SLAVE (slave));
 }
 
 static void
-on_chooser_hostname_selected (GdmChooserServer     *chooser_server,
+on_chooser_hostname_selected (GdmSession           *session,
                               const char           *name,
                               GdmXdmcpChooserSlave *slave)
 {
-        g_debug ("GdmXdmcpChooserSlave: emitting hostname selected: %s", name);
-        g_signal_emit (slave, signals [HOSTNAME_SELECTED], 0, name);
-
+        g_debug ("GdmXdmcpChooserSlave: connecting to host %s", name);
         gdm_dbus_xdmcp_chooser_slave_emit_hostname_selected (slave->priv->skeleton,
                                                              name);
 }
 
 static void
-on_chooser_disconnected (GdmChooserServer     *chooser_server,
+on_chooser_disconnected (GdmSession           *session,
                          GdmXdmcpChooserSlave *slave)
 {
         g_debug ("GdmXdmcpChooserSlave: Chooser disconnected");
@@ -145,7 +154,7 @@ on_chooser_disconnected (GdmChooserServer     *chooser_server,
 }
 
 static void
-on_chooser_connected (GdmChooserServer     *chooser_server,
+on_chooser_connected (GdmSession           *session,
                       GdmXdmcpChooserSlave *slave)
 {
         g_debug ("GdmXdmcpChooserSlave: Chooser connected");
@@ -166,8 +175,8 @@ run_chooser (GdmXdmcpChooserSlave *slave)
         char          *display_device;
         char          *display_hostname;
         char          *auth_file;
-        char          *address;
         gboolean       res;
+        GdmSession    *session;
 
         g_debug ("GdmXdmcpChooserSlave: Running chooser");
 
@@ -200,28 +209,15 @@ run_chooser (GdmXdmcpChooserSlave *slave)
         /* Run the init script. gdmslave suspends until script has terminated */
         gdm_slave_run_script (GDM_SLAVE (slave), GDMCONFDIR "/Init", GDM_USERNAME);
 
-        slave->priv->chooser_server = gdm_chooser_server_new (display_id);
-        g_signal_connect (slave->priv->chooser_server,
-                          "hostname-selected",
-                          G_CALLBACK (on_chooser_hostname_selected),
-                          slave);
-        g_signal_connect (slave->priv->chooser_server,
-                          "disconnected",
-                          G_CALLBACK (on_chooser_disconnected),
-                          slave);
-        g_signal_connect (slave->priv->chooser_server,
-                          "connected",
-                          G_CALLBACK (on_chooser_connected),
-                          slave);
-        gdm_chooser_server_start (slave->priv->chooser_server);
-
-        address = gdm_chooser_server_get_address (slave->priv->chooser_server);
-
         g_debug ("GdmXdmcpChooserSlave: Creating chooser on %s %s %s", display_name, display_device, display_hostname);
         slave->priv->chooser = gdm_chooser_session_new (display_name,
                                                         display_device,
                                                         display_hostname);
         g_signal_connect (slave->priv->chooser,
+                          "opened",
+                          G_CALLBACK (on_chooser_session_opened),
+                          slave);
+        g_signal_connect (slave->priv->chooser,
                           "started",
                           G_CALLBACK (on_chooser_session_start),
                           slave);
@@ -240,9 +236,27 @@ run_chooser (GdmXdmcpChooserSlave *slave)
         g_object_set (slave->priv->chooser,
                       "x11-authority-file", auth_file,
                       NULL);
-        gdm_welcome_session_set_server_address (GDM_WELCOME_SESSION (slave->priv->chooser), address);
+
         gdm_welcome_session_start (GDM_WELCOME_SESSION (slave->priv->chooser));
 
+        session = gdm_welcome_session_get_session (GDM_WELCOME_SESSION (slave->priv->chooser));
+
+        g_signal_connect (session,
+                          "hostname-selected",
+                          G_CALLBACK (on_chooser_hostname_selected),
+                          slave);
+        g_signal_connect (session,
+                          "client-disconnected",
+                          G_CALLBACK (on_chooser_disconnected),
+                          slave);
+        g_signal_connect (session,
+                          "disconnected",
+                          G_CALLBACK (on_chooser_disconnected),
+                          slave);
+        g_signal_connect (session,
+                          "client-connected",
+                          G_CALLBACK (on_chooser_connected),
+                          slave);
         g_free (display_id);
         g_free (display_name);
         g_free (display_device);
@@ -317,6 +331,29 @@ gdm_xdmcp_chooser_slave_stop (GdmSlave *slave)
         return TRUE;
 }
 
+static gboolean
+gdm_xdmcp_chooser_slave_open_session (GdmSlave   *slave,
+                                      char      **address,
+                                      GError    **error)
+{
+        GdmXdmcpChooserSlave *self = GDM_XDMCP_CHOOSER_SLAVE (slave);
+        GdmSession      *session;
+
+        session = gdm_welcome_session_get_session (GDM_WELCOME_SESSION (self->priv->chooser));
+
+        if (gdm_session_client_is_connected (session)) {
+                g_set_error (error,
+                             G_DBUS_ERROR,
+                             G_DBUS_ERROR_ACCESS_DENIED,
+                             _("Currently, only one client can be connected at once"));
+                return FALSE;
+        }
+
+        *address = gdm_session_get_server_address (session);
+
+        return TRUE;
+}
+
 static GObject *
 gdm_xdmcp_chooser_slave_constructor (GType                  type,
                                      guint                  n_construct_properties,
@@ -335,7 +372,6 @@ gdm_xdmcp_chooser_slave_constructor (GType                  type,
         return G_OBJECT (slave);
 }
 
-
 static void
 gdm_xdmcp_chooser_slave_class_init (GdmXdmcpChooserSlaveClass *klass)
 {
@@ -347,18 +383,7 @@ gdm_xdmcp_chooser_slave_class_init (GdmXdmcpChooserSlaveClass *klass)
 
         slave_class->start = gdm_xdmcp_chooser_slave_start;
         slave_class->stop = gdm_xdmcp_chooser_slave_stop;
-
-        signals [HOSTNAME_SELECTED] =
-                g_signal_new ("hostname-selected",
-                              G_OBJECT_CLASS_TYPE (object_class),
-                              G_SIGNAL_RUN_FIRST,
-                              G_STRUCT_OFFSET (GdmXdmcpChooserSlaveClass, hostname_selected),
-                              NULL,
-                              NULL,
-                              g_cclosure_marshal_VOID__STRING,
-                              G_TYPE_NONE,
-                              1,
-                              G_TYPE_STRING);
+        slave_class->open_session = gdm_xdmcp_chooser_slave_open_session;
 
         g_type_class_add_private (klass, sizeof (GdmXdmcpChooserSlavePrivate));
 }
@@ -379,6 +404,10 @@ gdm_xdmcp_chooser_slave_finalize (GObject *object)
 
         xdmcp_chooser_slave = GDM_XDMCP_CHOOSER_SLAVE (object);
 
+        g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (xdmcp_chooser_slave->priv->skeleton));
+
+        g_clear_object (&xdmcp_chooser_slave->priv->skeleton);
+
         g_return_if_fail (xdmcp_chooser_slave->priv != NULL);
 
         gdm_xdmcp_chooser_slave_stop (GDM_SLAVE (xdmcp_chooser_slave));
diff --git a/daemon/gdm-xdmcp-chooser-slave.h b/daemon/gdm-xdmcp-chooser-slave.h
index 61cdd13..3fd924a 100644
--- a/daemon/gdm-xdmcp-chooser-slave.h
+++ b/daemon/gdm-xdmcp-chooser-slave.h
@@ -46,8 +46,6 @@ typedef struct
 {
         GdmSlaveClass   parent_class;
 
-        void (* hostname_selected)          (GdmXdmcpChooserSlave  *slave,
-                                             const char            *hostname);
 } GdmXdmcpChooserSlaveClass;
 
 GType               gdm_xdmcp_chooser_slave_get_type   (void);



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