From 14c902f42a4ea74ce9450eb53817e1bf5be05d26 Mon Sep 17 00:00:00 2001 From: Ray Strode 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