Blob Blame History Raw
2011-11-07  Andreas Schwab  <schwab@redhat.com>

	* nss/nss_files/files-initgroups.c (_nss_files_initgroups_dyn):
	Fix size of allocated buffer.

2011-05-10  Ulrich Drepper  <drepper@gmail.com>

	[BZ #11257]
	* grp/initgroups.c (internal_getgrouplist): When we found the service
	list through the initgroups entry in nsswitch.conf do not always
	continue on a successful lookup.  Don't always use the
	__nss_group_data-ase value if it is set.
	* nss/nsswitch.conf (initgroups): Change action for successful db
	lookup to continue for compatibility.

2011-05-06  Ulrich Drepper  <drepper@gmail.com>

	* nss/nss_files/files-initgroups.c (_nss_files_initgroups_dyn): Return
	NSS_STATUS_NOTFOUND if no record was found.

2011-04-29  Ulrich Drepper  <drepper@gmail.com>

	* grp/initgroups.c (internal_getgrouplist): Prefer initgroups setting
	to groups setting in database lookup.
	* nss/nsswitch.conf: Add initgroups entry.

2011-04-21  Ulrich Drepper  <drepper@gmail.com>

	* nss/nss_files/files-initgroups.c (_nss_files_initgroups_dyn): Fix
	problem in reallocation in last patch.

2011-04-19  Ulrich Drepper  <drepper@gmail.com>

	* nss/nss_files/files-initgroups.c: New file.
	* nss/Makefile (libnss_files-routines): Add files-initgroups.
	* nss/Versions (libnss_files) [GLIBC_PRIVATE]: Export
	_nss_files_initgroups_dyn.

2011-01-13  Ulrich Drepper  <drepper@gmail.com>

	[BZ #10484]
	* nss/nss_files/files-hosts.c (HOST_DB_LOOKUP): Handle overflows of
	temporary buffer used to handle multi lookups locally.
	* include/alloca.h: Add libc_hidden_proto for __libc_alloca_cutoff.

2011-01-13  Ulrich Drepper  <drepper@gmail.com>

	[BZ #10484]
	* Versions [libc] (GLIBC_PRIVATE): Export __libc_alloca_cutoff.
	* alloca_cutoff.c: Add libc_hidden_def.

Index: glibc-2.12-2-gc4ccff1/grp/initgroups.c
===================================================================
--- glibc-2.12-2-gc4ccff1.orig/grp/initgroups.c
+++ glibc-2.12-2-gc4ccff1/grp/initgroups.c
@@ -43,6 +43,8 @@ extern int __nss_group_lookup (service_u
 extern void *__nss_lookup_function (service_user *ni, const char *fct_name);
 
 extern service_user *__nss_group_database attribute_hidden;
+static service_user *initgroups_database;
+static bool use_initgroups_entry;
 
 
 #include "compat-initgroups.c"
@@ -67,32 +69,41 @@ internal_getgrouplist (const char *user,
     }
 #endif
 
-  service_user *nip = NULL;
-  initgroups_dyn_function fct;
   enum nss_status status = NSS_STATUS_UNAVAIL;
-  int no_more;
-  /* Start is one, because we have the first group as parameter.  */
-  long int start = 1;
+  int no_more = 0;
 
   /* Never store more than the starting *SIZE number of elements.  */
   assert (*size > 0);
   (*groupsp)[0] = group;
+  /* Start is one, because we have the first group as parameter.  */
+  long int start = 1;
 
-  if (__nss_group_database != NULL)
+  if (initgroups_database == NULL)
     {
-      no_more = 0;
-      nip = __nss_group_database;
+      no_more = __nss_database_lookup ("initgroups", NULL, "",
+				       &initgroups_database);
+      if (no_more == 0 && initgroups_database == NULL)
+	{
+	  if (__nss_group_database == NULL)
+	    no_more = __nss_database_lookup ("group", NULL, "compat files",
+					     &__nss_group_database);
+
+	  initgroups_database = __nss_group_database;
+	}
+      else if (initgroups_database != NULL)
+	{
+	  assert (no_more == 0);
+	  use_initgroups_entry = true;
+	}
     }
-  else
-    no_more = __nss_database_lookup ("group", NULL,
-				     "compat [NOTFOUND=return] files", &nip);
 
+  service_user *nip = initgroups_database;
   while (! no_more)
     {
       long int prev_start = start;
 
-      fct = __nss_lookup_function (nip, "initgroups_dyn");
-
+      initgroups_dyn_function fct = __nss_lookup_function (nip,
+							   "initgroups_dyn");
       if (fct == NULL)
 	status = compat_call (nip, user, group, &start, size, groupsp,
 			      limit, &errno);
@@ -119,7 +130,13 @@ internal_getgrouplist (const char *user,
       if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
 	__libc_fatal ("illegal status in internal_getgrouplist");
 
-      if (status != NSS_STATUS_SUCCESS
+      /* For compatibility reason we will continue to look for more
+	 entries using the next service even though data has already
+	 been found if the nsswitch.conf file contained only a 'groups'
+	 line and no 'initgroups' line.  If the latter is available
+	 we always respect the status.  This means that the default
+	 for successful lookups is to return.  */
+      if ((use_initgroups_entry || status != NSS_STATUS_SUCCESS)
 	  && nss_next_action (nip, status) == NSS_ACTION_RETURN)
 	 break;
 
Index: glibc-2.12-2-gc4ccff1/include/alloca.h
===================================================================
--- glibc-2.12-2-gc4ccff1.orig/include/alloca.h
+++ glibc-2.12-2-gc4ccff1/include/alloca.h
@@ -14,6 +14,7 @@ extern void *__alloca (size_t __size);
 
 extern int __libc_use_alloca (size_t size) __attribute__ ((const));
 extern int __libc_alloca_cutoff (size_t size) __attribute__ ((const));
+libc_hidden_proto (__libc_alloca_cutoff)
 
 #define __MAX_ALLOCA_CUTOFF	65536
 
Index: glibc-2.12-2-gc4ccff1/nptl/Versions
===================================================================
--- glibc-2.12-2-gc4ccff1.orig/nptl/Versions
+++ glibc-2.12-2-gc4ccff1/nptl/Versions
@@ -27,6 +27,7 @@ libc {
     pthread_cond_broadcast; pthread_cond_timedwait;
   }
   GLIBC_PRIVATE {
+    __libc_alloca_cutoff;
     # Internal libc interface to libpthread
     __libc_dl_error_tsd;
   }
Index: glibc-2.12-2-gc4ccff1/nptl/alloca_cutoff.c
===================================================================
--- glibc-2.12-2-gc4ccff1.orig/nptl/alloca_cutoff.c
+++ glibc-2.12-2-gc4ccff1/nptl/alloca_cutoff.c
@@ -34,3 +34,4 @@ __libc_alloca_cutoff (size_t size)
 			  assume the maximum available stack space.  */
 		       ?: __MAX_ALLOCA_CUTOFF * 4));
 }
+libc_hidden_def (__libc_alloca_cutoff)
Index: glibc-2.12-2-gc4ccff1/nss/Makefile
===================================================================
--- glibc-2.12-2-gc4ccff1.orig/nss/Makefile
+++ glibc-2.12-2-gc4ccff1/nss/Makefile
@@ -63,7 +63,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
 
 
Index: glibc-2.12-2-gc4ccff1/nss/Versions
===================================================================
--- glibc-2.12-2-gc4ccff1.orig/nss/Versions
+++ glibc-2.12-2-gc4ccff1/nss/Versions
@@ -95,5 +95,7 @@ libnss_files {
     _nss_netgroup_parseline;
     _nss_files_getpublickey;
     _nss_files_getsecretkey;
+
+    _nss_files_initgroups_dyn;
   }
 }
Index: glibc-2.12-2-gc4ccff1/nss/nss_files/files-hosts.c
===================================================================
--- glibc-2.12-2-gc4ccff1.orig/nss/nss_files/files-hosts.c
+++ glibc-2.12-2-gc4ccff1/nss/nss_files/files-hosts.c
@@ -129,19 +129,22 @@ _nss_files_get##name##_r (proto,					   
 	  && _res_hconf.flags & HCONF_FLAG_MULTI)			      \
 	{								      \
 	  /* We have to get all host entries from the file.  */		      \
-	  const size_t tmp_buflen = MIN (buflen, 4096);			      \
-	  char tmp_buffer[tmp_buflen]					      \
+	  size_t tmp_buflen = MIN (buflen, 4096);			      \
+	  char tmp_buffer_stack[tmp_buflen]				      \
 	    __attribute__ ((__aligned__ (__alignof__ (struct hostent_data))));\
+	  char *tmp_buffer = tmp_buffer_stack;				      \
 	  struct hostent tmp_result_buf;				      \
 	  int naddrs = 1;						      \
 	  int naliases = 0;						      \
 	  char *bufferend;						      \
+	  bool tmp_buffer_malloced = false;				      \
 									      \
 	  while (result->h_aliases[naliases] != NULL)			      \
 	    ++naliases;							      \
 									      \
 	  bufferend = (char *) &result->h_aliases[naliases + 1];	      \
 									      \
+	again:								      \
 	  while ((status = internal_getent (&tmp_result_buf, tmp_buffer,      \
 					    tmp_buflen, errnop H_ERRNO_ARG    \
 					    EXTRA_ARGS_VALUE))		      \
@@ -182,7 +185,7 @@ _nss_files_get##name##_r (proto,					   
 		    }							      \
 		  /* If the real name is different add it also to the	      \
 		     aliases.  This means that there is a duplication	      \
-		     in the alias list but this is really the users	      \
+		     in the alias list but this is really the user's	      \
 		     problem.  */					      \
 		  if (strcmp (old_result->h_name,			      \
 			      tmp_result_buf.h_name) != 0)		      \
@@ -204,7 +207,7 @@ _nss_files_get##name##_r (proto,					   
 		      *errnop = ERANGE;					      \
 		      *herrnop = NETDB_INTERNAL;			      \
 		      status = NSS_STATUS_TRYAGAIN;			      \
-		      break;						      \
+		      goto out;						      \
 		    }							      \
 									      \
 		  new_h_addr_list =					      \
@@ -268,8 +271,54 @@ _nss_files_get##name##_r (proto,					   
 		}							      \
 	    }								      \
 									      \
-	  if (status != NSS_STATUS_TRYAGAIN)				      \
+	  if (status == NSS_STATUS_TRYAGAIN)				      \
+	    {								      \
+	      size_t newsize = 2 * tmp_buflen;				      \
+	      if (tmp_buffer_malloced)					      \
+		{							      \
+		  char *newp = realloc (tmp_buffer, newsize);		      \
+		  if (newp != NULL)					      \
+		    {							      \
+		      assert ((((uintptr_t) newp)			      \
+			       & (__alignof__ (struct hostent_data) - 1))     \
+			      == 0);					      \
+		      tmp_buffer = newp;				      \
+		      tmp_buflen = newsize;				      \
+		      goto again;					      \
+		    }							      \
+		}							      \
+	      else if (!__libc_use_alloca (buflen + newsize))		      \
+		{							      \
+		  tmp_buffer = malloc (newsize);			      \
+		  if (tmp_buffer != NULL)				      \
+		    {							      \
+		      assert ((((uintptr_t) tmp_buffer)			      \
+			       & (__alignof__ (struct hostent_data) - 1))     \
+			      == 0);					      \
+		      tmp_buffer_malloced = true;			      \
+		      tmp_buflen = newsize;				      \
+		      goto again;					      \
+		    }							      \
+		}							      \
+	      else							      \
+		{							      \
+		  tmp_buffer						      \
+		    = extend_alloca (tmp_buffer, tmp_buflen,		      \
+				     newsize				      \
+				     + __alignof__ (struct hostent_data));    \
+		  tmp_buffer = (char *) (((uintptr_t) tmp_buffer	      \
+					  + __alignof__ (struct hostent_data) \
+					  - 1)				      \
+					 & ~(__alignof__ (struct hostent_data)\
+					     - 1));			      \
+		  goto again;						      \
+		}							      \
+	    }								      \
+	  else								      \
 	    status = NSS_STATUS_SUCCESS;				      \
+	out:								      \
+	  if (tmp_buffer_malloced)					      \
+	    free (tmp_buffer);						      \
 	}								      \
 									      \
 									      \
Index: glibc-2.12-2-gc4ccff1/nss/nss_files/files-initgroups.c
===================================================================
--- /dev/null
+++ glibc-2.12-2-gc4ccff1/nss/nss_files/files-initgroups.c
@@ -0,0 +1,137 @@
+/* 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;
+  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 (!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;
+      int res;
+      while ((res = _nss_files_parse_grent (line, &grp, buffer, buflen,
+					    errnop)) == -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);
+	}
+
+      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;
+}
Index: glibc-2.12-2-gc4ccff1/nss/nsswitch.conf
===================================================================
--- glibc-2.12-2-gc4ccff1.orig/nss/nsswitch.conf
+++ glibc-2.12-2-gc4ccff1/nss/nsswitch.conf
@@ -5,6 +5,7 @@
 
 passwd:		db files
 group:		db files
+initgroups:	db [SUCCESS=continue] files
 shadow:		db files
 gshadow:	files