Blob Blame History Raw
From 14c902f42a4ea74ce9450eb53817e1bf5be05d26 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 8 Sep 2021 16:38:17 -0400
Subject: [PATCH 1/2] daemon: Allow SystemAccount=false to be set in cache file

At the moment we do dodgy checks based on uid to decide whether or not
an account is a system account.

For legacy reasons, sometimes normal users have really low UIDs.

This commit reshuffles things, so the cache file "wins" for deciding
whether or not a user is a system user.
---
 src/daemon.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/daemon.c b/src/daemon.c
index 66ac7ba..2b6650b 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -219,60 +219,68 @@ entry_generator_fgetpwent (Daemon       *daemon,
                 if (g_hash_table_size (shadow_users) == 0) {
                         g_clear_pointer (&shadow_users, g_hash_table_unref);
                         return NULL;
                 }
 
                 fp = fopen (PATH_PASSWD, "r");
                 if (fp == NULL) {
                         g_clear_pointer (&shadow_users, g_hash_table_unref);
                         g_warning ("Unable to open %s: %s", PATH_PASSWD, g_strerror (errno));
                         return NULL;
                 }
 
                 generator_state = g_malloc0 (sizeof (*generator_state));
                 generator_state->fp = fp;
                 generator_state->users = shadow_users;
 
                 *state = generator_state;
         }
 
         /* Every iteration */
         generator_state = *state;
 
         if (g_hash_table_size (users) < MAX_LOCAL_USERS) {
                 pwent = fgetpwent (generator_state->fp);
                 if (pwent != NULL) {
                         shadow_entry_buffers = g_hash_table_lookup (generator_state->users, pwent->pw_name);
 
                         if (shadow_entry_buffers != NULL) {
                             *spent = &shadow_entry_buffers->spbuf;
                         }
+
+                        /* Skip system users... */
+                        if (!user_classify_is_human (pwent->pw_uid, pwent->pw_name, pwent->pw_shell, (*spent)? (*spent)->sp_pwdp : NULL)) {
+                                g_debug ("skipping user: %s", pwent->pw_name);
+
+                                return entry_generator_fgetpwent (daemon, users, state, spent);
+                        }
+
                         return pwent;
                 }
         }
 
         /* Last iteration */
         fclose (generator_state->fp);
         g_hash_table_unref (generator_state->users);
         g_free (generator_state);
         *state = NULL;
 
         return NULL;
 }
 
 static struct passwd *
 entry_generator_cachedir (Daemon       *daemon,
                           GHashTable   *users,
                           gpointer     *state,
                           struct spwd **shadow_entry)
 {
         struct passwd *pwent;
         g_autoptr(GError) error = NULL;
         gboolean regular;
         GHashTableIter iter;
         gpointer key, value;
         GDir *dir;
 
         /* First iteration */
         if (*state == NULL) {
                 *state = g_dir_open (USERDIR, 0, &error);
                 if (error != NULL) {
@@ -373,66 +381,60 @@ entry_generator_requested_users (Daemon       *daemon,
                         }
                 }
         }
 
         /* Last iteration */
 
         *state = NULL;
         return NULL;
 }
 
 static void
 load_entries (Daemon             *daemon,
               GHashTable         *users,
               gboolean            explicitly_requested,
               EntryGeneratorFunc  entry_generator)
 {
         DaemonPrivate *priv = daemon_get_instance_private (daemon);
         gpointer generator_state = NULL;
         struct passwd *pwent;
         struct spwd *spent = NULL;
         User *user = NULL;
 
         g_assert (entry_generator != NULL);
 
         for (;;) {
                 spent = NULL;
                 pwent = entry_generator (daemon, users, &generator_state, &spent);
                 if (pwent == NULL)
                         break;
 
-                /* Skip system users... */
-                if (!explicitly_requested && !user_classify_is_human (pwent->pw_uid, pwent->pw_name, pwent->pw_shell, spent? spent->sp_pwdp : NULL)) {
-                        g_debug ("skipping user: %s", pwent->pw_name);
-                        continue;
-                }
-
                 /* Only process users that haven't been processed yet.
                  * We do always make sure entries get promoted
                  * to "cached" status if they are supposed to be
                  */
 
                 user = g_hash_table_lookup (users, pwent->pw_name);
 
                 if (user == NULL) {
                         user = g_hash_table_lookup (priv->users, pwent->pw_name);
                         if (user == NULL) {
                                 user = user_new (daemon, pwent->pw_uid);
                         } else {
                                 g_object_ref (user);
                         }
 
                         /* freeze & update users not already in the new list */
                         g_object_freeze_notify (G_OBJECT (user));
                         user_update_from_pwent (user, pwent, spent);
 
                         g_hash_table_insert (users, g_strdup (user_get_user_name (user)), user);
                         g_debug ("loaded user: %s", user_get_user_name (user));
                 }
 
                 if (!explicitly_requested) {
                         user_set_cached (user, TRUE);
                 }
         }
 
         /* Generator should have cleaned up */
         g_assert (generator_state == NULL);
@@ -501,66 +503,66 @@ has_network_realms (Daemon *daemon)
 
 static void
 reload_users (Daemon *daemon)
 {
         DaemonPrivate *priv = daemon_get_instance_private (daemon);
         AccountsAccounts *accounts = ACCOUNTS_ACCOUNTS (daemon);
         gboolean had_no_users, has_no_users, had_multiple_users, has_multiple_users;
         GHashTable *users;
         GHashTable *old_users;
         GHashTable *local;
         GHashTableIter iter;
         gsize number_of_normal_users = 0;
         gpointer name, value;
 
         /* Track the users that we saw during our (re)load */
         users = create_users_hash_table ();
 
         /*
          * NOTE: As we load data from all the sources, notifies are
          * frozen in load_entries() and then thawed as we process
          * them below.
          */
 
         /* Load the local users into our hash table */
         load_entries (daemon, users, FALSE, entry_generator_fgetpwent);
         local = g_hash_table_new (g_str_hash, g_str_equal);
         g_hash_table_iter_init (&iter, users);
         while (g_hash_table_iter_next (&iter, &name, NULL))
                 g_hash_table_add (local, name);
 
-        /* and add users to hash table that were explicitly requested  */
-        load_entries (daemon, users, TRUE, entry_generator_requested_users);
-
         /* Now add/update users from other sources, possibly non-local */
         load_entries (daemon, users, FALSE, entry_generator_cachedir);
 
+        /* and add users to hash table that were explicitly requested  */
+        load_entries (daemon, users, TRUE, entry_generator_requested_users);
+
         wtmp_helper_update_login_frequencies (users);
 
         /* Count the non-system users. Mark which users are local, which are not. */
         g_hash_table_iter_init (&iter, users);
         while (g_hash_table_iter_next (&iter, &name, &value)) {
                 User *user = value;
                 if (!user_get_system_account (user))
                         number_of_normal_users++;
                 user_update_local_account_property (user, g_hash_table_lookup (local, name) != NULL);
         }
         g_hash_table_destroy (local);
 
         had_no_users = accounts_accounts_get_has_no_users (accounts);
         has_no_users = number_of_normal_users == 0;
 
         if (has_no_users && has_network_realms (daemon)) {
                 g_debug ("No local users, but network realms detected, presuming there are remote users");
                 has_no_users = FALSE;
         }
 
         if (had_no_users != has_no_users)
                 accounts_accounts_set_has_no_users (accounts, has_no_users);
 
         had_multiple_users = accounts_accounts_get_has_multiple_users (accounts);
         has_multiple_users = number_of_normal_users > 1;
 
         if (had_multiple_users != has_multiple_users)
                 accounts_accounts_set_has_multiple_users (accounts, has_multiple_users);
 
         /* Swap out the users */
@@ -1017,73 +1019,71 @@ daemon_find_user_by_name (AccountsAccounts      *accounts,
 
 static ListUserData *
 list_user_data_new (Daemon                *daemon,
                     GDBusMethodInvocation *context)
 {
         ListUserData *data;
 
         data = g_new0 (ListUserData, 1);
 
         data->daemon = g_object_ref (daemon);
         data->context = context;
 
         return data;
 }
 
 static void
 list_user_data_free (ListUserData *data)
 {
         g_object_unref (data->daemon);
         g_free (data);
 }
 
 static void
 finish_list_cached_users (ListUserData *data)
 {
         DaemonPrivate *priv = daemon_get_instance_private (data->daemon);
         g_autoptr(GPtrArray) object_paths = NULL;
         GHashTableIter iter;
         gpointer key, value;
         uid_t uid;
-        const gchar *shell;
 
         object_paths = g_ptr_array_new ();
 
         g_hash_table_iter_init (&iter, priv->users);
         while (g_hash_table_iter_next (&iter, &key, &value)) {
                 const gchar *name = key;
                 User *user = value;
 
                 uid = user_get_uid (user);
-                shell = user_get_shell (user);
 
-                if (!user_classify_is_human (uid, name, shell, NULL)) {
+                if (user_get_system_account (user)) {
                         g_debug ("user %s %ld excluded", name, (long) uid);
                         continue;
                 }
 
                 if (!user_get_cached (user)) {
                         g_debug ("user %s %ld not cached", name, (long) uid);
                         continue;
                 }
 
                 g_debug ("user %s %ld not excluded", name, (long) uid);
                 g_ptr_array_add (object_paths, (gpointer) user_get_object_path (user));
         }
         g_ptr_array_add (object_paths, NULL);
 
         accounts_accounts_complete_list_cached_users (NULL, data->context, (const gchar * const *) object_paths->pdata);
 
         list_user_data_free (data);
 }
 
 static gboolean
 daemon_list_cached_users (AccountsAccounts      *accounts,
                           GDBusMethodInvocation *context)
 {
         Daemon *daemon = (Daemon*)accounts;
         DaemonPrivate *priv = daemon_get_instance_private (daemon);
         ListUserData *data;
 
         data = list_user_data_new (daemon, context);
 
         if (priv->reload_id > 0) {
-- 
2.31.1