summaryrefslogtreecommitdiff
path: root/nss
diff options
context:
space:
mode:
Diffstat (limited to 'nss')
-rw-r--r--nss/Makefile2
-rw-r--r--nss/Versions2
-rw-r--r--nss/nss_files/files-initgroups.c132
3 files changed, 135 insertions, 1 deletions
diff --git a/nss/Makefile b/nss/Makefile
index 2b0432f45c..c49f375e95 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -64,7 +64,7 @@ vpath %.c $(subdir-dirs)
libnss_files-routines := $(addprefix files-,$(databases)) \
- files-have_o_cloexec
+ files-initgroups files-have_o_cloexec
distribute += files-XXX.c files-parse.c
diff --git a/nss/Versions b/nss/Versions
index 7a9d67b429..1c6fd686f3 100644
--- a/nss/Versions
+++ b/nss/Versions
@@ -95,5 +95,7 @@ libnss_files {
_nss_netgroup_parseline;
_nss_files_getpublickey;
_nss_files_getsecretkey;
+
+ _nss_files_initgroups_dyn;
}
}
diff --git a/nss/nss_files/files-initgroups.c b/nss/nss_files/files-initgroups.c
new file mode 100644
index 0000000000..2d84cd8457
--- /dev/null
+++ b/nss/nss_files/files-initgroups.c
@@ -0,0 +1,132 @@
+/* Initgroups handling in nss_files module.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <alloca.h>
+#include <errno.h>
+#include <grp.h>
+#include <nss.h>
+#include <stdio_ext.h>
+#include <string.h>
+#include <sys/param.h>
+
+enum nss_status
+_nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
+ long int *size, gid_t **groupsp, long int limit,
+ int *errnop)
+{
+ FILE *stream = fopen ("/etc/group", "re");
+ if (stream == NULL)
+ {
+ *errnop = errno;
+ return *errnop == ENOMEM ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+ }
+
+ /* No other thread using this stream. */
+ __fsetlocking (stream, FSETLOCKING_BYCALLER);
+
+ char *line = NULL;
+ size_t linelen = 0;
+ enum nss_status status = NSS_STATUS_SUCCESS;
+
+ size_t buflen = 1024;
+ void *buffer = alloca (buflen);
+ bool buffer_use_malloc = false;
+
+ gid_t *groups = *groupsp;
+
+ /* We have to iterate over the entire file. */
+ while (!feof_unlocked (stream))
+ {
+ ssize_t n = getline (&line, &linelen, stream);
+ if (n < 0)
+ {
+ if (! feof_unlocked (stream))
+ status = ((*errnop = errno) == ENOMEM
+ ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL);
+ break;
+ }
+
+ struct group grp;
+ while (_nss_files_parse_grent (line, &grp, buffer, buflen, errnop) == -1)
+ {
+ size_t newbuflen = 2 * buflen;
+ if (buffer_use_malloc || ! __libc_use_alloca (buflen + newbuflen))
+ {
+ char *newbuf = realloc (buffer, buflen);
+ if (newbuf == NULL)
+ {
+ *errnop = ENOMEM;
+ status = NSS_STATUS_TRYAGAIN;
+ goto out;
+ }
+ buffer = newbuf;
+ buflen = newbuflen;
+ buffer_use_malloc = true;
+ }
+ else
+ buffer = extend_alloca (buffer, buflen, newbuflen);
+ }
+
+ if (grp.gr_gid != group)
+ for (char **m = grp.gr_mem; *m != NULL; ++m)
+ if (strcmp (*m, user) == 0)
+ {
+ /* Matches user. Insert this group. */
+ if (*start == *size)
+ {
+ /* Need a bigger buffer. */
+ if (limit > 0 && *size == limit)
+ /* We reached the maximum. */
+ goto out;
+
+ long int newsize;
+ if (limit <= 0)
+ newsize = 2 * *size;
+ else
+ newsize = MIN (limit, 2 * *size);
+
+ gid_t *newgroups = realloc (groups,
+ newsize * sizeof (*groups));
+ if (newgroups == NULL)
+ {
+ *errnop = ENOMEM;
+ status = NSS_STATUS_TRYAGAIN;
+ goto out;
+ }
+ *groupsp = groups = newgroups;
+ *size = newsize;
+ }
+
+ groups[*start] = grp.gr_gid;
+ *start += 1;
+
+ break;
+ }
+ }
+
+ out:
+ /* Free memory. */
+ if (buffer_use_malloc)
+ free (buffer);
+ free (line);
+
+ fclose (stream);
+
+ return status;
+}