From 1a6b7c24ec1947dd352243f4f5b8dea4156b7faf Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Oct 15 2021 16:23:00 +0000 Subject: import accountsservice-0.6.55-3.el8 --- diff --git a/SOURCES/0001-daemon-Allow-SystemAccount-false-to-be-set-in-cache-.patch b/SOURCES/0001-daemon-Allow-SystemAccount-false-to-be-set-in-cache-.patch new file mode 100644 index 0000000..84d5265 --- /dev/null +++ b/SOURCES/0001-daemon-Allow-SystemAccount-false-to-be-set-in-cache-.patch @@ -0,0 +1,304 @@ +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 + diff --git a/SOURCES/0002-main-Allow-cache-files-to-be-marked-immutable.patch b/SOURCES/0002-main-Allow-cache-files-to-be-marked-immutable.patch new file mode 100644 index 0000000..991a879 --- /dev/null +++ b/SOURCES/0002-main-Allow-cache-files-to-be-marked-immutable.patch @@ -0,0 +1,195 @@ +From 12127d9c04e8151c51bd14114dce424ff8448345 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 9 Sep 2021 09:40:49 -0400 +Subject: [PATCH 2/2] main: Allow cache files to be marked immutable + +At the moment, at start up we unconditionally reset permission of all +cache files in /var/lib/AccountsService/users. If the mode of the files +can't be reset, accountsservice fails to start. + +But there's a situation where we should proceed anyway: If the +mode is already correct, and the file is read-only, there is no reason +to refuse to proceed. + +This commit changes the code to explicitly validate the permissions of +the file before failing. +--- + src/main.c | 29 +++++++++++++++++++++++++---- + 1 file changed, 25 insertions(+), 4 deletions(-) + +diff --git a/src/main.c b/src/main.c +index 01cb617..36a2d7e 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -16,143 +16,164 @@ + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Written by: Matthias Clasen + */ + + #include "config.h" + + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + + #include "daemon.h" + + #define NAME_TO_CLAIM "org.freedesktop.Accounts" + + static gboolean + ensure_directory (const char *path, + gint mode, + GError **error) + { ++ GStatBuf stat_buffer = { 0 }; ++ + if (g_mkdir_with_parents (path, mode) < 0) { + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), + "Failed to create directory %s: %m", + path); + return FALSE; + } + +- if (g_chmod (path, mode) < 0) { ++ g_chmod (path, mode); ++ ++ if (g_stat (path, &stat_buffer) < 0) { ++ g_clear_error (error); ++ + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), +- "Failed to change permissions of directory %s: %m", ++ "Failed to validate permissions of directory %s: %m", + path); + return FALSE; + } + ++ if ((stat_buffer.st_mode & ~S_IFMT) != mode) { ++ g_set_error (error, ++ G_FILE_ERROR, ++ g_file_error_from_errno (errno), ++ "Directory %s has wrong mode %o; it should be %o", ++ path, stat_buffer.st_mode, mode); ++ return FALSE; ++ } ++ + return TRUE; + } + + static gboolean + ensure_file_permissions (const char *dir_path, + gint file_mode, + GError **error) + { + GDir *dir = NULL; + const gchar *filename; + gint errsv = 0; + + dir = g_dir_open (dir_path, 0, error); + if (dir == NULL) + return FALSE; + + while ((filename = g_dir_read_name (dir)) != NULL) { ++ GStatBuf stat_buffer = { 0 }; ++ + gchar *file_path = g_build_filename (dir_path, filename, NULL); + + g_debug ("Changing permission of %s to %04o", file_path, file_mode); +- if (g_chmod (file_path, file_mode) < 0) ++ g_chmod (file_path, file_mode); ++ ++ if (g_stat (file_path, &stat_buffer) < 0) + errsv = errno; + ++ if ((stat_buffer.st_mode & ~S_IFMT) != file_mode) ++ errsv = EACCES; ++ + g_free (file_path); + } + + g_dir_close (dir); + + /* Report any errors after all chmod()s have been attempted. */ + if (errsv != 0) { + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (errsv), + "Failed to change permissions of files in directory %s: %m", + dir_path); + return FALSE; + } + + return TRUE; + } + + static void + on_bus_acquired (GDBusConnection *connection, + const gchar *name, + gpointer user_data) + { + GMainLoop *loop = user_data; + Daemon *daemon; + g_autoptr(GError) error = NULL; + + if (!ensure_directory (ICONDIR, 0775, &error) || + !ensure_directory (USERDIR, 0700, &error) || + !ensure_file_permissions (USERDIR, 0600, &error)) { + g_printerr ("%s\n", error->message); + g_main_loop_quit (loop); + return; + } + + daemon = daemon_new (); + if (daemon == NULL) { + g_printerr ("Failed to initialize daemon\n"); + g_main_loop_quit (loop); + return; + } +- + openlog ("accounts-daemon", LOG_PID, LOG_DAEMON); + syslog (LOG_INFO, "started daemon version %s", VERSION); + closelog (); + openlog ("accounts-daemon", 0, LOG_AUTHPRIV); + } + + static void + on_name_lost (GDBusConnection *connection, + const gchar *name, + gpointer user_data) + { + GMainLoop *loop = user_data; + + g_debug ("got NameLost, exiting"); + g_main_loop_quit (loop); + } + + static gboolean debug; + + static void + on_log_debug (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) + { + g_autoptr(GString) string = NULL; + const gchar *progname; + int ret G_GNUC_UNUSED; + + string = g_string_new (NULL); +-- +2.31.1 + diff --git a/SPECS/accountsservice.spec b/SPECS/accountsservice.spec index 4548d9a..39603f0 100644 --- a/SPECS/accountsservice.spec +++ b/SPECS/accountsservice.spec @@ -2,7 +2,7 @@ Name: accountsservice Version: 0.6.55 -Release: 2%{?dist} +Release: 3%{?dist} Summary: D-Bus interfaces for querying and manipulating user account information License: GPLv3+ URL: https://www.freedesktop.org/wiki/Software/AccountsService/ @@ -34,6 +34,9 @@ Patch30001: 0001-lib-save-os-when-creating-user.patch Patch40001: 0001-user-Introduce-user-templates-for-setting-default-se.patch +Patch50001: 0001-daemon-Allow-SystemAccount-false-to-be-set-in-cache-.patch +Patch50002: 0002-main-Allow-cache-files-to-be-marked-immutable.patch + %description The accountsservice project provides a set of D-Bus interfaces for querying and manipulating user account information and an implementation @@ -119,6 +122,10 @@ cp $RPM_SOURCE_DIR/user-template $RPM_BUILD_ROOT%{_datadir}/accountsservice/user %{_datadir}/gtk-doc/html/libaccountsservice/* %changelog +* Tue Oct 12 2021 Ray Strode - 0.6.55-3 +- Allow cache files to configure and override system accounts + Resolves: #2012331 + * Wed Aug 04 2021 Ray Strode - 0.6.55-2 - Add support for user templates so user can specify default session Resolves: #1812788