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 <oholy@redhat.com>
-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 <mclasen@redhat.com>
-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 <rstrode@redhat.com>
-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 <rstrode@redhat.com>
 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 <rstrode@redhat.com>
-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 <glib.h>
- #include <glib/gi18n.h>
- #include <glib-object.h>
- #include <glib/gstdio.h>
- #include <gio/gio.h>
- #include <polkit/polkit.h>
- 
- #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 <sgallagh@redhat.com>
-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 <rstrode@redhat.com>
-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 <desrt@desrt.ca>
-  *          Matthias Clasen <mclasen@redhat.com>
-  */
- 
- #include "config.h"
- 
- #include "user-classify.h"
- 
- #include <string.h>
-+#include <unistd.h>
- 
- 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 <rstrode@redhat.com>
-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 <rstrode@redhat.com>
-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 <rstrode@redhat.com>
-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 <desrt@desrt.ca>
-  *          Matthias Clasen <mclasen@redhat.com>
-  */
- 
- #include "config.h"
- 
- #include "user-classify.h"
- 
- #include <string.h>
- 
--#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 <rstrode@redhat.com>
-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 <rstrode@redhat.com>
-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 <rstrode@redhat.com>
-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 <mclasen@redhat.com>
-  */
- 
- #include "config.h"
- 
- #include <stdlib.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/wait.h>
- #include <pwd.h>
-+#ifdef HAVE_SHADOW_H
-+#include <shadow.h>
-+#endif
- #include <unistd.h>
- #include <errno.h>
- #include <sys/types.h>
- #ifdef HAVE_UTMPX_H
- #include <utmpx.h>
- #endif
- 
- #include <glib.h>
- #include <glib/gi18n.h>
- #include <glib-object.h>
- #include <glib/gstdio.h>
- #include <gio/gio.h>
- #include <polkit/polkit.h>
- 
- #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 <rstrode@redhat.com>
-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 <sys/types.h>
- #include <pwd.h>
-+#include <shadow.h>
- 
- #include <glib.h>
- #include <gio/gio.h>
- 
- #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 <rstrode@redhat.com>
-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 <rstrode@redhat.com>
-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 <mclasen@redhat.com>
-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 <rstrode@redhat.com> - 0.6.35-14
-- address uncache regression introduced in last commit
+* Mon May 15 2017 Ray Strode <rstrode@redhat.com> - 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 <rstrode@redhat.com> - 0.6.35-13
-- address libaccountsservice crash when /etc/passwd changes
-  Resolves: #1432602
+* Mon Mar 27 2017 Ray Strode <rstrode@redhat.com> - 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 <rstrode@redhat.com> - 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 <klember@redhat.com> - 0.6.42-1
+- Update to 0.6.42
+- Resolves: #1424623
 
 * Tue Sep 06 2016 Ray Strode <rstrode@redhat.com> - 0.6.35-12
 - hide users with /sbin/nologin shell