about summary refs log tree commit diff
path: root/REORG.TODO/nss/nss_files/files-initgroups.c
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/nss/nss_files/files-initgroups.c')
-rw-r--r--REORG.TODO/nss/nss_files/files-initgroups.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/REORG.TODO/nss/nss_files/files-initgroups.c b/REORG.TODO/nss/nss_files/files-initgroups.c
new file mode 100644
index 0000000000..27cd8ece40
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-initgroups.c
@@ -0,0 +1,142 @@
+/* Initgroups handling in nss_files module.
+   Copyright (C) 2011-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <alloca.h>
+#include <errno.h>
+#include <grp.h>
+#include <nss.h>
+#include <stdio_ext.h>
+#include <string.h>
+#include <sys/param.h>
+#include <stdbool.h>
+#include <stdlib.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", "rce");
+  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;
+  bool any = false;
+
+  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 (1)
+    {
+      fpos_t pos;
+      fgetpos (stream, &pos);
+      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;
+      int res = _nss_files_parse_grent (line, &grp, buffer, buflen, errnop);
+      if (res == -1)
+	{
+	  size_t newbuflen = 2 * buflen;
+	  if (buffer_use_malloc || ! __libc_use_alloca (buflen + newbuflen))
+	    {
+	      void *newbuf = realloc (buffer_use_malloc ? buffer : NULL,
+				      newbuflen);
+	      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);
+	  /* Reread current line, the parser has clobbered it.  */
+	  fsetpos (stream, &pos);
+	  continue;
+	}
+
+      if (res > 0 && 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;
+	      any = true;
+
+	      break;
+	    }
+    }
+
+ out:
+  /* Free memory.  */
+  if (buffer_use_malloc)
+    free (buffer);
+  free (line);
+
+  fclose (stream);
+
+  return status == NSS_STATUS_SUCCESS && !any ? NSS_STATUS_NOTFOUND : status;
+}