From a2f448b54c52f2c6444749c93d7f3c5da4d96ae7 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 29 Jun 2016 16:32:17 -0400
Subject: [PATCH] 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      |  3 ++-
 src/wtmp-helper.c | 46 +++++++---------------------------------------
 src/wtmp-helper.h |  4 +---
 3 files changed, 10 insertions(+), 43 deletions(-)

Index: b/src/daemon.c
===================================================================
--- a/src/daemon.c	2019-07-17 19:44:41.730480284 +0800
+++ b/src/daemon.c	2019-07-17 19:46:51.651652322 +0800
@@ -313,9 +313,10 @@ reload_users (Daemon *daemon)
                 g_hash_table_add (local, name);
 
         /* Now add/update users from other sources, possibly non-local */
-        load_entries (daemon, users, wtmp_helper_entry_generator);
         load_entries (daemon, users, entry_generator_cachedir);
 
+        wtmp_helper_update_login_frequencies (users);
+
         /* 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))
Index: b/src/wtmp-helper.c
===================================================================
--- a/src/wtmp-helper.c	2019-07-17 19:44:41.730480284 +0800
+++ b/src/wtmp-helper.c	2019-07-17 20:00:23.466899145 +0800
@@ -41,11 +41,6 @@ typedef struct {
         gint64  logout_time;
 } UserPreviousLogin;
 
-typedef struct {
-        GHashTable *login_hash;
-        GHashTable *logout_hash;
-} WTmpGeneratorState;
-
 static void
 user_previous_login_free (UserPreviousLogin *previous_login)
 {
@@ -73,9 +68,8 @@ wtmp_helper_start (void)
                 return TRUE;
 }
 
-struct passwd *
-wtmp_helper_entry_generator (GHashTable *users,
-                             gpointer   *state)
+void
+wtmp_helper_update_login_frequencies (GHashTable *users)
 {
         GHashTable *login_hash, *logout_hash;
         struct utmpx *wtmp_entry;
@@ -83,27 +77,16 @@ wtmp_helper_entry_generator (GHashTable
         gpointer key, value;
         struct passwd *pwent;
         User *user;
-        WTmpGeneratorState *state_data;
         GVariantBuilder *builder, *builder2;
         GList *l;
 
-        if (*state == NULL) {
-                /* First iteration */
-
-                if (!wtmp_helper_start ()) {
-                        return NULL;
-                }
-
-                *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);
+        if (!wtmp_helper_start ()) {
+                return;
         }
 
-        /* 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;
@@ -165,8 +148,6 @@ wtmp_helper_entry_generator (GHashTable
                 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);
-
-                return pwent;
         }
 
         /* Last iteration */
@@ -204,9 +185,6 @@ wtmp_helper_entry_generator (GHashTable
 
         g_hash_table_unref (login_hash);
         g_hash_table_unref (logout_hash);
-        g_free (state_data);
-        *state = NULL;
-        return NULL;
 }
 
 const gchar *
@@ -217,13 +195,6 @@ wtmp_helper_get_path_for_monitor (void)
 
 #else /* HAVE_UTMPX_H */
 
-struct passwd *
-wtmp_helper_entry_generator (GHashTable *users,
-                             gpointer   *state)
-{
-        return NULL;
-}
-
 const gchar *
 wtmp_helper_get_path_for_monitor (void)
 {
Index: b/src/wtmp-helper.h
===================================================================
--- a/src/wtmp-helper.h	2019-07-17 19:46:51.651652322 +0800
+++ b/src/wtmp-helper.h	2019-07-17 20:11:45.904911418 +0800
@@ -25,7 +25,6 @@
 #include <pwd.h>
 
 const gchar *           wtmp_helper_get_path_for_monitor                (void);
-struct passwd *         wtmp_helper_entry_generator                     (GHashTable *users,
-                                                                         gpointer   *state);
+void                    wtmp_helper_update_login_frequencies            (GHashTable *users);
 
 #endif /* __WTMP_HELPER_H__ */
From ce3f71c806334e0a64222779a128e38c45ec90a6 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 27 Sep 2017 11:01:28 -0400
Subject: [PATCH] daemon: don't send spurious change signals when wtmp changes

Right now, we unintentionally send out a changed signal for
every tracked user anytime wtmp changes.

This commit fixes that.

https://bugs.freedesktop.org/show_bug.cgi?id=103488
---
 src/wtmp-helper.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/src/wtmp-helper.c b/src/wtmp-helper.c
index 787480b..a1edffe 100644
--- a/src/wtmp-helper.c
+++ b/src/wtmp-helper.c
@@ -165,6 +165,9 @@ wtmp_helper_update_login_frequencies (GHashTable *users)
         while (g_hash_table_iter_next (&iter, &key, &value)) {
                 UserAccounting    *accounting = (UserAccounting *) value;
                 UserPreviousLogin *previous_login;
+                gboolean           changed = FALSE;
+                guint64            old_login_frequency;
+                guint64            old_login_time;
 
                 user = g_hash_table_lookup (users, key);
                 if (user == NULL) {
@@ -172,8 +175,20 @@ wtmp_helper_update_login_frequencies (GHashTable *users)
                         continue;
                 }
 
-                g_object_set (user, "login-frequency", accounting->frequency, NULL);
-                g_object_set (user, "login-time", accounting->time, NULL);
+                g_object_get (user,
+                              "login-frequency", &old_login_frequency,
+                              "login-time", &old_login_time,
+                              NULL);
+
+                if (old_login_frequency != accounting->frequency) {
+                        g_object_set (user, "login-frequency", accounting->frequency, NULL);
+                        changed = TRUE;
+                }
+
+                if (old_login_time != accounting->time) {
+                        g_object_set (user, "login-time", accounting->time, NULL);
+                        changed = TRUE;
+                }
 
                 builder = g_variant_builder_new (G_VARIANT_TYPE ("a(xxa{sv})"));
                 for (l = g_list_last (accounting->previous_logins); l != NULL; l = l->prev) {
@@ -188,7 +203,8 @@ wtmp_helper_update_login_frequencies (GHashTable *users)
                 g_variant_builder_unref (builder);
                 g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free);
 
-                user_changed (user);
+                if (changed)
+                        user_changed (user);
         }
 
         g_hash_table_unref (login_hash);
-- 
2.16.4

From 081a2b74712233f2515920a85315e6e0d4e73960 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 25 Apr 2018 11:16:36 -0400
Subject: [PATCH] wtmp-helper: don't call getpwnam()

The wtmp helper code examines /var/log/wtmp to determine which
users log in the most frequently.

That code calls getpwnam() once for every entry in /var/log/wtmp.
This is very inefficient, since getpwnam() can be quite slow, and
/var/log/wtmp will often have the same users repeated over and
over again.

Also, we don't actually use the result for anything other than verifying
the existence of the user! And we already verify the existence of
the user later later in the code in a more efficient way (by finding
the user in the users hashtable).

This commit just drops the unnecessary getpwnam() call.

https://bugs.freedesktop.org/show_bug.cgi?id=106240
---
 src/wtmp-helper.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/src/wtmp-helper.c b/src/wtmp-helper.c
index a1edffe..01caa2e 100644
--- a/src/wtmp-helper.c
+++ b/src/wtmp-helper.c
@@ -75,7 +75,6 @@ wtmp_helper_update_login_frequencies (GHashTable *users)
         struct utmpx *wtmp_entry;
         GHashTableIter iter;
         gpointer key, value;
-        struct passwd *pwent;
         User *user;
         GVariantBuilder *builder, *builder2;
         GList *l;
@@ -128,11 +127,6 @@ wtmp_helper_update_login_frequencies (GHashTable *users)
                         continue;
                 }
 
-                pwent = getpwnam (wtmp_entry->ut_user);
-                if (pwent == NULL) {
-                        continue;
-                }
-
                 if (!g_hash_table_lookup_extended (login_hash,
                                                    wtmp_entry->ut_user,
                                                    &key, &value)) {
-- 
2.16.4

From 64b11314ea71b5e22edf4d968347489c5d5acd01 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 9 May 2019 14:58:34 -0400
Subject: [PATCH] data: don't send change updates for login-history

The login-history property of user objects can be quite large.
If wtmp is changed frequently, that can lead to memory fragmentation
in clients.

Furthermore, most clients never check login-history, so it's
wasted memory and wasted cpu.

This commit disables change notification for that property.  If
a client really needs to get updates, they can manually refresh
their cache when appropriate.
---
 data/org.freedesktop.Accounts.User.xml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/data/org.freedesktop.Accounts.User.xml b/data/org.freedesktop.Accounts.User.xml
index 8d3fe1c..3b839a3 100644
--- a/data/org.freedesktop.Accounts.User.xml
+++ b/data/org.freedesktop.Accounts.User.xml
@@ -812,6 +812,7 @@
   </property>
 
   <property name="LoginHistory" type="a(xxa{sv})" access="read">
+    <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
     <doc:doc>
       <doc:description>
         <doc:para>
-- 
2.16.4

