diff options
author | Ryan Lortie <desrt@desrt.ca> | 2014-03-08 17:26:05 -0500 |
---|---|---|
committer | Ryan Lortie <desrt@desrt.ca> | 2014-03-19 09:46:33 -0400 |
commit | 9771f8e9ba0d5c7bb3cf10b244463fcfd21f9776 (patch) | |
tree | 9510ed52fe8a5930bba6b6124fa92fd4f1588a93 | |
parent | cdee3f55a5821cc76ad270b8c709a7bb1e3ae1b2 (diff) |
daemon: split wtmp code into separate file
Split the code for opening and iterating the wtmp entries into a
separate 'wtmp-helper' file.
For now, this is a direct transplant of the existing code to a new file
with some minimal renaming and a function to get the name of the file to
monitor for changes (which is still setup from daemon.c).
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/daemon.c | 187 | ||||
-rw-r--r-- | src/wtmp-helper.c | 218 | ||||
-rw-r--r-- | src/wtmp-helper.h | 31 |
4 files changed, 258 insertions, 180 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 30e5c8a..7a28beb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,6 +41,8 @@ accounts_daemon_SOURCES = \ user.c \ util.h \ util.c \ + wtmp-helper.h \ + wtmp-helper.c \ main.c accounts_daemon_LDADD = \ diff --git a/src/daemon.c b/src/daemon.c index 233f374..e55ea9e 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -32,9 +32,6 @@ #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> @@ -44,6 +41,7 @@ #include <polkit/polkit.h> #include "user-classify.h" +#include "wtmp-helper.h" #include "daemon.h" #include "util.h" @@ -51,9 +49,6 @@ #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, @@ -72,9 +67,7 @@ struct DaemonPrivate { GFileMonitor *shadow_monitor; GFileMonitor *group_monitor; GFileMonitor *gdm_monitor; -#ifdef HAVE_UTMPX_H GFileMonitor *wtmp_monitor; -#endif guint reload_id; guint autologin_id; @@ -136,177 +129,11 @@ 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); -} - #ifndef HAVE_FGETPWENT #include "fgetpwent.c" #endif static struct passwd * -entry_generator_wtmp (GHashTable *users, - gpointer *state) -{ - 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; - logout_hash = state_data->logout_hash; - 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) { - 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)) { - 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); - - 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) { @@ -486,9 +313,7 @@ reload_users (Daemon *daemon) g_hash_table_add (local, name); /* Now add/update users from other sources, possibly non-local */ -#ifdef HAVE_UTMPX_H - load_entries (daemon, users, entry_generator_wtmp); -#endif + load_entries (daemon, users, wtmp_helper_entry_generator); load_entries (daemon, users, entry_generator_cachedir); /* Mark which users are local, which are not */ @@ -663,6 +488,10 @@ setup_monitor (Daemon *daemon, GFile *file; GFileMonitor *monitor; + if (!path) { + return NULL; + } + file = g_file_new_for_path (path); monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, @@ -701,11 +530,9 @@ daemon_init (Daemon *daemon) PATH_GROUP, on_users_monitor_changed); -#ifdef HAVE_UTMPX_H daemon->priv->wtmp_monitor = setup_monitor (daemon, - PATH_WTMP, + wtmp_helper_get_path_for_monitor (), on_users_monitor_changed); -#endif daemon->priv->gdm_monitor = setup_monitor (daemon, PATH_GDM_CUSTOM, diff --git a/src/wtmp-helper.c b/src/wtmp-helper.c new file mode 100644 index 0000000..5f7c6ed --- /dev/null +++ b/src/wtmp-helper.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * 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: Ondrej Holy <oholy@redhat.com> + * Ryan Lortie <desrt@desrt.ca> + */ + +#include "config.h" + +#include "wtmp-helper.h" +#include "user.h" + +#ifdef HAVE_UTMPX_H + +#include <utmpx.h> + +#define PATH_WTMP _PATH_WTMPX + +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); +} + +struct passwd * +wtmp_helper_entry_generator (GHashTable *users, + gpointer *state) +{ + 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; + logout_hash = state_data->logout_hash; + 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) { + 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)) { + 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); + + 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 * +entry_generator_wtmp (GHashTable *users, + gpointer *state) +{ + 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 new file mode 100644 index 0000000..7058415 --- /dev/null +++ b/src/wtmp-helper.h @@ -0,0 +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 <desrt@desrt.ca> + */ + +#ifndef __WTMP_HELPER_H__ +#define __WTMP_HELPER_H__ + +#include <glib.h> +#include <pwd.h> + +const gchar * wtmp_helper_get_path_for_monitor (void); +struct passwd * wtmp_helper_entry_generator (GHashTable *users, + gpointer *state); + +#endif /* __WTMP_HELPER_H__ */ |