diff --git a/.accountsservice.metadata b/.accountsservice.metadata index ac25f19..794dd8f 100644 --- a/.accountsservice.metadata +++ b/.accountsservice.metadata @@ -1 +1 @@ -915cf5df1ce04a2dfc6026ba58734f9cb77a3cae SOURCES/accountsservice-0.6.35.tar.xz +e9d13e6970c52e168eb7d6dc8441a3abafed3dfa SOURCES/accountsservice-0.6.45.tar.xz diff --git a/.gitignore b/.gitignore index 0276295..677f17f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/accountsservice-0.6.35.tar.xz +SOURCES/accountsservice-0.6.45.tar.xz diff --git a/SOURCES/0001-Add-asynchronous-api-for-user-uncaching.patch b/SOURCES/0001-Add-asynchronous-api-for-user-uncaching.patch deleted file mode 100644 index 4cc5f26..0000000 --- a/SOURCES/0001-Add-asynchronous-api-for-user-uncaching.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 564dc2f4a923c6e2c45a9920776ae93a97bebede Mon Sep 17 00:00:00 2001 -From: Ondrej Holy -Date: Thu, 18 Sep 2014 18:55:36 +0200 -Subject: [PATCH] Add asynchronous api for user uncaching - -It is needed for deleting enterprise accounts in gnome-control-center. -See https://bugzilla.gnome.org/show_bug.cgi?id=727871 for details. ---- - src/libaccountsservice/act-user-manager.c | 83 +++++++++++++++++++++++++++++++ - src/libaccountsservice/act-user-manager.h | 8 +++ - 2 files changed, 91 insertions(+) - -diff --git a/src/libaccountsservice/act-user-manager.c b/src/libaccountsservice/act-user-manager.c -index c1c6f5a..e7c3305 100644 ---- a/src/libaccountsservice/act-user-manager.c -+++ b/src/libaccountsservice/act-user-manager.c -@@ -3353,6 +3353,89 @@ act_user_manager_uncache_user (ActUserManager *manager, - return TRUE; - } - -+/* -+ * act_user_manager_uncache_user_async: -+ * @manager: a #ActUserManager -+ * @username: a unix user name -+ * @cancellable: (allow-none): optional #GCancellable object, -+ * %NULL to ignore -+ * @callback: (scope async): a #GAsyncReadyCallback to call -+ * when the request is satisfied -+ * @user_data: (closure): the data to pass to @callback -+ * -+ * Asynchronously uncaches a user account. -+ * -+ * For more details, see act_user_manager_uncache_user(), which -+ * is the synchronous version of this call. -+ * -+ * Since: 0.6.39 -+ */ -+void -+act_user_manager_uncache_user_async (ActUserManager *manager, -+ const char *username, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GSimpleAsyncResult *res; -+ -+ g_return_if_fail (ACT_IS_USER_MANAGER (manager)); -+ g_return_if_fail (manager->priv->accounts_proxy != NULL); -+ -+ g_debug ("ActUserManager: Uncaching user (async) '%s'", username); -+ -+ res = g_simple_async_result_new (G_OBJECT (manager), -+ callback, user_data, -+ act_user_manager_uncache_user_async); -+ g_simple_async_result_set_check_cancellable (res, cancellable); -+ -+ accounts_accounts_call_uncache_user (manager->priv->accounts_proxy, -+ username, -+ cancellable, -+ act_user_manager_async_complete_handler, res); -+} -+ -+/** -+ * act_user_manager_uncache_user_finish: -+ * @manager: a #ActUserManager -+ * @result: a #GAsyncResult -+ * @error: a #GError -+ * -+ * Finishes an asynchronous user uncaching. -+ * -+ * See act_user_manager_uncache_user_async(). -+ * -+ * Returns: %TRUE if the user account was successfully uncached -+ * -+ * Since: 0.6.39 -+ */ -+gboolean -+act_user_manager_uncache_user_finish (ActUserManager *manager, -+ GAsyncResult *result, -+ GError **error) -+{ -+ GAsyncResult *inner_result; -+ gboolean success; -+ GSimpleAsyncResult *res; -+ GError *remote_error = NULL; -+ -+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (manager), act_user_manager_uncache_user_async), FALSE); -+ -+ res = G_SIMPLE_ASYNC_RESULT (result); -+ inner_result = g_simple_async_result_get_op_res_gpointer (res); -+ g_assert (inner_result); -+ -+ success = accounts_accounts_call_uncache_user_finish (manager->priv->accounts_proxy, -+ inner_result, &remote_error); -+ -+ if (remote_error) { -+ g_dbus_error_strip_remote_error (remote_error); -+ g_propagate_error (error, remote_error); -+ } -+ -+ return success; -+} -+ - /** - * act_user_manager_delete_user: - * @manager: a #ActUserManager -diff --git a/src/libaccountsservice/act-user-manager.h b/src/libaccountsservice/act-user-manager.h -index 3d91f83..ae5fd2e 100644 ---- a/src/libaccountsservice/act-user-manager.h -+++ b/src/libaccountsservice/act-user-manager.h -@@ -122,6 +122,14 @@ ActUser * act_user_manager_cache_user_finish (ActUserManager * - gboolean act_user_manager_uncache_user (ActUserManager *manager, - const char *username, - GError **error); -+void act_user_manager_uncache_user_async (ActUserManager *manager, -+ const gchar *username, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data); -+gboolean act_user_manager_uncache_user_finish (ActUserManager *manager, -+ GAsyncResult *result, -+ GError **error); - - gboolean act_user_manager_delete_user (ActUserManager *manager, - ActUser *user, --- -1.9.3 - diff --git a/SOURCES/0001-Avoid-deleting-the-root-user.patch b/SOURCES/0001-Avoid-deleting-the-root-user.patch deleted file mode 100644 index 06c9b0c..0000000 --- a/SOURCES/0001-Avoid-deleting-the-root-user.patch +++ /dev/null @@ -1,51 +0,0 @@ -From a9b7e9e368e79957ef492304bf62742b1304b7bb Mon Sep 17 00:00:00 2001 -From: Matthias Clasen -Date: Fri, 1 Nov 2013 17:09:25 -0400 -Subject: [PATCH] Avoid deleting the root user - -The check we have in place against deleting the root user can -be tricked by exploiting the fact that we are checking a gint64, -and then later cast it to a uid_t. This can be seen with the -following test, which will delete your root account: - -qdbus --system org.freedesktop.Accounts /org/freedesktop/Accounts \ - org.freedesktop.Accounts.DeleteUser -9223372036854775808 true - -Found with the dfuzzer tool, -https://github.com/matusmarhefka/dfuzzer ---- - src/daemon.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/daemon.c b/src/daemon.c -index 9c9f617..b2720f4 100644 ---- a/src/daemon.c -+++ b/src/daemon.c -@@ -1232,7 +1232,7 @@ daemon_uncache_user (AccountsAccounts *accounts, - } - - typedef struct { -- gint64 uid; -+ uid_t uid; - gboolean remove_files; - } DeleteUserData; - -@@ -1314,13 +1314,13 @@ daemon_delete_user (AccountsAccounts *accounts, - Daemon *daemon = (Daemon*)accounts; - DeleteUserData *data; - -- if (uid == 0) { -+ if ((uid_t)uid == 0) { - throw_error (context, ERROR_FAILED, "Refuse to delete root user"); - return TRUE; - } - - data = g_new0 (DeleteUserData, 1); -- data->uid = uid; -+ data->uid = (uid_t)uid; - data->remove_files = remove_files; - - daemon_local_check_auth (daemon, --- -1.8.4.2 - diff --git a/SOURCES/0001-configure-actually-define-HAVE_GETUSERSHELL.patch b/SOURCES/0001-configure-actually-define-HAVE_GETUSERSHELL.patch deleted file mode 100644 index 2e39df9..0000000 --- a/SOURCES/0001-configure-actually-define-HAVE_GETUSERSHELL.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 8e3bad7b7eb7212aa7554fa445b2e8e29daaacaa Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 6 Sep 2016 15:33:30 -0400 -Subject: [PATCH] configure: actually define HAVE_GETUSERSHELL - -currently we check for it but never actually set it, leading to -dead code. - -This commit fixes that. ---- - configure.ac | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/configure.ac b/configure.ac -index eb5360e..54f4eb4 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -160,60 +160,65 @@ AC_CACHE_CHECK([for supported warning flags], accountsservice_cv_warn_cflags, [ - ACCOUNTSSERVICE_CC_TRY_FLAG([$W], [WARN_CFLAGS="$WARN_CFLAGS $W"]) - done - - accountsservice_cv_warn_cflags=$WARN_CFLAGS - accountsservice_cv_warn_maybe=$MAYBE_WARN - - AC_MSG_CHECKING([which warning flags were supported]) - ]) - - WARN_CFLAGS="$accountsservice_cv_warn_cflags" - - if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then - # Only add this when optimizing is enabled (default) - AC_MSG_CHECKING([whether optimization is enabled]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if __OPTIMIZE__ == 0 - #error No optimization - #endif - ]], [[]])], - [has_optimization=yes], - [has_optimization=no]) - if test $has_optimization = yes; then - WARN_CFLAGS="$WARN_CFLAGS -Wp,-D_FORTIFY_SOURCE=2" - fi - AC_MSG_RESULT($has_optimization) - fi - - AC_SUBST(WARN_CFLAGS) - - AC_CHECK_HEADERS([shadow.h utmpx.h]) - -+AC_CHECK_LIB(c, getusershell, have_getusershell=yes, have_getusershell=no) -+if test x$have_getusershell = xyes; then -+ AC_DEFINE(HAVE_GETUSERSHELL, 1, [Define i getusershell() is available]) -+fi -+ - dnl --------------------------------------------------------------------------- - dnl - gtk-doc Documentation - dnl --------------------------------------------------------------------------- - - m4_ifdef([GTK_DOC_CHECK], [ - GTK_DOC_CHECK([1.15], [--flavour no-tmpl]) - ],[ - AM_CONDITIONAL([ENABLE_GTK_DOC],[false]) - ]) - - dnl --------------------------------------------------------------------------- - dnl - DocBook Documentation - dnl --------------------------------------------------------------------------- - - AC_ARG_ENABLE(docbook-docs, - [AS_HELP_STRING([--enable-docbook-docs],[build documentation (requires xmlto)])], - enable_docbook_docs=$enableval,enable_docbook_docs=no) - AC_PATH_PROG(XMLTO, xmlto, no) - AC_MSG_CHECKING([whether to build DocBook documentation]) - if test x$XMLTO = xno ; then - have_docbook=no - else - have_docbook=yes - fi - if test x$enable_docbook_docs = xauto ; then - if test x$have_docbook = xno ; then - enable_docbook_docs=no - else - enable_docbook_docs=yes - fi --- -2.7.4 - diff --git a/SOURCES/0001-daemon-don-t-treat-explicitly-requested-users-as-cac.patch b/SOURCES/0001-daemon-don-t-treat-explicitly-requested-users-as-cac.patch index bbf9cdd..fba593f 100644 --- a/SOURCES/0001-daemon-don-t-treat-explicitly-requested-users-as-cac.patch +++ b/SOURCES/0001-daemon-don-t-treat-explicitly-requested-users-as-cac.patch @@ -1,4 +1,4 @@ -From 83567748f5f5c4eabc233680a553f3edd803a24d Mon Sep 17 00:00:00 2001 +From 59235d291c9aac5f68e17cc927f142cf5e532e46 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Thu, 4 May 2017 12:04:05 -0400 Subject: [PATCH] daemon: don't treat explicitly requested users as "cached" @@ -12,8 +12,6 @@ been explicitly requested in order to uncache it. So trying to uncache a user inadvertently caches the user. This commit fixes that. - -https://bugs.freedesktop.org/show_bug.cgi?id=101052 --- src/daemon.c | 71 +++++++++++++++++++++++++++++++++++++++--------------------- src/user.c | 17 +++++++++++++++ @@ -21,10 +19,10 @@ https://bugs.freedesktop.org/show_bug.cgi?id=101052 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/daemon.c b/src/daemon.c -index 4586eff..fce5a60 100644 +index 312394a..6e3e4b3 100644 --- a/src/daemon.c +++ b/src/daemon.c -@@ -481,100 +481,108 @@ entry_generator_requested_users (Daemon *daemon, +@@ -329,100 +329,108 @@ entry_generator_requested_users (Daemon *daemon, while (node != NULL) { const char *name; @@ -102,20 +100,20 @@ index 4586eff..fce5a60 100644 + } 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); - /* 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)); -+ } ++ /* 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)); ++ 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); + } @@ -149,7 +147,9 @@ index 4586eff..fce5a60 100644 /* * NOTE: As we load data from all the sources, notifies are -@@ -586,71 +594,79 @@ reload_users (Daemon *daemon) +@@ -432,71 +440,79 @@ reload_users (Daemon *daemon) + + /* 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); @@ -162,9 +162,7 @@ index 4586eff..fce5a60 100644 /* Now add/update users from other sources, possibly non-local */ load_entries (daemon, users, FALSE, entry_generator_cachedir); - #ifdef HAVE_UTMPX_H - wtmp_update_login_frequencies (users); - #endif + wtmp_helper_update_login_frequencies (users); /* Mark which users are local, which are not */ g_hash_table_iter_init (&iter, users); @@ -231,7 +229,7 @@ index 4586eff..fce5a60 100644 gboolean enabled; gchar *name = NULL; GError *error = NULL; -@@ -1063,60 +1079,65 @@ list_user_data_new (Daemon *daemon, +@@ -911,60 +927,65 @@ list_user_data_new (Daemon *daemon, static void list_user_data_free (ListUserData *data) { @@ -297,7 +295,7 @@ index 4586eff..fce5a60 100644 else { finish_list_cached_users (data); } -@@ -1303,123 +1324,123 @@ daemon_cache_user (AccountsAccounts *accounts, +@@ -1151,123 +1172,123 @@ daemon_cache_user (AccountsAccounts *accounts, static void daemon_uncache_user_authorized_cb (Daemon *daemon, User *dummy, @@ -429,16 +427,10 @@ index 4586eff..fce5a60 100644 g_error_free (error); return; diff --git a/src/user.c b/src/user.c -index 247ca2f..056be2f 100644 +index 802d07a..a83cfe4 100644 --- a/src/user.c +++ b/src/user.c -@@ -77,60 +77,61 @@ struct User { - - GDBusConnection *system_bus_connection; - gchar *object_path; - - Daemon *daemon; - +@@ -83,60 +83,61 @@ struct User { GKeyFile *keyfile; uid_t uid; @@ -456,6 +448,12 @@ index 247ca2f..056be2f 100644 gchar *location; guint64 login_frequency; gint64 login_time; + gint64 expiration_time; + gint64 last_change_time; + gint64 min_days_between_changes; + gint64 max_days_between_changes; + gint64 days_to_warn; + gint64 days_after_expiration_until_lock; GVariant *login_history; gchar *icon_file; gchar *default_icon_file; @@ -464,6 +462,9 @@ index 247ca2f..056be2f 100644 gboolean system_account; gboolean local_account; + gboolean cached; + + guint *extension_ids; + guint n_extension_ids; }; typedef struct UserClass @@ -491,10 +492,7 @@ index 247ca2f..056be2f 100644 g_debug (ADMIN_GROUP " group not found"); return ACCOUNT_TYPE_STANDARD; } - - for (i = 0; grp->gr_mem[i] != NULL; i++) { - if (g_strcmp0 (grp->gr_mem[i], pwent->pw_name) == 0) { -@@ -323,109 +324,112 @@ user_update_from_keyfile (User *user, +@@ -339,109 +340,112 @@ user_update_from_keyfile (User *user, user->location = s; g_object_notify (G_OBJECT (user), "location"); } @@ -607,7 +605,7 @@ index 247ca2f..056be2f 100644 static void move_extra_data (const gchar *old_name, -@@ -524,60 +528,73 @@ user_get_user_name (User *user) +@@ -810,60 +814,73 @@ user_get_user_name (User *user) gboolean user_get_system_account (User *user) { diff --git a/SOURCES/0001-daemon-make-sure-explicitly-requested-users-aren-t-l.patch b/SOURCES/0001-daemon-make-sure-explicitly-requested-users-aren-t-l.patch deleted file mode 100644 index f35251c..0000000 --- a/SOURCES/0001-daemon-make-sure-explicitly-requested-users-aren-t-l.patch +++ /dev/null @@ -1,584 +0,0 @@ -From 691d11c09d40cf6e9745e0c61e3fc59f77865e04 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 23 Mar 2017 16:59:11 -0400 -Subject: [PATCH] daemon: make sure explicitly requested users aren't lost on - reloads - -Right now, a user proxy can suddenly become defunct if the -/etc/passwd file is updated or some other reason leads to a reload. - -This commit makes sure that the objects associated with proxies -stick around across reloads. ---- - src/daemon.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ - 1 file changed, 67 insertions(+), 7 deletions(-) - -diff --git a/src/daemon.c b/src/daemon.c -index 815e2c9..4586eff 100644 ---- a/src/daemon.c -+++ b/src/daemon.c -@@ -41,78 +41,79 @@ - - #include - #include - #include - #include - #include - #include - - #include "user-classify.h" - #include "daemon.h" - #include "util.h" - - #define PATH_PASSWD "/etc/passwd" - #define PATH_SHADOW "/etc/shadow" - #define PATH_GROUP "/etc/group" - #define PATH_GDM_CUSTOM "/etc/gdm/custom.conf" - #ifdef HAVE_UTMPX_H - #define PATH_WTMP _PATH_WTMPX - #endif - - enum { - PROP_0, - PROP_DAEMON_VERSION - }; - - struct DaemonPrivate { - GDBusConnection *bus_connection; - GDBusProxy *bus_proxy; - - GHashTable *users; -+ GList *explicitly_requested_users; - - User *autologin; - - GFileMonitor *passwd_monitor; - GFileMonitor *shadow_monitor; - GFileMonitor *group_monitor; - GFileMonitor *gdm_monitor; - #ifdef HAVE_UTMPX_H - GFileMonitor *wtmp_monitor; - #endif - - guint reload_id; - guint autologin_id; - - PolkitAuthority *authority; - }; - --typedef struct passwd * (* EntryGeneratorFunc) (GHashTable *, gpointer *, struct spwd **shadow_entry); -+typedef struct passwd * (* EntryGeneratorFunc) (Daemon *, GHashTable *, gpointer *, struct spwd **shadow_entry); - - static void daemon_accounts_accounts_iface_init (AccountsAccountsIface *iface); - - G_DEFINE_TYPE_WITH_CODE (Daemon, daemon, ACCOUNTS_TYPE_ACCOUNTS_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_ACCOUNTS, daemon_accounts_accounts_iface_init)); - - #define DAEMON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_DAEMON, DaemonPrivate)) - - static const GDBusErrorEntry accounts_error_entries[] = - { - { ERROR_FAILED, "org.freedesktop.Accounts.Error.Failed" }, - { ERROR_USER_EXISTS, "org.freedesktop.Accounts.Error.UserExists" }, - { ERROR_USER_DOES_NOT_EXIST, "org.freedesktop.Accounts.Error.UserDoesNotExist" }, - { ERROR_PERMISSION_DENIED, "org.freedesktop.Accounts.Error.PermissionDenied" }, - { ERROR_NOT_SUPPORTED, "org.freedesktop.Accounts.Error.NotSupported" } - }; - - GQuark - error_quark (void) - { - static volatile gsize quark_volatile = 0; - - g_dbus_error_register_error_domain ("accounts_error", - &quark_volatile, - accounts_error_entries, - G_N_ELEMENTS (accounts_error_entries)); - - return (GQuark) quark_volatile; - } - #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } - -@@ -265,61 +266,62 @@ wtmp_update_login_frequencies (GHashTable *users) - - g_object_set (user, "login-frequency", accounting->frequency, NULL); - g_object_set (user, "login-time", accounting->time, NULL); - - builder = g_variant_builder_new (G_VARIANT_TYPE ("a(xxa{sv})")); - for (l = g_list_last (accounting->previous_logins); l != NULL; l = l->prev) { - previous_login = l->data; - - builder2 = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (builder2, "{sv}", "type", g_variant_new_string (previous_login->id)); - g_variant_builder_add (builder, "(xxa{sv})", previous_login->login_time, previous_login->logout_time, builder2); - g_variant_builder_unref (builder2); - } - g_object_set (user, "login-history", g_variant_new ("a(xxa{sv})", builder), NULL); - g_variant_builder_unref (builder); - g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free); - - user_changed (user); - } - - g_hash_table_unref (login_hash); - g_hash_table_unref (logout_hash); - } - #endif /* HAVE_UTMPX_H */ - - #ifndef MAX_LOCAL_USERS - #define MAX_LOCAL_USERS 50 - #endif - - static struct passwd * --entry_generator_fgetpwent (GHashTable *users, -+entry_generator_fgetpwent (Daemon *daemon, -+ GHashTable *users, - gpointer *state, - struct spwd **spent) - { - struct passwd *pwent; - - struct { - struct spwd spbuf; - char buf[1024]; - } *shadow_entry_buffers; - - struct { - FILE *fp; - GHashTable *users; - } *generator_state; - - /* First iteration */ - if (*state == NULL) { - GHashTable *shadow_users = NULL; - FILE *fp; - struct spwd *shadow_entry; - - fp = fopen (PATH_SHADOW, "r"); - if (fp == NULL) { - g_warning ("Unable to open %s: %s", PATH_SHADOW, g_strerror (errno)); - return NULL; - } - - shadow_users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - - do { -@@ -358,61 +360,62 @@ entry_generator_fgetpwent (GHashTable *users, - 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; - 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 (GHashTable *users, -+entry_generator_cachedir (Daemon *daemon, -+ GHashTable *users, - gpointer *state, - struct spwd **shadow_entry) - { - struct passwd *pwent; - const gchar *name; - GError *error = NULL; - gchar *filename; - gboolean regular; - GHashTableIter iter; - GKeyFile *key_file; - User *user; - GDir *dir; - - /* First iteration */ - if (*state == NULL) { - *state = g_dir_open (USERDIR, 0, &error); - if (error != NULL) { - if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) - g_warning ("couldn't list user cache directory: %s", USERDIR); - g_error_free (error); - return NULL; - } - } - - /* Every iteration */ - - /* - * Use names of files of regular type to lookup information - * about each user. Loop until we find something valid. - */ -@@ -430,145 +433,194 @@ entry_generator_cachedir (GHashTable *users, - if (regular) { - pwent = getpwnam (name); - if (pwent == NULL) { - g_debug ("user '%s' in cache dir but not present on system", name); - } else { - *shadow_entry = getspnam (pwent->pw_name); - - return pwent; - } - } - } - - /* Last iteration */ - g_dir_close (dir); - - /* Update all the users from the files in the cache dir */ - g_hash_table_iter_init (&iter, users); - while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&user)) { - filename = g_build_filename (USERDIR, name, NULL); - key_file = g_key_file_new (); - if (g_key_file_load_from_file (key_file, filename, 0, NULL)) - user_update_from_keyfile (user, key_file); - g_key_file_unref (key_file); - g_free (filename); - } - - *state = NULL; - return NULL; - } - -+static struct passwd * -+entry_generator_requested_users (Daemon *daemon, -+ GHashTable *users, -+ gpointer *state, -+ struct spwd **shadow_entry) -+{ -+ struct passwd *pwent; -+ GList *node; -+ -+ /* First iteration */ -+ if (*state == NULL) { -+ *state = daemon->priv->explicitly_requested_users; -+ } -+ -+ /* Every iteration */ -+ -+ if (g_hash_table_size (users) < MAX_LOCAL_USERS) { -+ node = *state; -+ while (node != NULL) { -+ const char *name; -+ -+ name = node->data; -+ node = node->next; -+ -+ *state = node; -+ -+ if (!g_hash_table_lookup (users, name)) { -+ pwent = getpwnam (name); -+ if (pwent == NULL) { -+ g_debug ("user '%s' requested previously but not present on system", name); -+ } else { -+ *shadow_entry = getspnam (pwent->pw_name); -+ -+ return pwent; -+ } -+ } -+ } -+ } -+ -+ /* Last iteration */ -+ -+ *state = NULL; -+ return NULL; -+} -+ - static void - load_entries (Daemon *daemon, - GHashTable *users, -+ gboolean allow_system_users, - EntryGeneratorFunc entry_generator) - { - 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 (users, &generator_state, &spent); -+ pwent = entry_generator (daemon, users, &generator_state, &spent); - if (pwent == NULL) - break; - - /* Skip system users... */ -- if (!user_classify_is_human (pwent->pw_uid, pwent->pw_name, pwent->pw_shell, spent? spent->sp_pwdp : NULL)) { -+ if (!allow_system_users && !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; - } - - /* ignore duplicate entries */ - if (g_hash_table_lookup (users, pwent->pw_name)) { - continue; - } - - user = g_hash_table_lookup (daemon->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)); - } - - /* Generator should have cleaned up */ - g_assert (generator_state == NULL); - } - - static GHashTable * - create_users_hash_table (void) - { - return g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - g_object_unref); - } - - static void - reload_users (Daemon *daemon) - { - GHashTable *users; - GHashTable *old_users; - GHashTable *local; - GHashTableIter iter; - gpointer name; - User *user; - - /* 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, entry_generator_fgetpwent); -+ 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, entry_generator_cachedir); -+ load_entries (daemon, users, FALSE, entry_generator_cachedir); - - #ifdef HAVE_UTMPX_H - wtmp_update_login_frequencies (users); - #endif - - /* Mark which users are local, which are not */ - g_hash_table_iter_init (&iter, users); - while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) - user_update_local_account_property (user, g_hash_table_lookup (local, name) != NULL); - - g_hash_table_destroy (local); - - /* Swap out the users */ - old_users = daemon->priv->users; - daemon->priv->users = users; - - /* Remove all the old users */ - g_hash_table_iter_init (&iter, old_users); - while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) { - if (!g_hash_table_lookup (users, name)) { - user_unregister (user); - accounts_accounts_emit_user_deleted (ACCOUNTS_ACCOUNTS (daemon), - user_get_object_path (user)); - } - } - - /* Register all the new users */ - g_hash_table_iter_init (&iter, users); - while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) { - if (!g_hash_table_lookup (old_users, name)) { -@@ -757,60 +809,62 @@ daemon_init (Daemon *daemon) - - #ifdef HAVE_UTMPX_H - daemon->priv->wtmp_monitor = setup_monitor (daemon, - PATH_WTMP, - on_users_monitor_changed); - #endif - - daemon->priv->gdm_monitor = setup_monitor (daemon, - PATH_GDM_CUSTOM, - on_gdm_monitor_changed); - - queue_reload_users (daemon); - queue_reload_autologin (daemon); - } - - static void - daemon_finalize (GObject *object) - { - Daemon *daemon; - - g_return_if_fail (IS_DAEMON (object)); - - daemon = DAEMON (object); - - if (daemon->priv->bus_proxy != NULL) - g_object_unref (daemon->priv->bus_proxy); - - if (daemon->priv->bus_connection != NULL) - g_object_unref (daemon->priv->bus_connection); - -+ g_list_free_full (daemon->priv->explicitly_requested_users, g_free); -+ - g_hash_table_destroy (daemon->priv->users); - - G_OBJECT_CLASS (daemon_parent_class)->finalize (object); - } - - static gboolean - register_accounts_daemon (Daemon *daemon) - { - GError *error = NULL; - - daemon->priv->authority = polkit_authority_get_sync (NULL, &error); - - if (daemon->priv->authority == NULL) { - if (error != NULL) { - g_critical ("error getting polkit authority: %s", error->message); - g_error_free (error); - } - goto error; - } - - daemon->priv->bus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); - if (daemon->priv->bus_connection == NULL) { - if (error != NULL) { - g_critical ("error getting system bus: %s", error->message); - g_error_free (error); - } - goto error; - } - - if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (daemon), -@@ -878,84 +932,90 @@ add_new_user_for_pwent (Daemon *daemon, - user_register (user); - - g_hash_table_insert (daemon->priv->users, - g_strdup (user_get_user_name (user)), - user); - - accounts_accounts_emit_user_added (ACCOUNTS_ACCOUNTS (daemon), user_get_object_path (user)); - - return user; - } - - User * - daemon_local_find_user_by_id (Daemon *daemon, - uid_t uid) - { - User *user; - struct passwd *pwent; - - pwent = getpwuid (uid); - if (pwent == NULL) { - g_debug ("unable to lookup uid %d", (int)uid); - return NULL; - } - - user = g_hash_table_lookup (daemon->priv->users, pwent->pw_name); - - if (user == NULL) { - struct spwd *spent; - spent = getspnam (pwent->pw_name); - user = add_new_user_for_pwent (daemon, pwent, spent); -+ -+ daemon->priv->explicitly_requested_users = g_list_append (daemon->priv->explicitly_requested_users, -+ g_strdup (pwent->pw_name)); - } - - return user; - } - - User * - daemon_local_find_user_by_name (Daemon *daemon, - const gchar *name) - { - User *user; - struct passwd *pwent; - - pwent = getpwnam (name); - if (pwent == NULL) { - g_debug ("unable to lookup name %s: %s", name, g_strerror (errno)); - return NULL; - } - - user = g_hash_table_lookup (daemon->priv->users, pwent->pw_name); - - if (user == NULL) { - struct spwd *spent; - spent = getspnam (pwent->pw_name); - user = add_new_user_for_pwent (daemon, pwent, spent); -+ -+ daemon->priv->explicitly_requested_users = g_list_append (daemon->priv->explicitly_requested_users, -+ g_strdup (pwent->pw_name)); - } - - return user; - } - - User * - daemon_local_get_automatic_login_user (Daemon *daemon) - { - return daemon->priv->autologin; - } - - static gboolean - daemon_find_user_by_id (AccountsAccounts *accounts, - GDBusMethodInvocation *context, - gint64 uid) - { - Daemon *daemon = (Daemon*)accounts; - User *user; - - user = daemon_local_find_user_by_id (daemon, uid); - - if (user) { - accounts_accounts_complete_find_user_by_id (NULL, context, user_get_object_path (user)); - } - else { - throw_error (context, ERROR_FAILED, "Failed to look up user with uid %d.", (int)uid); - } - - return TRUE; - } --- -2.12.0 - diff --git a/SOURCES/0001-systemd-ensure-that-accounts-service-starts-after-NS.patch b/SOURCES/0001-systemd-ensure-that-accounts-service-starts-after-NS.patch deleted file mode 100644 index a4b112b..0000000 --- a/SOURCES/0001-systemd-ensure-that-accounts-service-starts-after-NS.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 3d6d125917073b06849c336c93e475a5a43c0dd9 Mon Sep 17 00:00:00 2001 -From: Stephen Gallagher -Date: Fri, 17 Oct 2014 11:43:39 -0400 -Subject: [PATCH] systemd: ensure that accounts service starts after NSS - initializes - -The various NSS calls don't give accurate results in some configurations -until midway through boot up. This is because SSSD or winbind (or -whatever) needs to initialize. - -In order to prevent accounts service from using NSS prematurely, we need -to add an ordering constraint between the nss-user-lookup.target and -accountsservice. - -This commit accomplishes this by adding the appropriate Wants= and -After= directives to the accountsservice systemd unit file. ---- - data/accounts-daemon.service.in | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/data/accounts-daemon.service.in b/data/accounts-daemon.service.in -index 105bf6a..feedf3e 100644 ---- a/data/accounts-daemon.service.in -+++ b/data/accounts-daemon.service.in -@@ -1,15 +1,21 @@ - [Unit] - Description=Accounts Service - -+# In order to avoid races with identity-providing services like SSSD or -+# winbind, we need to ensure that Accounts Service starts after -+# nss-user-lookup.target -+After=nss-user-lookup.target ypbind.service -+Wants=nss-user-lookup.target -+ - [Service] - Type=dbus - BusName=org.freedesktop.Accounts - ExecStart=@libexecdir@/accounts-daemon - StandardOutput=syslog - - [Install] - # We pull this in by graphical.target instead of waiting for the bus - # activation, to speed things up a little: gdm uses this anyway so it is nice - # if it is already around when gdm wants to use it and doesn't have to wait for - # it. - WantedBy=graphical.target --- -2.3.7 - diff --git a/SOURCES/0001-user-classify-exclude-nologin-users.patch b/SOURCES/0001-user-classify-exclude-nologin-users.patch deleted file mode 100644 index 40f2963..0000000 --- a/SOURCES/0001-user-classify-exclude-nologin-users.patch +++ /dev/null @@ -1,231 +0,0 @@ -From 450731558cbd5c77aa6932d35f27abf898553db6 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 6 Sep 2016 13:54:48 -0400 -Subject: [PATCH] user-classify: exclude nologin users - -Sometimes admins set a user's shell to nologin to hide it from -the user list. This commit fixes accountsservice so that behavior -works again. ---- - src/user-classify.c | 77 +++++++++++++++++++++++++++++------------------------ - 1 file changed, 42 insertions(+), 35 deletions(-) - -diff --git a/src/user-classify.c b/src/user-classify.c -index 69e6809..b79a35f 100644 ---- a/src/user-classify.c -+++ b/src/user-classify.c -@@ -1,169 +1,176 @@ - /* - * Copyright (C) 2009-2010 Red Hat, Inc. - * Copyright (C) 2013 Canonical Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the licence, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Ryan Lortie - * Matthias Clasen - */ - - #include "config.h" - - #include "user-classify.h" - - #include -+#include - - static const char *default_excludes[] = { - "bin", - "root", - "daemon", - "adm", - "lp", - "sync", - "shutdown", - "halt", - "mail", - "news", - "uucp", - "operator", - "nobody", - "nobody4", - "noaccess", - "postgres", - "pvm", - "rpm", - "nfsnobody", - "pcap", - "mysql", - "ftp", - "games", - "man", - "at", - "gdm", - "gnome-initial-setup" - }; - - static gboolean - user_classify_is_blacklisted (const char *username) - { - static GHashTable *exclusions; - - if (exclusions == NULL) { - guint i; - - exclusions = g_hash_table_new (g_str_hash, g_str_equal); - - for (i = 0; i < G_N_ELEMENTS (default_excludes); i++) { - g_hash_table_add (exclusions, (gpointer) default_excludes[i]); - } - } - - if (g_hash_table_contains (exclusions, username)) { - return TRUE; - } - - return FALSE; - } - - #define PATH_NOLOGIN "/sbin/nologin" - #define PATH_FALSE "/bin/false" - - #ifdef ENABLE_USER_HEURISTICS - static gboolean - user_classify_is_excluded_by_heuristics (const gchar *username, -- const gchar *shell, - const gchar *password_hash) - { - gboolean ret = FALSE; - -- if (shell != NULL) { -- char *basename, *nologin_basename, *false_basename; -- --#ifdef HAVE_GETUSERSHELL -- char *valid_shell; -- -- ret = TRUE; -- setusershell (); -- while ((valid_shell = getusershell ()) != NULL) { -- if (g_strcmp0 (shell, valid_shell) != 0) -- continue; -- ret = FALSE; -- } -- endusershell (); --#endif -- -- basename = g_path_get_basename (shell); -- nologin_basename = g_path_get_basename (PATH_NOLOGIN); -- false_basename = g_path_get_basename (PATH_FALSE); -- -- if (shell[0] == '\0') { -- ret = TRUE; -- } else if (g_strcmp0 (basename, nologin_basename) == 0) { -- ret = TRUE; -- } else if (g_strcmp0 (basename, false_basename) == 0) { -- ret = TRUE; -- } -- -- g_free (basename); -- g_free (nologin_basename); -- g_free (false_basename); -- } -- - if (password_hash != NULL) { - /* skip over the account-is-locked '!' prefix if present */ - if (password_hash[0] == '!') - password_hash++; - - if (password_hash[0] != '\0') { - /* modern hashes start with "$n$" */ - if (password_hash[0] == '$') { - if (strlen (password_hash) < 4) - ret = TRUE; - - /* DES crypt is base64 encoded [./A-Za-z0-9]* - */ - } else if (!g_ascii_isalnum (password_hash[0]) && - password_hash[0] != '.' && - password_hash[0] != '/') { - ret = TRUE; - } - } - - } - - return ret; - } - #endif /* ENABLE_USER_HEURISTICS */ - -+static gboolean -+is_invalid_shell (const char *shell) -+{ -+ char *basename, *nologin_basename, *false_basename; -+ int ret = FALSE; -+ -+#ifdef HAVE_GETUSERSHELL -+ char *valid_shell; -+ -+ setusershell (); -+ while ((valid_shell = getusershell ()) != NULL) { -+ if (g_strcmp0 (shell, valid_shell) != 0) -+ continue; -+ ret = FALSE; -+ } -+ endusershell (); -+#endif -+ -+ basename = g_path_get_basename (shell); -+ nologin_basename = g_path_get_basename (PATH_NOLOGIN); -+ false_basename = g_path_get_basename (PATH_FALSE); -+ -+ if (shell[0] == '\0') { -+ ret = TRUE; -+ } else if (g_strcmp0 (basename, nologin_basename) == 0) { -+ ret = TRUE; -+ } else if (g_strcmp0 (basename, false_basename) == 0) { -+ ret = TRUE; -+ } -+ -+ g_free (basename); -+ g_free (nologin_basename); -+ g_free (false_basename); -+ -+ return ret; -+} -+ - gboolean - user_classify_is_human (uid_t uid, - const gchar *username, - const gchar *shell, - const gchar *password_hash) - { - if (user_classify_is_blacklisted (username)) - return FALSE; - -+ if (shell != NULL && is_invalid_shell (shell)) -+ return FALSE; -+ - #ifdef ENABLE_USER_HEURISTICS - /* only do heuristics on the range 500-1000 to catch one off migration problems in Fedora */ - if (uid >= 500 && uid < MINIMUM_UID) { -- if (!user_classify_is_excluded_by_heuristics (username, shell, password_hash)) -+ if (!user_classify_is_excluded_by_heuristics (username, password_hash)) - return TRUE; - } - #endif - - return uid >= MINIMUM_UID; - } --- -2.7.4 - diff --git a/SOURCES/fix-leak.patch b/SOURCES/fix-leak.patch deleted file mode 100644 index ca12772..0000000 --- a/SOURCES/fix-leak.patch +++ /dev/null @@ -1,86 +0,0 @@ -From cfee906f39afa58d883e4fbed1888274c79c6e30 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 29 Jan 2014 10:29:04 -0500 -Subject: [PATCH] user: fix memory leak in save_extra_data function - -The save_extra_data function serializes a key file -assocated with the user to disk. - -It fails to free the in memory buffer, however. - -This commit fixes that. - -see downstream bug https://bugzilla.redhat.com/show_bug.cgi?id=1003033 ---- - src/user.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/user.c b/src/user.c -index 163d136..de30090 100644 ---- a/src/user.c -+++ b/src/user.c -@@ -407,60 +407,61 @@ user_save_to_keyfile (User *user, - - if (user->location) - g_key_file_set_string (keyfile, "User", "Location", user->location); - - if (user->password_hint) - g_key_file_set_string (keyfile, "User", "PasswordHint", user->password_hint); - - if (user->icon_file) - g_key_file_set_string (keyfile, "User", "Icon", user->icon_file); - - g_key_file_set_boolean (keyfile, "User", "SystemAccount", user->system_account); - } - - static void - save_extra_data (User *user) - { - gchar *filename; - gchar *data; - GError *error; - - user_save_to_keyfile (user, user->keyfile); - - error = NULL; - data = g_key_file_to_data (user->keyfile, NULL, &error); - if (error == NULL) { - filename = g_build_filename (USERDIR, - user->user_name, - NULL); - g_file_set_contents (filename, data, -1, &error); - g_free (filename); -+ g_free (data); - } - if (error) { - g_warning ("Saving data for user %s failed: %s", - user->user_name, error->message); - g_error_free (error); - } - } - - static void - move_extra_data (const gchar *old_name, - const gchar *new_name) - { - gchar *old_filename; - gchar *new_filename; - - old_filename = g_build_filename (USERDIR, - old_name, NULL); - new_filename = g_build_filename (USERDIR, - new_name, NULL); - - g_rename (old_filename, new_filename); - - g_free (old_filename); - g_free (new_filename); - } - - static gchar * - compute_object_path (User *user) - { - gchar *object_path; --- -1.8.4.2 - diff --git a/SOURCES/fix-log-leak.patch b/SOURCES/fix-log-leak.patch deleted file mode 100644 index 1e59714..0000000 --- a/SOURCES/fix-log-leak.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 1ff7d912fe329867a40c8e473cf0bde8d55202ef Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 1 Jul 2016 08:13:09 -0400 -Subject: [PATCH] main: fix leak in log handler - ---- - src/main.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/main.c b/src/main.c -index 2f799e5..cc62e05 100644 ---- a/src/main.c -+++ b/src/main.c -@@ -94,60 +94,62 @@ on_bus_acquired (GDBusConnection *connection, - static void - on_name_lost (GDBusConnection *connection, - const gchar *name, - gpointer 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) - { - GString *string; - const gchar *progname; - int ret G_GNUC_UNUSED; - - string = g_string_new (NULL); - - progname = g_get_prgname (); - g_string_append_printf (string, "(%s:%lu): %s%sDEBUG: %s\n", - progname ? progname : "process", (gulong)getpid (), - log_domain ? log_domain : "", log_domain ? "-" : "", - message ? message : "(NULL) message"); - - ret = write (1, string->str, string->len); -+ -+ g_string_free (string, TRUE); - } - - static void - log_handler (const gchar *domain, - GLogLevelFlags level, - const gchar *message, - gpointer data) - { - /* filter out DEBUG messages if debug isn't set */ - if ((level & G_LOG_LEVEL_MASK) == G_LOG_LEVEL_DEBUG && !debug) - return; - - g_log_default_handler (domain, level, message, data); - } - - static gboolean - on_signal_quit (gpointer data) - { - g_main_loop_quit (data); - return FALSE; - } - - int - main (int argc, char *argv[]) - { - GError *error; - gint ret; - GBusNameOwnerFlags flags; - GOptionContext *context; - static gboolean replace; --- -2.7.4 - diff --git a/SOURCES/fix-user-classification-logic.patch b/SOURCES/fix-user-classification-logic.patch deleted file mode 100644 index b241b32..0000000 --- a/SOURCES/fix-user-classification-logic.patch +++ /dev/null @@ -1,377 +0,0 @@ -From 1ef1e18936f1bfad019f3d6427135629f4bdc2a1 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 15 Nov 2013 10:11:15 -0500 -Subject: [PATCH] Change up user classification logic again - -relying on login.defs is fragile, and the -user heuristics are fragile. - -This commit requires an explicit uid minimum -get configured, and heuristics now only get -applied to the specific problematic range -they were added to address. - -https://bugs.freedesktop.org/show_bug.cgi?id=71801 ---- - configure.ac | 8 +++- - src/user-classify.c | 129 ++++++++++------------------------------------------ - 2 files changed, 32 insertions(+), 105 deletions(-) - -diff --git a/configure.ac b/configure.ac -index a7f4e20..eb5360e 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -28,65 +28,71 @@ AC_SUBST(LT_AGE) - PKG_CHECK_MODULES(GIO, gio-2.0 gio-unix-2.0) - PKG_CHECK_MODULES(POLKIT, gio-unix-2.0 polkit-gobject-1) - - AM_MAINTAINER_MODE([enable]) - - # client library dependencies - LIBACCOUNTSSERVICE_LIBS="$GIO_LIBS" - AC_SUBST(LIBACCOUNTSSERVICE_LIBS) - LIBACCOUNTSSERVICE_CFLAGS="$GIO_CFLAGS" - AC_SUBST(LIBACCOUNTSSERVICE_CFLAGS) - - GOBJECT_INTROSPECTION_CHECK([0.9.12]) - - dnl --------------------------------------------------------------------------- - dnl - Core configuration - dnl --------------------------------------------------------------------------- - - AC_ARG_ENABLE(admin-group, - [AS_HELP_STRING([--enable-admin-group],[Set group for administrative accounts @<:@default=auto@:>@])], - ,enable_admin_group=auto) - AS_IF([test x$enable_admin_group = xauto], [ - AC_CHECK_FILE(/etc/redhat-release, enable_admin_group=wheel) - AC_CHECK_FILE(/etc/debian_version, enable_admin_group=sudo) - AS_IF([test x$enable_admin_group = xauto], [ - enable_admin_group=wheel - ]) - ]) - AC_DEFINE_UNQUOTED([ADMIN_GROUP], ["$enable_admin_group"], [Define to the group for administrator users]) - - AC_ARG_ENABLE(user-heuristics, -- [AS_HELP_STRING([--enable-user-heuristics],[Enable heuristics for guessing system vs. human users])], -+ [AS_HELP_STRING([--enable-user-heuristics],[Enable heuristics for guessing system vs. human users in the range 500-minimum-uid])], - [if test "$enableval" = yes; then - AC_DEFINE([ENABLE_USER_HEURISTICS], , [System vs. human user heuristics enabled]) - fi]) - -+AC_ARG_WITH(minimum-uid, -+ [AS_HELP_STRING([--with-minimum-uid],[Set minimum uid for human users])], -+ ,with_minimum_uid=1000) -+ -+AC_DEFINE_UNQUOTED([MINIMUM_UID], $with_minimum_uid, [Define to the minumum UID of human users]) -+ - dnl --------------------------------------------------------------------------- - dnl - coverage - dnl --------------------------------------------------------------------------- - - AC_MSG_CHECKING([whether to build with gcov testing]) - AC_ARG_ENABLE([coverage], - AS_HELP_STRING([--enable-coverage], - [Whether to enable gcov code coverage]), - [], [enable_coverage=no]) - AC_MSG_RESULT([$enable_coverage]) - - if test "$enable_coverage" = "yes"; then - if test "$GCC" != "yes"; then - AC_MSG_ERROR(Coverage testing requires GCC) - fi - CFLAGS="$CFLAGS -O0 -g --coverage" - fi - - AM_CONDITIONAL([WITH_COVERAGE], [test "$enable_coverage" = "yes"]) - - dnl --------------------------------------------------------------------------- - dnl - Warnings - dnl --------------------------------------------------------------------------- - - AC_ARG_ENABLE(more-warnings, - AS_HELP_STRING([--enable-more-warnings], - [Maximum compiler warnings]), - set_more_warnings="$enableval",[ - if test -d $srcdir/.git; then - set_more_warnings=yes -diff --git a/src/user-classify.c b/src/user-classify.c -index b68c9ae..69e6809 100644 ---- a/src/user-classify.c -+++ b/src/user-classify.c -@@ -1,248 +1,169 @@ - /* - * Copyright (C) 2009-2010 Red Hat, Inc. - * Copyright (C) 2013 Canonical Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the licence, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Ryan Lortie - * Matthias Clasen - */ - - #include "config.h" - - #include "user-classify.h" - - #include - --#ifdef ENABLE_USER_HEURISTICS - static const char *default_excludes[] = { - "bin", - "root", - "daemon", - "adm", - "lp", - "sync", - "shutdown", - "halt", - "mail", - "news", - "uucp", - "operator", - "nobody", - "nobody4", - "noaccess", - "postgres", - "pvm", - "rpm", - "nfsnobody", - "pcap", - "mysql", - "ftp", - "games", - "man", - "at", - "gdm", - "gnome-initial-setup" - }; - --#define PATH_NOLOGIN "/sbin/nologin" --#define PATH_FALSE "/bin/false" -- - static gboolean --user_classify_is_excluded_by_heuristics (const gchar *username, -- const gchar *shell, -- const gchar *password_hash) -+user_classify_is_blacklisted (const char *username) - { - static GHashTable *exclusions; -- gboolean ret = FALSE; - - if (exclusions == NULL) { - guint i; - - exclusions = g_hash_table_new (g_str_hash, g_str_equal); - - for (i = 0; i < G_N_ELEMENTS (default_excludes); i++) { - g_hash_table_add (exclusions, (gpointer) default_excludes[i]); - } - } - - if (g_hash_table_contains (exclusions, username)) { - return TRUE; - } - -+ return FALSE; -+} -+ -+#define PATH_NOLOGIN "/sbin/nologin" -+#define PATH_FALSE "/bin/false" -+ -+#ifdef ENABLE_USER_HEURISTICS -+static gboolean -+user_classify_is_excluded_by_heuristics (const gchar *username, -+ const gchar *shell, -+ const gchar *password_hash) -+{ -+ gboolean ret = FALSE; -+ - if (shell != NULL) { - char *basename, *nologin_basename, *false_basename; - - #ifdef HAVE_GETUSERSHELL - char *valid_shell; - - ret = TRUE; - setusershell (); - while ((valid_shell = getusershell ()) != NULL) { - if (g_strcmp0 (shell, valid_shell) != 0) - continue; - ret = FALSE; - } - endusershell (); - #endif - - basename = g_path_get_basename (shell); - nologin_basename = g_path_get_basename (PATH_NOLOGIN); - false_basename = g_path_get_basename (PATH_FALSE); - - if (shell[0] == '\0') { - ret = TRUE; - } else if (g_strcmp0 (basename, nologin_basename) == 0) { - ret = TRUE; - } else if (g_strcmp0 (basename, false_basename) == 0) { - ret = TRUE; - } - - g_free (basename); - g_free (nologin_basename); - g_free (false_basename); - } - - if (password_hash != NULL) { - /* skip over the account-is-locked '!' prefix if present */ - if (password_hash[0] == '!') - password_hash++; - - if (password_hash[0] != '\0') { - /* modern hashes start with "$n$" */ - if (password_hash[0] == '$') { - if (strlen (password_hash) < 4) - ret = TRUE; - - /* DES crypt is base64 encoded [./A-Za-z0-9]* - */ - } else if (!g_ascii_isalnum (password_hash[0]) && - password_hash[0] != '.' && - password_hash[0] != '/') { - ret = TRUE; - } - } - - } - - return ret; - } -- --#else /* ENABLE_USER_HEURISTICS */ -- --static gboolean --user_classify_parse_login_defs_field (const gchar *contents, -- const gchar *key, -- uid_t *result) --{ -- gsize key_len; -- gint64 value; -- gchar *end; -- -- key_len = strlen (key); -- -- for (;;) { -- /* Our key has to be at the start of the line, followed by whitespace */ -- if (strncmp (contents, key, key_len) == 0 && g_ascii_isspace (contents[key_len])) { -- /* Found it. Move contents past the key itself and break out. */ -- contents += key_len; -- break; -- } -- -- /* Didn't find it. Find the end of the line. */ -- contents = strchr (contents, '\n'); -- -- /* EOF? */ -- if (!contents) { -- /* We didn't find the field... */ -- return FALSE; -- } -- -- /* Start at the beginning of the next line on next iteration. */ -- contents++; -- } -- -- /* 'contents' now points at the whitespace character just after -- * the field name. strtoll can deal with that. -- */ -- value = g_ascii_strtoll (contents, &end, 10); -- -- if (*end && !g_ascii_isspace (*end)) { -- g_warning ("Trailing junk after '%s' field in login.defs", key); -- return FALSE; -- } -- -- if (value <= 0 || value >= G_MAXINT32) { -- g_warning ("Value for '%s' field out of range", key); -- return FALSE; -- } -- -- *result = value; -- -- return TRUE; --} -- --static void --user_classify_read_login_defs (uid_t *min_uid, -- uid_t *max_uid) --{ -- GError *error = NULL; -- char *contents; -- -- if (!g_file_get_contents ("/etc/login.defs", &contents, NULL, &error)) { -- g_warning ("Could not open /etc/login.defs: %s. Falling back to default human uid range of %d to %d", -- error->message, (int) *min_uid, (int) *max_uid); -- g_error_free (error); -- return; -- } -- -- if (!user_classify_parse_login_defs_field (contents, "UID_MIN", min_uid)) { -- g_warning ("Could not find UID_MIN value in login.defs. Using default of %d", (int) *min_uid); -- } -- -- if (!user_classify_parse_login_defs_field (contents, "UID_MAX", max_uid)) { -- g_warning ("Could not find UID_MIN value in login.defs. Using default of %d", (int) *max_uid); -- } -- -- g_free (contents); --} -- --static gboolean --user_classify_is_in_human_range (uid_t uid) --{ -- static uid_t min_uid = 1000, max_uid = 60000; -- static gboolean initialised; -- -- if (!initialised) { -- user_classify_read_login_defs (&min_uid, &max_uid); -- initialised = TRUE; -- } -- -- return min_uid <= uid && uid <= max_uid; --} - #endif /* ENABLE_USER_HEURISTICS */ - - gboolean - user_classify_is_human (uid_t uid, - const gchar *username, - const gchar *shell, - const gchar *password_hash) - { -+ if (user_classify_is_blacklisted (username)) -+ return FALSE; -+ - #ifdef ENABLE_USER_HEURISTICS -- return !user_classify_is_excluded_by_heuristics (username, shell, password_hash); --#else -- return user_classify_is_in_human_range (uid); -+ /* only do heuristics on the range 500-1000 to catch one off migration problems in Fedora */ -+ if (uid >= 500 && uid < MINIMUM_UID) { -+ if (!user_classify_is_excluded_by_heuristics (username, shell, password_hash)) -+ return TRUE; -+ } - #endif -+ -+ return uid >= MINIMUM_UID; - } --- -1.8.3.1 - diff --git a/SOURCES/rip-out-extension-interface.patch b/SOURCES/rip-out-extension-interface.patch deleted file mode 100644 index b2f3483..0000000 --- a/SOURCES/rip-out-extension-interface.patch +++ /dev/null @@ -1,868 +0,0 @@ -From f86c93014e698d81d43fe1ebaf805fa794e5a984 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 22 Oct 2013 15:42:16 -0400 -Subject: [PATCH] daemon: rip out extension interface - -It requires newer glib than we're shipping ---- - configure.ac | 2 +- - src/Makefile.am | 1 - - src/daemon.c | 11 --- - src/daemon.h | 3 - - src/user.c | 273 -------------------------------------------------------- - 5 files changed, 1 insertion(+), 289 deletions(-) - -diff --git a/configure.ac b/configure.ac -index cb1fcda..a7f4e20 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1,58 +1,58 @@ - AC_INIT([AccountsService],[0.6.35]) - AM_INIT_AUTOMAKE(no-dist-gzip dist-xz tar-ustar foreign) - - GETTEXT_PACKAGE=accounts-service - AC_SUBST(GETTEXT_PACKAGE) - AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", - [the gettext translation domain]) - - # Support silent build rules, requires at least automake-1.11. Enable - # by either passing --enable-silent-rules to configure or passing V=0 - # to make - m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - - AC_USE_SYSTEM_EXTENSIONS - AC_PROG_CC - PKG_PROG_PKG_CONFIG - AM_GLIB_GNU_GETTEXT - IT_PROG_INTLTOOL([0.40.0]) - - LT_INIT - LT_CURRENT=0 - LT_REVISION=0 - LT_AGE=0 - AC_SUBST(LT_CURRENT) - AC_SUBST(LT_REVISION) - AC_SUBST(LT_AGE) - --PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.37.3 gio-unix-2.0) -+PKG_CHECK_MODULES(GIO, gio-2.0 gio-unix-2.0) - PKG_CHECK_MODULES(POLKIT, gio-unix-2.0 polkit-gobject-1) - - AM_MAINTAINER_MODE([enable]) - - # client library dependencies - LIBACCOUNTSSERVICE_LIBS="$GIO_LIBS" - AC_SUBST(LIBACCOUNTSSERVICE_LIBS) - LIBACCOUNTSSERVICE_CFLAGS="$GIO_CFLAGS" - AC_SUBST(LIBACCOUNTSSERVICE_CFLAGS) - - GOBJECT_INTROSPECTION_CHECK([0.9.12]) - - dnl --------------------------------------------------------------------------- - dnl - Core configuration - dnl --------------------------------------------------------------------------- - - AC_ARG_ENABLE(admin-group, - [AS_HELP_STRING([--enable-admin-group],[Set group for administrative accounts @<:@default=auto@:>@])], - ,enable_admin_group=auto) - AS_IF([test x$enable_admin_group = xauto], [ - AC_CHECK_FILE(/etc/redhat-release, enable_admin_group=wheel) - AC_CHECK_FILE(/etc/debian_version, enable_admin_group=sudo) - AS_IF([test x$enable_admin_group = xauto], [ - enable_admin_group=wheel - ]) - ]) - AC_DEFINE_UNQUOTED([ADMIN_GROUP], ["$enable_admin_group"], [Define to the group for administrator users]) - - AC_ARG_ENABLE(user-heuristics, - [AS_HELP_STRING([--enable-user-heuristics],[Enable heuristics for guessing system vs. human users])], -diff --git a/src/Makefile.am b/src/Makefile.am -index 6940f2d..de57e7a 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -7,52 +7,51 @@ INCLUDES = \ - -DICONDIR=\"$(localstatedir)/lib/AccountsService/icons\" \ - -DUSERDIR=\"$(localstatedir)/lib/AccountsService/users\" \ - -I$(srcdir) \ - -I$(builddir) \ - $(POLKIT_CFLAGS) \ - $(WARN_CFLAGS) - - noinst_LTLIBRARIES = libaccounts-generated.la - - libaccounts_generated_la_SOURCES = \ - accounts-generated.c \ - accounts-generated.h \ - accounts-user-generated.c \ - accounts-user-generated.h \ - $(NULL) - BUILT_SOURCES += $(libaccounts_generated_la_SOURCES) - - accounts-generated.c accounts-generated.h: $(top_srcdir)/data/org.freedesktop.Accounts.xml Makefile - gdbus-codegen --generate-c-code accounts-generated --c-namespace Accounts --interface-prefix=org.freedesktop. $(top_srcdir)/data/org.freedesktop.Accounts.xml - - accounts-user-generated.c accounts-user-generated.h: $(top_srcdir)/data/org.freedesktop.Accounts.User.xml Makefile - gdbus-codegen --generate-c-code accounts-user-generated --c-namespace Accounts --interface-prefix=org.freedesktop.Accounts. $(top_srcdir)/data/org.freedesktop.Accounts.User.xml - - libexec_PROGRAMS = accounts-daemon - - accounts_daemon_SOURCES = \ - $(enums_h_sources) \ - types.h \ - daemon.h \ - daemon.c \ -- extensions.c \ - user-classify.h \ - user-classify.c \ - user.h \ - user.c \ - util.h \ - util.c \ - main.c - - accounts_daemon_LDADD = \ - libaccounts-generated.la \ - $(POLKIT_LIBS) - - CLEANFILES = \ - $(BUILT_SOURCES) \ - *.gcda \ - *.gcno \ - $(NULL) - - install-data-hook: - $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/AccountsService/users" - $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/AccountsService/icons" -diff --git a/src/daemon.c b/src/daemon.c -index 9c9f617..ea75190 100644 ---- a/src/daemon.c -+++ b/src/daemon.c -@@ -53,61 +53,60 @@ - #define PATH_GDM_CUSTOM "/etc/gdm/custom.conf" - #ifdef HAVE_UTMPX_H - #define PATH_WTMP _PATH_WTMPX - #endif - - enum { - PROP_0, - PROP_DAEMON_VERSION - }; - - struct DaemonPrivate { - GDBusConnection *bus_connection; - GDBusProxy *bus_proxy; - - GHashTable *users; - - User *autologin; - - GFileMonitor *passwd_monitor; - GFileMonitor *shadow_monitor; - GFileMonitor *group_monitor; - GFileMonitor *gdm_monitor; - #ifdef HAVE_UTMPX_H - GFileMonitor *wtmp_monitor; - #endif - - guint reload_id; - guint autologin_id; - - PolkitAuthority *authority; -- GHashTable *extension_ifaces; - }; - - typedef struct passwd * (* EntryGeneratorFunc) (GHashTable *, gpointer *); - - static void daemon_accounts_accounts_iface_init (AccountsAccountsIface *iface); - - G_DEFINE_TYPE_WITH_CODE (Daemon, daemon, ACCOUNTS_TYPE_ACCOUNTS_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_ACCOUNTS, daemon_accounts_accounts_iface_init)); - - #define DAEMON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_DAEMON, DaemonPrivate)) - - static const GDBusErrorEntry accounts_error_entries[] = - { - { ERROR_FAILED, "org.freedesktop.Accounts.Error.Failed" }, - { ERROR_USER_EXISTS, "org.freedesktop.Accounts.Error.UserExists" }, - { ERROR_USER_DOES_NOT_EXIST, "org.freedesktop.Accounts.Error.UserDoesNotExist" }, - { ERROR_PERMISSION_DENIED, "org.freedesktop.Accounts.Error.PermissionDenied" }, - { ERROR_NOT_SUPPORTED, "org.freedesktop.Accounts.Error.NotSupported" } - }; - - GQuark - error_quark (void) - { - static volatile gsize quark_volatile = 0; - - g_dbus_error_register_error_domain ("accounts_error", - &quark_volatile, - accounts_error_entries, - G_N_ELEMENTS (accounts_error_entries)); - - return (GQuark) quark_volatile; -@@ -656,107 +655,103 @@ setup_monitor (Daemon *daemon, - FileChangeCallback *callback) - { - GError *error = NULL; - GFile *file; - GFileMonitor *monitor; - - file = g_file_new_for_path (path); - monitor = g_file_monitor_file (file, - G_FILE_MONITOR_NONE, - NULL, - &error); - if (monitor != NULL) { - g_signal_connect (monitor, - "changed", - G_CALLBACK (callback), - daemon); - } else { - g_warning ("Unable to monitor %s: %s", path, error->message); - g_error_free (error); - } - g_object_unref (file); - - return monitor; - } - - static void - daemon_init (Daemon *daemon) - { - daemon->priv = DAEMON_GET_PRIVATE (daemon); - -- daemon->priv->extension_ifaces = daemon_read_extension_ifaces (); -- - daemon->priv->users = create_users_hash_table (); - - daemon->priv->passwd_monitor = setup_monitor (daemon, - PATH_PASSWD, - on_users_monitor_changed); - daemon->priv->shadow_monitor = setup_monitor (daemon, - PATH_SHADOW, - on_users_monitor_changed); - daemon->priv->group_monitor = setup_monitor (daemon, - PATH_GROUP, - on_users_monitor_changed); - - #ifdef HAVE_UTMPX_H - daemon->priv->wtmp_monitor = setup_monitor (daemon, - PATH_WTMP, - on_users_monitor_changed); - #endif - - daemon->priv->gdm_monitor = setup_monitor (daemon, - PATH_GDM_CUSTOM, - on_gdm_monitor_changed); - - queue_reload_users (daemon); - queue_reload_autologin (daemon); - } - - static void - daemon_finalize (GObject *object) - { - Daemon *daemon; - - g_return_if_fail (IS_DAEMON (object)); - - daemon = DAEMON (object); - - if (daemon->priv->bus_proxy != NULL) - g_object_unref (daemon->priv->bus_proxy); - - if (daemon->priv->bus_connection != NULL) - g_object_unref (daemon->priv->bus_connection); - - g_hash_table_destroy (daemon->priv->users); - -- g_hash_table_unref (daemon->priv->extension_ifaces); -- - G_OBJECT_CLASS (daemon_parent_class)->finalize (object); - } - - static gboolean - register_accounts_daemon (Daemon *daemon) - { - GError *error = NULL; - - daemon->priv->authority = polkit_authority_get_sync (NULL, &error); - - if (daemon->priv->authority == NULL) { - if (error != NULL) { - g_critical ("error getting polkit authority: %s", error->message); - g_error_free (error); - } - goto error; - } - - daemon->priv->bus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); - if (daemon->priv->bus_connection == NULL) { - if (error != NULL) { - g_critical ("error getting system bus: %s", error->message); - g_error_free (error); - } - goto error; - } - - if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (daemon), - daemon->priv->bus_connection, - "/org/freedesktop/Accounts", -@@ -1526,66 +1521,60 @@ daemon_local_set_automatic_login (Daemon *daemon, - { - if (daemon->priv->autologin == user && enabled) { - return TRUE; - } - - if (daemon->priv->autologin != user && !enabled) { - return TRUE; - } - - if (!save_autologin (daemon, user_get_user_name (user), enabled, error)) { - return FALSE; - } - - if (daemon->priv->autologin != NULL) { - g_object_set (daemon->priv->autologin, "automatic-login", FALSE, NULL); - g_signal_emit_by_name (daemon->priv->autologin, "changed", 0); - g_object_unref (daemon->priv->autologin); - daemon->priv->autologin = NULL; - } - - if (enabled) { - g_object_set (user, "automatic-login", TRUE, NULL); - g_signal_emit_by_name (user, "changed", 0); - g_object_ref (user); - daemon->priv->autologin = user; - } - - return TRUE; - } - --GHashTable * --daemon_get_extension_ifaces (Daemon *daemon) --{ -- return daemon->priv->extension_ifaces; --} -- - static void - get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) - { - switch (prop_id) { - case PROP_DAEMON_VERSION: - g_value_set_string (value, VERSION); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - } - - static void - set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) - { - switch (prop_id) { - case PROP_DAEMON_VERSION: - g_assert_not_reached (); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -diff --git a/src/daemon.h b/src/daemon.h -index b7e072e..e036407 100644 ---- a/src/daemon.h -+++ b/src/daemon.h -@@ -69,36 +69,33 @@ GQuark error_quark (void); - GType daemon_get_type (void) G_GNUC_CONST; - Daemon *daemon_new (void); - - /* local methods */ - - User *daemon_local_find_user_by_id (Daemon *daemon, - uid_t uid); - User *daemon_local_find_user_by_name (Daemon *daemon, - const gchar *name); - User *daemon_local_get_automatic_login_user (Daemon *daemon); - - typedef void (*AuthorizedCallback) (Daemon *daemon, - User *user, - GDBusMethodInvocation *context, - gpointer data); - - void daemon_local_check_auth (Daemon *daemon, - User *user, - const gchar *action_id, - gboolean allow_interaction, - AuthorizedCallback auth_cb, - GDBusMethodInvocation *context, - gpointer data, - GDestroyNotify destroy_notify); - - gboolean daemon_local_set_automatic_login (Daemon *daemon, - User *user, - gboolean enabled, - GError **error); - --GHashTable * daemon_read_extension_ifaces (void); --GHashTable * daemon_get_extension_ifaces (Daemon *daemon); -- - G_END_DECLS - - #endif /* __DAEMON_H__ */ -diff --git a/src/user.c b/src/user.c -index 1698eeb..163d136 100644 ---- a/src/user.c -+++ b/src/user.c -@@ -77,63 +77,60 @@ struct User { - - GDBusConnection *system_bus_connection; - gchar *object_path; - - Daemon *daemon; - - GKeyFile *keyfile; - - uid_t uid; - gid_t gid; - gchar *user_name; - gchar *real_name; - AccountType account_type; - PasswordMode password_mode; - gchar *password_hint; - gchar *home_dir; - gchar *shell; - gchar *email; - gchar *language; - gchar *x_session; - gchar *location; - guint64 login_frequency; - gint64 login_time; - GVariant *login_history; - gchar *icon_file; - gchar *default_icon_file; - gboolean locked; - gboolean automatic_login; - gboolean system_account; - gboolean local_account; -- -- guint *extension_ids; -- guint n_extension_ids; - }; - - typedef struct UserClass - { - AccountsUserSkeletonClass parent_class; - } UserClass; - - static void user_accounts_user_iface_init (AccountsUserIface *iface); - - G_DEFINE_TYPE_WITH_CODE (User, user, ACCOUNTS_TYPE_USER_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_USER, user_accounts_user_iface_init)); - - static gint - account_type_from_pwent (struct passwd *pwent) - { - struct group *grp; - gid_t wheel; - gid_t *groups; - gint ngroups; - gint i; - - if (pwent->pw_uid == 0) { - g_debug ("user is root so account type is administrator"); - return ACCOUNT_TYPE_ADMINISTRATOR; - } - - grp = getgrnam (ADMIN_GROUP); - if (grp == NULL) { - g_debug (ADMIN_GROUP " group not found"); - return ACCOUNT_TYPE_STANDARD; - } -@@ -436,379 +433,109 @@ save_extra_data (User *user) - user->user_name, - NULL); - g_file_set_contents (filename, data, -1, &error); - g_free (filename); - } - if (error) { - g_warning ("Saving data for user %s failed: %s", - user->user_name, error->message); - g_error_free (error); - } - } - - static void - move_extra_data (const gchar *old_name, - const gchar *new_name) - { - gchar *old_filename; - gchar *new_filename; - - old_filename = g_build_filename (USERDIR, - old_name, NULL); - new_filename = g_build_filename (USERDIR, - new_name, NULL); - - g_rename (old_filename, new_filename); - - g_free (old_filename); - g_free (new_filename); - } - --static GVariant * --user_extension_get_value (User *user, -- GDBusInterfaceInfo *interface, -- const GDBusPropertyInfo *property) --{ -- const GVariantType *type = G_VARIANT_TYPE (property->signature); -- GVariant *value; -- gchar *printed; -- gint i; -- -- /* First, try to get the value from the keyfile */ -- printed = g_key_file_get_value (user->keyfile, interface->name, property->name, NULL); -- if (printed) { -- value = g_variant_parse (type, printed, NULL, NULL, NULL); -- g_free (printed); -- -- if (value != NULL) -- return value; -- } -- -- /* If that didn't work, try for a default value annotation */ -- for (i = 0; property->annotations && property->annotations[i]; i++) { -- GDBusAnnotationInfo *annotation = property->annotations[i]; -- -- if (g_str_equal (annotation->key, "org.freedesktop.Accounts.DefaultValue.String")) { -- if (g_str_equal (property->signature, "s")) -- return g_variant_ref_sink (g_variant_new_string (annotation->value)); -- } -- else if (g_str_equal (annotation->key, "org.freedesktop.Accounts.DefaultValue")) { -- value = g_variant_parse (type, annotation->value, NULL, NULL, NULL); -- if (value != NULL) -- return value; -- } -- } -- -- /* Nothing found... */ -- return NULL; --} -- --static void --user_extension_get_property (User *user, -- Daemon *daemon, -- GDBusInterfaceInfo *interface, -- GDBusMethodInvocation *invocation) --{ -- const GDBusPropertyInfo *property = g_dbus_method_invocation_get_property_info (invocation); -- GVariant *value; -- -- value = user_extension_get_value (user, interface, property); -- -- if (value) { -- g_dbus_method_invocation_return_value (invocation, g_variant_new ("(v)", value)); -- g_variant_unref (value); -- } -- else { -- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, -- "Key '%s' is not set and has no default value", -- property->name); -- } --} -- --static void --user_extension_get_all_properties (User *user, -- Daemon *daemon, -- GDBusInterfaceInfo *interface, -- GDBusMethodInvocation *invocation) --{ -- GVariantBuilder builder; -- gint i; -- -- g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); -- for (i = 0; interface->properties && interface->properties[i]; i++) { -- GDBusPropertyInfo *property = interface->properties[i]; -- GVariant *value; -- -- value = user_extension_get_value (user, interface, property); -- -- if (value) { -- g_variant_builder_add (&builder, "{sv}", property->name, value); -- g_variant_unref (value); -- } -- } -- -- g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{sv})", &builder)); --} -- --static void --user_extension_set_property (User *user, -- Daemon *daemon, -- GDBusInterfaceInfo *interface, -- GDBusMethodInvocation *invocation) --{ -- const GDBusPropertyInfo *property = g_dbus_method_invocation_get_property_info (invocation); -- GVariant *value; -- gchar *printed; -- gchar *prev; -- -- g_variant_get_child (g_dbus_method_invocation_get_parameters (invocation), 2, "v", &value); -- -- /* We'll always have the type when we parse it back so -- * we don't need it to be printed with annotations. -- */ -- printed = g_variant_print (value, FALSE); -- -- /* May as well try to avoid the thrashing... */ -- prev = g_key_file_get_value (user->keyfile, interface->name, property->name, NULL); -- -- if (!prev || !g_str_equal (printed, prev)) { -- g_key_file_set_value (user->keyfile, interface->name, property->name, printed); -- -- /* Emit a change signal. Use invalidation -- * because the data may not be world-readable. -- */ -- g_dbus_connection_emit_signal (g_dbus_method_invocation_get_connection (invocation), -- NULL, /* destination_bus_name */ -- g_dbus_method_invocation_get_object_path (invocation), -- "org.freedesktop.DBus.Properties", "PropertiesChanged", -- g_variant_new_parsed ("( %s, %a{sv}, [ %s ] )", -- interface->name, NULL, property->name), -- NULL); -- -- accounts_user_emit_changed (ACCOUNTS_USER (user)); -- save_extra_data (user); -- } -- -- g_variant_unref (value); -- g_free (printed); -- g_free (prev); -- -- g_dbus_method_invocation_return_value (invocation, g_variant_new ("()")); --} -- --static void --user_extension_authentication_done (Daemon *daemon, -- User *user, -- GDBusMethodInvocation *invocation, -- gpointer user_data) --{ -- GDBusInterfaceInfo *interface = user_data; -- const gchar *method_name; -- -- method_name = g_dbus_method_invocation_get_method_name (invocation); -- -- if (g_str_equal (method_name, "Get")) -- user_extension_get_property (user, daemon, interface, invocation); -- else if (g_str_equal (method_name, "GetAll")) -- user_extension_get_all_properties (user, daemon, interface, invocation); -- else if (g_str_equal (method_name, "Set")) -- user_extension_set_property (user, daemon, interface, invocation); -- else -- g_assert_not_reached (); --} -- --static void --user_extension_method_call (GDBusConnection *connection, -- const gchar *sender, -- const gchar *object_path, -- const gchar *interface_name, -- const gchar *method_name, -- GVariant *parameters, -- GDBusMethodInvocation *invocation, -- gpointer user_data) --{ -- User *user = user_data; -- GDBusInterfaceInfo *iface_info; -- const gchar *annotation_name; -- const gchar *action_id; -- gint uid; -- gint i; -- -- /* We don't allow method calls on extension interfaces, so we -- * should only ever see property calls here. -- */ -- g_assert_cmpstr (interface_name, ==, "org.freedesktop.DBus.Properties"); -- -- /* Now get the real interface name */ -- g_variant_get_child (parameters, 0, "&s", &interface_name); -- -- if (get_caller_uid (invocation, &uid) && (uid_t) uid == user->uid) { -- /* Operation on sender's own User object */ -- if (g_str_equal (method_name, "Set")) { -- annotation_name = "org.freedesktop.Accounts.Authentication.ChangeOwn"; -- action_id = "org.freedesktop.accounts.change-own-user-data"; -- } -- else { -- annotation_name = "org.freedesktop.Accounts.Authentication.ReadOwn"; -- action_id = ""; /* reading allowed by default */ -- } -- } -- else { -- /* Operation on someone else's User object */ -- if (g_str_equal (method_name, "Set")) { -- annotation_name = "org.freedesktop.Accounts.Authentication.ChangeAny"; -- action_id = "org.freedesktop.accounts.user-administration"; -- } -- else { -- annotation_name = "org.freedesktop.Accounts.Authentication.ReadAny"; -- action_id = ""; /* reading allowed by default */ -- } -- } -- -- iface_info = g_hash_table_lookup (daemon_get_extension_ifaces (user->daemon), interface_name); -- g_assert (iface_info != NULL); -- -- for (i = 0; iface_info->annotations && iface_info->annotations[i]; i++) { -- if (g_str_equal (iface_info->annotations[i]->key, annotation_name)) { -- action_id = iface_info->annotations[i]->value; -- break; -- } -- } -- -- if (action_id[0] == '\0') { -- /* Should always allow this call, so just do it now */ -- user_extension_authentication_done (user->daemon, user, invocation, iface_info); -- } -- else { -- daemon_local_check_auth (user->daemon, user, action_id, TRUE, -- user_extension_authentication_done, -- invocation, iface_info, NULL); -- } --} -- --static void --user_register_extensions (User *user) --{ -- static const GDBusInterfaceVTable vtable = { -- user_extension_method_call, -- NULL /* get_property */, -- NULL /* set_property */ -- }; -- GHashTable *extensions; -- GHashTableIter iter; -- gpointer iface; -- gint i = 0; -- -- g_assert (user->extension_ids == NULL); -- g_assert (user->n_extension_ids == 0); -- -- extensions = daemon_get_extension_ifaces (user->daemon); -- user->n_extension_ids = g_hash_table_size (extensions); -- user->extension_ids = g_new (guint, user->n_extension_ids); -- g_hash_table_iter_init (&iter, extensions); -- -- /* Ignore errors when registering more interfaces because (a) -- * they won't happen and (b) even if they do, we still want to -- * publish the main user interface. -- */ -- while (g_hash_table_iter_next (&iter, NULL, &iface)) -- user->extension_ids[i++] = g_dbus_connection_register_object (user->system_bus_connection, -- user->object_path, iface, -- &vtable, user, NULL, NULL); --} -- - static gchar * - compute_object_path (User *user) - { - gchar *object_path; - - object_path = g_strdup_printf ("/org/freedesktop/Accounts/User%ld", - (long) user->uid); - - return object_path; - } - - void - user_register (User *user) - { - GError *error = NULL; - - user->system_bus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); - if (user->system_bus_connection == NULL) { - if (error != NULL) { - g_critical ("error getting system bus: %s", error->message); - g_error_free (error); - } - return; - } - - user->object_path = compute_object_path (user); - - if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (user), - user->system_bus_connection, - user->object_path, - &error)) { - if (error != NULL) { - g_critical ("error exporting user object: %s", error->message); - g_error_free (error); - } - return; - } -- -- user_register_extensions (user); - } - - void - user_save (User *user) - { - save_extra_data (user); - } - - void - user_unregister (User *user) - { - g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (user)); -- -- if (user->extension_ids) { -- guint i; -- -- for (i = 0; i < user->n_extension_ids; i++) { -- /* In theory, if an error happened during registration, we could have 0 here. */ -- if (user->extension_ids[i] == 0) -- continue; -- -- g_dbus_connection_unregister_object (user->system_bus_connection, user->extension_ids[i]); -- } -- -- g_clear_pointer (&user->extension_ids, g_free); -- user->n_extension_ids = 0; -- } - } - - void - user_changed (User *user) - { - accounts_user_emit_changed (ACCOUNTS_USER (user)); - } - - User * - user_new (Daemon *daemon, - uid_t uid) - { - User *user; - - user = g_object_new (TYPE_USER, NULL); - user->daemon = daemon; - user->uid = uid; - - return user; - } - - const gchar * - user_get_user_name (User *user) - { - return user->user_name; - } - - gboolean - user_get_system_account (User *user) - { --- -1.8.3.1 - diff --git a/SOURCES/scale-better.patch b/SOURCES/scale-better.patch deleted file mode 100644 index 98a0517..0000000 --- a/SOURCES/scale-better.patch +++ /dev/null @@ -1,1667 +0,0 @@ -From 2b23e50057fc92da30093fbebb78b320fc4107d0 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 29 Jun 2016 10:50:37 -0400 -Subject: [PATCH 1/5] user: check if user is in wheel more efficiently - -We currently get all the groups a user belongs to in one pass, -then check each one to see if it's wheel. - -It's much more efficient to just get the wheel group and check if -any of its members are the user. - -https://bugs.freedesktop.org/show_bug.cgi?id=48177 ---- - src/user.c | 13 ++----------- - 1 file changed, 2 insertions(+), 11 deletions(-) - -diff --git a/src/user.c b/src/user.c -index de30090..52f57d0 100644 ---- a/src/user.c -+++ b/src/user.c -@@ -92,88 +92,79 @@ struct User { - gchar *home_dir; - gchar *shell; - gchar *email; - gchar *language; - gchar *x_session; - gchar *location; - guint64 login_frequency; - gint64 login_time; - GVariant *login_history; - gchar *icon_file; - gchar *default_icon_file; - gboolean locked; - gboolean automatic_login; - gboolean system_account; - gboolean local_account; - }; - - typedef struct UserClass - { - AccountsUserSkeletonClass parent_class; - } UserClass; - - static void user_accounts_user_iface_init (AccountsUserIface *iface); - - G_DEFINE_TYPE_WITH_CODE (User, user, ACCOUNTS_TYPE_USER_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_USER, user_accounts_user_iface_init)); - - static gint - account_type_from_pwent (struct passwd *pwent) - { - struct group *grp; -- gid_t wheel; -- gid_t *groups; -- gint ngroups; - gint i; - - if (pwent->pw_uid == 0) { - g_debug ("user is root so account type is administrator"); - return ACCOUNT_TYPE_ADMINISTRATOR; - } - - grp = getgrnam (ADMIN_GROUP); - if (grp == NULL) { - g_debug (ADMIN_GROUP " group not found"); - return ACCOUNT_TYPE_STANDARD; - } -- wheel = grp->gr_gid; - -- ngroups = get_user_groups (pwent->pw_name, pwent->pw_gid, &groups); -- -- for (i = 0; i < ngroups; i++) { -- if (groups[i] == wheel) { -- g_free (groups); -+ for (i = 0; grp->gr_mem[i] != NULL; i++) { -+ if (g_strcmp0 (grp->gr_mem[i], pwent->pw_name) == 0) { - return ACCOUNT_TYPE_ADMINISTRATOR; - } - } - -- g_free (groups); -- - return ACCOUNT_TYPE_STANDARD; - } - - void - user_update_from_pwent (User *user, - struct passwd *pwent) - { - #ifdef HAVE_SHADOW_H - struct spwd *spent; - #endif - gchar *real_name; - gboolean changed; - const gchar *passwd; - gboolean locked; - PasswordMode mode; - AccountType account_type; - - g_object_freeze_notify (G_OBJECT (user)); - - changed = FALSE; - - if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') { - gchar *first_comma = NULL; - gchar *valid_utf8_name = NULL; - - if (g_utf8_validate (pwent->pw_gecos, -1, NULL)) { - valid_utf8_name = pwent->pw_gecos; - first_comma = g_utf8_strchr (valid_utf8_name, -1, ','); - } - else { --- -2.7.4 - - -From c2b87f89a85ffa5465a523aa291ea0018a050cc5 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 28 Jun 2016 15:43:08 -0400 -Subject: [PATCH 2/5] daemon: get local users from /etc/shadow not /etc/passwd - -For some sites, it's common practice to rsync around large -/etc/passwd files containing the password entries for remote -users. That means accountsservices' "assume /etc/passwd is local -users" heuristic falls over. - -This commit changes it to only treat users in /etc/shadow as local. - -https://bugs.freedesktop.org/show_bug.cgi?id=48177 ---- - src/daemon.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ - 1 file changed, 53 insertions(+), 6 deletions(-) - -diff --git a/src/daemon.c b/src/daemon.c -index 38f6a47..5c269af 100644 ---- a/src/daemon.c -+++ b/src/daemon.c -@@ -2,60 +2,63 @@ - * - * Copyright (C) 2009-2010 Red Hat, Inc. - * Copyright (c) 2013 Canonical Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * 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 -+#ifdef HAVE_SHADOW_H -+#include -+#endif - #include - #include - #include - #ifdef HAVE_UTMPX_H - #include - #endif - - #include - #include - #include - #include - #include - #include - - #include "user-classify.h" - #include "daemon.h" - #include "util.h" - - #define PATH_PASSWD "/etc/passwd" - #define PATH_SHADOW "/etc/shadow" - #define PATH_GROUP "/etc/group" - #define PATH_GDM_CUSTOM "/etc/gdm/custom.conf" - #ifdef HAVE_UTMPX_H - #define PATH_WTMP _PATH_WTMPX - #endif - - enum { - PROP_0, - PROP_DAEMON_VERSION - }; -@@ -279,81 +282,125 @@ entry_generator_wtmp (GHashTable *users, - - builder = g_variant_builder_new (G_VARIANT_TYPE ("a(xxa{sv})")); - for (l = g_list_last (accounting->previous_logins); l != NULL; l = l->prev) { - previous_login = l->data; - - builder2 = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (builder2, "{sv}", "type", g_variant_new_string (previous_login->id)); - g_variant_builder_add (builder, "(xxa{sv})", previous_login->login_time, previous_login->logout_time, builder2); - g_variant_builder_unref (builder2); - } - g_object_set (user, "login-history", g_variant_new ("a(xxa{sv})", builder), NULL); - g_variant_builder_unref (builder); - g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free); - - user_changed (user); - } - - g_hash_table_unref (login_hash); - g_hash_table_unref (logout_hash); - g_free (state_data); - *state = NULL; - return NULL; - } - #endif /* HAVE_UTMPX_H */ - - static struct passwd * - entry_generator_fgetpwent (GHashTable *users, - gpointer *state) - { - struct passwd *pwent; -- FILE *fp; -+ struct { -+ FILE *fp; -+ GHashTable *users; -+ } *generator_state; - - /* First iteration */ - if (*state == NULL) { -- *state = fp = fopen (PATH_PASSWD, "r"); -+ GHashTable *shadow_users = NULL; -+ FILE *fp; -+#ifdef HAVE_SHADOW_H -+ struct spwd *shadow_entry; -+ -+ fp = fopen (PATH_SHADOW, "r"); -+ if (fp == NULL) { -+ g_warning ("Unable to open %s: %s", PATH_SHADOW, g_strerror (errno)); -+ return NULL; -+ } -+ -+ shadow_users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); -+ -+ do { -+ shadow_entry = fgetspent (fp); -+ if (shadow_entry != NULL) { -+ g_hash_table_add (shadow_users, g_strdup (shadow_entry->sp_namp)); -+ } else if (errno != EINTR) { -+ break; -+ } -+ } while (shadow_entry != NULL); -+ -+ fclose (fp); -+ -+ if (g_hash_table_size (shadow_users) == 0) { -+ g_clear_pointer (&shadow_users, g_hash_table_unref); -+ return NULL; -+ } -+#endif -+ -+ 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 */ -- fp = *state; -- pwent = fgetpwent (fp); -+ generator_state = *state; -+ pwent = fgetpwent (generator_state->fp); - if (pwent != NULL) { -- return pwent; -+ if (!generator_state->users || g_hash_table_lookup (generator_state->users, pwent->pw_name)) -+ return pwent; - } - - /* Last iteration */ -- fclose (fp); -+ 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 (GHashTable *users, - gpointer *state) - { - struct passwd *pwent; - const gchar *name; - GError *error = NULL; - gchar *filename; - gboolean regular; - GHashTableIter iter; - GKeyFile *key_file; - User *user; - GDir *dir; - - /* First iteration */ - if (*state == NULL) { - *state = g_dir_open (USERDIR, 0, &error); - if (error != NULL) { - if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) - g_warning ("couldn't list user cache directory: %s", USERDIR); - g_error_free (error); - return NULL; - } - } - - /* Every iteration */ - --- -2.7.4 - - -From 011ef555b0db601186a38c43f9359589ed61e230 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 29 Jun 2016 15:57:38 -0400 -Subject: [PATCH 3/5] daemon: don't call getspnam for local users - -We're already iterating over the whole shadow file, so -just cache the entries instead of calling getspname a -few lines later. - -https://bugs.freedesktop.org/show_bug.cgi?id=48177 ---- - src/daemon.c | 86 +++++++++++++++++++++++++++++++++++++++++------------------- - src/user.c | 11 ++------ - src/user.h | 4 ++- - 3 files changed, 64 insertions(+), 37 deletions(-) - -diff --git a/src/daemon.c b/src/daemon.c -index 5c269af..71a3ea4 100644 ---- a/src/daemon.c -+++ b/src/daemon.c -@@ -58,61 +58,61 @@ - #define PATH_WTMP _PATH_WTMPX - #endif - - enum { - PROP_0, - PROP_DAEMON_VERSION - }; - - struct DaemonPrivate { - GDBusConnection *bus_connection; - GDBusProxy *bus_proxy; - - GHashTable *users; - - User *autologin; - - GFileMonitor *passwd_monitor; - GFileMonitor *shadow_monitor; - GFileMonitor *group_monitor; - GFileMonitor *gdm_monitor; - #ifdef HAVE_UTMPX_H - GFileMonitor *wtmp_monitor; - #endif - - guint reload_id; - guint autologin_id; - - PolkitAuthority *authority; - }; - --typedef struct passwd * (* EntryGeneratorFunc) (GHashTable *, gpointer *); -+typedef struct passwd * (* EntryGeneratorFunc) (GHashTable *, gpointer *, struct spwd **shadow_entry); - - static void daemon_accounts_accounts_iface_init (AccountsAccountsIface *iface); - - G_DEFINE_TYPE_WITH_CODE (Daemon, daemon, ACCOUNTS_TYPE_ACCOUNTS_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_ACCOUNTS, daemon_accounts_accounts_iface_init)); - - #define DAEMON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_DAEMON, DaemonPrivate)) - - static const GDBusErrorEntry accounts_error_entries[] = - { - { ERROR_FAILED, "org.freedesktop.Accounts.Error.Failed" }, - { ERROR_USER_EXISTS, "org.freedesktop.Accounts.Error.UserExists" }, - { ERROR_USER_DOES_NOT_EXIST, "org.freedesktop.Accounts.Error.UserDoesNotExist" }, - { ERROR_PERMISSION_DENIED, "org.freedesktop.Accounts.Error.PermissionDenied" }, - { ERROR_NOT_SUPPORTED, "org.freedesktop.Accounts.Error.NotSupported" } - }; - - GQuark - error_quark (void) - { - static volatile gsize quark_volatile = 0; - - g_dbus_error_register_error_domain ("accounts_error", - &quark_volatile, - accounts_error_entries, - G_N_ELEMENTS (accounts_error_entries)); - - return (GQuark) quark_volatile; - } - #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } - -@@ -138,62 +138,63 @@ error_get_type (void) - return etype; - } - - #ifdef HAVE_UTMPX_H - - typedef struct { - guint64 frequency; - gint64 time; - GList *previous_logins; - } UserAccounting; - - typedef struct { - gchar *id; - gint64 login_time; - gint64 logout_time; - } UserPreviousLogin; - - typedef struct { - GHashTable *login_hash; - GHashTable *logout_hash; - } WTmpGeneratorState; - - static void - user_previous_login_free (UserPreviousLogin *previous_login) - { - g_free (previous_login->id); - g_free (previous_login); - } - - static struct passwd * --entry_generator_wtmp (GHashTable *users, -- gpointer *state) -+entry_generator_wtmp (GHashTable *users, -+ gpointer *state, -+ struct spwd **spent) - { - GHashTable *login_hash, *logout_hash; - struct utmpx *wtmp_entry; - GHashTableIter iter; - gpointer key, value; - struct passwd *pwent; - User *user; - WTmpGeneratorState *state_data; - GVariantBuilder *builder, *builder2; - GList *l; - - if (*state == NULL) { - /* First iteration */ - #ifdef UTXDB_LOG - if (setutxdb (UTXDB_LOG, NULL) != 0) { - return NULL; - } - #else - utmpxname (PATH_WTMP); - setutxent (); - #endif - *state = g_new (WTmpGeneratorState, 1); - state_data = *state; - state_data->login_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - state_data->logout_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - } - - /* Every iteration */ - state_data = *state; - login_hash = state_data->login_hash; -@@ -232,284 +233,308 @@ entry_generator_wtmp (GHashTable *users, - } - - pwent = getpwnam (wtmp_entry->ut_user); - if (pwent == NULL) { - continue; - } - - if (!g_hash_table_lookup_extended (login_hash, - wtmp_entry->ut_user, - &key, &value)) { - accounting = g_new (UserAccounting, 1); - accounting->frequency = 0; - accounting->previous_logins = NULL; - - g_hash_table_insert (login_hash, g_strdup (wtmp_entry->ut_user), accounting); - } else { - accounting = value; - } - - accounting->frequency++; - accounting->time = wtmp_entry->ut_tv.tv_sec; - - /* Add zero logout time to change it later on logout record */ - previous_login = g_new (UserPreviousLogin, 1); - previous_login->id = g_strdup (wtmp_entry->ut_line); - previous_login->login_time = wtmp_entry->ut_tv.tv_sec; - previous_login->logout_time = 0; - accounting->previous_logins = g_list_prepend (accounting->previous_logins, previous_login); - - g_hash_table_insert (logout_hash, g_strdup (wtmp_entry->ut_line), previous_login); -+ *spent = getspnam (pwent->pw_name); - - return pwent; - } - - /* Last iteration */ - endutxent (); - - g_hash_table_iter_init (&iter, login_hash); - while (g_hash_table_iter_next (&iter, &key, &value)) { - UserAccounting *accounting = (UserAccounting *) value; - UserPreviousLogin *previous_login; - - user = g_hash_table_lookup (users, key); - if (user == NULL) { - g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free); - continue; - } - - g_object_set (user, "login-frequency", accounting->frequency, NULL); - g_object_set (user, "login-time", accounting->time, NULL); - - builder = g_variant_builder_new (G_VARIANT_TYPE ("a(xxa{sv})")); - for (l = g_list_last (accounting->previous_logins); l != NULL; l = l->prev) { - previous_login = l->data; - - builder2 = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (builder2, "{sv}", "type", g_variant_new_string (previous_login->id)); - g_variant_builder_add (builder, "(xxa{sv})", previous_login->login_time, previous_login->logout_time, builder2); - g_variant_builder_unref (builder2); - } - g_object_set (user, "login-history", g_variant_new ("a(xxa{sv})", builder), NULL); - g_variant_builder_unref (builder); - g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free); - - user_changed (user); - } - - g_hash_table_unref (login_hash); - g_hash_table_unref (logout_hash); - g_free (state_data); - *state = NULL; - return NULL; - } - #endif /* HAVE_UTMPX_H */ - - static struct passwd * --entry_generator_fgetpwent (GHashTable *users, -- gpointer *state) -+entry_generator_fgetpwent (GHashTable *users, -+ gpointer *state, -+ struct spwd **spent) - { - struct passwd *pwent; -+ -+ struct { -+ struct spwd spbuf; -+ char buf[1024]; -+ } *shadow_entry_buffers; -+ - struct { - FILE *fp; - GHashTable *users; - } *generator_state; - - /* First iteration */ - if (*state == NULL) { - GHashTable *shadow_users = NULL; - FILE *fp; --#ifdef HAVE_SHADOW_H - struct spwd *shadow_entry; - - fp = fopen (PATH_SHADOW, "r"); - if (fp == NULL) { - g_warning ("Unable to open %s: %s", PATH_SHADOW, g_strerror (errno)); - return NULL; - } - -- shadow_users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); -+ shadow_users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - - do { -- shadow_entry = fgetspent (fp); -- if (shadow_entry != NULL) { -- g_hash_table_add (shadow_users, g_strdup (shadow_entry->sp_namp)); -- } else if (errno != EINTR) { -- break; -+ int ret = 0; -+ -+ shadow_entry_buffers = g_malloc0 (sizeof (*shadow_entry_buffers)); -+ -+ ret = fgetspent_r (fp, &shadow_entry_buffers->spbuf, shadow_entry_buffers->buf, sizeof (shadow_entry_buffers->buf), &shadow_entry); -+ if (ret == 0) { -+ g_hash_table_insert (shadow_users, g_strdup (shadow_entry->sp_namp), shadow_entry_buffers); -+ } else { -+ g_free (shadow_entry_buffers); -+ -+ if (errno != EINTR) { -+ break; -+ } - } - } while (shadow_entry != NULL); - - fclose (fp); - - if (g_hash_table_size (shadow_users) == 0) { - g_clear_pointer (&shadow_users, g_hash_table_unref); - return NULL; - } --#endif - - 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; - pwent = fgetpwent (generator_state->fp); - if (pwent != NULL) { -- if (!generator_state->users || g_hash_table_lookup (generator_state->users, pwent->pw_name)) -+ shadow_entry_buffers = g_hash_table_lookup (generator_state->users, pwent->pw_name); -+ -+ if (shadow_entry_buffers != NULL) { -+ *spent = &shadow_entry_buffers->spbuf; - 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 (GHashTable *users, -- gpointer *state) -+entry_generator_cachedir (GHashTable *users, -+ gpointer *state, -+ struct spwd **shadow_entry) - { - struct passwd *pwent; - const gchar *name; - GError *error = NULL; - gchar *filename; - gboolean regular; - GHashTableIter iter; - GKeyFile *key_file; - User *user; - GDir *dir; - - /* First iteration */ - if (*state == NULL) { - *state = g_dir_open (USERDIR, 0, &error); - if (error != NULL) { - if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) - g_warning ("couldn't list user cache directory: %s", USERDIR); - g_error_free (error); - return NULL; - } - } - - /* Every iteration */ - - /* - * Use names of files of regular type to lookup information - * about each user. Loop until we find something valid. - */ - dir = *state; - while (TRUE) { - name = g_dir_read_name (dir); - if (name == NULL) - break; - - /* Only load files in this directory */ - filename = g_build_filename (USERDIR, name, NULL); - regular = g_file_test (filename, G_FILE_TEST_IS_REGULAR); - g_free (filename); - - if (regular) { - pwent = getpwnam (name); -- if (pwent == NULL) -+ if (pwent == NULL) { - g_debug ("user '%s' in cache dir but not present on system", name); -- else -+ } else { -+ *shadow_entry = getspnam (pwent->pw_name); -+ - return pwent; -+ } - } - } - - /* Last iteration */ - g_dir_close (dir); - - /* Update all the users from the files in the cache dir */ - g_hash_table_iter_init (&iter, users); - while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&user)) { - filename = g_build_filename (USERDIR, name, NULL); - key_file = g_key_file_new (); - if (g_key_file_load_from_file (key_file, filename, 0, NULL)) - user_update_from_keyfile (user, key_file); - g_key_file_unref (key_file); - g_free (filename); - } - - *state = NULL; - return NULL; - } - - static void - load_entries (Daemon *daemon, - GHashTable *users, - EntryGeneratorFunc entry_generator) - { - gpointer generator_state = NULL; - struct passwd *pwent; -+ struct spwd *spent = NULL; - User *user = NULL; - - g_assert (entry_generator != NULL); - - for (;;) { -- pwent = entry_generator (users, &generator_state); -+ spent = NULL; -+ pwent = entry_generator (users, &generator_state, &spent); - if (pwent == NULL) - break; - - /* Skip system users... */ -- if (!user_classify_is_human (pwent->pw_uid, pwent->pw_name, pwent->pw_shell, NULL)) { -+ 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); - continue; - } - - /* ignore duplicate entries */ - if (g_hash_table_lookup (users, pwent->pw_name)) { - continue; - } - - user = g_hash_table_lookup (daemon->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); -+ 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)); - } - - /* Generator should have cleaned up */ - g_assert (generator_state == NULL); - } - - static GHashTable * - create_users_hash_table (void) - { - return g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - g_object_unref); - } - - static void - reload_users (Daemon *daemon) - { - GHashTable *users; - GHashTable *old_users; - GHashTable *local; - GHashTableIter iter; - gpointer name; - User *user; - - /* Track the users that we saw during our (re)load */ - users = create_users_hash_table (); -@@ -827,115 +852,122 @@ daemon_new (void) - g_object_unref (daemon); - goto error; - } - - return daemon; - - error: - return NULL; - } - - static void - throw_error (GDBusMethodInvocation *context, - gint error_code, - const gchar *format, - ...) - { - va_list args; - gchar *message; - - va_start (args, format); - message = g_strdup_vprintf (format, args); - va_end (args); - - g_dbus_method_invocation_return_error (context, ERROR, error_code, "%s", message); - - g_free (message); - } - - static User * - add_new_user_for_pwent (Daemon *daemon, -- struct passwd *pwent) -+ struct passwd *pwent, -+ struct spwd *spent) - { - User *user; - - user = user_new (daemon, pwent->pw_uid); -- user_update_from_pwent (user, pwent); -+ user_update_from_pwent (user, pwent, spent); - user_register (user); - - g_hash_table_insert (daemon->priv->users, - g_strdup (user_get_user_name (user)), - user); - - accounts_accounts_emit_user_added (ACCOUNTS_ACCOUNTS (daemon), user_get_object_path (user)); - - return user; - } - - User * - daemon_local_find_user_by_id (Daemon *daemon, - uid_t uid) - { - User *user; - struct passwd *pwent; - - pwent = getpwuid (uid); - if (pwent == NULL) { - g_debug ("unable to lookup uid %d", (int)uid); - return NULL; - } - - user = g_hash_table_lookup (daemon->priv->users, pwent->pw_name); - -- if (user == NULL) -- user = add_new_user_for_pwent (daemon, pwent); -+ if (user == NULL) { -+ struct spwd *spent; -+ spent = getspnam (pwent->pw_name); -+ user = add_new_user_for_pwent (daemon, pwent, spent); -+ } - - return user; - } - - User * - daemon_local_find_user_by_name (Daemon *daemon, - const gchar *name) - { - User *user; - struct passwd *pwent; - - pwent = getpwnam (name); - if (pwent == NULL) { - g_debug ("unable to lookup name %s: %s", name, g_strerror (errno)); - return NULL; - } - - user = g_hash_table_lookup (daemon->priv->users, pwent->pw_name); - -- if (user == NULL) -- user = add_new_user_for_pwent (daemon, pwent); -+ if (user == NULL) { -+ struct spwd *spent; -+ spent = getspnam (pwent->pw_name); -+ user = add_new_user_for_pwent (daemon, pwent, spent); -+ } - - return user; - } - - User * - daemon_local_get_automatic_login_user (Daemon *daemon) - { - return daemon->priv->autologin; - } - - static gboolean - daemon_find_user_by_id (AccountsAccounts *accounts, - GDBusMethodInvocation *context, - gint64 uid) - { - Daemon *daemon = (Daemon*)accounts; - User *user; - - user = daemon_local_find_user_by_id (daemon, uid); - - if (user) { - accounts_accounts_complete_find_user_by_id (NULL, context, user_get_object_path (user)); - } - else { - throw_error (context, ERROR_FAILED, "Failed to look up user with uid %d.", (int)uid); - } - - return TRUE; - } - -diff --git a/src/user.c b/src/user.c -index 52f57d0..247ca2f 100644 ---- a/src/user.c -+++ b/src/user.c -@@ -116,65 +116,63 @@ static void user_accounts_user_iface_init (AccountsUserIface *iface); - G_DEFINE_TYPE_WITH_CODE (User, user, ACCOUNTS_TYPE_USER_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_USER, user_accounts_user_iface_init)); - - static gint - account_type_from_pwent (struct passwd *pwent) - { - struct group *grp; - gint i; - - if (pwent->pw_uid == 0) { - g_debug ("user is root so account type is administrator"); - return ACCOUNT_TYPE_ADMINISTRATOR; - } - - grp = getgrnam (ADMIN_GROUP); - if (grp == NULL) { - g_debug (ADMIN_GROUP " group not found"); - return ACCOUNT_TYPE_STANDARD; - } - - for (i = 0; grp->gr_mem[i] != NULL; i++) { - if (g_strcmp0 (grp->gr_mem[i], pwent->pw_name) == 0) { - return ACCOUNT_TYPE_ADMINISTRATOR; - } - } - - return ACCOUNT_TYPE_STANDARD; - } - - void - user_update_from_pwent (User *user, -- struct passwd *pwent) -+ struct passwd *pwent, -+ struct spwd *spent) - { --#ifdef HAVE_SHADOW_H -- struct spwd *spent; --#endif - gchar *real_name; - gboolean changed; - const gchar *passwd; - gboolean locked; - PasswordMode mode; - AccountType account_type; - - g_object_freeze_notify (G_OBJECT (user)); - - changed = FALSE; - - if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') { - gchar *first_comma = NULL; - gchar *valid_utf8_name = NULL; - - if (g_utf8_validate (pwent->pw_gecos, -1, NULL)) { - valid_utf8_name = pwent->pw_gecos; - first_comma = g_utf8_strchr (valid_utf8_name, -1, ','); - } - else { - g_warning ("User %s has invalid UTF-8 in GECOS field. " - "It would be a good thing to check /etc/passwd.", - pwent->pw_name ? pwent->pw_name : ""); - } - - if (first_comma) { - real_name = g_strndup (valid_utf8_name, - (first_comma - valid_utf8_name)); - } - else if (valid_utf8_name) { -@@ -219,93 +217,88 @@ user_update_from_pwent (User *user, - g_object_notify (G_OBJECT (user), "account-type"); - } - - /* Username */ - if (g_strcmp0 (user->user_name, pwent->pw_name) != 0) { - g_free (user->user_name); - user->user_name = g_strdup (pwent->pw_name); - changed = TRUE; - g_object_notify (G_OBJECT (user), "user-name"); - } - - /* Home Directory */ - if (g_strcmp0 (user->home_dir, pwent->pw_dir) != 0) { - g_free (user->home_dir); - user->home_dir = g_strdup (pwent->pw_dir); - g_free (user->default_icon_file); - user->default_icon_file = g_build_filename (user->home_dir, ".face", NULL); - changed = TRUE; - g_object_notify (G_OBJECT (user), "home-directory"); - } - - /* Shell */ - if (g_strcmp0 (user->shell, pwent->pw_shell) != 0) { - g_free (user->shell); - user->shell = g_strdup (pwent->pw_shell); - changed = TRUE; - g_object_notify (G_OBJECT (user), "shell"); - } - - passwd = NULL; --#ifdef HAVE_SHADOW_H -- spent = getspnam (pwent->pw_name); - if (spent) - passwd = spent->sp_pwdp; --#endif - - if (passwd && passwd[0] == '!') { - locked = TRUE; - } - else { - locked = FALSE; - } - - if (user->locked != locked) { - user->locked = locked; - changed = TRUE; - g_object_notify (G_OBJECT (user), "locked"); - } - - if (passwd == NULL || passwd[0] != 0) { - mode = PASSWORD_MODE_REGULAR; - } - else { - mode = PASSWORD_MODE_NONE; - } - --#ifdef HAVE_SHADOW_H - if (spent) { - if (spent->sp_lstchg == 0) { - mode = PASSWORD_MODE_SET_AT_LOGIN; - } - } --#endif - - if (user->password_mode != mode) { - user->password_mode = mode; - changed = TRUE; - g_object_notify (G_OBJECT (user), "password-mode"); - } - - user->system_account = !user_classify_is_human (user->uid, user->user_name, pwent->pw_shell, passwd); - - g_object_thaw_notify (G_OBJECT (user)); - - if (changed) - accounts_user_emit_changed (ACCOUNTS_USER (user)); - } - - void - user_update_from_keyfile (User *user, - GKeyFile *keyfile) - { - gchar *s; - - g_object_freeze_notify (G_OBJECT (user)); - - s = g_key_file_get_string (keyfile, "User", "Language", NULL); - if (s != NULL) { - /* TODO: validate / normalize */ - g_free (user->language); - user->language = s; - g_object_notify (G_OBJECT (user), "language"); - } -diff --git a/src/user.h b/src/user.h -index 0848b50..22548f9 100644 ---- a/src/user.h -+++ b/src/user.h -@@ -1,80 +1,82 @@ - /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * - * Copyright (C) 2009-2010 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - #ifndef __USER__ - #define __USER__ - - #include - #include -+#include - - #include - #include - - #include "types.h" - - G_BEGIN_DECLS - - #define TYPE_USER (user_get_type ()) - #define USER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TYPE_USER, User)) - #define IS_USER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TYPE_USER)) - - typedef enum { - ACCOUNT_TYPE_STANDARD, - ACCOUNT_TYPE_ADMINISTRATOR, - #define ACCOUNT_TYPE_LAST ACCOUNT_TYPE_ADMINISTRATOR - } AccountType; - - typedef enum { - PASSWORD_MODE_REGULAR, - PASSWORD_MODE_SET_AT_LOGIN, - PASSWORD_MODE_NONE, - #define PASSWORD_MODE_LAST PASSWORD_MODE_NONE - } PasswordMode; - - /* local methods */ - - GType user_get_type (void) G_GNUC_CONST; - User * user_new (Daemon *daemon, - uid_t uid); - - void user_update_from_pwent (User *user, -- struct passwd *pwent); -+ struct passwd *pwent, -+ struct spwd *spent); - void user_update_from_keyfile (User *user, - GKeyFile *keyfile); - void user_update_local_account_property (User *user, - gboolean local); - void user_update_system_account_property (User *user, - gboolean system); - - void user_register (User *user); - void user_unregister (User *user); - void user_changed (User *user); - - void user_save (User *user); - - const gchar * user_get_user_name (User *user); - gboolean user_get_system_account (User *user); - gboolean user_get_local_account (User *user); - const gchar * user_get_object_path (User *user); - uid_t user_get_uid (User *user); - const gchar * user_get_shell (User *user); - - G_END_DECLS - - #endif --- -2.7.4 - - -From 2accf123c55f3c6a9596e9fc2d614fcb07c88559 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 29 Jun 2016 16:22:42 -0400 -Subject: [PATCH 4/5] daemon: constrain max local users to 50 - -Systems with tens of thousands of users don't want all those users -showing up in the user list. - -Set a cap at an even 50, which should cover the lion's share of use -cases well. Of course, if a user not in the list explicitly -logs in (from Not Listed? or whatever) they get added to the list. - -https://bugs.freedesktop.org/show_bug.cgi?id=48177 ---- - src/daemon.c | 19 +++++++++++++------ - 1 file changed, 13 insertions(+), 6 deletions(-) - -diff --git a/src/daemon.c b/src/daemon.c -index 71a3ea4..cb586bb 100644 ---- a/src/daemon.c -+++ b/src/daemon.c -@@ -279,60 +279,64 @@ entry_generator_wtmp (GHashTable *users, - continue; - } - - g_object_set (user, "login-frequency", accounting->frequency, NULL); - g_object_set (user, "login-time", accounting->time, NULL); - - builder = g_variant_builder_new (G_VARIANT_TYPE ("a(xxa{sv})")); - for (l = g_list_last (accounting->previous_logins); l != NULL; l = l->prev) { - previous_login = l->data; - - builder2 = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (builder2, "{sv}", "type", g_variant_new_string (previous_login->id)); - g_variant_builder_add (builder, "(xxa{sv})", previous_login->login_time, previous_login->logout_time, builder2); - g_variant_builder_unref (builder2); - } - g_object_set (user, "login-history", g_variant_new ("a(xxa{sv})", builder), NULL); - g_variant_builder_unref (builder); - g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free); - - user_changed (user); - } - - g_hash_table_unref (login_hash); - g_hash_table_unref (logout_hash); - g_free (state_data); - *state = NULL; - return NULL; - } - #endif /* HAVE_UTMPX_H */ - -+#ifndef MAX_LOCAL_USERS -+#define MAX_LOCAL_USERS 50 -+#endif -+ - static struct passwd * - entry_generator_fgetpwent (GHashTable *users, - gpointer *state, - struct spwd **spent) - { - struct passwd *pwent; - - struct { - struct spwd spbuf; - char buf[1024]; - } *shadow_entry_buffers; - - struct { - FILE *fp; - GHashTable *users; - } *generator_state; - - /* First iteration */ - if (*state == NULL) { - GHashTable *shadow_users = NULL; - FILE *fp; - struct spwd *shadow_entry; - - fp = fopen (PATH_SHADOW, "r"); - if (fp == NULL) { - g_warning ("Unable to open %s: %s", PATH_SHADOW, g_strerror (errno)); - return NULL; - } - - shadow_users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); -@@ -350,67 +354,70 @@ entry_generator_fgetpwent (GHashTable *users, - - if (errno != EINTR) { - break; - } - } - } while (shadow_entry != NULL); - - fclose (fp); - - 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; -- 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; -- return pwent; -+ 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; -+ 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 (GHashTable *users, - gpointer *state, - struct spwd **shadow_entry) - { - struct passwd *pwent; - const gchar *name; - GError *error = NULL; - gchar *filename; - gboolean regular; - GHashTableIter iter; - GKeyFile *key_file; - User *user; - GDir *dir; - - /* First iteration */ - if (*state == NULL) { - *state = g_dir_open (USERDIR, 0, &error); --- -2.7.4 - - -From ed58ad3210010a09b6f114b4d392afb66ad0bbfa Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 29 Jun 2016 16:32:17 -0400 -Subject: [PATCH 5/5] daemon: don't source user list from wtmp - -wtmp can get rather large on some systems from ssh logins. -Furthermore it's pretty much completely redundant given the user -cache in /var/lib/AccountService - -This commit changes the wtmp code to only get used for maintaining -login frequency and accounting, not for generating new users. - -https://bugs.freedesktop.org/show_bug.cgi?id=48177 ---- - src/daemon.c | 42 ++++++++++++------------------------------ - 1 file changed, 12 insertions(+), 30 deletions(-) - -diff --git a/src/daemon.c b/src/daemon.c -index cb586bb..815e2c9 100644 ---- a/src/daemon.c -+++ b/src/daemon.c -@@ -137,95 +137,83 @@ error_get_type (void) - } - return etype; - } - - #ifdef HAVE_UTMPX_H - - typedef struct { - guint64 frequency; - gint64 time; - GList *previous_logins; - } UserAccounting; - - typedef struct { - gchar *id; - gint64 login_time; - gint64 logout_time; - } UserPreviousLogin; - - typedef struct { - GHashTable *login_hash; - GHashTable *logout_hash; - } WTmpGeneratorState; - - static void - user_previous_login_free (UserPreviousLogin *previous_login) - { - g_free (previous_login->id); - g_free (previous_login); - } - --static struct passwd * --entry_generator_wtmp (GHashTable *users, -- gpointer *state, -- struct spwd **spent) -+static void -+wtmp_update_login_frequencies (GHashTable *users) - { - GHashTable *login_hash, *logout_hash; - struct utmpx *wtmp_entry; - GHashTableIter iter; - gpointer key, value; - struct passwd *pwent; - User *user; -- WTmpGeneratorState *state_data; - GVariantBuilder *builder, *builder2; - GList *l; - -- if (*state == NULL) { -- /* First iteration */ - #ifdef UTXDB_LOG -- if (setutxdb (UTXDB_LOG, NULL) != 0) { -- return NULL; -- } -+ if (setutxdb (UTXDB_LOG, NULL) != 0) { -+ return NULL; -+ } - #else -- utmpxname (PATH_WTMP); -- setutxent (); -+ utmpxname (PATH_WTMP); -+ setutxent (); - #endif -- *state = g_new (WTmpGeneratorState, 1); -- state_data = *state; -- state_data->login_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); -- state_data->logout_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); -- } - -- /* Every iteration */ -- state_data = *state; -- login_hash = state_data->login_hash; -- logout_hash = state_data->logout_hash; -+ login_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); -+ logout_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - while ((wtmp_entry = getutxent ())) { - UserAccounting *accounting; - UserPreviousLogin *previous_login; - - if (wtmp_entry->ut_type == BOOT_TIME) { - /* Set boot time for missing logout records */ - g_hash_table_iter_init (&iter, logout_hash); - while (g_hash_table_iter_next (&iter, &key, &value)) { - previous_login = (UserPreviousLogin *) value; - - if (previous_login->logout_time == 0) { - previous_login->logout_time = wtmp_entry->ut_tv.tv_sec; - } - } - g_hash_table_remove_all (logout_hash); - } else if (wtmp_entry->ut_type == DEAD_PROCESS) { - /* Save corresponding logout time */ - if (g_hash_table_lookup_extended (logout_hash, wtmp_entry->ut_line, &key, &value)) { - previous_login = (UserPreviousLogin *) value; - previous_login->logout_time = wtmp_entry->ut_tv.tv_sec; - - g_hash_table_remove (logout_hash, previous_login->id); - } - } - - if (wtmp_entry->ut_type != USER_PROCESS) { - continue; - } - - if (wtmp_entry->ut_user[0] == 0) { -@@ -233,103 +221,96 @@ entry_generator_wtmp (GHashTable *users, - } - - pwent = getpwnam (wtmp_entry->ut_user); - if (pwent == NULL) { - continue; - } - - if (!g_hash_table_lookup_extended (login_hash, - wtmp_entry->ut_user, - &key, &value)) { - accounting = g_new (UserAccounting, 1); - accounting->frequency = 0; - accounting->previous_logins = NULL; - - g_hash_table_insert (login_hash, g_strdup (wtmp_entry->ut_user), accounting); - } else { - accounting = value; - } - - accounting->frequency++; - accounting->time = wtmp_entry->ut_tv.tv_sec; - - /* Add zero logout time to change it later on logout record */ - previous_login = g_new (UserPreviousLogin, 1); - previous_login->id = g_strdup (wtmp_entry->ut_line); - previous_login->login_time = wtmp_entry->ut_tv.tv_sec; - previous_login->logout_time = 0; - accounting->previous_logins = g_list_prepend (accounting->previous_logins, previous_login); - - g_hash_table_insert (logout_hash, g_strdup (wtmp_entry->ut_line), previous_login); -- *spent = getspnam (pwent->pw_name); -- -- return pwent; - } - -- /* Last iteration */ - endutxent (); - - g_hash_table_iter_init (&iter, login_hash); - while (g_hash_table_iter_next (&iter, &key, &value)) { - UserAccounting *accounting = (UserAccounting *) value; - UserPreviousLogin *previous_login; - - user = g_hash_table_lookup (users, key); - if (user == NULL) { - g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free); - continue; - } - - g_object_set (user, "login-frequency", accounting->frequency, NULL); - g_object_set (user, "login-time", accounting->time, NULL); - - builder = g_variant_builder_new (G_VARIANT_TYPE ("a(xxa{sv})")); - for (l = g_list_last (accounting->previous_logins); l != NULL; l = l->prev) { - previous_login = l->data; - - builder2 = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (builder2, "{sv}", "type", g_variant_new_string (previous_login->id)); - g_variant_builder_add (builder, "(xxa{sv})", previous_login->login_time, previous_login->logout_time, builder2); - g_variant_builder_unref (builder2); - } - g_object_set (user, "login-history", g_variant_new ("a(xxa{sv})", builder), NULL); - g_variant_builder_unref (builder); - g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free); - - user_changed (user); - } - - g_hash_table_unref (login_hash); - g_hash_table_unref (logout_hash); -- g_free (state_data); -- *state = NULL; -- return NULL; - } - #endif /* HAVE_UTMPX_H */ - - #ifndef MAX_LOCAL_USERS - #define MAX_LOCAL_USERS 50 - #endif - - static struct passwd * - entry_generator_fgetpwent (GHashTable *users, - gpointer *state, - struct spwd **spent) - { - struct passwd *pwent; - - struct { - struct spwd spbuf; - char buf[1024]; - } *shadow_entry_buffers; - - struct { - FILE *fp; - GHashTable *users; - } *generator_state; - - /* First iteration */ - if (*state == NULL) { - GHashTable *shadow_users = NULL; - FILE *fp; - struct spwd *shadow_entry; - -@@ -533,64 +514,65 @@ create_users_hash_table (void) - g_object_unref); - } - - static void - reload_users (Daemon *daemon) - { - GHashTable *users; - GHashTable *old_users; - GHashTable *local; - GHashTableIter iter; - gpointer name; - User *user; - - /* 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, 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); - - /* Now add/update users from other sources, possibly non-local */ -+ load_entries (daemon, users, entry_generator_cachedir); -+ - #ifdef HAVE_UTMPX_H -- load_entries (daemon, users, entry_generator_wtmp); -+ wtmp_update_login_frequencies (users); - #endif -- load_entries (daemon, users, entry_generator_cachedir); - - /* Mark which users are local, which are not */ - g_hash_table_iter_init (&iter, users); - while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) - user_update_local_account_property (user, g_hash_table_lookup (local, name) != NULL); - - g_hash_table_destroy (local); - - /* Swap out the users */ - old_users = daemon->priv->users; - daemon->priv->users = users; - - /* Remove all the old users */ - g_hash_table_iter_init (&iter, old_users); - while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) { - if (!g_hash_table_lookup (users, name)) { - user_unregister (user); - accounts_accounts_emit_user_deleted (ACCOUNTS_ACCOUNTS (daemon), - user_get_object_path (user)); - } - } - - /* Register all the new users */ - g_hash_table_iter_init (&iter, users); - while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) { - if (!g_hash_table_lookup (old_users, name)) { - user_register (user); - accounts_accounts_emit_user_added (ACCOUNTS_ACCOUNTS (daemon), - user_get_object_path (user)); - } --- -2.7.4 - diff --git a/SOURCES/userdel-f.patch b/SOURCES/userdel-f.patch deleted file mode 100644 index 003d69e..0000000 --- a/SOURCES/userdel-f.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 77e2d73723aaef376d97597a61328619b8a204c3 Mon Sep 17 00:00:00 2001 -From: Matthias Clasen -Date: Fri, 10 Jan 2014 12:38:55 -0500 -Subject: [PATCH] Call userdel consistently - -When deleting the users files, we use -f, otherwise we don't. This -leads to inconsistent behaviour. Always pass -f. ---- - src/daemon.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/src/daemon.c b/src/daemon.c -index b2720f4..cb36f01 100644 ---- a/src/daemon.c -+++ b/src/daemon.c -@@ -1289,9 +1289,10 @@ daemon_delete_user_authorized_cb (Daemon *daemon, - argv[5] = NULL; - } - else { -- argv[1] = "--"; -- argv[2] = pwent->pw_name; -- argv[3] = NULL; -+ argv[1] = "-f"; -+ argv[2] = "--"; -+ argv[3] = pwent->pw_name; -+ argv[4] = NULL; - } - - error = NULL; --- -1.8.4.2 - diff --git a/SPECS/accountsservice.spec b/SPECS/accountsservice.spec index e4ce1c7..8a9dc95 100644 --- a/SPECS/accountsservice.spec +++ b/SPECS/accountsservice.spec @@ -1,8 +1,8 @@ %global _hardened_build 1 Name: accountsservice -Version: 0.6.35 -Release: 14%{?dist} +Version: 0.6.45 +Release: 2%{?dist} Summary: D-Bus interfaces for querying and manipulating user account information Group: System Environment/Daemons @@ -12,14 +12,13 @@ URL: http://www.fedoraproject.org/wiki/Features/UserAccountDialog Source0: http://www.freedesktop.org/software/accountsservice/accountsservice-%{version}.tar.xz BuildRequires: glib2-devel -BuildRequires: dbus-glib-devel BuildRequires: polkit-devel BuildRequires: intltool BuildRequires: systemd-units BuildRequires: systemd-devel BuildRequires: gobject-introspection-devel -BuildRequires: automake, autoconf, libtool BuildRequires: gtk-doc +BuildRequires: git Requires: polkit Requires: shadow-utils @@ -28,19 +27,7 @@ Requires(post): systemd-units Requires(preun): systemd-units Requires(postun): systemd-units -Patch0: rip-out-extension-interface.patch -Patch1: 0001-Avoid-deleting-the-root-user.patch -Patch2: fix-user-classification-logic.patch -Patch3: userdel-f.patch -Patch4: fix-leak.patch -Patch5: 0001-Add-asynchronous-api-for-user-uncaching.patch -Patch6: 0001-systemd-ensure-that-accounts-service-starts-after-NS.patch -Patch7: scale-better.patch -Patch8: fix-log-leak.patch -Patch9: 0001-user-classify-exclude-nologin-users.patch -Patch10: 0001-configure-actually-define-HAVE_GETUSERSHELL.patch -Patch11: 0001-daemon-make-sure-explicitly-requested-users-aren-t-l.patch -Patch12: 0001-daemon-don-t-treat-explicitly-requested-users-as-cac.patch +Patch0: 0001-daemon-don-t-treat-explicitly-requested-users-as-cac.patch %package libs Summary: Client-side library to talk to accountsservice @@ -70,23 +57,9 @@ of these interfaces, based on the useradd, usermod and userdel commands. %prep -%setup -q -%patch0 -p1 -b .rip-out-extension-interface -%patch1 -p1 -b .dont-delete-root -%patch2 -p1 -b .fix-user-classification-logic -%patch3 -p1 -b .userdel-f -%patch4 -p1 -b .fix-leak -%patch5 -p1 -b .async-api-uncaching -%patch6 -p1 -b .start-after-nsswitch -%patch7 -p1 -b .scale-better -%patch8 -p1 -b .fix-log-leak -%patch9 -p1 -b .hide-nologin-users -%patch10 -p1 -b .define-HAVE_GETUSERSHELL -%patch11 -p1 -b .crashfix -%patch12 -p1 -b .uncache-fix +%autosetup -S git %build -autoreconf -f -i %configure --enable-user-heuristics make %{?_smp_mflags} @@ -112,7 +85,6 @@ rm $RPM_BUILD_ROOT%{_libdir}/*.a %systemd_postun accounts-daemon.service %files -f accounts-service.lang -%defattr(-,root,root,-) %doc COPYING README AUTHORS %{_sysconfdir}/dbus-1/system.d/org.freedesktop.Accounts.conf %{_libexecdir}/accounts-daemon @@ -138,13 +110,25 @@ rm $RPM_BUILD_ROOT%{_libdir}/*.a %{_datadir}/gtk-doc/html/libaccountsservice/* %changelog -* Mon May 15 2017 Ray Strode - 0.6.35-14 -- address uncache regression introduced in last commit +* Mon May 15 2017 Ray Strode - 0.6.45-2 +- Don't tread explicitly requested users as cached + Fixes UncacheUser operation. + Resolves: 1446620 Related: #1432602 -* Mon Apr 24 2017 Ray Strode - 0.6.35-13 -- address libaccountsservice crash when /etc/passwd changes - Resolves: #1432602 +* Mon Mar 27 2017 Ray Strode - 0.6.45-1 +- Update to 0.6.45 so password expiration policy is wrapped by libaccountsservice + Related: #1424623 #1334464 + +* Mon Mar 27 2017 Ray Strode - 0.6.42-2 +- Update to 0.6.44 + Related: #1424623 +- export password expiration policy from shadow + Resolves: #1334464 + +* Thu Oct 20 2016 Kalev Lember - 0.6.42-1 +- Update to 0.6.42 +- Resolves: #1424623 * Tue Sep 06 2016 Ray Strode - 0.6.35-12 - hide users with /sbin/nologin shell