File gdm-remote-desktop-unlock.patch of Package gdm.16051

diff -Npur gdm-3.10.0.1/daemon/gdm-manager.c gdm-3.10.0.1-new/daemon/gdm-manager.c
--- gdm-3.10.0.1/daemon/gdm-manager.c	2014-09-12 07:57:28.394215171 +0800
+++ gdm-3.10.0.1-new/daemon/gdm-manager.c	2014-09-12 07:48:29.330241013 +0800
@@ -39,7 +39,7 @@
 #endif
 
 #include "gdm-common.h"
-
+#include "gdm-session.h"
 #include "gdm-dbus-util.h"
 #include "gdm-manager.h"
 #include "gdm-manager-glue.h"
@@ -54,6 +54,14 @@
 #define GDM_MANAGER_PATH          GDM_DBUS_PATH "/Manager"
 #define GDM_MANAGER_DISPLAYS_PATH GDM_DBUS_PATH "/Displays"
 
+#define CK_NAME      "org.freedesktop.ConsoleKit"
+#define CK_PATH      "/org/freedesktop/ConsoleKit"
+#define CK_INTERFACE "org.freedesktop.ConsoleKit"
+#define CK_MANAGER_PATH      "/org/freedesktop/ConsoleKit/Manager"
+#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager"
+#define CK_SEAT_INTERFACE    "org.freedesktop.ConsoleKit.Seat"
+#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
+
 struct GdmManagerPrivate
 {
         GdmDisplayStore        *display_store;
@@ -178,6 +186,168 @@ get_session_id_for_pid (GDBusConnection
 }
 
 #ifdef WITH_SYSTEMD
+static char *
+get_seat_id_for_systemd_session_id (const char  *session_id,
+                                    GError     **error)
+{
+        int ret;
+        char *seat, *out_seat;
+
+        seat = NULL;
+        ret = sd_session_get_seat (session_id, &seat);
+
+        if (ret == -ENOENT) {
+                out_seat = NULL;
+        } else if (ret < 0) {
+                g_set_error (error,
+                             GDM_DISPLAY_ERROR,
+                             GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
+                             "Error getting uid for session id %s from systemd: %s",
+                             session_id,
+                             g_strerror (-ret));
+                out_seat = NULL;
+        } else {
+                out_seat = g_strdup (seat);
+                free (seat);
+        }
+
+        return out_seat;
+}
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+static char *
+get_seat_id_for_consolekit_session_id (GDBusConnection  *connection,
+                                       const char       *session_id,
+                                       GError          **error)
+{
+        GVariant *reply;
+        char *retval;
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             "org.freedesktop.ConsoleKit",
+                                             session_id,
+                                             "org.freedesktop.ConsoleKit.Session",
+                                             "GetSeatId",
+                                             NULL,
+                                             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_seat_id_for_session_id (GDBusConnection  *connection,
+                            const char       *session_id,
+                            GError          **error)
+{
+#ifdef WITH_SYSTEMD
+        if (LOGIND_RUNNING()) {
+                return get_seat_id_for_systemd_session_id (session_id, error);
+        }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+        return get_seat_id_for_consolekit_session_id (connection, session_id, error);
+#endif
+
+        return NULL;
+}
+
+#ifdef WITH_CONSOLE_KIT
+static gboolean
+is_consolekit_remote_session (GdmManager       *self,
+                             GDBusConnection  *connection,
+                             const char       *session_id,
+                             GError          **error)
+{
+        GVariant *reply;
+        gboolean is_remote;
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             "org.freedesktop.ConsoleKit",
+                                             session_id,
+                                             "org.freedesktop.ConsoleKit.Session",
+                                             "IsLocal",
+                                             NULL,
+                                             G_VARIANT_TYPE ("(b)"),
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL,
+                                             error);
+        if (reply == NULL) {
+                return FALSE;
+        }
+
+        g_variant_get (reply, "(b)", &is_remote);
+        g_variant_unref (reply);
+
+        return is_remote;
+}
+#endif
+
+#ifdef WITH_SYSTEMD
+static gboolean
+is_systemd_remote_session (GdmManager  *self,
+                           const char  *session_id,
+                           GError     **error)
+{
+        char *seat;
+        int ret;
+        gboolean is_remote;
+
+        /* FIXME: The next release of logind is going to have explicit api for
+         * checking remoteness.
+         */
+        seat = NULL;
+        ret = sd_session_get_seat (session_id, &seat);
+
+        if (ret < 0 && ret != -ENOENT) {
+                g_debug ("GdmManager: Error while retrieving seat for session %s: %s",
+                         session_id, strerror (-ret));
+        }
+
+        if (seat != NULL) {
+                is_remote = FALSE;
+                free (seat);
+        } else {
+                is_remote = TRUE;
+        }
+
+        return is_remote;
+}
+#endif
+
+static gboolean
+is_remote_session (GdmManager       *self,
+                  GDBusConnection  *connection,
+                  const char       *session_id,
+                  GError          **error)
+{
+#ifdef WITH_SYSTEMD
+        if (LOGIND_RUNNING()) {
+                return is_systemd_remote_session (self, session_id, error);
+        }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+        return is_consolekit_remote_session (self, connection, session_id, error);
+#endif
+
+        return FALSE;
+}
+
+#ifdef WITH_SYSTEMD
 static gboolean
 get_uid_for_systemd_session_id (const char  *session_id,
                                 uid_t       *uid,
@@ -261,7 +431,6 @@ lookup_by_session_id (const char *id,
         const char *looking_for = user_data;
         char *current;
         gboolean res;
-
         current = gdm_display_get_session_id (display);
 
         res = g_strcmp0 (current, looking_for) == 0;
@@ -271,12 +440,106 @@ lookup_by_session_id (const char *id,
         return res;
 }
 
-static GdmDisplay *
+#ifdef WITH_CONSOLE_KIT
+static gboolean
+is_consolekit_login_session (GdmManager       *self,
+                             GDBusConnection  *connection,
+                             const char       *session_id,
+                             GError          **error)
+{
+        GVariant *reply;
+        char *session_type = NULL;
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             "org.freedesktop.ConsoleKit",
+                                             session_id,
+                                             "org.freedesktop.ConsoleKit.Session",
+                                             "GetSessionType",
+                                             NULL,
+                                             G_VARIANT_TYPE ("(s)"),
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL,
+                                             error);
+        if (reply == NULL) {
+                return FALSE;
+        }
+
+        g_variant_get (reply, "(s)", &session_type);
+        g_variant_unref (reply);
+
+        if (g_strcmp0 (session_type, "LoginWindow") != 0) {
+                g_free (session_type);
+
+                return FALSE;
+        }
+
+        g_free (session_type);
+        return TRUE;
+}
+#endif
+
+#ifdef WITH_SYSTEMD
+static gboolean
+is_systemd_login_session (GdmManager  *self,
+                          const char  *session_id,
+                          GError     **error)
+{
+        char *session_class = NULL;
+        int ret;
+
+        ret = sd_session_get_class (session_id, &session_class);
+
+        if (ret < 0) {
+                g_set_error (error,
+                             GDM_DISPLAY_ERROR,
+                             GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
+                             "Error getting class for session id %s from systemd: %s",
+                             session_id,
+                             g_strerror (-ret));
+                return FALSE;
+        }
+
+        if (g_strcmp0 (session_class, "greeter") != 0) {
+                g_free (session_class);
+                return FALSE;
+        }
+
+        g_free (session_class);
+        return TRUE;
+}
+#endif
+
+static gboolean
+is_login_session (GdmManager       *self,
+                  GDBusConnection  *connection,
+                  const char       *session_id,
+                  GError          **error)
+{
+#ifdef WITH_SYSTEMD
+        if (LOGIND_RUNNING()) {
+                return is_systemd_login_session (self, session_id, error);
+        }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+        return is_consolekit_login_session (self, connection, session_id, error);
+#endif
+
+        return FALSE;
+}
+
+static void
 get_display_and_details_for_bus_sender (GdmManager       *self,
-                            GDBusConnection  *connection,
-                            const char       *sender,
-                            GPid             *out_pid,
-                            uid_t            *out_uid)
+                                        GDBusConnection  *connection,
+                                        const char       *sender,
+                                        GdmDisplay      **out_display,
+                                        char            **out_seat_id,
+                                        char            **out_session_id,
+                                        GPid             *out_pid,
+                                        uid_t            *out_uid,
+                                        gboolean         *out_is_login_screen,
+                                        gboolean         *out_is_remote)
 {
         GdmDisplay *display = NULL;
         char       *session_id = NULL;
@@ -294,6 +557,10 @@ get_display_and_details_for_bus_sender (
                 goto out;
         }
 
+        if (out_pid != NULL) {
+                *out_pid = pid;
+        }
+
         ret = gdm_dbus_get_uid_for_name (sender, &caller_uid, &error);
 
         if (!ret) {
@@ -312,6 +579,21 @@ get_display_and_details_for_bus_sender (
                 goto out;
         }
 
+        if (out_session_id != NULL) {
+                *out_session_id = g_strdup (session_id);
+        }
+
+        if (out_is_login_screen != NULL) {
+                *out_is_login_screen = is_login_session (self, connection, session_id, &error);
+
+                if (error != NULL) {
+                        g_debug ("GdmManager: Error while checking if sender is login screen: %s",
+                                 error->message);
+                        g_error_free (error);
+                        goto out;
+                }
+        }
+
         if (!get_uid_for_session_id (connection, session_id, &session_uid, &error)) {
                 g_debug ("GdmManager: Error while retrieving uid for session: %s",
                          error->message);
@@ -319,25 +601,44 @@ get_display_and_details_for_bus_sender (
                 goto out;
         }
 
+        if (out_uid != NULL) {
+                *out_uid = session_uid;
+        }
+
         if (caller_uid != session_uid) {
-                g_debug ("GdmManager: uid for sender and uid for session don't match");
                 goto out;
         }
 
+        if (out_seat_id != NULL) {
+                *out_seat_id = get_seat_id_for_session_id (connection, session_id, &error);
+
+                if (error != NULL) {
+                        g_debug ("GdmManager: Error while retrieving seat id for session: %s",
+                                 error->message);
+                        g_clear_error (&error);
+                }
+        }
+
+        if (out_is_remote != NULL) {
+                *out_is_remote = is_remote_session (self, connection, session_id, &error);
+
+                if (error != NULL) {
+                        g_debug ("GdmManager: Error while retrieving remoteness for session: %s",
+                                 error->message);
+                        g_clear_error (&error);
+                }
+        }
+
         display = gdm_display_store_find (self->priv->display_store,
                                           lookup_by_session_id,
                                           (gpointer) session_id);
-out:
-        g_free (session_id);
-
-        if (display != NULL) {
-            if (out_pid != NULL)
-                *out_pid = pid;
 
-            if (out_uid != NULL)
-                *out_uid = session_uid;
+        if (out_display != NULL) {
+                *out_display = display;
         }
-        return display;
+
+out:
+        g_free (session_id);
 }
 
 static gboolean
@@ -357,7 +658,7 @@ gdm_manager_handle_open_session (GdmDBus
 
         sender = g_dbus_method_invocation_get_sender (invocation);
         connection = g_dbus_method_invocation_get_connection (invocation);
-        display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid);
+        get_display_and_details_for_bus_sender (self, connection, sender, &display, NULL, NULL, &pid, &uid, NULL, NULL);
 
         if (display == NULL) {
                 g_dbus_method_invocation_return_error_literal (invocation,
@@ -384,47 +685,298 @@ gdm_manager_handle_open_session (GdmDBus
         return TRUE;
 }
 
+#ifdef WITH_CONSOLE_KIT
+static gboolean
+session_unlock_for_ck (GdmManager *manager,
+                       const char *ssid)
+{
+        GError *error = NULL;
+        GVariant *reply;
+
+        reply = g_dbus_connection_call_sync (manager->priv->connection,
+                                             CK_NAME,
+                                             ssid,
+                                             CK_SESSION_INTERFACE,
+                                             "Unlock",
+                                             NULL, /* parameters */
+                                             NULL, /* expected reply */
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL,
+                                             &error);
+        if (reply == NULL) {
+                g_debug ("GdmManager: ConsoleKit %s raised:\n %s\n\n",
+                         g_dbus_error_get_remote_error (error), error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+
+        g_variant_unref (reply);
+
+        return TRUE;
+}
+#endif
+
+#ifdef WITH_SYSTEMD
+static gboolean
+session_unlock_for_systemd (GdmManager *manager,
+                            const char *ssid)
+{
+        GError *error = NULL;
+        GVariant *reply;
+
+        reply = g_dbus_connection_call_sync (manager->priv->connection,
+                                             "org.freedesktop.login1",
+                                             "/org/freedesktop/login1",
+                                             "org.freedesktop.login1.Manager",
+                                             "UnlockSession",
+                                             g_variant_new ("(s)", ssid),
+                                             NULL, /* expected reply */
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1,
+                                             NULL,
+                                             &error);
+        if (reply == NULL) {
+                g_debug ("GdmManager: logind 'UnlockSession' %s raised:\n %s\n\n",
+                         g_dbus_error_get_remote_error (error), error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+
+        g_variant_unref (reply);
+
+        return TRUE;
+}
+#endif
+
+static gboolean
+session_unlock (GdmManager *manager,
+                const char *ssid)
+{
+
+        g_debug ("Unlocking session %s", ssid);
+
+#ifdef WITH_SYSTEMD
+        if (LOGIND_RUNNING()) {
+                return session_unlock_for_systemd (manager, ssid);
+        }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+        return session_unlock_for_ck (manager, ssid);
+#else
+        return TRUE;
+#endif
+}
+
+static void
+on_reauthentication_client_connected (GdmSession              *session,
+                                      GCredentials            *credentials,
+                                      GPid                     pid_of_client,
+                                      GdmManager              *self)
+{
+        g_debug ("GdmManager: client connected to reauthentication server");
+}
+
+static void
+on_reauthentication_client_disconnected (GdmSession              *session,
+                                         GCredentials            *credentials,
+                                         GPid                     pid_of_client,
+                                         GdmManager              *self)
+{
+        g_debug ("GdmManger: client disconnected from reauthentication server");
+        gdm_session_close (session);
+        g_object_unref (session);
+}
+
+static void
+on_reauthentication_cancelled (GdmSession *session,
+                               GdmManager *self)
+{
+        g_debug ("GdmManager: client cancelled reauthentication request");
+        gdm_session_close (session);
+        g_object_unref (session);
+}
+static void
+on_reauthentication_conversation_started (GdmSession *session,
+                                          const char *service_name,
+                                          GdmManager *self)
+{
+        g_debug ("GdmManager: reauthentication service '%s' started",
+                 service_name);
+}
+
+static void
+on_reauthentication_conversation_stopped (GdmSession *session,
+                                          const char *service_name,
+                                          GdmManager *self)
+{
+        g_debug ("GdmManager: reauthentication service '%s' stopped",
+                 service_name);
+}
+
+static void
+on_reauthentication_verification_complete (GdmSession *session,
+                                           const char *service_name,
+                                           GdmManager *self)
+{
+        const char *session_id;
+        session_id = g_object_get_data (G_OBJECT (session), "caller-session-id");
+        g_debug ("GdmManager: reauthenticated user in unmanaged session '%s' with service '%s'",
+                 session_id, service_name);
+        session_unlock (self, session_id);
+        gdm_session_close (session);
+        g_object_unref (session);
+}
+
+static void
+remove_session_weak_refs (GdmManager *self,
+                          GdmSession *session)
+{
+        g_object_weak_unref (G_OBJECT (self),
+                             (GWeakNotify)
+                             gdm_session_close,
+                             session);
+        g_object_weak_unref (G_OBJECT (self),
+                             (GWeakNotify)
+                             g_object_unref,
+                             session);
+}
+
+static void
+add_session_weak_refs (GdmManager *self,
+                       GdmSession *session)
+{
+        g_object_weak_ref (G_OBJECT (self),
+                           (GWeakNotify)
+                           gdm_session_close,
+                           session);
+        g_object_weak_ref (G_OBJECT (self),
+                           (GWeakNotify)
+                           g_object_unref,
+                           session);
+        g_object_weak_ref (G_OBJECT (session),
+                           (GWeakNotify)
+                           remove_session_weak_refs,
+                           self);
+}
+
+static char *
+open_temporary_reauthentication_channel (GdmManager            *self,
+                                         char                  *seat_id,
+                                         char                  *session_id,
+                                         GPid                   pid,
+                                         uid_t                  uid,
+                                         gboolean               is_remote)
+{
+        GdmSession *session;
+        char **environment;
+        const char *display, *auth_file;
+        const char *address;
+
+        /* Note we're just using a minimal environment here rather than the
+         * session's environment because the caller is unprivileged and the
+         * associated worker will be privileged */
+        environment = g_get_environ ();
+        display = "";
+        auth_file = "/dev/null";
+        session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE,
+                                   uid,
+                                   display,
+                                   NULL,
+                                   NULL,
+                                   seat_id,
+                                   auth_file,
+                                   is_remote == FALSE,
+                                   (const char * const *)
+                                   environment);
+        g_strfreev (environment);
+
+
+        g_object_set_data_full (G_OBJECT (session),
+                                "caller-session-id",
+                                g_strdup (session_id),
+                                (GDestroyNotify)
+                                g_free);
+
+        add_session_weak_refs (self, session);
+
+
+        g_signal_connect (session,
+                          "client-connected",
+                          G_CALLBACK (on_reauthentication_client_connected),
+                          self);
+        g_signal_connect (session,
+                          "client-disconnected",
+                          G_CALLBACK (on_reauthentication_client_disconnected),
+                          self);
+        g_signal_connect (session,
+                          "cancelled",
+                          G_CALLBACK (on_reauthentication_cancelled),
+                          self);
+        g_signal_connect (session,
+                          "conversation-started",
+                          G_CALLBACK (on_reauthentication_conversation_started),
+                          self);
+        g_signal_connect (session,
+                          "conversation-stopped",
+                          G_CALLBACK (on_reauthentication_conversation_stopped),
+                          self);
+        g_signal_connect (session,
+                          "verification-complete",
+                          G_CALLBACK (on_reauthentication_verification_complete),
+                          self);
+
+        address = gdm_session_get_server_address (session);
+
+        return g_strdup (address);
+}
+
 static gboolean
 gdm_manager_handle_open_reauthentication_channel (GdmDBusManager        *manager,
                                                   GDBusMethodInvocation *invocation,
                                                   const char            *username)
 {
         GdmManager       *self = GDM_MANAGER (manager);
-        const char       *sender = NULL;
-        GError           *error = NULL;
+        const char       *sender;
+        GdmDisplay       *display = NULL;
+        GdmSession       *session;
         GDBusConnection  *connection;
-        GdmDisplay       *display;
-        char             *address;
-        GPid              pid;
-        uid_t             uid;
-
+        char             *seat_id = NULL;
+        char             *session_id = NULL;
+        GPid              pid = 0;
+        uid_t             uid = (uid_t) -1;
+        gboolean          is_login_screen = FALSE;
+        gboolean          is_remote = FALSE;
+	char		 *address;
+	GError 		 *error = NULL;
         g_debug ("GdmManager: trying to open reauthentication channel for user %s", username);
-
+ 
         sender = g_dbus_method_invocation_get_sender (invocation);
         connection = g_dbus_method_invocation_get_connection (invocation);
-        display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid);
+        get_display_and_details_for_bus_sender (self, connection, sender, &display, &seat_id, &session_id, &pid, &uid, &is_login_screen, &is_remote);
 
         if (display == NULL) {
-                g_dbus_method_invocation_return_error_literal (invocation,
-                                                               G_DBUS_ERROR,
-                                                               G_DBUS_ERROR_ACCESS_DENIED,
-                                                               _("No session available"));
-
-                return TRUE;
-        }
-
-        address = gdm_display_open_reauthentication_channel_sync (display,
+                address = open_temporary_reauthentication_channel (self,
+                                                                   seat_id,
+                                                                   session_id,
+                                                                   pid,
+                                                                   uid,
+                                                                   TRUE);
+        } else {
+	        address = gdm_display_open_reauthentication_channel_sync (display,
                                                                   username,
                                                                   pid,
                                                                   uid,
                                                                   NULL,
                                                                   &error);
+	}
 
         if (address == NULL) {
                 g_dbus_method_invocation_return_gerror (invocation, error);
                 g_error_free (error);
                 return TRUE;
-        }
+	}
 
         gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager),
                                                                  invocation,
diff -Npur gdm-3.10.0.1/daemon/gdm-session-worker.c gdm-3.10.0.1-new/daemon/gdm-session-worker.c
--- gdm-3.10.0.1/daemon/gdm-session-worker.c	2014-09-12 07:57:28.526215164 +0800
+++ gdm-3.10.0.1-new/daemon/gdm-session-worker.c	2014-09-12 07:02:22.682373642 +0800
@@ -1041,7 +1041,7 @@ gdm_session_worker_initialize_pam (GdmSe
 #ifdef PAM_XAUTHDATA
         struct pam_xauth_data *pam_xauth;
 #endif
-        int                    error_code;
+        int                    error_code = PAM_SUCCESS;
         char                  *pam_tty;
 
         g_assert (worker->priv->pam_handle == NULL);
@@ -1134,37 +1134,39 @@ gdm_session_worker_initialize_pam (GdmSe
         }
 
 #ifdef PAM_XDISPLAY
-        /* set XDISPLAY */
-        error_code = pam_set_item (worker->priv->pam_handle, PAM_XDISPLAY, x11_display_name);
-
-        if (error_code != PAM_SUCCESS) {
-                g_debug ("error informing authentication system of display string %s: %s",
-                         x11_display_name,
-                         pam_strerror (worker->priv->pam_handle, error_code));
-                g_set_error (error,
-                             GDM_SESSION_WORKER_ERROR,
-                             GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
-                             "%s", "");
-                goto out;
+        if (worker->priv->x11_display_name != NULL && worker->priv->x11_display_name[0] != '\0') {
+                error_code = pam_set_item (worker->priv->pam_handle, PAM_XDISPLAY, worker->priv->x11_display_name);
+                if (error_code != PAM_SUCCESS) {
+                        g_debug ("error informing authentication system of display string %s: %s",
+                                 worker->priv->x11_display_name,
+                                 pam_strerror (worker->priv->pam_handle, error_code));
+                        g_set_error (error,
+                                     GDM_SESSION_WORKER_ERROR,
+                                     GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
+                                     "%s", "");
+                        goto out;
+                }
         }
 #endif
+
 #ifdef PAM_XAUTHDATA
         /* set XAUTHDATA */
         pam_xauth = _get_xauth_for_pam (x11_authority_file);
-        error_code = pam_set_item (worker->priv->pam_handle, PAM_XAUTHDATA, pam_xauth);
-        if (error_code != PAM_SUCCESS) {
-                g_debug ("error informing authentication system of display string %s: %s",
-                         x11_display_name,
-                         pam_strerror (worker->priv->pam_handle, error_code));
+        if (pam_xauth != NULL) {
+                error_code = pam_set_item (worker->priv->pam_handle, PAM_XAUTHDATA, pam_xauth);
+        	if (error_code != PAM_SUCCESS) {
+                        g_debug ("error informing authentication system of display string %s: %s",
+                                 x11_display_name,
+                                 pam_strerror (worker->priv->pam_handle, error_code));
+                                 g_free (pam_xauth);
+                        g_set_error (error,
+                                     GDM_SESSION_WORKER_ERROR,
+                                     GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
+                                     "%s", "");
+                        goto out;
+                }
                 g_free (pam_xauth);
-
-                g_set_error (error,
-                             GDM_SESSION_WORKER_ERROR,
-                             GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
-                             "%s", "");
-                goto out;
         }
-        g_free (pam_xauth);
 #endif
 
         if (worker->priv->suse_session_name)
diff -Npur gdm-3.10.0.1/daemon/Makefile.am gdm-3.10.0.1-new/daemon/Makefile.am
--- gdm-3.10.0.1/daemon/Makefile.am	2013-09-20 03:29:34.000000000 +0800
+++ gdm-3.10.0.1-new/daemon/Makefile.am	2014-09-12 07:47:18.178244424 +0800
@@ -321,6 +321,14 @@ gdm_SOURCES = 			\
 	gdm-transient-display.h		\
 	gdm-manager.c			\
 	gdm-manager.h			\
+	gdm-session.c                   \
+	gdm-session.h                   \
+	gdm-session-record.c            \
+	gdm-session-record.h            \
+	gdm-session-worker-common.c     \
+	gdm-session-worker-common.h     \
+	gdm-session-worker-job.c        \
+	gdm-session-worker-job.h        \
 	gdm-slave-proxy.c		\
 	gdm-slave-proxy.h		\
 	gdm-dbus-util.c			\
@@ -334,6 +342,12 @@ nodist_gdm_SOURCES = 			\
 	gdm-local-display-factory-glue.c	\
 	gdm-manager-glue.h			\
 	gdm-manager-glue.c			\
+	gdm-session-glue.h                      \
+	gdm-session-glue.c                      \
+	gdm-session-worker-glue.c               \
+	gdm-session-worker-glue.h               \
+	gdm-session-enum-types.c		\
+	gdm-session-enum-types.h		\
 	gdm-transient-display-glue.h		\
 	gdm-transient-display-glue.c		\
 	gdm-static-display-glue.h		\
diff -Npur gdm-3.10.0.1/daemon/Makefile.in gdm-3.10.0.1-new/daemon/Makefile.in
--- gdm-3.10.0.1/daemon/Makefile.in	2013-10-16 22:46:14.000000000 +0800
+++ gdm-3.10.0.1-new/daemon/Makefile.in	2014-09-12 07:57:05.354216275 +0800
@@ -126,7 +126,10 @@ am__gdm_SOURCES_DIST = main.c gdm-displa
 	gdm-local-display-factory.h gdm-display.c gdm-display.h \
 	gdm-static-display.c gdm-static-display.h \
 	gdm-transient-display.c gdm-transient-display.h gdm-manager.c \
-	gdm-manager.h gdm-slave-proxy.c gdm-slave-proxy.h \
+	gdm-manager.h gdm-session.c gdm-session.h gdm-session-record.c \
+	gdm-session-record.h gdm-session-worker-common.c \
+	gdm-session-worker-common.h gdm-session-worker-job.c \
+	gdm-session-worker-job.h gdm-slave-proxy.c gdm-slave-proxy.h \
 	gdm-dbus-util.c gdm-dbus-util.h gdm-xdmcp-display-factory.c \
 	gdm-xdmcp-display-factory.h gdm-xdmcp-display.c \
 	gdm-xdmcp-display.h gdm-xdmcp-greeter-display.c \
@@ -144,7 +147,10 @@ am_gdm_OBJECTS = main.$(OBJEXT) gdm-disp
 	gdm-display-store.$(OBJEXT) gdm-display-factory.$(OBJEXT) \
 	gdm-local-display-factory.$(OBJEXT) gdm-display.$(OBJEXT) \
 	gdm-static-display.$(OBJEXT) gdm-transient-display.$(OBJEXT) \
-	gdm-manager.$(OBJEXT) gdm-slave-proxy.$(OBJEXT) \
+	gdm-manager.$(OBJEXT) gdm-session.$(OBJEXT) \
+	gdm-session-record.$(OBJEXT) \
+	gdm-session-worker-common.$(OBJEXT) \
+	gdm-session-worker-job.$(OBJEXT) gdm-slave-proxy.$(OBJEXT) \
 	gdm-dbus-util.$(OBJEXT) $(am__objects_1) $(am__objects_3) \
 	$(am__objects_5)
 am__objects_6 = gdm-xdmcp-display-glue.$(OBJEXT) \
@@ -152,7 +158,9 @@ am__objects_6 = gdm-xdmcp-display-glue.$
 @XDMCP_SUPPORT_TRUE@am__objects_7 = $(am__objects_6)
 nodist_gdm_OBJECTS = gdm-display-glue.$(OBJEXT) \
 	gdm-local-display-factory-glue.$(OBJEXT) \
-	gdm-manager-glue.$(OBJEXT) \
+	gdm-manager-glue.$(OBJEXT) gdm-session-glue.$(OBJEXT) \
+	gdm-session-enum-types.$(OBJEXT) \
+	gdm-session-worker-glue.$(OBJEXT) \
 	gdm-transient-display-glue.$(OBJEXT) \
 	gdm-static-display-glue.$(OBJEXT) gdm-slave-glue.$(OBJEXT) \
 	$(am__objects_1) $(am__objects_7)
@@ -789,16 +797,20 @@ gdm_SOURCES = main.c gdm-display-access-
 	gdm-local-display-factory.h gdm-display.c gdm-display.h \
 	gdm-static-display.c gdm-static-display.h \
 	gdm-transient-display.c gdm-transient-display.h gdm-manager.c \
-	gdm-manager.h gdm-slave-proxy.c gdm-slave-proxy.h \
+	gdm-manager.h gdm-session.c gdm-session.h gdm-session-record.c \
+	gdm-session-record.h gdm-session-worker-common.c \
+	gdm-session-worker-common.h gdm-session-worker-job.c \
+	gdm-session-worker-job.h gdm-slave-proxy.c gdm-slave-proxy.h \
 	gdm-dbus-util.c gdm-dbus-util.h $(NULL) $(am__append_4) \
 	$(am__append_6)
 nodist_gdm_SOURCES = gdm-display-glue.h 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) $(am__append_5)
+	gdm-manager-glue.c gdm-session-glue.h gdm-session-glue.c \
+	gdm-session-worker-glue.c gdm-session-worker-glue.h \
+	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) $(am__append_5)
 XDMCP_SOURCES = \
 	gdm-xdmcp-display-factory.c	\
 	gdm-xdmcp-display-factory.h	\