From 98f428709e94e5a6aece070c74a8603dee7e58e2 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 28 Jun 2016 15:43:08 -0400 Subject: [PATCH] daemon: get local users from /etc/shadow not /etc/passwd For some sites, it's common practice to rsync around large /etc/passwd files containing the password entries for remote users. That means accountsservices' "assume /etc/passwd is local users" heuristic falls over. This commit changes it to only treat users in /etc/shadow as local. https://bugs.freedesktop.org/show_bug.cgi?id=48177 --- src/daemon.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/src/daemon.c b/src/daemon.c index e62e124..1b2bacd 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -2,60 +2,63 @@ * * Copyright (C) 2009-2010 Red Hat, Inc. * Copyright (c) 2013 Canonical Limited * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Written by: Matthias Clasen */ #include "config.h" #include #include #include #include #include #include #include +#ifdef HAVE_SHADOW_H +#include +#endif #include #include #include #include #include #include #include #include #include #include "user-classify.h" #include "wtmp-helper.h" #include "daemon.h" #include "util.h" #define PATH_PASSWD "/etc/passwd" #define PATH_SHADOW "/etc/shadow" #define PATH_GROUP "/etc/group" #define PATH_GDM_CUSTOM "/etc/gdm/custom.conf" enum { PROP_0, PROP_DAEMON_VERSION }; struct DaemonPrivate { GDBusConnection *bus_connection; GHashTable *users; @@ -110,81 +113,125 @@ GType error_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { ENUM_ENTRY (ERROR_FAILED, "Failed"), ENUM_ENTRY (ERROR_USER_EXISTS, "UserExists"), ENUM_ENTRY (ERROR_USER_DOES_NOT_EXIST, "UserDoesntExist"), ENUM_ENTRY (ERROR_PERMISSION_DENIED, "PermissionDenied"), ENUM_ENTRY (ERROR_NOT_SUPPORTED, "NotSupported"), { 0, 0, 0 } }; g_assert (NUM_ERRORS == G_N_ELEMENTS (values) - 1); etype = g_enum_register_static ("Error", values); } return etype; } #ifndef HAVE_FGETPWENT #include "fgetpwent.c" #endif static struct passwd * entry_generator_fgetpwent (GHashTable *users, gpointer *state) { struct passwd *pwent; - FILE *fp; + struct { + FILE *fp; + GHashTable *users; + } *generator_state; /* First iteration */ if (*state == NULL) { - *state = fp = fopen (PATH_PASSWD, "r"); + GHashTable *shadow_users = NULL; + FILE *fp; +#ifdef HAVE_SHADOW_H + struct spwd *shadow_entry; + + fp = fopen (PATH_SHADOW, "r"); + if (fp == NULL) { + g_warning ("Unable to open %s: %s", PATH_SHADOW, g_strerror (errno)); + return NULL; + } + + shadow_users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + do { + shadow_entry = fgetspent (fp); + if (shadow_entry != NULL) { + g_hash_table_add (shadow_users, g_strdup (shadow_entry->sp_namp)); + } else if (errno != EINTR) { + break; + } + } while (shadow_entry != NULL); + + fclose (fp); + + if (g_hash_table_size (shadow_users) == 0) { + g_clear_pointer (&shadow_users, g_hash_table_unref); + return NULL; + } +#endif + + fp = fopen (PATH_PASSWD, "r"); if (fp == NULL) { + g_clear_pointer (&shadow_users, g_hash_table_unref); g_warning ("Unable to open %s: %s", PATH_PASSWD, g_strerror (errno)); return NULL; } + + generator_state = g_malloc0 (sizeof (generator_state)); + generator_state->fp = fp; + generator_state->users = shadow_users; + + *state = generator_state; } /* Every iteration */ - fp = *state; - pwent = fgetpwent (fp); + generator_state = *state; + pwent = fgetpwent (generator_state->fp); if (pwent != NULL) { - return pwent; + if (!generator_state->users || g_hash_table_lookup (generator_state->users, pwent->pw_name)) + return pwent; } /* Last iteration */ - fclose (fp); + fclose (generator_state->fp); + g_hash_table_unref (generator_state->users); + g_free (generator_state); *state = NULL; + return NULL; } static struct passwd * entry_generator_cachedir (GHashTable *users, gpointer *state) { struct passwd *pwent; const gchar *name; GError *error = NULL; gchar *filename; gboolean regular; GHashTableIter iter; GKeyFile *key_file; User *user; GDir *dir; /* First iteration */ if (*state == NULL) { *state = g_dir_open (USERDIR, 0, &error); if (error != NULL) { if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) g_warning ("couldn't list user cache directory: %s", USERDIR); g_error_free (error); return NULL; } } /* Every iteration */ -- 2.7.4