Blame SOURCES/0001-daemon-don-t-treat-explicitly-requested-users-as-cac.patch

34a24a
From 59235d291c9aac5f68e17cc927f142cf5e532e46 Mon Sep 17 00:00:00 2001
34a24a
From: Ray Strode <rstrode@redhat.com>
34a24a
Date: Thu, 4 May 2017 12:04:05 -0400
34a24a
Subject: [PATCH] daemon: don't treat explicitly requested users as "cached"
34a24a
34a24a
The ListCachedUsers method currently returns users that have
34a24a
been explicitly requested by a client.  It's weird that merely
34a24a
querying a user can make it show up in login screen user lists.
34a24a
Furthermore, UncacheUser is broken since commit
34a24a
177509e9460b149ecbf85e75c930be2ea00b7d05 because the user has
34a24a
been explicitly requested in order to uncache it.  So trying
34a24a
to uncache a user inadvertently caches the user.
34a24a
34a24a
This commit fixes that.
34a24a
---
34a24a
 src/daemon.c | 71 +++++++++++++++++++++++++++++++++++++++---------------------
34a24a
 src/user.c   | 17 +++++++++++++++
34a24a
 src/user.h   |  3 +++
34a24a
 3 files changed, 66 insertions(+), 25 deletions(-)
34a24a
34a24a
diff --git a/src/daemon.c b/src/daemon.c
34a24a
index 312394a..6e3e4b3 100644
34a24a
--- a/src/daemon.c
34a24a
+++ b/src/daemon.c
34a24a
@@ -329,100 +329,108 @@ entry_generator_requested_users (Daemon       *daemon,
34a24a
                 while (node != NULL) {
34a24a
                         const char *name;
34a24a
 
34a24a
                         name = node->data;
34a24a
                         node = node->next;
34a24a
 
34a24a
                         *state = node;
34a24a
 
34a24a
                         if (!g_hash_table_lookup (users, name)) {
34a24a
                                 pwent = getpwnam (name);
34a24a
                                 if (pwent == NULL) {
34a24a
                                         g_debug ("user '%s' requested previously but not present on system", name);
34a24a
                                 } else {
34a24a
                                         *shadow_entry = getspnam (pwent->pw_name);
34a24a
 
34a24a
                                         return pwent;
34a24a
                                 }
34a24a
                         }
34a24a
                 }
34a24a
         }
34a24a
 
34a24a
         /* Last iteration */
34a24a
 
34a24a
         *state = NULL;
34a24a
         return NULL;
34a24a
 }
34a24a
 
34a24a
 static void
34a24a
 load_entries (Daemon             *daemon,
34a24a
               GHashTable         *users,
34a24a
-              gboolean            allow_system_users,
34a24a
+              gboolean            explicitly_requested,
34a24a
               EntryGeneratorFunc  entry_generator)
34a24a
 {
34a24a
         gpointer generator_state = NULL;
34a24a
         struct passwd *pwent;
34a24a
         struct spwd *spent = NULL;
34a24a
         User *user = NULL;
34a24a
 
34a24a
         g_assert (entry_generator != NULL);
34a24a
 
34a24a
         for (;;) {
34a24a
                 spent = NULL;
34a24a
                 pwent = entry_generator (daemon, users, &generator_state, &spent);
34a24a
                 if (pwent == NULL)
34a24a
                         break;
34a24a
 
34a24a
                 /* Skip system users... */
34a24a
-                if (!allow_system_users && !user_classify_is_human (pwent->pw_uid, pwent->pw_name, pwent->pw_shell, spent? spent->sp_pwdp : NULL)) {
34a24a
+                if (!explicitly_requested && !user_classify_is_human (pwent->pw_uid, pwent->pw_name, pwent->pw_shell, spent? spent->sp_pwdp : NULL)) {
34a24a
                         g_debug ("skipping user: %s", pwent->pw_name);
34a24a
                         continue;
34a24a
                 }
34a24a
 
34a24a
-                /* ignore duplicate entries */
34a24a
-                if (g_hash_table_lookup (users, pwent->pw_name)) {
34a24a
-                        continue;
34a24a
-                }
34a24a
+                /* Only process users that haven't been processed yet.
34a24a
+                 * We do always make sure entries get promoted
34a24a
+                 * to "cached" status if they are supposed to be
34a24a
+                 */
34a24a
+
34a24a
+                user = g_hash_table_lookup (users, pwent->pw_name);
34a24a
 
34a24a
-                user = g_hash_table_lookup (daemon->priv->users, pwent->pw_name);
34a24a
                 if (user == NULL) {
34a24a
-                        user = user_new (daemon, pwent->pw_uid);
34a24a
-                } else {
34a24a
-                        g_object_ref (user);
34a24a
-                }
34a24a
+                        user = g_hash_table_lookup (daemon->priv->users, pwent->pw_name);
34a24a
+                        if (user == NULL) {
34a24a
+                                user = user_new (daemon, pwent->pw_uid);
34a24a
+                        } else {
34a24a
+                                g_object_ref (user);
34a24a
+                        }
34a24a
 
34a24a
-                /* freeze & update users not already in the new list */
34a24a
-                g_object_freeze_notify (G_OBJECT (user));
34a24a
-                user_update_from_pwent (user, pwent, spent);
34a24a
+                        /* freeze & update users not already in the new list */
34a24a
+                        g_object_freeze_notify (G_OBJECT (user));
34a24a
+                        user_update_from_pwent (user, pwent, spent);
34a24a
 
34a24a
-                g_hash_table_insert (users, g_strdup (user_get_user_name (user)), user);
34a24a
-                g_debug ("loaded user: %s", user_get_user_name (user));
34a24a
+                        g_hash_table_insert (users, g_strdup (user_get_user_name (user)), user);
34a24a
+                        g_debug ("loaded user: %s", user_get_user_name (user));
34a24a
+                }
34a24a
+
34a24a
+                if (!explicitly_requested) {
34a24a
+                        user_set_cached (user, TRUE);
34a24a
+                }
34a24a
         }
34a24a
 
34a24a
         /* Generator should have cleaned up */
34a24a
         g_assert (generator_state == NULL);
34a24a
 }
34a24a
 
34a24a
 static GHashTable *
34a24a
 create_users_hash_table (void)
34a24a
 {
34a24a
         return g_hash_table_new_full (g_str_hash,
34a24a
                                       g_str_equal,
34a24a
                                       g_free,
34a24a
                                       g_object_unref);
34a24a
 }
34a24a
 
34a24a
 static void
34a24a
 reload_users (Daemon *daemon)
34a24a
 {
34a24a
         GHashTable *users;
34a24a
         GHashTable *old_users;
34a24a
         GHashTable *local;
34a24a
         GHashTableIter iter;
34a24a
         gpointer name;
34a24a
         User *user;
34a24a
 
34a24a
         /* Track the users that we saw during our (re)load */
34a24a
         users = create_users_hash_table ();
34a24a
 
34a24a
         /*
34a24a
          * NOTE: As we load data from all the sources, notifies are
34a24a
@@ -432,71 +440,79 @@ reload_users (Daemon *daemon)
34a24a
 
34a24a
         /* Load the local users into our hash table */
34a24a
         load_entries (daemon, users, FALSE, entry_generator_fgetpwent);
34a24a
         local = g_hash_table_new (g_str_hash, g_str_equal);
34a24a
         g_hash_table_iter_init (&iter, users);
34a24a
         while (g_hash_table_iter_next (&iter, &name, NULL))
34a24a
                 g_hash_table_add (local, name);
34a24a
 
34a24a
         /* and add users to hash table that were explicitly requested  */
34a24a
         load_entries (daemon, users, TRUE, entry_generator_requested_users);
34a24a
 
34a24a
         /* Now add/update users from other sources, possibly non-local */
34a24a
         load_entries (daemon, users, FALSE, entry_generator_cachedir);
34a24a
 
34a24a
         wtmp_helper_update_login_frequencies (users);
34a24a
 
34a24a
         /* Mark which users are local, which are not */
34a24a
         g_hash_table_iter_init (&iter, users);
34a24a
         while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user))
34a24a
                 user_update_local_account_property (user, g_hash_table_lookup (local, name) != NULL);
34a24a
 
34a24a
         g_hash_table_destroy (local);
34a24a
 
34a24a
         /* Swap out the users */
34a24a
         old_users = daemon->priv->users;
34a24a
         daemon->priv->users = users;
34a24a
 
34a24a
         /* Remove all the old users */
34a24a
         g_hash_table_iter_init (&iter, old_users);
34a24a
         while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) {
34a24a
-                if (!g_hash_table_lookup (users, name)) {
34a24a
+                User *refreshed_user;
34a24a
+
34a24a
+                refreshed_user = g_hash_table_lookup (users, name);
34a24a
+
34a24a
+                if (!refreshed_user || !user_get_cached (refreshed_user)) {
34a24a
                         user_unregister (user);
34a24a
                         accounts_accounts_emit_user_deleted (ACCOUNTS_ACCOUNTS (daemon),
34a24a
                                                              user_get_object_path (user));
34a24a
                 }
34a24a
         }
34a24a
 
34a24a
         /* Register all the new users */
34a24a
         g_hash_table_iter_init (&iter, users);
34a24a
         while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) {
34a24a
-                if (!g_hash_table_lookup (old_users, name)) {
34a24a
+                User *stale_user;
34a24a
+
34a24a
+                stale_user = g_hash_table_lookup (old_users, name);
34a24a
+
34a24a
+                if (!stale_user || !user_get_cached (stale_user) && user_get_cached (user)) {
34a24a
                         user_register (user);
34a24a
                         accounts_accounts_emit_user_added (ACCOUNTS_ACCOUNTS (daemon),
34a24a
                                                            user_get_object_path (user));
34a24a
                 }
34a24a
                 g_object_thaw_notify (G_OBJECT (user));
34a24a
         }
34a24a
 
34a24a
         g_hash_table_destroy (old_users);
34a24a
 }
34a24a
 
34a24a
 static gboolean
34a24a
 reload_users_timeout (Daemon *daemon)
34a24a
 {
34a24a
         reload_users (daemon);
34a24a
         daemon->priv->reload_id = 0;
34a24a
 
34a24a
         return FALSE;
34a24a
 }
34a24a
 
34a24a
 static gboolean load_autologin (Daemon    *daemon,
34a24a
                                 gchar    **name,
34a24a
                                 gboolean  *enabled,
34a24a
                                 GError   **error);
34a24a
 
34a24a
 static gboolean
34a24a
 reload_autologin_timeout (Daemon *daemon)
34a24a
 {
34a24a
         gboolean enabled;
34a24a
         gchar *name = NULL;
34a24a
         GError *error = NULL;
34a24a
@@ -911,60 +927,65 @@ list_user_data_new (Daemon                *daemon,
34a24a
 static void
34a24a
 list_user_data_free (ListUserData *data)
34a24a
 {
34a24a
         g_object_unref (data->daemon);
34a24a
         g_free (data);
34a24a
 }
34a24a
 
34a24a
 static gboolean
34a24a
 finish_list_cached_users (gpointer user_data)
34a24a
 {
34a24a
         ListUserData *data = user_data;
34a24a
         GPtrArray *object_paths;
34a24a
         GHashTableIter iter;
34a24a
         const gchar *name;
34a24a
         User *user;
34a24a
         uid_t uid;
34a24a
         const gchar *shell;
34a24a
 
34a24a
         object_paths = g_ptr_array_new ();
34a24a
 
34a24a
         g_hash_table_iter_init (&iter, data->daemon->priv->users);
34a24a
         while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&user)) {
34a24a
                 uid = user_get_uid (user);
34a24a
                 shell = user_get_shell (user);
34a24a
 
34a24a
                 if (!user_classify_is_human (uid, name, shell, NULL)) {
34a24a
                         g_debug ("user %s %ld excluded", name, (long) uid);
34a24a
                         continue;
34a24a
                 }
34a24a
 
34a24a
+                if (!user_get_cached (user)) {
34a24a
+                        g_debug ("user %s %ld not cached", name, (long) uid);
34a24a
+                        continue;
34a24a
+                }
34a24a
+
34a24a
                 g_debug ("user %s %ld not excluded", name, (long) uid);
34a24a
                 g_ptr_array_add (object_paths, (gpointer) user_get_object_path (user));
34a24a
         }
34a24a
         g_ptr_array_add (object_paths, NULL);
34a24a
 
34a24a
         accounts_accounts_complete_list_cached_users (NULL, data->context, (const gchar * const *) object_paths->pdata);
34a24a
 
34a24a
         g_ptr_array_free (object_paths, TRUE);
34a24a
 
34a24a
         list_user_data_free (data);
34a24a
 
34a24a
         return FALSE;
34a24a
 }
34a24a
 
34a24a
 static gboolean
34a24a
 daemon_list_cached_users (AccountsAccounts      *accounts,
34a24a
                           GDBusMethodInvocation *context)
34a24a
 {
34a24a
         Daemon *daemon = (Daemon*)accounts;
34a24a
         ListUserData *data;
34a24a
 
34a24a
         data = list_user_data_new (daemon, context);
34a24a
 
34a24a
         if (daemon->priv->reload_id > 0) {
34a24a
                 /* reload in progress, wait a bit */
34a24a
                 g_idle_add (finish_list_cached_users, data);
34a24a
         }
34a24a
         else {
34a24a
                 finish_list_cached_users (data);
34a24a
         }
34a24a
@@ -1151,123 +1172,123 @@ daemon_cache_user (AccountsAccounts      *accounts,
34a24a
 static void
34a24a
 daemon_uncache_user_authorized_cb (Daemon                *daemon,
34a24a
                                    User                  *dummy,
34a24a
                                    GDBusMethodInvocation *context,
34a24a
                                    gpointer               data)
34a24a
 {
34a24a
         const gchar *user_name = data;
34a24a
         gchar       *filename;
34a24a
         User        *user;
34a24a
 
34a24a
         sys_log (context, "uncache user '%s'", user_name);
34a24a
 
34a24a
         user = daemon_local_find_user_by_name (daemon, user_name);
34a24a
         if (user == NULL) {
34a24a
                 throw_error (context, ERROR_USER_DOES_NOT_EXIST,
34a24a
                              "No user with the name %s found", user_name);
34a24a
                 return;
34a24a
         }
34a24a
 
34a24a
         /* Always use the canonical user name looked up */
34a24a
         user_name = user_get_user_name (user);
34a24a
 
34a24a
         filename = g_build_filename (USERDIR, user_name, NULL);
34a24a
         g_remove (filename);
34a24a
         g_free (filename);
34a24a
 
34a24a
         filename = g_build_filename (ICONDIR, user_name, NULL);
34a24a
         g_remove (filename);
34a24a
         g_free (filename);
34a24a
 
34a24a
+        user_set_cached (user, FALSE);
34a24a
+
34a24a
         accounts_accounts_complete_uncache_user (NULL, context);
34a24a
 
34a24a
         queue_reload_users (daemon);
34a24a
 }
34a24a
 
34a24a
 static gboolean
34a24a
 daemon_uncache_user (AccountsAccounts      *accounts,
34a24a
                      GDBusMethodInvocation *context,
34a24a
                      const gchar           *user_name)
34a24a
 {
34a24a
         Daemon *daemon = (Daemon*)accounts;
34a24a
 
34a24a
         daemon_local_check_auth (daemon,
34a24a
                                  NULL,
34a24a
                                  "org.freedesktop.accounts.user-administration",
34a24a
                                  TRUE,
34a24a
                                  daemon_uncache_user_authorized_cb,
34a24a
                                  context,
34a24a
                                  g_strdup (user_name),
34a24a
                                  g_free);
34a24a
 
34a24a
         return TRUE;
34a24a
 }
34a24a
 
34a24a
 typedef struct {
34a24a
         uid_t uid;
34a24a
         gboolean remove_files;
34a24a
 } DeleteUserData;
34a24a
 
34a24a
 static void
34a24a
 daemon_delete_user_authorized_cb (Daemon                *daemon,
34a24a
                                   User                  *dummy,
34a24a
                                   GDBusMethodInvocation *context,
34a24a
                                   gpointer               data)
34a24a
 
34a24a
 {
34a24a
         DeleteUserData *ud = data;
34a24a
         GError *error;
34a24a
         gchar *filename;
34a24a
         struct passwd *pwent;
34a24a
         const gchar *argv[6];
34a24a
+        User *user;
34a24a
 
34a24a
         pwent = getpwuid (ud->uid);
34a24a
 
34a24a
         if (pwent == NULL) {
34a24a
                 throw_error (context, ERROR_USER_DOES_NOT_EXIST, "No user with uid %d found", ud->uid);
34a24a
 
34a24a
                 return;
34a24a
         }
34a24a
 
34a24a
         sys_log (context, "delete user '%s' (%d)", pwent->pw_name, ud->uid);
34a24a
 
34a24a
-        if (daemon->priv->autologin != NULL) {
34a24a
-                User *user;
34a24a
+        user = daemon_local_find_user_by_id (daemon, ud->uid);
34a24a
 
34a24a
-                user = daemon_local_find_user_by_id (daemon, ud->uid);
34a24a
+        if (user != NULL) {
34a24a
+                user_set_cached (user, FALSE);
34a24a
 
34a24a
-                g_assert (user != NULL);
34a24a
-
34a24a
-                if (daemon->priv->autologin == user) {
34a24a
+                if (daemon->priv->autologin  == user) {
34a24a
                         daemon_local_set_automatic_login (daemon, user, FALSE, NULL);
34a24a
                 }
34a24a
-
34a24a
         }
34a24a
 
34a24a
         filename = g_build_filename (USERDIR, pwent->pw_name, NULL);
34a24a
         g_remove (filename);
34a24a
         g_free (filename);
34a24a
 
34a24a
         filename = g_build_filename (ICONDIR, pwent->pw_name, NULL);
34a24a
         g_remove (filename);
34a24a
         g_free (filename);
34a24a
 
34a24a
         argv[0] = "/usr/sbin/userdel";
34a24a
         if (ud->remove_files) {
34a24a
                 argv[1] = "-f";
34a24a
                 argv[2] = "-r";
34a24a
                 argv[3] = "--";
34a24a
                 argv[4] = pwent->pw_name;
34a24a
                 argv[5] = NULL;
34a24a
         }
34a24a
         else {
34a24a
                 argv[1] = "-f";
34a24a
                 argv[2] = "--";
34a24a
                 argv[3] = pwent->pw_name;
34a24a
                 argv[4] = NULL;
34a24a
         }
34a24a
 
34a24a
         error = NULL;
34a24a
         if (!spawn_with_login_uid (context, argv, &error)) {
34a24a
                 throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
34a24a
                 g_error_free (error);
34a24a
                 return;
34a24a
diff --git a/src/user.c b/src/user.c
34a24a
index 802d07a..a83cfe4 100644
34a24a
--- a/src/user.c
34a24a
+++ b/src/user.c
34a24a
@@ -83,60 +83,61 @@ struct User {
34a24a
         GKeyFile     *keyfile;
34a24a
 
34a24a
         uid_t         uid;
34a24a
         gid_t         gid;
34a24a
         gchar        *user_name;
34a24a
         gchar        *real_name;
34a24a
         AccountType   account_type;
34a24a
         PasswordMode  password_mode;
34a24a
         gchar        *password_hint;
34a24a
         gchar        *home_dir;
34a24a
         gchar        *shell;
34a24a
         gchar        *email;
34a24a
         gchar        *language;
34a24a
         gchar        *x_session;
34a24a
         gchar        *location;
34a24a
         guint64       login_frequency;
34a24a
         gint64        login_time;
34a24a
         gint64        expiration_time;
34a24a
         gint64        last_change_time;
34a24a
         gint64        min_days_between_changes;
34a24a
         gint64        max_days_between_changes;
34a24a
         gint64        days_to_warn;
34a24a
         gint64        days_after_expiration_until_lock;
34a24a
         GVariant     *login_history;
34a24a
         gchar        *icon_file;
34a24a
         gchar        *default_icon_file;
34a24a
         gboolean      locked;
34a24a
         gboolean      automatic_login;
34a24a
         gboolean      system_account;
34a24a
         gboolean      local_account;
34a24a
+        gboolean      cached;
34a24a
 
34a24a
         guint        *extension_ids;
34a24a
         guint         n_extension_ids;
34a24a
 };
34a24a
 
34a24a
 typedef struct UserClass
34a24a
 {
34a24a
         AccountsUserSkeletonClass parent_class;
34a24a
 } UserClass;
34a24a
 
34a24a
 static void user_accounts_user_iface_init (AccountsUserIface *iface);
34a24a
 
34a24a
 G_DEFINE_TYPE_WITH_CODE (User, user, ACCOUNTS_TYPE_USER_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_USER, user_accounts_user_iface_init));
34a24a
 
34a24a
 static gint
34a24a
 account_type_from_pwent (struct passwd *pwent)
34a24a
 {
34a24a
         struct group *grp;
34a24a
         gint i;
34a24a
 
34a24a
         if (pwent->pw_uid == 0) {
34a24a
                 g_debug ("user is root so account type is administrator");
34a24a
                 return ACCOUNT_TYPE_ADMINISTRATOR;
34a24a
         }
34a24a
 
34a24a
         grp = getgrnam (ADMIN_GROUP);
34a24a
         if (grp == NULL) {
34a24a
                 g_debug (ADMIN_GROUP " group not found");
34a24a
                 return ACCOUNT_TYPE_STANDARD;
34a24a
         }
34a24a
@@ -339,109 +340,112 @@ user_update_from_keyfile (User     *user,
34a24a
                 user->location = s;
34a24a
                 g_object_notify (G_OBJECT (user), "location");
34a24a
         }
34a24a
 
34a24a
         s = g_key_file_get_string (keyfile, "User", "PasswordHint", NULL);
34a24a
         if (s != NULL) {
34a24a
                 g_free (user->password_hint);
34a24a
                 user->password_hint = s;
34a24a
                 g_object_notify (G_OBJECT (user), "password-hint");
34a24a
         }
34a24a
 
34a24a
         s = g_key_file_get_string (keyfile, "User", "Icon", NULL);
34a24a
         if (s != NULL) {
34a24a
                 g_free (user->icon_file);
34a24a
                 user->icon_file = s;
34a24a
                 g_object_notify (G_OBJECT (user), "icon-file");
34a24a
         }
34a24a
 
34a24a
         if (g_key_file_has_key (keyfile, "User", "SystemAccount", NULL)) {
34a24a
             gboolean system_account;
34a24a
 
34a24a
             system_account = g_key_file_get_boolean (keyfile, "User", "SystemAccount", NULL);
34a24a
             if (system_account != user->system_account) {
34a24a
                     user->system_account = system_account;
34a24a
                     g_object_notify (G_OBJECT (user), "system-account");
34a24a
             }
34a24a
         }
34a24a
 
34a24a
         g_clear_pointer (&user->keyfile, g_key_file_unref);
34a24a
         user->keyfile = g_key_file_ref (keyfile);
34a24a
+        user_set_cached (user, TRUE);
34a24a
 
34a24a
         g_object_thaw_notify (G_OBJECT (user));
34a24a
 }
34a24a
 
34a24a
 void
34a24a
 user_update_local_account_property (User          *user,
34a24a
                                     gboolean       local)
34a24a
 {
34a24a
         if (local == user->local_account)
34a24a
                 return;
34a24a
         user->local_account = local;
34a24a
         g_object_notify (G_OBJECT (user), "local-account");
34a24a
 }
34a24a
 
34a24a
 void
34a24a
 user_update_system_account_property (User          *user,
34a24a
                                      gboolean       system)
34a24a
 {
34a24a
         if (system == user->system_account)
34a24a
                 return;
34a24a
         user->system_account = system;
34a24a
         g_object_notify (G_OBJECT (user), "system-account");
34a24a
 }
34a24a
 
34a24a
 static void
34a24a
 user_save_to_keyfile (User     *user,
34a24a
                       GKeyFile *keyfile)
34a24a
 {
34a24a
         g_key_file_remove_group (keyfile, "User", NULL);
34a24a
 
34a24a
         if (user->email)
34a24a
                 g_key_file_set_string (keyfile, "User", "Email", user->email);
34a24a
 
34a24a
         if (user->language)
34a24a
                 g_key_file_set_string (keyfile, "User", "Language", user->language);
34a24a
 
34a24a
         if (user->x_session)
34a24a
                 g_key_file_set_string (keyfile, "User", "XSession", user->x_session);
34a24a
 
34a24a
         if (user->location)
34a24a
                 g_key_file_set_string (keyfile, "User", "Location", user->location);
34a24a
 
34a24a
         if (user->password_hint)
34a24a
                 g_key_file_set_string (keyfile, "User", "PasswordHint", user->password_hint);
34a24a
 
34a24a
         if (user->icon_file)
34a24a
                 g_key_file_set_string (keyfile, "User", "Icon", user->icon_file);
34a24a
 
34a24a
         g_key_file_set_boolean (keyfile, "User", "SystemAccount", user->system_account);
34a24a
+
34a24a
+        user_set_cached (user, TRUE);
34a24a
 }
34a24a
 
34a24a
 static void
34a24a
 save_extra_data (User *user)
34a24a
 {
34a24a
         gchar *filename;
34a24a
         gchar *data;
34a24a
         GError *error;
34a24a
 
34a24a
         user_save_to_keyfile (user, user->keyfile);
34a24a
 
34a24a
         error = NULL;
34a24a
         data = g_key_file_to_data (user->keyfile, NULL, &error);
34a24a
         if (error == NULL) {
34a24a
                 filename = g_build_filename (USERDIR,
34a24a
                                              user->user_name,
34a24a
                                              NULL);
34a24a
                 g_file_set_contents (filename, data, -1, &error);
34a24a
                 g_free (filename);
34a24a
                 g_free (data);
34a24a
         }
34a24a
         if (error) {
34a24a
                 g_warning ("Saving data for user %s failed: %s",
34a24a
                            user->user_name, error->message);
34a24a
                 g_error_free (error);
34a24a
         }
34a24a
 }
34a24a
 
34a24a
 static void
34a24a
 move_extra_data (const gchar *old_name,
34a24a
@@ -810,60 +814,73 @@ user_get_user_name (User *user)
34a24a
 gboolean
34a24a
 user_get_system_account (User *user)
34a24a
 {
34a24a
         return user->system_account;
34a24a
 }
34a24a
 
34a24a
 gboolean
34a24a
 user_get_local_account (User *user)
34a24a
 {
34a24a
         return user->local_account;
34a24a
 }
34a24a
 
34a24a
 const gchar *
34a24a
 user_get_object_path (User *user)
34a24a
 {
34a24a
         return user->object_path;
34a24a
 }
34a24a
 
34a24a
 uid_t
34a24a
 user_get_uid (User *user)
34a24a
 {
34a24a
         return user->uid;
34a24a
 }
34a24a
 
34a24a
 const gchar *
34a24a
 user_get_shell(User *user)
34a24a
 {
34a24a
 	return user->shell;
34a24a
 }
34a24a
 
34a24a
+gboolean
34a24a
+user_get_cached (User *user)
34a24a
+{
34a24a
+        return user->cached;
34a24a
+}
34a24a
+
34a24a
+void
34a24a
+user_set_cached (User     *user,
34a24a
+                 gboolean  cached)
34a24a
+{
34a24a
+        user->cached = cached;
34a24a
+}
34a24a
+
34a24a
 static void
34a24a
 throw_error (GDBusMethodInvocation *context,
34a24a
              gint                   error_code,
34a24a
              const gchar           *format,
34a24a
              ...)
34a24a
 {
34a24a
         va_list args;
34a24a
         gchar *message;
34a24a
 
34a24a
         va_start (args, format);
34a24a
         message = g_strdup_vprintf (format, args);
34a24a
         va_end (args);
34a24a
 
34a24a
         g_dbus_method_invocation_return_error (context, ERROR, error_code, "%s", message);
34a24a
 
34a24a
         g_free (message);
34a24a
 }
34a24a
 
34a24a
 static void
34a24a
 user_change_real_name_authorized_cb (Daemon                *daemon,
34a24a
                                      User                  *user,
34a24a
                                      GDBusMethodInvocation *context,
34a24a
                                      gpointer               data)
34a24a
 
34a24a
 {
34a24a
         gchar *name = data;
34a24a
         GError *error;
34a24a
         const gchar *argv[6];
34a24a
 
34a24a
         if (g_strcmp0 (user->real_name, name) != 0) {
34a24a
diff --git a/src/user.h b/src/user.h
34a24a
index 22548f9..39c6f13 100644
34a24a
--- a/src/user.h
34a24a
+++ b/src/user.h
34a24a
@@ -36,47 +36,50 @@ G_BEGIN_DECLS
34a24a
 #define IS_USER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TYPE_USER))
34a24a
 
34a24a
 typedef enum {
34a24a
         ACCOUNT_TYPE_STANDARD,
34a24a
         ACCOUNT_TYPE_ADMINISTRATOR,
34a24a
 #define ACCOUNT_TYPE_LAST ACCOUNT_TYPE_ADMINISTRATOR
34a24a
 } AccountType;
34a24a
 
34a24a
 typedef enum {
34a24a
         PASSWORD_MODE_REGULAR,
34a24a
         PASSWORD_MODE_SET_AT_LOGIN,
34a24a
         PASSWORD_MODE_NONE,
34a24a
 #define PASSWORD_MODE_LAST PASSWORD_MODE_NONE
34a24a
 } PasswordMode;
34a24a
 
34a24a
 /* local methods */
34a24a
 
34a24a
 GType          user_get_type                (void) G_GNUC_CONST;
34a24a
 User *         user_new                     (Daemon        *daemon,
34a24a
                                              uid_t          uid);
34a24a
 
34a24a
 void           user_update_from_pwent       (User          *user,
34a24a
                                              struct passwd *pwent,
34a24a
                                              struct spwd   *spent);
34a24a
 void           user_update_from_keyfile     (User          *user,
34a24a
                                              GKeyFile      *keyfile);
34a24a
 void           user_update_local_account_property (User          *user,
34a24a
                                                    gboolean       local);
34a24a
 void           user_update_system_account_property (User          *user,
34a24a
                                                     gboolean       system);
34a24a
+gboolean       user_get_cached              (User          *user);
34a24a
+void           user_set_cached              (User          *user,
34a24a
+                                             gboolean       cached);
34a24a
 
34a24a
 void           user_register                (User          *user);
34a24a
 void           user_unregister              (User          *user);
34a24a
 void           user_changed                 (User          *user);
34a24a
 
34a24a
 void           user_save                    (User          *user);
34a24a
 
34a24a
 const gchar *  user_get_user_name           (User          *user);
34a24a
 gboolean       user_get_system_account      (User          *user);
34a24a
 gboolean       user_get_local_account       (User          *user);
34a24a
 const gchar *  user_get_object_path         (User          *user);
34a24a
 uid_t          user_get_uid                 (User          *user);
34a24a
 const gchar *  user_get_shell               (User          *user);
34a24a
 
34a24a
 G_END_DECLS
34a24a
 
34a24a
 #endif
34a24a
-- 
34a24a
2.12.2
34a24a