|
|
44ca26 |
From 2b23e50057fc92da30093fbebb78b320fc4107d0 Mon Sep 17 00:00:00 2001
|
|
|
44ca26 |
From: Ray Strode <rstrode@redhat.com>
|
|
|
44ca26 |
Date: Wed, 29 Jun 2016 10:50:37 -0400
|
|
|
44ca26 |
Subject: [PATCH 1/5] user: check if user is in wheel more efficiently
|
|
|
44ca26 |
|
|
|
44ca26 |
We currently get all the groups a user belongs to in one pass,
|
|
|
44ca26 |
then check each one to see if it's wheel.
|
|
|
44ca26 |
|
|
|
44ca26 |
It's much more efficient to just get the wheel group and check if
|
|
|
44ca26 |
any of its members are the user.
|
|
|
44ca26 |
|
|
|
44ca26 |
https://bugs.freedesktop.org/show_bug.cgi?id=48177
|
|
|
44ca26 |
---
|
|
|
44ca26 |
src/user.c | 13 ++-----------
|
|
|
44ca26 |
1 file changed, 2 insertions(+), 11 deletions(-)
|
|
|
44ca26 |
|
|
|
44ca26 |
diff --git a/src/user.c b/src/user.c
|
|
|
44ca26 |
index de30090..52f57d0 100644
|
|
|
44ca26 |
--- a/src/user.c
|
|
|
44ca26 |
+++ b/src/user.c
|
|
|
44ca26 |
@@ -92,88 +92,79 @@ struct User {
|
|
|
44ca26 |
gchar *home_dir;
|
|
|
44ca26 |
gchar *shell;
|
|
|
44ca26 |
gchar *email;
|
|
|
44ca26 |
gchar *language;
|
|
|
44ca26 |
gchar *x_session;
|
|
|
44ca26 |
gchar *location;
|
|
|
44ca26 |
guint64 login_frequency;
|
|
|
44ca26 |
gint64 login_time;
|
|
|
44ca26 |
GVariant *login_history;
|
|
|
44ca26 |
gchar *icon_file;
|
|
|
44ca26 |
gchar *default_icon_file;
|
|
|
44ca26 |
gboolean locked;
|
|
|
44ca26 |
gboolean automatic_login;
|
|
|
44ca26 |
gboolean system_account;
|
|
|
44ca26 |
gboolean local_account;
|
|
|
44ca26 |
};
|
|
|
44ca26 |
|
|
|
44ca26 |
typedef struct UserClass
|
|
|
44ca26 |
{
|
|
|
44ca26 |
AccountsUserSkeletonClass parent_class;
|
|
|
44ca26 |
} UserClass;
|
|
|
44ca26 |
|
|
|
44ca26 |
static void user_accounts_user_iface_init (AccountsUserIface *iface);
|
|
|
44ca26 |
|
|
|
44ca26 |
G_DEFINE_TYPE_WITH_CODE (User, user, ACCOUNTS_TYPE_USER_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_USER, user_accounts_user_iface_init));
|
|
|
44ca26 |
|
|
|
44ca26 |
static gint
|
|
|
44ca26 |
account_type_from_pwent (struct passwd *pwent)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
struct group *grp;
|
|
|
44ca26 |
- gid_t wheel;
|
|
|
44ca26 |
- gid_t *groups;
|
|
|
44ca26 |
- gint ngroups;
|
|
|
44ca26 |
gint i;
|
|
|
44ca26 |
|
|
|
44ca26 |
if (pwent->pw_uid == 0) {
|
|
|
44ca26 |
g_debug ("user is root so account type is administrator");
|
|
|
44ca26 |
return ACCOUNT_TYPE_ADMINISTRATOR;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
grp = getgrnam (ADMIN_GROUP);
|
|
|
44ca26 |
if (grp == NULL) {
|
|
|
44ca26 |
g_debug (ADMIN_GROUP " group not found");
|
|
|
44ca26 |
return ACCOUNT_TYPE_STANDARD;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
- wheel = grp->gr_gid;
|
|
|
44ca26 |
|
|
|
44ca26 |
- ngroups = get_user_groups (pwent->pw_name, pwent->pw_gid, &groups);
|
|
|
44ca26 |
-
|
|
|
44ca26 |
- for (i = 0; i < ngroups; i++) {
|
|
|
44ca26 |
- if (groups[i] == wheel) {
|
|
|
44ca26 |
- g_free (groups);
|
|
|
44ca26 |
+ for (i = 0; grp->gr_mem[i] != NULL; i++) {
|
|
|
44ca26 |
+ if (g_strcmp0 (grp->gr_mem[i], pwent->pw_name) == 0) {
|
|
|
44ca26 |
return ACCOUNT_TYPE_ADMINISTRATOR;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
- g_free (groups);
|
|
|
44ca26 |
-
|
|
|
44ca26 |
return ACCOUNT_TYPE_STANDARD;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
void
|
|
|
44ca26 |
user_update_from_pwent (User *user,
|
|
|
44ca26 |
struct passwd *pwent)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
#ifdef HAVE_SHADOW_H
|
|
|
44ca26 |
struct spwd *spent;
|
|
|
44ca26 |
#endif
|
|
|
44ca26 |
gchar *real_name;
|
|
|
44ca26 |
gboolean changed;
|
|
|
44ca26 |
const gchar *passwd;
|
|
|
44ca26 |
gboolean locked;
|
|
|
44ca26 |
PasswordMode mode;
|
|
|
44ca26 |
AccountType account_type;
|
|
|
44ca26 |
|
|
|
44ca26 |
g_object_freeze_notify (G_OBJECT (user));
|
|
|
44ca26 |
|
|
|
44ca26 |
changed = FALSE;
|
|
|
44ca26 |
|
|
|
44ca26 |
if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') {
|
|
|
44ca26 |
gchar *first_comma = NULL;
|
|
|
44ca26 |
gchar *valid_utf8_name = NULL;
|
|
|
44ca26 |
|
|
|
44ca26 |
if (g_utf8_validate (pwent->pw_gecos, -1, NULL)) {
|
|
|
44ca26 |
valid_utf8_name = pwent->pw_gecos;
|
|
|
44ca26 |
first_comma = g_utf8_strchr (valid_utf8_name, -1, ',');
|
|
|
44ca26 |
}
|
|
|
44ca26 |
else {
|
|
|
44ca26 |
--
|
|
|
44ca26 |
2.7.4
|
|
|
44ca26 |
|
|
|
44ca26 |
|
|
|
44ca26 |
From c2b87f89a85ffa5465a523aa291ea0018a050cc5 Mon Sep 17 00:00:00 2001
|
|
|
44ca26 |
From: Ray Strode <rstrode@redhat.com>
|
|
|
44ca26 |
Date: Tue, 28 Jun 2016 15:43:08 -0400
|
|
|
44ca26 |
Subject: [PATCH 2/5] daemon: get local users from /etc/shadow not /etc/passwd
|
|
|
44ca26 |
|
|
|
44ca26 |
For some sites, it's common practice to rsync around large
|
|
|
44ca26 |
/etc/passwd files containing the password entries for remote
|
|
|
44ca26 |
users. That means accountsservices' "assume /etc/passwd is local
|
|
|
44ca26 |
users" heuristic falls over.
|
|
|
44ca26 |
|
|
|
44ca26 |
This commit changes it to only treat users in /etc/shadow as local.
|
|
|
44ca26 |
|
|
|
44ca26 |
https://bugs.freedesktop.org/show_bug.cgi?id=48177
|
|
|
44ca26 |
---
|
|
|
44ca26 |
src/daemon.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
|
|
|
44ca26 |
1 file changed, 53 insertions(+), 6 deletions(-)
|
|
|
44ca26 |
|
|
|
44ca26 |
diff --git a/src/daemon.c b/src/daemon.c
|
|
|
44ca26 |
index 38f6a47..5c269af 100644
|
|
|
44ca26 |
--- a/src/daemon.c
|
|
|
44ca26 |
+++ b/src/daemon.c
|
|
|
44ca26 |
@@ -2,60 +2,63 @@
|
|
|
44ca26 |
*
|
|
|
44ca26 |
* Copyright (C) 2009-2010 Red Hat, Inc.
|
|
|
44ca26 |
* Copyright (c) 2013 Canonical Limited
|
|
|
44ca26 |
*
|
|
|
44ca26 |
* This program is free software; you can redistribute it and/or modify
|
|
|
44ca26 |
* it under the terms of the GNU General Public License as published by
|
|
|
44ca26 |
* the Free Software Foundation; either version 3 of the License, or
|
|
|
44ca26 |
* (at your option) any later version.
|
|
|
44ca26 |
*
|
|
|
44ca26 |
* This program is distributed in the hope that it will be useful,
|
|
|
44ca26 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
44ca26 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
44ca26 |
* GNU General Public License for more details.
|
|
|
44ca26 |
*
|
|
|
44ca26 |
* You should have received a copy of the GNU General Public License
|
|
|
44ca26 |
* along with this program; if not, write to the Free Software
|
|
|
44ca26 |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
44ca26 |
*
|
|
|
44ca26 |
* Written by: Matthias Clasen <mclasen@redhat.com>
|
|
|
44ca26 |
*/
|
|
|
44ca26 |
|
|
|
44ca26 |
#include "config.h"
|
|
|
44ca26 |
|
|
|
44ca26 |
#include <stdlib.h>
|
|
|
44ca26 |
#include <stdio.h>
|
|
|
44ca26 |
#include <sys/types.h>
|
|
|
44ca26 |
#include <sys/stat.h>
|
|
|
44ca26 |
#include <fcntl.h>
|
|
|
44ca26 |
#include <sys/wait.h>
|
|
|
44ca26 |
#include <pwd.h>
|
|
|
44ca26 |
+#ifdef HAVE_SHADOW_H
|
|
|
44ca26 |
+#include <shadow.h>
|
|
|
44ca26 |
+#endif
|
|
|
44ca26 |
#include <unistd.h>
|
|
|
44ca26 |
#include <errno.h>
|
|
|
44ca26 |
#include <sys/types.h>
|
|
|
44ca26 |
#ifdef HAVE_UTMPX_H
|
|
|
44ca26 |
#include <utmpx.h>
|
|
|
44ca26 |
#endif
|
|
|
44ca26 |
|
|
|
44ca26 |
#include <glib.h>
|
|
|
44ca26 |
#include <glib/gi18n.h>
|
|
|
44ca26 |
#include <glib-object.h>
|
|
|
44ca26 |
#include <glib/gstdio.h>
|
|
|
44ca26 |
#include <gio/gio.h>
|
|
|
44ca26 |
#include <polkit/polkit.h>
|
|
|
44ca26 |
|
|
|
44ca26 |
#include "user-classify.h"
|
|
|
44ca26 |
#include "daemon.h"
|
|
|
44ca26 |
#include "util.h"
|
|
|
44ca26 |
|
|
|
44ca26 |
#define PATH_PASSWD "/etc/passwd"
|
|
|
44ca26 |
#define PATH_SHADOW "/etc/shadow"
|
|
|
44ca26 |
#define PATH_GROUP "/etc/group"
|
|
|
44ca26 |
#define PATH_GDM_CUSTOM "/etc/gdm/custom.conf"
|
|
|
44ca26 |
#ifdef HAVE_UTMPX_H
|
|
|
44ca26 |
#define PATH_WTMP _PATH_WTMPX
|
|
|
44ca26 |
#endif
|
|
|
44ca26 |
|
|
|
44ca26 |
enum {
|
|
|
44ca26 |
PROP_0,
|
|
|
44ca26 |
PROP_DAEMON_VERSION
|
|
|
44ca26 |
};
|
|
|
44ca26 |
@@ -279,81 +282,125 @@ entry_generator_wtmp (GHashTable *users,
|
|
|
44ca26 |
|
|
|
44ca26 |
builder = g_variant_builder_new (G_VARIANT_TYPE ("a(xxa{sv})"));
|
|
|
44ca26 |
for (l = g_list_last (accounting->previous_logins); l != NULL; l = l->prev) {
|
|
|
44ca26 |
previous_login = l->data;
|
|
|
44ca26 |
|
|
|
44ca26 |
builder2 = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
|
|
44ca26 |
g_variant_builder_add (builder2, "{sv}", "type", g_variant_new_string (previous_login->id));
|
|
|
44ca26 |
g_variant_builder_add (builder, "(xxa{sv})", previous_login->login_time, previous_login->logout_time, builder2);
|
|
|
44ca26 |
g_variant_builder_unref (builder2);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
g_object_set (user, "login-history", g_variant_new ("a(xxa{sv})", builder), NULL);
|
|
|
44ca26 |
g_variant_builder_unref (builder);
|
|
|
44ca26 |
g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free);
|
|
|
44ca26 |
|
|
|
44ca26 |
user_changed (user);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_unref (login_hash);
|
|
|
44ca26 |
g_hash_table_unref (logout_hash);
|
|
|
44ca26 |
g_free (state_data);
|
|
|
44ca26 |
*state = NULL;
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
#endif /* HAVE_UTMPX_H */
|
|
|
44ca26 |
|
|
|
44ca26 |
static struct passwd *
|
|
|
44ca26 |
entry_generator_fgetpwent (GHashTable *users,
|
|
|
44ca26 |
gpointer *state)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
struct passwd *pwent;
|
|
|
44ca26 |
- FILE *fp;
|
|
|
44ca26 |
+ struct {
|
|
|
44ca26 |
+ FILE *fp;
|
|
|
44ca26 |
+ GHashTable *users;
|
|
|
44ca26 |
+ } *generator_state;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* First iteration */
|
|
|
44ca26 |
if (*state == NULL) {
|
|
|
44ca26 |
- *state = fp = fopen (PATH_PASSWD, "r");
|
|
|
44ca26 |
+ GHashTable *shadow_users = NULL;
|
|
|
44ca26 |
+ FILE *fp;
|
|
|
44ca26 |
+#ifdef HAVE_SHADOW_H
|
|
|
44ca26 |
+ struct spwd *shadow_entry;
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ fp = fopen (PATH_SHADOW, "r");
|
|
|
44ca26 |
+ if (fp == NULL) {
|
|
|
44ca26 |
+ g_warning ("Unable to open %s: %s", PATH_SHADOW, g_strerror (errno));
|
|
|
44ca26 |
+ return NULL;
|
|
|
44ca26 |
+ }
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ shadow_users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ do {
|
|
|
44ca26 |
+ shadow_entry = fgetspent (fp);
|
|
|
44ca26 |
+ if (shadow_entry != NULL) {
|
|
|
44ca26 |
+ g_hash_table_add (shadow_users, g_strdup (shadow_entry->sp_namp));
|
|
|
44ca26 |
+ } else if (errno != EINTR) {
|
|
|
44ca26 |
+ break;
|
|
|
44ca26 |
+ }
|
|
|
44ca26 |
+ } while (shadow_entry != NULL);
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ fclose (fp);
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ if (g_hash_table_size (shadow_users) == 0) {
|
|
|
44ca26 |
+ g_clear_pointer (&shadow_users, g_hash_table_unref);
|
|
|
44ca26 |
+ return NULL;
|
|
|
44ca26 |
+ }
|
|
|
44ca26 |
+#endif
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ fp = fopen (PATH_PASSWD, "r");
|
|
|
44ca26 |
if (fp == NULL) {
|
|
|
44ca26 |
+ g_clear_pointer (&shadow_users, g_hash_table_unref);
|
|
|
44ca26 |
g_warning ("Unable to open %s: %s", PATH_PASSWD, g_strerror (errno));
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ generator_state = g_malloc0 (sizeof (*generator_state));
|
|
|
44ca26 |
+ generator_state->fp = fp;
|
|
|
44ca26 |
+ generator_state->users = shadow_users;
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ *state = generator_state;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Every iteration */
|
|
|
44ca26 |
- fp = *state;
|
|
|
44ca26 |
- pwent = fgetpwent (fp);
|
|
|
44ca26 |
+ generator_state = *state;
|
|
|
44ca26 |
+ pwent = fgetpwent (generator_state->fp);
|
|
|
44ca26 |
if (pwent != NULL) {
|
|
|
44ca26 |
- return pwent;
|
|
|
44ca26 |
+ if (!generator_state->users || g_hash_table_lookup (generator_state->users, pwent->pw_name))
|
|
|
44ca26 |
+ return pwent;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Last iteration */
|
|
|
44ca26 |
- fclose (fp);
|
|
|
44ca26 |
+ fclose (generator_state->fp);
|
|
|
44ca26 |
+ g_hash_table_unref (generator_state->users);
|
|
|
44ca26 |
+ g_free (generator_state);
|
|
|
44ca26 |
*state = NULL;
|
|
|
44ca26 |
+
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
static struct passwd *
|
|
|
44ca26 |
entry_generator_cachedir (GHashTable *users,
|
|
|
44ca26 |
gpointer *state)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
struct passwd *pwent;
|
|
|
44ca26 |
const gchar *name;
|
|
|
44ca26 |
GError *error = NULL;
|
|
|
44ca26 |
gchar *filename;
|
|
|
44ca26 |
gboolean regular;
|
|
|
44ca26 |
GHashTableIter iter;
|
|
|
44ca26 |
GKeyFile *key_file;
|
|
|
44ca26 |
User *user;
|
|
|
44ca26 |
GDir *dir;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* First iteration */
|
|
|
44ca26 |
if (*state == NULL) {
|
|
|
44ca26 |
*state = g_dir_open (USERDIR, 0, &error);
|
|
|
44ca26 |
if (error != NULL) {
|
|
|
44ca26 |
if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
|
|
|
44ca26 |
g_warning ("couldn't list user cache directory: %s", USERDIR);
|
|
|
44ca26 |
g_error_free (error);
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Every iteration */
|
|
|
44ca26 |
|
|
|
44ca26 |
--
|
|
|
44ca26 |
2.7.4
|
|
|
44ca26 |
|
|
|
44ca26 |
|
|
|
44ca26 |
From 011ef555b0db601186a38c43f9359589ed61e230 Mon Sep 17 00:00:00 2001
|
|
|
44ca26 |
From: Ray Strode <rstrode@redhat.com>
|
|
|
44ca26 |
Date: Wed, 29 Jun 2016 15:57:38 -0400
|
|
|
44ca26 |
Subject: [PATCH 3/5] daemon: don't call getspnam for local users
|
|
|
44ca26 |
|
|
|
44ca26 |
We're already iterating over the whole shadow file, so
|
|
|
44ca26 |
just cache the entries instead of calling getspname a
|
|
|
44ca26 |
few lines later.
|
|
|
44ca26 |
|
|
|
44ca26 |
https://bugs.freedesktop.org/show_bug.cgi?id=48177
|
|
|
44ca26 |
---
|
|
|
44ca26 |
src/daemon.c | 86 +++++++++++++++++++++++++++++++++++++++++-------------------
|
|
|
44ca26 |
src/user.c | 11 ++------
|
|
|
44ca26 |
src/user.h | 4 ++-
|
|
|
44ca26 |
3 files changed, 64 insertions(+), 37 deletions(-)
|
|
|
44ca26 |
|
|
|
44ca26 |
diff --git a/src/daemon.c b/src/daemon.c
|
|
|
44ca26 |
index 5c269af..71a3ea4 100644
|
|
|
44ca26 |
--- a/src/daemon.c
|
|
|
44ca26 |
+++ b/src/daemon.c
|
|
|
44ca26 |
@@ -58,61 +58,61 @@
|
|
|
44ca26 |
#define PATH_WTMP _PATH_WTMPX
|
|
|
44ca26 |
#endif
|
|
|
44ca26 |
|
|
|
44ca26 |
enum {
|
|
|
44ca26 |
PROP_0,
|
|
|
44ca26 |
PROP_DAEMON_VERSION
|
|
|
44ca26 |
};
|
|
|
44ca26 |
|
|
|
44ca26 |
struct DaemonPrivate {
|
|
|
44ca26 |
GDBusConnection *bus_connection;
|
|
|
44ca26 |
GDBusProxy *bus_proxy;
|
|
|
44ca26 |
|
|
|
44ca26 |
GHashTable *users;
|
|
|
44ca26 |
|
|
|
44ca26 |
User *autologin;
|
|
|
44ca26 |
|
|
|
44ca26 |
GFileMonitor *passwd_monitor;
|
|
|
44ca26 |
GFileMonitor *shadow_monitor;
|
|
|
44ca26 |
GFileMonitor *group_monitor;
|
|
|
44ca26 |
GFileMonitor *gdm_monitor;
|
|
|
44ca26 |
#ifdef HAVE_UTMPX_H
|
|
|
44ca26 |
GFileMonitor *wtmp_monitor;
|
|
|
44ca26 |
#endif
|
|
|
44ca26 |
|
|
|
44ca26 |
guint reload_id;
|
|
|
44ca26 |
guint autologin_id;
|
|
|
44ca26 |
|
|
|
44ca26 |
PolkitAuthority *authority;
|
|
|
44ca26 |
};
|
|
|
44ca26 |
|
|
|
44ca26 |
-typedef struct passwd * (* EntryGeneratorFunc) (GHashTable *, gpointer *);
|
|
|
44ca26 |
+typedef struct passwd * (* EntryGeneratorFunc) (GHashTable *, gpointer *, struct spwd **shadow_entry);
|
|
|
44ca26 |
|
|
|
44ca26 |
static void daemon_accounts_accounts_iface_init (AccountsAccountsIface *iface);
|
|
|
44ca26 |
|
|
|
44ca26 |
G_DEFINE_TYPE_WITH_CODE (Daemon, daemon, ACCOUNTS_TYPE_ACCOUNTS_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_ACCOUNTS, daemon_accounts_accounts_iface_init));
|
|
|
44ca26 |
|
|
|
44ca26 |
#define DAEMON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_DAEMON, DaemonPrivate))
|
|
|
44ca26 |
|
|
|
44ca26 |
static const GDBusErrorEntry accounts_error_entries[] =
|
|
|
44ca26 |
{
|
|
|
44ca26 |
{ ERROR_FAILED, "org.freedesktop.Accounts.Error.Failed" },
|
|
|
44ca26 |
{ ERROR_USER_EXISTS, "org.freedesktop.Accounts.Error.UserExists" },
|
|
|
44ca26 |
{ ERROR_USER_DOES_NOT_EXIST, "org.freedesktop.Accounts.Error.UserDoesNotExist" },
|
|
|
44ca26 |
{ ERROR_PERMISSION_DENIED, "org.freedesktop.Accounts.Error.PermissionDenied" },
|
|
|
44ca26 |
{ ERROR_NOT_SUPPORTED, "org.freedesktop.Accounts.Error.NotSupported" }
|
|
|
44ca26 |
};
|
|
|
44ca26 |
|
|
|
44ca26 |
GQuark
|
|
|
44ca26 |
error_quark (void)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
static volatile gsize quark_volatile = 0;
|
|
|
44ca26 |
|
|
|
44ca26 |
g_dbus_error_register_error_domain ("accounts_error",
|
|
|
44ca26 |
&quark_volatile,
|
|
|
44ca26 |
accounts_error_entries,
|
|
|
44ca26 |
G_N_ELEMENTS (accounts_error_entries));
|
|
|
44ca26 |
|
|
|
44ca26 |
return (GQuark) quark_volatile;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
|
|
|
44ca26 |
|
|
|
44ca26 |
@@ -138,62 +138,63 @@ error_get_type (void)
|
|
|
44ca26 |
return etype;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
#ifdef HAVE_UTMPX_H
|
|
|
44ca26 |
|
|
|
44ca26 |
typedef struct {
|
|
|
44ca26 |
guint64 frequency;
|
|
|
44ca26 |
gint64 time;
|
|
|
44ca26 |
GList *previous_logins;
|
|
|
44ca26 |
} UserAccounting;
|
|
|
44ca26 |
|
|
|
44ca26 |
typedef struct {
|
|
|
44ca26 |
gchar *id;
|
|
|
44ca26 |
gint64 login_time;
|
|
|
44ca26 |
gint64 logout_time;
|
|
|
44ca26 |
} UserPreviousLogin;
|
|
|
44ca26 |
|
|
|
44ca26 |
typedef struct {
|
|
|
44ca26 |
GHashTable *login_hash;
|
|
|
44ca26 |
GHashTable *logout_hash;
|
|
|
44ca26 |
} WTmpGeneratorState;
|
|
|
44ca26 |
|
|
|
44ca26 |
static void
|
|
|
44ca26 |
user_previous_login_free (UserPreviousLogin *previous_login)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
g_free (previous_login->id);
|
|
|
44ca26 |
g_free (previous_login);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
static struct passwd *
|
|
|
44ca26 |
-entry_generator_wtmp (GHashTable *users,
|
|
|
44ca26 |
- gpointer *state)
|
|
|
44ca26 |
+entry_generator_wtmp (GHashTable *users,
|
|
|
44ca26 |
+ gpointer *state,
|
|
|
44ca26 |
+ struct spwd **spent)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
GHashTable *login_hash, *logout_hash;
|
|
|
44ca26 |
struct utmpx *wtmp_entry;
|
|
|
44ca26 |
GHashTableIter iter;
|
|
|
44ca26 |
gpointer key, value;
|
|
|
44ca26 |
struct passwd *pwent;
|
|
|
44ca26 |
User *user;
|
|
|
44ca26 |
WTmpGeneratorState *state_data;
|
|
|
44ca26 |
GVariantBuilder *builder, *builder2;
|
|
|
44ca26 |
GList *l;
|
|
|
44ca26 |
|
|
|
44ca26 |
if (*state == NULL) {
|
|
|
44ca26 |
/* First iteration */
|
|
|
44ca26 |
#ifdef UTXDB_LOG
|
|
|
44ca26 |
if (setutxdb (UTXDB_LOG, NULL) != 0) {
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
#else
|
|
|
44ca26 |
utmpxname (PATH_WTMP);
|
|
|
44ca26 |
setutxent ();
|
|
|
44ca26 |
#endif
|
|
|
44ca26 |
*state = g_new (WTmpGeneratorState, 1);
|
|
|
44ca26 |
state_data = *state;
|
|
|
44ca26 |
state_data->login_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
|
44ca26 |
state_data->logout_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Every iteration */
|
|
|
44ca26 |
state_data = *state;
|
|
|
44ca26 |
login_hash = state_data->login_hash;
|
|
|
44ca26 |
@@ -232,284 +233,308 @@ entry_generator_wtmp (GHashTable *users,
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
pwent = getpwnam (wtmp_entry->ut_user);
|
|
|
44ca26 |
if (pwent == NULL) {
|
|
|
44ca26 |
continue;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
if (!g_hash_table_lookup_extended (login_hash,
|
|
|
44ca26 |
wtmp_entry->ut_user,
|
|
|
44ca26 |
&key, &value)) {
|
|
|
44ca26 |
accounting = g_new (UserAccounting, 1);
|
|
|
44ca26 |
accounting->frequency = 0;
|
|
|
44ca26 |
accounting->previous_logins = NULL;
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_insert (login_hash, g_strdup (wtmp_entry->ut_user), accounting);
|
|
|
44ca26 |
} else {
|
|
|
44ca26 |
accounting = value;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
accounting->frequency++;
|
|
|
44ca26 |
accounting->time = wtmp_entry->ut_tv.tv_sec;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Add zero logout time to change it later on logout record */
|
|
|
44ca26 |
previous_login = g_new (UserPreviousLogin, 1);
|
|
|
44ca26 |
previous_login->id = g_strdup (wtmp_entry->ut_line);
|
|
|
44ca26 |
previous_login->login_time = wtmp_entry->ut_tv.tv_sec;
|
|
|
44ca26 |
previous_login->logout_time = 0;
|
|
|
44ca26 |
accounting->previous_logins = g_list_prepend (accounting->previous_logins, previous_login);
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_insert (logout_hash, g_strdup (wtmp_entry->ut_line), previous_login);
|
|
|
44ca26 |
+ *spent = getspnam (pwent->pw_name);
|
|
|
44ca26 |
|
|
|
44ca26 |
return pwent;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Last iteration */
|
|
|
44ca26 |
endutxent ();
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_iter_init (&iter, login_hash);
|
|
|
44ca26 |
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
|
|
44ca26 |
UserAccounting *accounting = (UserAccounting *) value;
|
|
|
44ca26 |
UserPreviousLogin *previous_login;
|
|
|
44ca26 |
|
|
|
44ca26 |
user = g_hash_table_lookup (users, key);
|
|
|
44ca26 |
if (user == NULL) {
|
|
|
44ca26 |
g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free);
|
|
|
44ca26 |
continue;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
g_object_set (user, "login-frequency", accounting->frequency, NULL);
|
|
|
44ca26 |
g_object_set (user, "login-time", accounting->time, NULL);
|
|
|
44ca26 |
|
|
|
44ca26 |
builder = g_variant_builder_new (G_VARIANT_TYPE ("a(xxa{sv})"));
|
|
|
44ca26 |
for (l = g_list_last (accounting->previous_logins); l != NULL; l = l->prev) {
|
|
|
44ca26 |
previous_login = l->data;
|
|
|
44ca26 |
|
|
|
44ca26 |
builder2 = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
|
|
44ca26 |
g_variant_builder_add (builder2, "{sv}", "type", g_variant_new_string (previous_login->id));
|
|
|
44ca26 |
g_variant_builder_add (builder, "(xxa{sv})", previous_login->login_time, previous_login->logout_time, builder2);
|
|
|
44ca26 |
g_variant_builder_unref (builder2);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
g_object_set (user, "login-history", g_variant_new ("a(xxa{sv})", builder), NULL);
|
|
|
44ca26 |
g_variant_builder_unref (builder);
|
|
|
44ca26 |
g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free);
|
|
|
44ca26 |
|
|
|
44ca26 |
user_changed (user);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_unref (login_hash);
|
|
|
44ca26 |
g_hash_table_unref (logout_hash);
|
|
|
44ca26 |
g_free (state_data);
|
|
|
44ca26 |
*state = NULL;
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
#endif /* HAVE_UTMPX_H */
|
|
|
44ca26 |
|
|
|
44ca26 |
static struct passwd *
|
|
|
44ca26 |
-entry_generator_fgetpwent (GHashTable *users,
|
|
|
44ca26 |
- gpointer *state)
|
|
|
44ca26 |
+entry_generator_fgetpwent (GHashTable *users,
|
|
|
44ca26 |
+ gpointer *state,
|
|
|
44ca26 |
+ struct spwd **spent)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
struct passwd *pwent;
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ struct {
|
|
|
44ca26 |
+ struct spwd spbuf;
|
|
|
44ca26 |
+ char buf[1024];
|
|
|
44ca26 |
+ } *shadow_entry_buffers;
|
|
|
44ca26 |
+
|
|
|
44ca26 |
struct {
|
|
|
44ca26 |
FILE *fp;
|
|
|
44ca26 |
GHashTable *users;
|
|
|
44ca26 |
} *generator_state;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* First iteration */
|
|
|
44ca26 |
if (*state == NULL) {
|
|
|
44ca26 |
GHashTable *shadow_users = NULL;
|
|
|
44ca26 |
FILE *fp;
|
|
|
44ca26 |
-#ifdef HAVE_SHADOW_H
|
|
|
44ca26 |
struct spwd *shadow_entry;
|
|
|
44ca26 |
|
|
|
44ca26 |
fp = fopen (PATH_SHADOW, "r");
|
|
|
44ca26 |
if (fp == NULL) {
|
|
|
44ca26 |
g_warning ("Unable to open %s: %s", PATH_SHADOW, g_strerror (errno));
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
- shadow_users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
|
44ca26 |
+ shadow_users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
|
44ca26 |
|
|
|
44ca26 |
do {
|
|
|
44ca26 |
- shadow_entry = fgetspent (fp);
|
|
|
44ca26 |
- if (shadow_entry != NULL) {
|
|
|
44ca26 |
- g_hash_table_add (shadow_users, g_strdup (shadow_entry->sp_namp));
|
|
|
44ca26 |
- } else if (errno != EINTR) {
|
|
|
44ca26 |
- break;
|
|
|
44ca26 |
+ int ret = 0;
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ shadow_entry_buffers = g_malloc0 (sizeof (*shadow_entry_buffers));
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ ret = fgetspent_r (fp, &shadow_entry_buffers->spbuf, shadow_entry_buffers->buf, sizeof (shadow_entry_buffers->buf), &shadow_entry);
|
|
|
44ca26 |
+ if (ret == 0) {
|
|
|
44ca26 |
+ g_hash_table_insert (shadow_users, g_strdup (shadow_entry->sp_namp), shadow_entry_buffers);
|
|
|
44ca26 |
+ } else {
|
|
|
44ca26 |
+ g_free (shadow_entry_buffers);
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ if (errno != EINTR) {
|
|
|
44ca26 |
+ break;
|
|
|
44ca26 |
+ }
|
|
|
44ca26 |
}
|
|
|
44ca26 |
} while (shadow_entry != NULL);
|
|
|
44ca26 |
|
|
|
44ca26 |
fclose (fp);
|
|
|
44ca26 |
|
|
|
44ca26 |
if (g_hash_table_size (shadow_users) == 0) {
|
|
|
44ca26 |
g_clear_pointer (&shadow_users, g_hash_table_unref);
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
-#endif
|
|
|
44ca26 |
|
|
|
44ca26 |
fp = fopen (PATH_PASSWD, "r");
|
|
|
44ca26 |
if (fp == NULL) {
|
|
|
44ca26 |
g_clear_pointer (&shadow_users, g_hash_table_unref);
|
|
|
44ca26 |
g_warning ("Unable to open %s: %s", PATH_PASSWD, g_strerror (errno));
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
generator_state = g_malloc0 (sizeof (*generator_state));
|
|
|
44ca26 |
generator_state->fp = fp;
|
|
|
44ca26 |
generator_state->users = shadow_users;
|
|
|
44ca26 |
|
|
|
44ca26 |
*state = generator_state;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Every iteration */
|
|
|
44ca26 |
generator_state = *state;
|
|
|
44ca26 |
pwent = fgetpwent (generator_state->fp);
|
|
|
44ca26 |
if (pwent != NULL) {
|
|
|
44ca26 |
- if (!generator_state->users || g_hash_table_lookup (generator_state->users, pwent->pw_name))
|
|
|
44ca26 |
+ shadow_entry_buffers = g_hash_table_lookup (generator_state->users, pwent->pw_name);
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ if (shadow_entry_buffers != NULL) {
|
|
|
44ca26 |
+ *spent = &shadow_entry_buffers->spbuf;
|
|
|
44ca26 |
return pwent;
|
|
|
44ca26 |
+ }
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Last iteration */
|
|
|
44ca26 |
fclose (generator_state->fp);
|
|
|
44ca26 |
g_hash_table_unref (generator_state->users);
|
|
|
44ca26 |
g_free (generator_state);
|
|
|
44ca26 |
*state = NULL;
|
|
|
44ca26 |
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
static struct passwd *
|
|
|
44ca26 |
-entry_generator_cachedir (GHashTable *users,
|
|
|
44ca26 |
- gpointer *state)
|
|
|
44ca26 |
+entry_generator_cachedir (GHashTable *users,
|
|
|
44ca26 |
+ gpointer *state,
|
|
|
44ca26 |
+ struct spwd **shadow_entry)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
struct passwd *pwent;
|
|
|
44ca26 |
const gchar *name;
|
|
|
44ca26 |
GError *error = NULL;
|
|
|
44ca26 |
gchar *filename;
|
|
|
44ca26 |
gboolean regular;
|
|
|
44ca26 |
GHashTableIter iter;
|
|
|
44ca26 |
GKeyFile *key_file;
|
|
|
44ca26 |
User *user;
|
|
|
44ca26 |
GDir *dir;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* First iteration */
|
|
|
44ca26 |
if (*state == NULL) {
|
|
|
44ca26 |
*state = g_dir_open (USERDIR, 0, &error);
|
|
|
44ca26 |
if (error != NULL) {
|
|
|
44ca26 |
if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
|
|
|
44ca26 |
g_warning ("couldn't list user cache directory: %s", USERDIR);
|
|
|
44ca26 |
g_error_free (error);
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Every iteration */
|
|
|
44ca26 |
|
|
|
44ca26 |
/*
|
|
|
44ca26 |
* Use names of files of regular type to lookup information
|
|
|
44ca26 |
* about each user. Loop until we find something valid.
|
|
|
44ca26 |
*/
|
|
|
44ca26 |
dir = *state;
|
|
|
44ca26 |
while (TRUE) {
|
|
|
44ca26 |
name = g_dir_read_name (dir);
|
|
|
44ca26 |
if (name == NULL)
|
|
|
44ca26 |
break;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Only load files in this directory */
|
|
|
44ca26 |
filename = g_build_filename (USERDIR, name, NULL);
|
|
|
44ca26 |
regular = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
|
|
|
44ca26 |
g_free (filename);
|
|
|
44ca26 |
|
|
|
44ca26 |
if (regular) {
|
|
|
44ca26 |
pwent = getpwnam (name);
|
|
|
44ca26 |
- if (pwent == NULL)
|
|
|
44ca26 |
+ if (pwent == NULL) {
|
|
|
44ca26 |
g_debug ("user '%s' in cache dir but not present on system", name);
|
|
|
44ca26 |
- else
|
|
|
44ca26 |
+ } else {
|
|
|
44ca26 |
+ *shadow_entry = getspnam (pwent->pw_name);
|
|
|
44ca26 |
+
|
|
|
44ca26 |
return pwent;
|
|
|
44ca26 |
+ }
|
|
|
44ca26 |
}
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Last iteration */
|
|
|
44ca26 |
g_dir_close (dir);
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Update all the users from the files in the cache dir */
|
|
|
44ca26 |
g_hash_table_iter_init (&iter, users);
|
|
|
44ca26 |
while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&user)) {
|
|
|
44ca26 |
filename = g_build_filename (USERDIR, name, NULL);
|
|
|
44ca26 |
key_file = g_key_file_new ();
|
|
|
44ca26 |
if (g_key_file_load_from_file (key_file, filename, 0, NULL))
|
|
|
44ca26 |
user_update_from_keyfile (user, key_file);
|
|
|
44ca26 |
g_key_file_unref (key_file);
|
|
|
44ca26 |
g_free (filename);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
*state = NULL;
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
static void
|
|
|
44ca26 |
load_entries (Daemon *daemon,
|
|
|
44ca26 |
GHashTable *users,
|
|
|
44ca26 |
EntryGeneratorFunc entry_generator)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
gpointer generator_state = NULL;
|
|
|
44ca26 |
struct passwd *pwent;
|
|
|
44ca26 |
+ struct spwd *spent = NULL;
|
|
|
44ca26 |
User *user = NULL;
|
|
|
44ca26 |
|
|
|
44ca26 |
g_assert (entry_generator != NULL);
|
|
|
44ca26 |
|
|
|
44ca26 |
for (;;) {
|
|
|
44ca26 |
- pwent = entry_generator (users, &generator_state);
|
|
|
44ca26 |
+ spent = NULL;
|
|
|
44ca26 |
+ pwent = entry_generator (users, &generator_state, &spent);
|
|
|
44ca26 |
if (pwent == NULL)
|
|
|
44ca26 |
break;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Skip system users... */
|
|
|
44ca26 |
- if (!user_classify_is_human (pwent->pw_uid, pwent->pw_name, pwent->pw_shell, NULL)) {
|
|
|
44ca26 |
+ if (!user_classify_is_human (pwent->pw_uid, pwent->pw_name, pwent->pw_shell, spent? spent->sp_pwdp : NULL)) {
|
|
|
44ca26 |
g_debug ("skipping user: %s", pwent->pw_name);
|
|
|
44ca26 |
continue;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* ignore duplicate entries */
|
|
|
44ca26 |
if (g_hash_table_lookup (users, pwent->pw_name)) {
|
|
|
44ca26 |
continue;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
user = g_hash_table_lookup (daemon->priv->users, pwent->pw_name);
|
|
|
44ca26 |
if (user == NULL) {
|
|
|
44ca26 |
user = user_new (daemon, pwent->pw_uid);
|
|
|
44ca26 |
} else {
|
|
|
44ca26 |
g_object_ref (user);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* freeze & update users not already in the new list */
|
|
|
44ca26 |
g_object_freeze_notify (G_OBJECT (user));
|
|
|
44ca26 |
- user_update_from_pwent (user, pwent);
|
|
|
44ca26 |
+ user_update_from_pwent (user, pwent, spent);
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_insert (users, g_strdup (user_get_user_name (user)), user);
|
|
|
44ca26 |
g_debug ("loaded user: %s", user_get_user_name (user));
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Generator should have cleaned up */
|
|
|
44ca26 |
g_assert (generator_state == NULL);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
static GHashTable *
|
|
|
44ca26 |
create_users_hash_table (void)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
return g_hash_table_new_full (g_str_hash,
|
|
|
44ca26 |
g_str_equal,
|
|
|
44ca26 |
g_free,
|
|
|
44ca26 |
g_object_unref);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
static void
|
|
|
44ca26 |
reload_users (Daemon *daemon)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
GHashTable *users;
|
|
|
44ca26 |
GHashTable *old_users;
|
|
|
44ca26 |
GHashTable *local;
|
|
|
44ca26 |
GHashTableIter iter;
|
|
|
44ca26 |
gpointer name;
|
|
|
44ca26 |
User *user;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Track the users that we saw during our (re)load */
|
|
|
44ca26 |
users = create_users_hash_table ();
|
|
|
44ca26 |
@@ -827,115 +852,122 @@ daemon_new (void)
|
|
|
44ca26 |
g_object_unref (daemon);
|
|
|
44ca26 |
goto error;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
return daemon;
|
|
|
44ca26 |
|
|
|
44ca26 |
error:
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
static void
|
|
|
44ca26 |
throw_error (GDBusMethodInvocation *context,
|
|
|
44ca26 |
gint error_code,
|
|
|
44ca26 |
const gchar *format,
|
|
|
44ca26 |
...)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
va_list args;
|
|
|
44ca26 |
gchar *message;
|
|
|
44ca26 |
|
|
|
44ca26 |
va_start (args, format);
|
|
|
44ca26 |
message = g_strdup_vprintf (format, args);
|
|
|
44ca26 |
va_end (args);
|
|
|
44ca26 |
|
|
|
44ca26 |
g_dbus_method_invocation_return_error (context, ERROR, error_code, "%s", message);
|
|
|
44ca26 |
|
|
|
44ca26 |
g_free (message);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
static User *
|
|
|
44ca26 |
add_new_user_for_pwent (Daemon *daemon,
|
|
|
44ca26 |
- struct passwd *pwent)
|
|
|
44ca26 |
+ struct passwd *pwent,
|
|
|
44ca26 |
+ struct spwd *spent)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
User *user;
|
|
|
44ca26 |
|
|
|
44ca26 |
user = user_new (daemon, pwent->pw_uid);
|
|
|
44ca26 |
- user_update_from_pwent (user, pwent);
|
|
|
44ca26 |
+ user_update_from_pwent (user, pwent, spent);
|
|
|
44ca26 |
user_register (user);
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_insert (daemon->priv->users,
|
|
|
44ca26 |
g_strdup (user_get_user_name (user)),
|
|
|
44ca26 |
user);
|
|
|
44ca26 |
|
|
|
44ca26 |
accounts_accounts_emit_user_added (ACCOUNTS_ACCOUNTS (daemon), user_get_object_path (user));
|
|
|
44ca26 |
|
|
|
44ca26 |
return user;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
User *
|
|
|
44ca26 |
daemon_local_find_user_by_id (Daemon *daemon,
|
|
|
44ca26 |
uid_t uid)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
User *user;
|
|
|
44ca26 |
struct passwd *pwent;
|
|
|
44ca26 |
|
|
|
44ca26 |
pwent = getpwuid (uid);
|
|
|
44ca26 |
if (pwent == NULL) {
|
|
|
44ca26 |
g_debug ("unable to lookup uid %d", (int)uid);
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
user = g_hash_table_lookup (daemon->priv->users, pwent->pw_name);
|
|
|
44ca26 |
|
|
|
44ca26 |
- if (user == NULL)
|
|
|
44ca26 |
- user = add_new_user_for_pwent (daemon, pwent);
|
|
|
44ca26 |
+ if (user == NULL) {
|
|
|
44ca26 |
+ struct spwd *spent;
|
|
|
44ca26 |
+ spent = getspnam (pwent->pw_name);
|
|
|
44ca26 |
+ user = add_new_user_for_pwent (daemon, pwent, spent);
|
|
|
44ca26 |
+ }
|
|
|
44ca26 |
|
|
|
44ca26 |
return user;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
User *
|
|
|
44ca26 |
daemon_local_find_user_by_name (Daemon *daemon,
|
|
|
44ca26 |
const gchar *name)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
User *user;
|
|
|
44ca26 |
struct passwd *pwent;
|
|
|
44ca26 |
|
|
|
44ca26 |
pwent = getpwnam (name);
|
|
|
44ca26 |
if (pwent == NULL) {
|
|
|
44ca26 |
g_debug ("unable to lookup name %s: %s", name, g_strerror (errno));
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
user = g_hash_table_lookup (daemon->priv->users, pwent->pw_name);
|
|
|
44ca26 |
|
|
|
44ca26 |
- if (user == NULL)
|
|
|
44ca26 |
- user = add_new_user_for_pwent (daemon, pwent);
|
|
|
44ca26 |
+ if (user == NULL) {
|
|
|
44ca26 |
+ struct spwd *spent;
|
|
|
44ca26 |
+ spent = getspnam (pwent->pw_name);
|
|
|
44ca26 |
+ user = add_new_user_for_pwent (daemon, pwent, spent);
|
|
|
44ca26 |
+ }
|
|
|
44ca26 |
|
|
|
44ca26 |
return user;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
User *
|
|
|
44ca26 |
daemon_local_get_automatic_login_user (Daemon *daemon)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
return daemon->priv->autologin;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
static gboolean
|
|
|
44ca26 |
daemon_find_user_by_id (AccountsAccounts *accounts,
|
|
|
44ca26 |
GDBusMethodInvocation *context,
|
|
|
44ca26 |
gint64 uid)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
Daemon *daemon = (Daemon*)accounts;
|
|
|
44ca26 |
User *user;
|
|
|
44ca26 |
|
|
|
44ca26 |
user = daemon_local_find_user_by_id (daemon, uid);
|
|
|
44ca26 |
|
|
|
44ca26 |
if (user) {
|
|
|
44ca26 |
accounts_accounts_complete_find_user_by_id (NULL, context, user_get_object_path (user));
|
|
|
44ca26 |
}
|
|
|
44ca26 |
else {
|
|
|
44ca26 |
throw_error (context, ERROR_FAILED, "Failed to look up user with uid %d.", (int)uid);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
return TRUE;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
diff --git a/src/user.c b/src/user.c
|
|
|
44ca26 |
index 52f57d0..247ca2f 100644
|
|
|
44ca26 |
--- a/src/user.c
|
|
|
44ca26 |
+++ b/src/user.c
|
|
|
44ca26 |
@@ -116,65 +116,63 @@ static void user_accounts_user_iface_init (AccountsUserIface *iface);
|
|
|
44ca26 |
G_DEFINE_TYPE_WITH_CODE (User, user, ACCOUNTS_TYPE_USER_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_USER, user_accounts_user_iface_init));
|
|
|
44ca26 |
|
|
|
44ca26 |
static gint
|
|
|
44ca26 |
account_type_from_pwent (struct passwd *pwent)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
struct group *grp;
|
|
|
44ca26 |
gint i;
|
|
|
44ca26 |
|
|
|
44ca26 |
if (pwent->pw_uid == 0) {
|
|
|
44ca26 |
g_debug ("user is root so account type is administrator");
|
|
|
44ca26 |
return ACCOUNT_TYPE_ADMINISTRATOR;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
grp = getgrnam (ADMIN_GROUP);
|
|
|
44ca26 |
if (grp == NULL) {
|
|
|
44ca26 |
g_debug (ADMIN_GROUP " group not found");
|
|
|
44ca26 |
return ACCOUNT_TYPE_STANDARD;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
for (i = 0; grp->gr_mem[i] != NULL; i++) {
|
|
|
44ca26 |
if (g_strcmp0 (grp->gr_mem[i], pwent->pw_name) == 0) {
|
|
|
44ca26 |
return ACCOUNT_TYPE_ADMINISTRATOR;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
return ACCOUNT_TYPE_STANDARD;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
void
|
|
|
44ca26 |
user_update_from_pwent (User *user,
|
|
|
44ca26 |
- struct passwd *pwent)
|
|
|
44ca26 |
+ struct passwd *pwent,
|
|
|
44ca26 |
+ struct spwd *spent)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
-#ifdef HAVE_SHADOW_H
|
|
|
44ca26 |
- struct spwd *spent;
|
|
|
44ca26 |
-#endif
|
|
|
44ca26 |
gchar *real_name;
|
|
|
44ca26 |
gboolean changed;
|
|
|
44ca26 |
const gchar *passwd;
|
|
|
44ca26 |
gboolean locked;
|
|
|
44ca26 |
PasswordMode mode;
|
|
|
44ca26 |
AccountType account_type;
|
|
|
44ca26 |
|
|
|
44ca26 |
g_object_freeze_notify (G_OBJECT (user));
|
|
|
44ca26 |
|
|
|
44ca26 |
changed = FALSE;
|
|
|
44ca26 |
|
|
|
44ca26 |
if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') {
|
|
|
44ca26 |
gchar *first_comma = NULL;
|
|
|
44ca26 |
gchar *valid_utf8_name = NULL;
|
|
|
44ca26 |
|
|
|
44ca26 |
if (g_utf8_validate (pwent->pw_gecos, -1, NULL)) {
|
|
|
44ca26 |
valid_utf8_name = pwent->pw_gecos;
|
|
|
44ca26 |
first_comma = g_utf8_strchr (valid_utf8_name, -1, ',');
|
|
|
44ca26 |
}
|
|
|
44ca26 |
else {
|
|
|
44ca26 |
g_warning ("User %s has invalid UTF-8 in GECOS field. "
|
|
|
44ca26 |
"It would be a good thing to check /etc/passwd.",
|
|
|
44ca26 |
pwent->pw_name ? pwent->pw_name : "");
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
if (first_comma) {
|
|
|
44ca26 |
real_name = g_strndup (valid_utf8_name,
|
|
|
44ca26 |
(first_comma - valid_utf8_name));
|
|
|
44ca26 |
}
|
|
|
44ca26 |
else if (valid_utf8_name) {
|
|
|
44ca26 |
@@ -219,93 +217,88 @@ user_update_from_pwent (User *user,
|
|
|
44ca26 |
g_object_notify (G_OBJECT (user), "account-type");
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Username */
|
|
|
44ca26 |
if (g_strcmp0 (user->user_name, pwent->pw_name) != 0) {
|
|
|
44ca26 |
g_free (user->user_name);
|
|
|
44ca26 |
user->user_name = g_strdup (pwent->pw_name);
|
|
|
44ca26 |
changed = TRUE;
|
|
|
44ca26 |
g_object_notify (G_OBJECT (user), "user-name");
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Home Directory */
|
|
|
44ca26 |
if (g_strcmp0 (user->home_dir, pwent->pw_dir) != 0) {
|
|
|
44ca26 |
g_free (user->home_dir);
|
|
|
44ca26 |
user->home_dir = g_strdup (pwent->pw_dir);
|
|
|
44ca26 |
g_free (user->default_icon_file);
|
|
|
44ca26 |
user->default_icon_file = g_build_filename (user->home_dir, ".face", NULL);
|
|
|
44ca26 |
changed = TRUE;
|
|
|
44ca26 |
g_object_notify (G_OBJECT (user), "home-directory");
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Shell */
|
|
|
44ca26 |
if (g_strcmp0 (user->shell, pwent->pw_shell) != 0) {
|
|
|
44ca26 |
g_free (user->shell);
|
|
|
44ca26 |
user->shell = g_strdup (pwent->pw_shell);
|
|
|
44ca26 |
changed = TRUE;
|
|
|
44ca26 |
g_object_notify (G_OBJECT (user), "shell");
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
passwd = NULL;
|
|
|
44ca26 |
-#ifdef HAVE_SHADOW_H
|
|
|
44ca26 |
- spent = getspnam (pwent->pw_name);
|
|
|
44ca26 |
if (spent)
|
|
|
44ca26 |
passwd = spent->sp_pwdp;
|
|
|
44ca26 |
-#endif
|
|
|
44ca26 |
|
|
|
44ca26 |
if (passwd && passwd[0] == '!') {
|
|
|
44ca26 |
locked = TRUE;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
else {
|
|
|
44ca26 |
locked = FALSE;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
if (user->locked != locked) {
|
|
|
44ca26 |
user->locked = locked;
|
|
|
44ca26 |
changed = TRUE;
|
|
|
44ca26 |
g_object_notify (G_OBJECT (user), "locked");
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
if (passwd == NULL || passwd[0] != 0) {
|
|
|
44ca26 |
mode = PASSWORD_MODE_REGULAR;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
else {
|
|
|
44ca26 |
mode = PASSWORD_MODE_NONE;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
-#ifdef HAVE_SHADOW_H
|
|
|
44ca26 |
if (spent) {
|
|
|
44ca26 |
if (spent->sp_lstchg == 0) {
|
|
|
44ca26 |
mode = PASSWORD_MODE_SET_AT_LOGIN;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
}
|
|
|
44ca26 |
-#endif
|
|
|
44ca26 |
|
|
|
44ca26 |
if (user->password_mode != mode) {
|
|
|
44ca26 |
user->password_mode = mode;
|
|
|
44ca26 |
changed = TRUE;
|
|
|
44ca26 |
g_object_notify (G_OBJECT (user), "password-mode");
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
user->system_account = !user_classify_is_human (user->uid, user->user_name, pwent->pw_shell, passwd);
|
|
|
44ca26 |
|
|
|
44ca26 |
g_object_thaw_notify (G_OBJECT (user));
|
|
|
44ca26 |
|
|
|
44ca26 |
if (changed)
|
|
|
44ca26 |
accounts_user_emit_changed (ACCOUNTS_USER (user));
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
void
|
|
|
44ca26 |
user_update_from_keyfile (User *user,
|
|
|
44ca26 |
GKeyFile *keyfile)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
gchar *s;
|
|
|
44ca26 |
|
|
|
44ca26 |
g_object_freeze_notify (G_OBJECT (user));
|
|
|
44ca26 |
|
|
|
44ca26 |
s = g_key_file_get_string (keyfile, "User", "Language", NULL);
|
|
|
44ca26 |
if (s != NULL) {
|
|
|
44ca26 |
/* TODO: validate / normalize */
|
|
|
44ca26 |
g_free (user->language);
|
|
|
44ca26 |
user->language = s;
|
|
|
44ca26 |
g_object_notify (G_OBJECT (user), "language");
|
|
|
44ca26 |
}
|
|
|
44ca26 |
diff --git a/src/user.h b/src/user.h
|
|
|
44ca26 |
index 0848b50..22548f9 100644
|
|
|
44ca26 |
--- a/src/user.h
|
|
|
44ca26 |
+++ b/src/user.h
|
|
|
44ca26 |
@@ -1,80 +1,82 @@
|
|
|
44ca26 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
|
|
44ca26 |
*
|
|
|
44ca26 |
* Copyright (C) 2009-2010 Red Hat, Inc.
|
|
|
44ca26 |
*
|
|
|
44ca26 |
* This program is free software; you can redistribute it and/or modify
|
|
|
44ca26 |
* it under the terms of the GNU General Public License as published by
|
|
|
44ca26 |
* the Free Software Foundation; either version 3 of the License, or
|
|
|
44ca26 |
* (at your option) any later version.
|
|
|
44ca26 |
*
|
|
|
44ca26 |
* This program is distributed in the hope that it will be useful,
|
|
|
44ca26 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
44ca26 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
44ca26 |
* GNU General Public License for more details.
|
|
|
44ca26 |
*
|
|
|
44ca26 |
* You should have received a copy of the GNU General Public License
|
|
|
44ca26 |
* along with this program; if not, write to the Free Software
|
|
|
44ca26 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
44ca26 |
*/
|
|
|
44ca26 |
|
|
|
44ca26 |
#ifndef __USER__
|
|
|
44ca26 |
#define __USER__
|
|
|
44ca26 |
|
|
|
44ca26 |
#include <sys/types.h>
|
|
|
44ca26 |
#include <pwd.h>
|
|
|
44ca26 |
+#include <shadow.h>
|
|
|
44ca26 |
|
|
|
44ca26 |
#include <glib.h>
|
|
|
44ca26 |
#include <gio/gio.h>
|
|
|
44ca26 |
|
|
|
44ca26 |
#include "types.h"
|
|
|
44ca26 |
|
|
|
44ca26 |
G_BEGIN_DECLS
|
|
|
44ca26 |
|
|
|
44ca26 |
#define TYPE_USER (user_get_type ())
|
|
|
44ca26 |
#define USER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TYPE_USER, User))
|
|
|
44ca26 |
#define IS_USER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TYPE_USER))
|
|
|
44ca26 |
|
|
|
44ca26 |
typedef enum {
|
|
|
44ca26 |
ACCOUNT_TYPE_STANDARD,
|
|
|
44ca26 |
ACCOUNT_TYPE_ADMINISTRATOR,
|
|
|
44ca26 |
#define ACCOUNT_TYPE_LAST ACCOUNT_TYPE_ADMINISTRATOR
|
|
|
44ca26 |
} AccountType;
|
|
|
44ca26 |
|
|
|
44ca26 |
typedef enum {
|
|
|
44ca26 |
PASSWORD_MODE_REGULAR,
|
|
|
44ca26 |
PASSWORD_MODE_SET_AT_LOGIN,
|
|
|
44ca26 |
PASSWORD_MODE_NONE,
|
|
|
44ca26 |
#define PASSWORD_MODE_LAST PASSWORD_MODE_NONE
|
|
|
44ca26 |
} PasswordMode;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* local methods */
|
|
|
44ca26 |
|
|
|
44ca26 |
GType user_get_type (void) G_GNUC_CONST;
|
|
|
44ca26 |
User * user_new (Daemon *daemon,
|
|
|
44ca26 |
uid_t uid);
|
|
|
44ca26 |
|
|
|
44ca26 |
void user_update_from_pwent (User *user,
|
|
|
44ca26 |
- struct passwd *pwent);
|
|
|
44ca26 |
+ struct passwd *pwent,
|
|
|
44ca26 |
+ struct spwd *spent);
|
|
|
44ca26 |
void user_update_from_keyfile (User *user,
|
|
|
44ca26 |
GKeyFile *keyfile);
|
|
|
44ca26 |
void user_update_local_account_property (User *user,
|
|
|
44ca26 |
gboolean local);
|
|
|
44ca26 |
void user_update_system_account_property (User *user,
|
|
|
44ca26 |
gboolean system);
|
|
|
44ca26 |
|
|
|
44ca26 |
void user_register (User *user);
|
|
|
44ca26 |
void user_unregister (User *user);
|
|
|
44ca26 |
void user_changed (User *user);
|
|
|
44ca26 |
|
|
|
44ca26 |
void user_save (User *user);
|
|
|
44ca26 |
|
|
|
44ca26 |
const gchar * user_get_user_name (User *user);
|
|
|
44ca26 |
gboolean user_get_system_account (User *user);
|
|
|
44ca26 |
gboolean user_get_local_account (User *user);
|
|
|
44ca26 |
const gchar * user_get_object_path (User *user);
|
|
|
44ca26 |
uid_t user_get_uid (User *user);
|
|
|
44ca26 |
const gchar * user_get_shell (User *user);
|
|
|
44ca26 |
|
|
|
44ca26 |
G_END_DECLS
|
|
|
44ca26 |
|
|
|
44ca26 |
#endif
|
|
|
44ca26 |
--
|
|
|
44ca26 |
2.7.4
|
|
|
44ca26 |
|
|
|
44ca26 |
|
|
|
44ca26 |
From 2accf123c55f3c6a9596e9fc2d614fcb07c88559 Mon Sep 17 00:00:00 2001
|
|
|
44ca26 |
From: Ray Strode <rstrode@redhat.com>
|
|
|
44ca26 |
Date: Wed, 29 Jun 2016 16:22:42 -0400
|
|
|
44ca26 |
Subject: [PATCH 4/5] daemon: constrain max local users to 50
|
|
|
44ca26 |
|
|
|
44ca26 |
Systems with tens of thousands of users don't want all those users
|
|
|
44ca26 |
showing up in the user list.
|
|
|
44ca26 |
|
|
|
44ca26 |
Set a cap at an even 50, which should cover the lion's share of use
|
|
|
44ca26 |
cases well. Of course, if a user not in the list explicitly
|
|
|
44ca26 |
logs in (from Not Listed? or whatever) they get added to the list.
|
|
|
44ca26 |
|
|
|
44ca26 |
https://bugs.freedesktop.org/show_bug.cgi?id=48177
|
|
|
44ca26 |
---
|
|
|
44ca26 |
src/daemon.c | 19 +++++++++++++------
|
|
|
44ca26 |
1 file changed, 13 insertions(+), 6 deletions(-)
|
|
|
44ca26 |
|
|
|
44ca26 |
diff --git a/src/daemon.c b/src/daemon.c
|
|
|
44ca26 |
index 71a3ea4..cb586bb 100644
|
|
|
44ca26 |
--- a/src/daemon.c
|
|
|
44ca26 |
+++ b/src/daemon.c
|
|
|
44ca26 |
@@ -279,60 +279,64 @@ entry_generator_wtmp (GHashTable *users,
|
|
|
44ca26 |
continue;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
g_object_set (user, "login-frequency", accounting->frequency, NULL);
|
|
|
44ca26 |
g_object_set (user, "login-time", accounting->time, NULL);
|
|
|
44ca26 |
|
|
|
44ca26 |
builder = g_variant_builder_new (G_VARIANT_TYPE ("a(xxa{sv})"));
|
|
|
44ca26 |
for (l = g_list_last (accounting->previous_logins); l != NULL; l = l->prev) {
|
|
|
44ca26 |
previous_login = l->data;
|
|
|
44ca26 |
|
|
|
44ca26 |
builder2 = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
|
|
44ca26 |
g_variant_builder_add (builder2, "{sv}", "type", g_variant_new_string (previous_login->id));
|
|
|
44ca26 |
g_variant_builder_add (builder, "(xxa{sv})", previous_login->login_time, previous_login->logout_time, builder2);
|
|
|
44ca26 |
g_variant_builder_unref (builder2);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
g_object_set (user, "login-history", g_variant_new ("a(xxa{sv})", builder), NULL);
|
|
|
44ca26 |
g_variant_builder_unref (builder);
|
|
|
44ca26 |
g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free);
|
|
|
44ca26 |
|
|
|
44ca26 |
user_changed (user);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_unref (login_hash);
|
|
|
44ca26 |
g_hash_table_unref (logout_hash);
|
|
|
44ca26 |
g_free (state_data);
|
|
|
44ca26 |
*state = NULL;
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
#endif /* HAVE_UTMPX_H */
|
|
|
44ca26 |
|
|
|
44ca26 |
+#ifndef MAX_LOCAL_USERS
|
|
|
44ca26 |
+#define MAX_LOCAL_USERS 50
|
|
|
44ca26 |
+#endif
|
|
|
44ca26 |
+
|
|
|
44ca26 |
static struct passwd *
|
|
|
44ca26 |
entry_generator_fgetpwent (GHashTable *users,
|
|
|
44ca26 |
gpointer *state,
|
|
|
44ca26 |
struct spwd **spent)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
struct passwd *pwent;
|
|
|
44ca26 |
|
|
|
44ca26 |
struct {
|
|
|
44ca26 |
struct spwd spbuf;
|
|
|
44ca26 |
char buf[1024];
|
|
|
44ca26 |
} *shadow_entry_buffers;
|
|
|
44ca26 |
|
|
|
44ca26 |
struct {
|
|
|
44ca26 |
FILE *fp;
|
|
|
44ca26 |
GHashTable *users;
|
|
|
44ca26 |
} *generator_state;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* First iteration */
|
|
|
44ca26 |
if (*state == NULL) {
|
|
|
44ca26 |
GHashTable *shadow_users = NULL;
|
|
|
44ca26 |
FILE *fp;
|
|
|
44ca26 |
struct spwd *shadow_entry;
|
|
|
44ca26 |
|
|
|
44ca26 |
fp = fopen (PATH_SHADOW, "r");
|
|
|
44ca26 |
if (fp == NULL) {
|
|
|
44ca26 |
g_warning ("Unable to open %s: %s", PATH_SHADOW, g_strerror (errno));
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
shadow_users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
|
44ca26 |
@@ -350,67 +354,70 @@ entry_generator_fgetpwent (GHashTable *users,
|
|
|
44ca26 |
|
|
|
44ca26 |
if (errno != EINTR) {
|
|
|
44ca26 |
break;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
}
|
|
|
44ca26 |
} while (shadow_entry != NULL);
|
|
|
44ca26 |
|
|
|
44ca26 |
fclose (fp);
|
|
|
44ca26 |
|
|
|
44ca26 |
if (g_hash_table_size (shadow_users) == 0) {
|
|
|
44ca26 |
g_clear_pointer (&shadow_users, g_hash_table_unref);
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
fp = fopen (PATH_PASSWD, "r");
|
|
|
44ca26 |
if (fp == NULL) {
|
|
|
44ca26 |
g_clear_pointer (&shadow_users, g_hash_table_unref);
|
|
|
44ca26 |
g_warning ("Unable to open %s: %s", PATH_PASSWD, g_strerror (errno));
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
generator_state = g_malloc0 (sizeof (*generator_state));
|
|
|
44ca26 |
generator_state->fp = fp;
|
|
|
44ca26 |
generator_state->users = shadow_users;
|
|
|
44ca26 |
|
|
|
44ca26 |
*state = generator_state;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Every iteration */
|
|
|
44ca26 |
generator_state = *state;
|
|
|
44ca26 |
- pwent = fgetpwent (generator_state->fp);
|
|
|
44ca26 |
- if (pwent != NULL) {
|
|
|
44ca26 |
- shadow_entry_buffers = g_hash_table_lookup (generator_state->users, pwent->pw_name);
|
|
|
44ca26 |
|
|
|
44ca26 |
- if (shadow_entry_buffers != NULL) {
|
|
|
44ca26 |
- *spent = &shadow_entry_buffers->spbuf;
|
|
|
44ca26 |
- return pwent;
|
|
|
44ca26 |
+ if (g_hash_table_size (users) < MAX_LOCAL_USERS) {
|
|
|
44ca26 |
+ pwent = fgetpwent (generator_state->fp);
|
|
|
44ca26 |
+ if (pwent != NULL) {
|
|
|
44ca26 |
+ shadow_entry_buffers = g_hash_table_lookup (generator_state->users, pwent->pw_name);
|
|
|
44ca26 |
+
|
|
|
44ca26 |
+ if (shadow_entry_buffers != NULL) {
|
|
|
44ca26 |
+ *spent = &shadow_entry_buffers->spbuf;
|
|
|
44ca26 |
+ return pwent;
|
|
|
44ca26 |
+ }
|
|
|
44ca26 |
}
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Last iteration */
|
|
|
44ca26 |
fclose (generator_state->fp);
|
|
|
44ca26 |
g_hash_table_unref (generator_state->users);
|
|
|
44ca26 |
g_free (generator_state);
|
|
|
44ca26 |
*state = NULL;
|
|
|
44ca26 |
|
|
|
44ca26 |
return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
static struct passwd *
|
|
|
44ca26 |
entry_generator_cachedir (GHashTable *users,
|
|
|
44ca26 |
gpointer *state,
|
|
|
44ca26 |
struct spwd **shadow_entry)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
struct passwd *pwent;
|
|
|
44ca26 |
const gchar *name;
|
|
|
44ca26 |
GError *error = NULL;
|
|
|
44ca26 |
gchar *filename;
|
|
|
44ca26 |
gboolean regular;
|
|
|
44ca26 |
GHashTableIter iter;
|
|
|
44ca26 |
GKeyFile *key_file;
|
|
|
44ca26 |
User *user;
|
|
|
44ca26 |
GDir *dir;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* First iteration */
|
|
|
44ca26 |
if (*state == NULL) {
|
|
|
44ca26 |
*state = g_dir_open (USERDIR, 0, &error);
|
|
|
44ca26 |
--
|
|
|
44ca26 |
2.7.4
|
|
|
44ca26 |
|
|
|
44ca26 |
|
|
|
44ca26 |
From ed58ad3210010a09b6f114b4d392afb66ad0bbfa Mon Sep 17 00:00:00 2001
|
|
|
44ca26 |
From: Ray Strode <rstrode@redhat.com>
|
|
|
44ca26 |
Date: Wed, 29 Jun 2016 16:32:17 -0400
|
|
|
44ca26 |
Subject: [PATCH 5/5] daemon: don't source user list from wtmp
|
|
|
44ca26 |
|
|
|
44ca26 |
wtmp can get rather large on some systems from ssh logins.
|
|
|
44ca26 |
Furthermore it's pretty much completely redundant given the user
|
|
|
44ca26 |
cache in /var/lib/AccountService
|
|
|
44ca26 |
|
|
|
44ca26 |
This commit changes the wtmp code to only get used for maintaining
|
|
|
44ca26 |
login frequency and accounting, not for generating new users.
|
|
|
44ca26 |
|
|
|
44ca26 |
https://bugs.freedesktop.org/show_bug.cgi?id=48177
|
|
|
44ca26 |
---
|
|
|
44ca26 |
src/daemon.c | 42 ++++++++++++------------------------------
|
|
|
44ca26 |
1 file changed, 12 insertions(+), 30 deletions(-)
|
|
|
44ca26 |
|
|
|
44ca26 |
diff --git a/src/daemon.c b/src/daemon.c
|
|
|
44ca26 |
index cb586bb..815e2c9 100644
|
|
|
44ca26 |
--- a/src/daemon.c
|
|
|
44ca26 |
+++ b/src/daemon.c
|
|
|
44ca26 |
@@ -137,95 +137,83 @@ error_get_type (void)
|
|
|
44ca26 |
}
|
|
|
44ca26 |
return etype;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
#ifdef HAVE_UTMPX_H
|
|
|
44ca26 |
|
|
|
44ca26 |
typedef struct {
|
|
|
44ca26 |
guint64 frequency;
|
|
|
44ca26 |
gint64 time;
|
|
|
44ca26 |
GList *previous_logins;
|
|
|
44ca26 |
} UserAccounting;
|
|
|
44ca26 |
|
|
|
44ca26 |
typedef struct {
|
|
|
44ca26 |
gchar *id;
|
|
|
44ca26 |
gint64 login_time;
|
|
|
44ca26 |
gint64 logout_time;
|
|
|
44ca26 |
} UserPreviousLogin;
|
|
|
44ca26 |
|
|
|
44ca26 |
typedef struct {
|
|
|
44ca26 |
GHashTable *login_hash;
|
|
|
44ca26 |
GHashTable *logout_hash;
|
|
|
44ca26 |
} WTmpGeneratorState;
|
|
|
44ca26 |
|
|
|
44ca26 |
static void
|
|
|
44ca26 |
user_previous_login_free (UserPreviousLogin *previous_login)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
g_free (previous_login->id);
|
|
|
44ca26 |
g_free (previous_login);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
-static struct passwd *
|
|
|
44ca26 |
-entry_generator_wtmp (GHashTable *users,
|
|
|
44ca26 |
- gpointer *state,
|
|
|
44ca26 |
- struct spwd **spent)
|
|
|
44ca26 |
+static void
|
|
|
44ca26 |
+wtmp_update_login_frequencies (GHashTable *users)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
GHashTable *login_hash, *logout_hash;
|
|
|
44ca26 |
struct utmpx *wtmp_entry;
|
|
|
44ca26 |
GHashTableIter iter;
|
|
|
44ca26 |
gpointer key, value;
|
|
|
44ca26 |
struct passwd *pwent;
|
|
|
44ca26 |
User *user;
|
|
|
44ca26 |
- WTmpGeneratorState *state_data;
|
|
|
44ca26 |
GVariantBuilder *builder, *builder2;
|
|
|
44ca26 |
GList *l;
|
|
|
44ca26 |
|
|
|
44ca26 |
- if (*state == NULL) {
|
|
|
44ca26 |
- /* First iteration */
|
|
|
44ca26 |
#ifdef UTXDB_LOG
|
|
|
44ca26 |
- if (setutxdb (UTXDB_LOG, NULL) != 0) {
|
|
|
44ca26 |
- return NULL;
|
|
|
44ca26 |
- }
|
|
|
44ca26 |
+ if (setutxdb (UTXDB_LOG, NULL) != 0) {
|
|
|
44ca26 |
+ return NULL;
|
|
|
44ca26 |
+ }
|
|
|
44ca26 |
#else
|
|
|
44ca26 |
- utmpxname (PATH_WTMP);
|
|
|
44ca26 |
- setutxent ();
|
|
|
44ca26 |
+ utmpxname (PATH_WTMP);
|
|
|
44ca26 |
+ setutxent ();
|
|
|
44ca26 |
#endif
|
|
|
44ca26 |
- *state = g_new (WTmpGeneratorState, 1);
|
|
|
44ca26 |
- state_data = *state;
|
|
|
44ca26 |
- state_data->login_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
|
44ca26 |
- state_data->logout_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
|
44ca26 |
- }
|
|
|
44ca26 |
|
|
|
44ca26 |
- /* Every iteration */
|
|
|
44ca26 |
- state_data = *state;
|
|
|
44ca26 |
- login_hash = state_data->login_hash;
|
|
|
44ca26 |
- logout_hash = state_data->logout_hash;
|
|
|
44ca26 |
+ login_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
|
44ca26 |
+ logout_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
|
44ca26 |
while ((wtmp_entry = getutxent ())) {
|
|
|
44ca26 |
UserAccounting *accounting;
|
|
|
44ca26 |
UserPreviousLogin *previous_login;
|
|
|
44ca26 |
|
|
|
44ca26 |
if (wtmp_entry->ut_type == BOOT_TIME) {
|
|
|
44ca26 |
/* Set boot time for missing logout records */
|
|
|
44ca26 |
g_hash_table_iter_init (&iter, logout_hash);
|
|
|
44ca26 |
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
|
|
44ca26 |
previous_login = (UserPreviousLogin *) value;
|
|
|
44ca26 |
|
|
|
44ca26 |
if (previous_login->logout_time == 0) {
|
|
|
44ca26 |
previous_login->logout_time = wtmp_entry->ut_tv.tv_sec;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
}
|
|
|
44ca26 |
g_hash_table_remove_all (logout_hash);
|
|
|
44ca26 |
} else if (wtmp_entry->ut_type == DEAD_PROCESS) {
|
|
|
44ca26 |
/* Save corresponding logout time */
|
|
|
44ca26 |
if (g_hash_table_lookup_extended (logout_hash, wtmp_entry->ut_line, &key, &value)) {
|
|
|
44ca26 |
previous_login = (UserPreviousLogin *) value;
|
|
|
44ca26 |
previous_login->logout_time = wtmp_entry->ut_tv.tv_sec;
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_remove (logout_hash, previous_login->id);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
if (wtmp_entry->ut_type != USER_PROCESS) {
|
|
|
44ca26 |
continue;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
if (wtmp_entry->ut_user[0] == 0) {
|
|
|
44ca26 |
@@ -233,103 +221,96 @@ entry_generator_wtmp (GHashTable *users,
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
pwent = getpwnam (wtmp_entry->ut_user);
|
|
|
44ca26 |
if (pwent == NULL) {
|
|
|
44ca26 |
continue;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
if (!g_hash_table_lookup_extended (login_hash,
|
|
|
44ca26 |
wtmp_entry->ut_user,
|
|
|
44ca26 |
&key, &value)) {
|
|
|
44ca26 |
accounting = g_new (UserAccounting, 1);
|
|
|
44ca26 |
accounting->frequency = 0;
|
|
|
44ca26 |
accounting->previous_logins = NULL;
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_insert (login_hash, g_strdup (wtmp_entry->ut_user), accounting);
|
|
|
44ca26 |
} else {
|
|
|
44ca26 |
accounting = value;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
accounting->frequency++;
|
|
|
44ca26 |
accounting->time = wtmp_entry->ut_tv.tv_sec;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Add zero logout time to change it later on logout record */
|
|
|
44ca26 |
previous_login = g_new (UserPreviousLogin, 1);
|
|
|
44ca26 |
previous_login->id = g_strdup (wtmp_entry->ut_line);
|
|
|
44ca26 |
previous_login->login_time = wtmp_entry->ut_tv.tv_sec;
|
|
|
44ca26 |
previous_login->logout_time = 0;
|
|
|
44ca26 |
accounting->previous_logins = g_list_prepend (accounting->previous_logins, previous_login);
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_insert (logout_hash, g_strdup (wtmp_entry->ut_line), previous_login);
|
|
|
44ca26 |
- *spent = getspnam (pwent->pw_name);
|
|
|
44ca26 |
-
|
|
|
44ca26 |
- return pwent;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
- /* Last iteration */
|
|
|
44ca26 |
endutxent ();
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_iter_init (&iter, login_hash);
|
|
|
44ca26 |
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
|
|
44ca26 |
UserAccounting *accounting = (UserAccounting *) value;
|
|
|
44ca26 |
UserPreviousLogin *previous_login;
|
|
|
44ca26 |
|
|
|
44ca26 |
user = g_hash_table_lookup (users, key);
|
|
|
44ca26 |
if (user == NULL) {
|
|
|
44ca26 |
g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free);
|
|
|
44ca26 |
continue;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
g_object_set (user, "login-frequency", accounting->frequency, NULL);
|
|
|
44ca26 |
g_object_set (user, "login-time", accounting->time, NULL);
|
|
|
44ca26 |
|
|
|
44ca26 |
builder = g_variant_builder_new (G_VARIANT_TYPE ("a(xxa{sv})"));
|
|
|
44ca26 |
for (l = g_list_last (accounting->previous_logins); l != NULL; l = l->prev) {
|
|
|
44ca26 |
previous_login = l->data;
|
|
|
44ca26 |
|
|
|
44ca26 |
builder2 = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
|
|
44ca26 |
g_variant_builder_add (builder2, "{sv}", "type", g_variant_new_string (previous_login->id));
|
|
|
44ca26 |
g_variant_builder_add (builder, "(xxa{sv})", previous_login->login_time, previous_login->logout_time, builder2);
|
|
|
44ca26 |
g_variant_builder_unref (builder2);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
g_object_set (user, "login-history", g_variant_new ("a(xxa{sv})", builder), NULL);
|
|
|
44ca26 |
g_variant_builder_unref (builder);
|
|
|
44ca26 |
g_list_free_full (accounting->previous_logins, (GDestroyNotify) user_previous_login_free);
|
|
|
44ca26 |
|
|
|
44ca26 |
user_changed (user);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_unref (login_hash);
|
|
|
44ca26 |
g_hash_table_unref (logout_hash);
|
|
|
44ca26 |
- g_free (state_data);
|
|
|
44ca26 |
- *state = NULL;
|
|
|
44ca26 |
- return NULL;
|
|
|
44ca26 |
}
|
|
|
44ca26 |
#endif /* HAVE_UTMPX_H */
|
|
|
44ca26 |
|
|
|
44ca26 |
#ifndef MAX_LOCAL_USERS
|
|
|
44ca26 |
#define MAX_LOCAL_USERS 50
|
|
|
44ca26 |
#endif
|
|
|
44ca26 |
|
|
|
44ca26 |
static struct passwd *
|
|
|
44ca26 |
entry_generator_fgetpwent (GHashTable *users,
|
|
|
44ca26 |
gpointer *state,
|
|
|
44ca26 |
struct spwd **spent)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
struct passwd *pwent;
|
|
|
44ca26 |
|
|
|
44ca26 |
struct {
|
|
|
44ca26 |
struct spwd spbuf;
|
|
|
44ca26 |
char buf[1024];
|
|
|
44ca26 |
} *shadow_entry_buffers;
|
|
|
44ca26 |
|
|
|
44ca26 |
struct {
|
|
|
44ca26 |
FILE *fp;
|
|
|
44ca26 |
GHashTable *users;
|
|
|
44ca26 |
} *generator_state;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* First iteration */
|
|
|
44ca26 |
if (*state == NULL) {
|
|
|
44ca26 |
GHashTable *shadow_users = NULL;
|
|
|
44ca26 |
FILE *fp;
|
|
|
44ca26 |
struct spwd *shadow_entry;
|
|
|
44ca26 |
|
|
|
44ca26 |
@@ -533,64 +514,65 @@ create_users_hash_table (void)
|
|
|
44ca26 |
g_object_unref);
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
static void
|
|
|
44ca26 |
reload_users (Daemon *daemon)
|
|
|
44ca26 |
{
|
|
|
44ca26 |
GHashTable *users;
|
|
|
44ca26 |
GHashTable *old_users;
|
|
|
44ca26 |
GHashTable *local;
|
|
|
44ca26 |
GHashTableIter iter;
|
|
|
44ca26 |
gpointer name;
|
|
|
44ca26 |
User *user;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Track the users that we saw during our (re)load */
|
|
|
44ca26 |
users = create_users_hash_table ();
|
|
|
44ca26 |
|
|
|
44ca26 |
/*
|
|
|
44ca26 |
* NOTE: As we load data from all the sources, notifies are
|
|
|
44ca26 |
* frozen in load_entries() and then thawed as we process
|
|
|
44ca26 |
* them below.
|
|
|
44ca26 |
*/
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Load the local users into our hash table */
|
|
|
44ca26 |
load_entries (daemon, users, entry_generator_fgetpwent);
|
|
|
44ca26 |
local = g_hash_table_new (g_str_hash, g_str_equal);
|
|
|
44ca26 |
g_hash_table_iter_init (&iter, users);
|
|
|
44ca26 |
while (g_hash_table_iter_next (&iter, &name, NULL))
|
|
|
44ca26 |
g_hash_table_add (local, name);
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Now add/update users from other sources, possibly non-local */
|
|
|
44ca26 |
+ load_entries (daemon, users, entry_generator_cachedir);
|
|
|
44ca26 |
+
|
|
|
44ca26 |
#ifdef HAVE_UTMPX_H
|
|
|
44ca26 |
- load_entries (daemon, users, entry_generator_wtmp);
|
|
|
44ca26 |
+ wtmp_update_login_frequencies (users);
|
|
|
44ca26 |
#endif
|
|
|
44ca26 |
- load_entries (daemon, users, entry_generator_cachedir);
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Mark which users are local, which are not */
|
|
|
44ca26 |
g_hash_table_iter_init (&iter, users);
|
|
|
44ca26 |
while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user))
|
|
|
44ca26 |
user_update_local_account_property (user, g_hash_table_lookup (local, name) != NULL);
|
|
|
44ca26 |
|
|
|
44ca26 |
g_hash_table_destroy (local);
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Swap out the users */
|
|
|
44ca26 |
old_users = daemon->priv->users;
|
|
|
44ca26 |
daemon->priv->users = users;
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Remove all the old users */
|
|
|
44ca26 |
g_hash_table_iter_init (&iter, old_users);
|
|
|
44ca26 |
while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) {
|
|
|
44ca26 |
if (!g_hash_table_lookup (users, name)) {
|
|
|
44ca26 |
user_unregister (user);
|
|
|
44ca26 |
accounts_accounts_emit_user_deleted (ACCOUNTS_ACCOUNTS (daemon),
|
|
|
44ca26 |
user_get_object_path (user));
|
|
|
44ca26 |
}
|
|
|
44ca26 |
}
|
|
|
44ca26 |
|
|
|
44ca26 |
/* Register all the new users */
|
|
|
44ca26 |
g_hash_table_iter_init (&iter, users);
|
|
|
44ca26 |
while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) {
|
|
|
44ca26 |
if (!g_hash_table_lookup (old_users, name)) {
|
|
|
44ca26 |
user_register (user);
|
|
|
44ca26 |
accounts_accounts_emit_user_added (ACCOUNTS_ACCOUNTS (daemon),
|
|
|
44ca26 |
user_get_object_path (user));
|
|
|
44ca26 |
}
|
|
|
44ca26 |
--
|
|
|
44ca26 |
2.7.4
|
|
|
44ca26 |
|