From a2f448b54c52f2c6444749c93d7f3c5da4d96ae7 Mon Sep 17 00:00:00 2001 From: Ray Strode 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(-) diff --git a/src/daemon.c b/src/daemon.c index 1700c8a..651651e 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -362,63 +362,64 @@ 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, 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)) 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)); } g_object_thaw_notify (G_OBJECT (user)); diff --git a/src/wtmp-helper.c b/src/wtmp-helper.c index d9a43ea..787480b 100644 --- a/src/wtmp-helper.c +++ b/src/wtmp-helper.c @@ -14,124 +14,106 @@ * * 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: Ondrej Holy * Ryan Lortie */ #include "config.h" #include "wtmp-helper.h" #include "user.h" #ifdef HAVE_UTMPX_H #include 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 gboolean wtmp_helper_start (void) { #if defined(HAVE_SETUTXDB) if (setutxdb (UTXDB_LOG, NULL) != 0) { return FALSE; } #elif defined(PATH_WTMP) if (utmpxname (PATH_WTMP) != 0) { return FALSE; } setutxent (); #else #error You have utmpx.h, but no known way to use it for wtmp entries #endif return TRUE; } -struct passwd * -wtmp_helper_entry_generator (GHashTable *users, - gpointer *state, - struct spwd **shadow_entry) +void +wtmp_helper_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 */ - - 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; gboolean shutdown_or_reboot = FALSE; if (g_str_equal (wtmp_entry->ut_line, "~")) { if (g_str_equal (wtmp_entry->ut_user, "shutdown") || g_str_equal (wtmp_entry->ut_user, "reboot")) { shutdown_or_reboot = TRUE; } } if (wtmp_entry->ut_type == BOOT_TIME || shutdown_or_reboot) { /* Set shutdown, reboot, or 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); @@ -147,98 +129,84 @@ wtmp_helper_entry_generator (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); - - *shadow_entry = 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; } const gchar * wtmp_helper_get_path_for_monitor (void) { return PATH_WTMP; } #else /* HAVE_UTMPX_H */ -struct passwd * -wtmp_helper_entry_generator (GHashTable *users, - gpointer *state, - struct spwd **shadow_entry) -{ - return NULL; -} - const gchar * wtmp_helper_get_path_for_monitor (void) { return NULL; } #endif /* HAVE_UTMPX_H */ diff --git a/src/wtmp-helper.h b/src/wtmp-helper.h index fa65ead..047ea5c 100644 --- a/src/wtmp-helper.h +++ b/src/wtmp-helper.h @@ -1,33 +1,31 @@ /* * Copyright (C) 2014 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 */ #ifndef __WTMP_HELPER_H__ #define __WTMP_HELPER_H__ #include #include #include const gchar * wtmp_helper_get_path_for_monitor (void); -struct passwd * wtmp_helper_entry_generator (GHashTable *users, - gpointer *state, - struct spwd **shadow_entry); +void wtmp_helper_update_login_frequencies (GHashTable *users); #endif /* __WTMP_HELPER_H__ */ -- 2.7.4