diff options
author | Ryan Lortie <desrt@desrt.ca> | 2014-03-13 18:51:18 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2014-03-14 23:25:56 -0400 |
commit | cdee3f55a5821cc76ad270b8c709a7bb1e3ae1b2 (patch) | |
tree | 6f86f6207690bdb70daba3081bd8e474fe512183 | |
parent | 3863f54e5efe8c3f929dc93ea026a17d5855a786 (diff) | |
download | accountsservice-cdee3f55a5821cc76ad270b8c709a7bb1e3ae1b2.tar.gz |
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
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/daemon.c | 4 | ||||
-rw-r--r-- | src/fgetpwent.c | 108 |
4 files changed, 118 insertions, 0 deletions
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 6940f2d..30e5c8a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -47,6 +47,10 @@ accounts_daemon_LDADD = \ libaccounts-generated.la \ $(POLKIT_LIBS) +EXTRA_DIST = \ + fgetpwent.c \ + $(NULL) + CLEANFILES = \ $(BUILT_SOURCES) \ *.gcda \ diff --git a/src/daemon.c b/src/daemon.c index cb36f01..233f374 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -162,6 +162,10 @@ user_previous_login_free (UserPreviousLogin *previous_login) g_free (previous_login); } +#ifndef HAVE_FGETPWENT +#include "fgetpwent.c" +#endif + static struct passwd * entry_generator_wtmp (GHashTable *users, gpointer *state) diff --git a/src/fgetpwent.c b/src/fgetpwent.c new file mode 100644 index 0000000..3a2d77c --- /dev/null +++ b/src/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 <desrt@desrt.ca> + */ + +static gchar * +fgetpwent_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 * +fgetpwent (FILE *fp) +{ + static struct passwd pw; + guint64 intval; + gchar *line; + + /* In case of failure, we ignore the line and start again */ +again: + line = fgetpwent_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; +} |