From 357286071053d08611e872dad48c14525da79e9c Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Thu, 13 Mar 2014 18:51:18 -0400 Subject: [PATCH] daemon: emulate fgetpwent() if we don't have it We use fgetpwent directly on /etc/passwd in order to ensure we only get a list of local users (and not ones from the network directory service). Unfortunately, this function is not commonly found on non-GNU systems. Provide our own implementation of fgetpwent if the operating system does not provide it. https://bugs.freedesktop.org/show_bug.cgi?id=41747 --- configure.ac | 2 + src/Makefile.am | 4 ++ src/as-fgetpwent.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/daemon.c | 8 +++- 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 src/as-fgetpwent.c diff --git a/configure.ac b/configure.ac index 39c5b92..ee9dbcb 100644 --- a/configure.ac +++ b/configure.ac @@ -187,6 +187,8 @@ AC_SUBST(WARN_CFLAGS) AC_CHECK_HEADERS([shadow.h utmpx.h]) +AC_CHECK_FUNCS([fgetpwent]) + dnl --------------------------------------------------------------------------- dnl - gtk-doc Documentation dnl --------------------------------------------------------------------------- diff --git a/src/Makefile.am b/src/Makefile.am index f3b9039..845edac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -49,6 +49,10 @@ accounts_daemon_LDADD = \ libaccounts-generated.la \ $(POLKIT_LIBS) +EXTRA_DIST = \ + as-fgetpwent.c \ + $(NULL) + CLEANFILES = \ $(BUILT_SOURCES) \ *.gcda \ diff --git a/src/as-fgetpwent.c b/src/as-fgetpwent.c new file mode 100644 index 0000000..eb513e0 --- /dev/null +++ b/src/as-fgetpwent.c @@ -0,0 +1,108 @@ +/* + * 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 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 + */ + +static gchar * +as_getline (FILE *fp) +{ + static GString str; + + /* We could be "more clever" here and avoid the strlen() but this is a + * clear case of dumb is better. + */ + str.len = 0; + while (!str.len || str.str[str.len - 1] != '\n') + { + if (str.allocated_len < str.len + 32) + { + str.allocated_len = str.len + 32; + str.str = g_realloc (str.str, str.allocated_len); + } + + if (fgets (str.str + str.len, str.allocated_len - str.len, fp) == NULL) + return NULL; + + str.len = strlen (str.str + str.len) + str.len; + } + + /* chomp the '\n' */ + str.str[str.len - 1] = '\0'; + + return str.str; +} + +static struct passwd * +as_fgetpwent (FILE *fp) +{ + static struct passwd pw; + guint64 intval; + gchar *line; + + /* In case of failure, we ignore the line and start again */ +again: + line = as_getline (fp); + if (!line) + return NULL; + + while (g_ascii_isspace (*line)) + line++; + + /* comments, empty lines */ + if (line[0] == '#' || line[0] == '\0') + goto again; + + /* username */ + pw.pw_name = line; + if (!(line = strchr (line, ':'))) + goto again; + *line++ = '\0'; + + /* password */ + pw.pw_passwd = line; + if (!(line = strchr (line, ':'))) + goto again; + *line++ = '\0'; + + /* uid */ + pw.pw_uid = intval = g_ascii_strtoull (line, &line, 10); + if (pw.pw_uid != intval || *line++ != ':') + goto again; + + /* gid */ + pw.pw_gid = intval = g_ascii_strtoull (line, &line, 10); + if (pw.pw_gid != intval || *line++ != ':') + goto again; + + /* gecos */ + pw.pw_gecos = line; + if (!(line = strchr (line, ':'))) + goto again; + *line++ = '\0'; + + /* home directory */ + pw.pw_dir = line; + if (!(line = strchr (line, ':'))) + goto again; + *line++ = '\0'; + + /* shell */ + pw.pw_shell = line; + + return &pw; +} diff --git a/src/daemon.c b/src/daemon.c index b58d7e9..a8ee2ca 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -129,6 +129,12 @@ error_get_type (void) return etype; } +#ifdef HAVE_FGETPWENT +#define as_fgetpwent(fp) fgetpwent(fp) +#else +#include "as-fgetpwent.c" +#endif + static struct passwd * entry_generator_fgetpwent (GHashTable *users, gpointer *state) @@ -147,7 +153,7 @@ entry_generator_fgetpwent (GHashTable *users, /* Every iteration */ fp = *state; - pwent = fgetpwent (fp); + pwent = as_fgetpwent (fp); if (pwent != NULL) { return pwent; } -- 1.8.5.3