You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
304 lines
11 KiB
304 lines
11 KiB
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 |
|
|
|
|