[gdm] daemon: ensure account is loaded before login



commit 8ecc1022c3e3c0b162ac8008237f04b003792c49
Author: Ray Strode <rstrode redhat com>
Date:   Tue Mar 1 15:19:33 2011 -0500

    daemon: ensure account is loaded before login
    
    Since we load the user account information asynchronously, it's
    conceivable that in some oddly timed situations, the
    user's language and session won't be loaded by the time we are
    ready for login.
    
    This commit adds an explicit stage in the login cycle for waiting
    on the user to load.

 daemon/gdm-session-settings.c |   95 ++++++++++++++++++++++++++++++++--------
 daemon/gdm-session-worker.c   |   46 +++++++++++++++++++-
 2 files changed, 121 insertions(+), 20 deletions(-)
---
diff --git a/daemon/gdm-session-settings.c b/daemon/gdm-session-settings.c
index b9b809b..ec56dc0 100644
--- a/daemon/gdm-session-settings.c
+++ b/daemon/gdm-session-settings.c
@@ -37,6 +37,7 @@
 struct _GdmSessionSettingsPrivate
 {
         ActUserManager *user_manager;
+        ActUser *user;
         char *session_name;
         char *language_name;
 };
@@ -58,6 +59,7 @@ enum {
         PROP_0 = 0,
         PROP_SESSION_NAME,
         PROP_LANGUAGE_NAME,
+        PROP_IS_LOADED
 };
 
 G_DEFINE_TYPE (GdmSessionSettings, gdm_session_settings, G_TYPE_OBJECT)
@@ -96,6 +98,10 @@ gdm_session_settings_class_install_properties (GdmSessionSettingsClass *settings
                                         NULL,
                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
         g_object_class_install_property (object_class, PROP_LANGUAGE_NAME, param_spec);
+
+        param_spec = g_param_spec_boolean ("is-loaded", NULL, NULL,
+                                           FALSE, G_PARAM_READABLE);
+        g_object_class_install_property (object_class, PROP_IS_LOADED, param_spec);
 }
 
 static void
@@ -117,6 +123,10 @@ gdm_session_settings_finalize (GObject *object)
 
         settings = GDM_SESSION_SETTINGS (object);
 
+        if (settings->priv->user != NULL) {
+                g_object_unref (settings->priv->user);
+        }
+
         g_free (settings->priv->session_name);
         g_free (settings->priv->language_name);
 
@@ -210,6 +220,10 @@ gdm_session_settings_get_property (GObject    *object,
                         g_value_set_string (value, settings->priv->language_name);
                 break;
 
+                case PROP_IS_LOADED:
+                        g_value_set_boolean (value, gdm_session_settings_is_loaded (settings));
+                break;
+
                 default:
                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -229,42 +243,85 @@ gdm_session_settings_new (void)
 gboolean
 gdm_session_settings_is_loaded (GdmSessionSettings  *settings)
 {
-        return settings->priv->session_name != NULL ||
-               settings->priv->language_name != NULL;
+        if (settings->priv->user == NULL) {
+                return FALSE;
+        }
+
+        return act_user_is_loaded (settings->priv->user);
 }
 
-gboolean
-gdm_session_settings_load (GdmSessionSettings  *settings,
-                           const char          *username)
+static void
+load_settings_from_user (GdmSessionSettings *settings)
 {
-        ActUser *user;
         const char *session_name;
         const char *language_name;
 
-        g_return_val_if_fail (settings != NULL, FALSE);
-        g_return_val_if_fail (username != NULL, FALSE);
-        g_return_val_if_fail (!gdm_session_settings_is_loaded (settings), FALSE);
-
-        user = act_user_manager_get_user (settings->priv->user_manager,
-                                          username);
-
-        if (!act_user_is_loaded (user)) {
-                g_object_unref (user);
-                return FALSE;
+        if (!act_user_is_loaded (settings->priv->user)) {
+                g_warning ("GdmSessionSettings: trying to load user settings from unloaded user");
+                return;
         }
 
-        session_name = act_user_get_x_session (user);
+        session_name = act_user_get_x_session (settings->priv->user);
 
         if (session_name != NULL) {
                 gdm_session_settings_set_session_name (settings, session_name);
         }
 
-        language_name = act_user_get_language (user);
+        language_name = act_user_get_language (settings->priv->user);
 
         if (language_name != NULL) {
                 gdm_session_settings_set_language_name (settings, language_name);
         }
-        g_object_unref (user);
+
+        g_object_notify (G_OBJECT (settings), "is-loaded");
+}
+
+static void
+on_user_is_loaded_changed (ActUser            *user,
+                           GParamSpec         *pspec,
+                           GdmSessionSettings *settings)
+{
+        if (act_user_is_loaded (settings->priv->user)) {
+                load_settings_from_user (settings);
+        }
+}
+
+gboolean
+gdm_session_settings_load (GdmSessionSettings  *settings,
+                           const char          *username)
+{
+        ActUser *old_user;
+
+        g_return_val_if_fail (settings != NULL, FALSE);
+        g_return_val_if_fail (username != NULL, FALSE);
+        g_return_val_if_fail (!gdm_session_settings_is_loaded (settings), FALSE);
+
+        if (settings->priv->user != NULL) {
+                old_user = settings->priv->user;
+
+                g_signal_handlers_disconnect_by_func (G_OBJECT (settings->priv->user),
+                                                      G_CALLBACK (on_user_is_loaded_changed),
+                                                      settings);
+        } else {
+                old_user = NULL;
+        }
+
+        settings->priv->user = act_user_manager_get_user (settings->priv->user_manager,
+                                                          username);
+        if (old_user != NULL) {
+                g_object_unref (old_user);
+                old_user = NULL;
+        }
+
+        if (!act_user_is_loaded (settings->priv->user)) {
+                g_signal_connect (settings->priv->user,
+                                  "notify::is-loaded",
+                                  G_CALLBACK (on_user_is_loaded_changed),
+                                  settings);
+                return FALSE;
+        }
+
+        load_settings_from_user (settings);
 
         return TRUE;
 }
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 3dd714f..0b1f478 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -92,6 +92,7 @@ enum {
         GDM_SESSION_WORKER_STATE_AUTHENTICATED,
         GDM_SESSION_WORKER_STATE_AUTHORIZED,
         GDM_SESSION_WORKER_STATE_ACCREDITED,
+        GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_FETCHED,
         GDM_SESSION_WORKER_STATE_SESSION_OPENED,
         GDM_SESSION_WORKER_STATE_SESSION_STARTED,
         GDM_SESSION_WORKER_STATE_REAUTHENTICATED,
@@ -2067,7 +2068,7 @@ gdm_session_worker_open_user_session (GdmSessionWorker  *worker,
 {
         int error_code;
 
-        g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCREDITED);
+        g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_FETCHED);
         g_assert (geteuid () == 0);
 
         error_code = pam_open_session (worker->priv->pam_handle, 0);
@@ -2379,6 +2380,43 @@ do_accredit (GdmSessionWorker *worker)
 }
 
 static void
+on_settings_is_loaded_changed (GdmSessionWorker *worker)
+{
+        if (!gdm_session_settings_is_loaded (worker->priv->user_settings)) {
+                return;
+        }
+
+        if (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCREDITED) {
+                worker->priv->state = GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_FETCHED;
+                queue_state_change (worker);
+        }
+
+        g_signal_handlers_disconnect_by_func (G_OBJECT (worker->priv->user_settings),
+                                              G_CALLBACK (on_settings_is_loaded_changed),
+                                              worker);
+}
+
+static void
+do_fetch_account_details (GdmSessionWorker *worker)
+{
+        g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCREDITED);
+
+        if (gdm_session_settings_is_loaded (worker->priv->user_settings)) {
+                worker->priv->state = GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_FETCHED;
+                queue_state_change (worker);
+                return;
+        }
+
+        g_signal_connect (G_OBJECT (worker->priv->user_settings),
+                          "notify::is-loaded",
+                          G_CALLBACK (on_settings_is_loaded_changed),
+                          worker);
+
+        gdm_session_settings_load (worker->priv->user_settings,
+                                   worker->priv->username);
+}
+
+static void
 do_open_session (GdmSessionWorker *worker)
 {
         GError  *error;
@@ -2441,6 +2479,9 @@ get_state_name (int state)
         case GDM_SESSION_WORKER_STATE_ACCREDITED:
                 name = "ACCREDITED";
                 break;
+        case GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_FETCHED:
+                name = "ACCOUNT_DETAILS_FETCHED";
+                break;
         case GDM_SESSION_WORKER_STATE_SESSION_OPENED:
                 name = "SESSION_OPENED";
                 break;
@@ -2479,6 +2520,9 @@ state_change_idle (GdmSessionWorker *worker)
         case GDM_SESSION_WORKER_STATE_ACCREDITED:
                 do_accredit (worker);
                 break;
+        case GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_FETCHED:
+                do_fetch_account_details (worker);
+                break;
         case GDM_SESSION_WORKER_STATE_SESSION_OPENED:
                 do_open_session (worker);
                 break;



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