about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--grp/initgroups.c37
-rw-r--r--hesiod/Versions2
-rw-r--r--hesiod/nss_hesiod/hesiod-grp.c41
-rw-r--r--nis/Versions9
-rw-r--r--nis/nss_compat/compat-initgroups.c18
-rw-r--r--nis/nss_nis/nis-initgroups.c18
7 files changed, 93 insertions, 48 deletions
diff --git a/ChangeLog b/ChangeLog
index 25c83be513..46fc4bdd18 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,21 @@
 2000-07-23  Ulrich Drepper  <drepper@redhat.com>
 
+	* grp/initgroups.c (initgroups): Don't limit the possible number
+	of groups to NGROUPS_MAX.  Allow dynamic resizing.  Loop around
+	the setgroups call while the call fails and descrease the number
+	of groups each round.
+	The name of the initgroups function in the NSS modules changed.
+	(compat_call): Adapt for dynamic resizing.
+	* hesiod/nss_hesiod/hesiod-grp.c (_nss_hesiod_initgroups_dyn):
+	Implement dynamic resizing.
+	* nis/nss_compat/compat-initgroups.c (_nss_compat_initgroups_dyn):
+	Likewise.
+	* nis/nss_nis/compat-initgroups.c (_nss_nis_initgroups_dyn): Likewise.
+	* hesiod/Versions: Change exported interface name.
+	* nis/Versions: Change exported interface name.
+
+2000-07-23  Ulrich Drepper  <drepper@redhat.com>
+
 	* locale/iso-639.def: Some errors corrected.
 	Patch by Keld Simonsen.
 
diff --git a/grp/initgroups.c b/grp/initgroups.c
index 06c48bb040..950ebfec0b 100644
--- a/grp/initgroups.c
+++ b/grp/initgroups.c
@@ -49,7 +49,7 @@ extern service_user *__nss_group_database;
 
 static enum nss_status
 compat_call (service_user *nip, const char *user, gid_t group, long int *start,
-	     long int *size, gid_t *groups, long int limit, int *errnop)
+	     long int *size, gid_t **groupsp, int *errnop)
 {
   struct group grpbuf;
   size_t buflen = __sysconf (_SC_GETGR_R_SIZE_MAX);
@@ -58,6 +58,7 @@ compat_call (service_user *nip, const char *user, gid_t group, long int *start,
   set_function setgrent_fct;
   get_function getgrent_fct;
   end_function endgrent_fct;
+  gid_t *groups = *groupsp;
 
   getgrent_fct = __nss_lookup_function (nip, "getgrent_r");
   if (getgrent_fct == NULL)
@@ -97,22 +98,20 @@ compat_call (service_user *nip, const char *user, gid_t group, long int *start,
             if (strcmp (*m, user) == 0)
               {
                 /* Matches user.  Insert this group.  */
-                if (*start == *size && limit <= 0)
+                if (__builtin_expect (*start == *size, 0))
                   {
                     /* Need a bigger buffer.  */
-                    groups = realloc (groups, 2 * *size * sizeof (*groups));
-                    if (groups == NULL)
+		    gid_t *newgroups;
+                    newgroups = realloc (groups, 2 * *size * sizeof (*groups));
+                    if (newgroups == NULL)
                       goto done;
+		    *groupsp = groups = newgroups;
                     *size *= 2;
                   }
 
                 groups[*start] = grpbuf.gr_gid;
                 *start += 1;
 
-                if (*start == limit)
-                  /* Can't take any more groups; stop searching.  */
-                  goto done;
-
                 break;
               }
         }
@@ -149,10 +148,9 @@ initgroups (user, group)
   long int start = 1;
   long int size;
   gid_t *groups;
+  int result;
 #ifdef NGROUPS_MAX
-# define limit NGROUPS_MAX
-
-  size = limit;
+  size = NGROUPS_MAX;
 #else
   long int limit = __sysconf (_SC_NGROUPS_MAX);
 
@@ -181,19 +179,19 @@ initgroups (user, group)
 
   while (! no_more)
     {
-      fct = __nss_lookup_function (nip, "initgroups");
+      fct = __nss_lookup_function (nip, "initgroups_dyn");
 
       if (fct == NULL)
 	{
-	  status = compat_call (nip, user, group, &start, &size, groups,
-				limit, &errno);
+	  status = compat_call (nip, user, group, &start, &size, &groups,
+				&errno);
 
 	  if (nss_next_action (nip, NSS_STATUS_UNAVAIL) != NSS_ACTION_CONTINUE)
 	    break;
 	}
       else
-	status = DL_CALL_FCT (fct, (user, group, &start, &size, groups, limit,
-				     &errno));
+	status = DL_CALL_FCT (fct, (user, group, &start, &size, &groups,
+				    &errno));
 
       /* This is really only for debugging.  */
       if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
@@ -209,6 +207,11 @@ initgroups (user, group)
 	nip = nip->next;
     }
 
-  return setgroups (start, groups);
+  /* Try to set the maximum number of groups the kernel can handle.  */
+  do
+    result = setgroups (start, groups);
+  while (result == -1 && errno == EINVAL && --start > 0);
+
+  return result;
 #endif
 }
diff --git a/hesiod/Versions b/hesiod/Versions
index c51dee9c50..180befb5b3 100644
--- a/hesiod/Versions
+++ b/hesiod/Versions
@@ -8,7 +8,7 @@ libnss_hesiod {
     _nss_hesiod_getservbyname_r;
   }
   GLIBC_2.2 {
-    _nss_hesiod_initgroups;
+    _nss_hesiod_initgroups_dyn;
     _nss_hesiod_getservbyport_r;
     _nss_hesiod_setprotoent; _nss_hesiod_endprotoent;
     _nss_hesiod_getprotobyname_r; _nss_hesiod_getprotobynumber_r;
diff --git a/hesiod/nss_hesiod/hesiod-grp.c b/hesiod/nss_hesiod/hesiod-grp.c
index 2d5b96b7f9..a89ed4edaf 100644
--- a/hesiod/nss_hesiod/hesiod-grp.c
+++ b/hesiod/nss_hesiod/hesiod-grp.c
@@ -164,14 +164,14 @@ internal_gid_from_group (void *context, const char *groupname, gid_t *group)
 }
 
 enum nss_status
-_nss_hesiod_initgroups (const char *user, gid_t group, long int *start,
-                        long int *size, gid_t *groups, long int limit,
-                        int *errnop)
+_nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start,
+			    long int *size, gid_t **groupsp, int *errnop)
 {
   enum nss_status status = NSS_STATUS_SUCCESS;
   char **list = NULL;
   char *p;
   void *context;
+  gid_t *groups = *groupsp;
 
   context = _nss_hesiod_init ();
   if (context == NULL)
@@ -185,11 +185,24 @@ _nss_hesiod_initgroups (const char *user, gid_t group, long int *start,
       return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
     }
 
-  if (!internal_gid_in_list (groups, group, *start) && *start < limit)
-    groups[(*start)++] = group;
+  if (!internal_gid_in_list (groups, group, *start))
+    {
+      if (__builtin_expect (*start == *size, 0))
+	{
+	  /* Need a bigger buffer.  */
+	  gid_t *newgroups;
+	  newgroups = realloc (groups, 2 * *size * sizeof (*groups));
+	  if (newgroups == NULL)
+	    goto done;
+	  *groupsp = groups = newgroups;
+	  *size *= 2;
+	}
+
+      groups[(*start)++] = group;
+    }
 
   p = *list;
-  while (*p != '\0' && *start < limit)
+  while (*p != '\0')
     {
       char *endp;
       char *q;
@@ -214,12 +227,26 @@ _nss_hesiod_initgroups (const char *user, gid_t group, long int *start,
 
 	  if (status == NSS_STATUS_SUCCESS
 	      && !internal_gid_in_list (groups, group, *start))
-	    groups[(*start)++] = group;
+	    {
+	      if (__builtin_expect (*start == *size, 0))
+		{
+		  /* Need a bigger buffer.  */
+		  gid_t *newgroups;
+		  newgroups = realloc (groups, 2 * *size * sizeof (*groups));
+		  if (newgroups == NULL)
+		    goto done;
+		  *groupsp = groups = newgroups;
+		  *size *= 2;
+		}
+
+	      groups[(*start)++] = group;
+	    }
 	}
 
       p = q;
     }
 
+ done:
   hesiod_free_list (context, list);
   hesiod_end (context);
 
diff --git a/nis/Versions b/nis/Versions
index ec8ade0dd3..8bcf9a8f0e 100644
--- a/nis/Versions
+++ b/nis/Versions
@@ -64,9 +64,12 @@ libnss_compat {
     _nss_compat_endgrent; _nss_compat_endpwent; _nss_compat_endspent;
     _nss_compat_getgrent_r; _nss_compat_getgrgid_r; _nss_compat_getgrnam_r;
     _nss_compat_getpwent_r; _nss_compat_getpwnam_r; _nss_compat_getpwuid_r;
-    _nss_compat_getspent_r; _nss_compat_getspnam_r; _nss_compat_initgroups;
+    _nss_compat_getspent_r; _nss_compat_getspnam_r;
     _nss_compat_setgrent; _nss_compat_setpwent; _nss_compat_setspent;
   }
+  GLIBC_2.2 {
+    _nss_compat_initgroups_dyn;
+  }
 }
 
 libnss_nis {
@@ -85,14 +88,14 @@ libnss_nis {
     _nss_nis_getpwnam_r; _nss_nis_getpwuid_r; _nss_nis_getrpcbyname_r;
     _nss_nis_getrpcbynumber_r; _nss_nis_getrpcent_r; _nss_nis_getsecretkey;
     _nss_nis_getservbyname_r; _nss_nis_getservbyport_r; _nss_nis_getservent_r;
-    _nss_nis_getspent_r; _nss_nis_getspnam_r; _nss_nis_initgroups;
+    _nss_nis_getspent_r; _nss_nis_getspnam_r;
     _nss_nis_netname2user; _nss_nis_setaliasent; _nss_nis_setetherent;
     _nss_nis_setgrent; _nss_nis_sethostent; _nss_nis_setnetent;
     _nss_nis_setnetgrent; _nss_nis_setprotoent; _nss_nis_setpwent;
     _nss_nis_setrpcent; _nss_nis_setservent; _nss_nis_setspent;
   }
   GLIBC_2.2 {
-    _nss_nis_getipnodebyname_r;
+    _nss_nis_getipnodebyname_r; _nss_nis_initgroups_dyn;
   }
 }
 
diff --git a/nis/nss_compat/compat-initgroups.c b/nis/nss_compat/compat-initgroups.c
index 6051a1ae99..4d14615126 100644
--- a/nis/nss_compat/compat-initgroups.c
+++ b/nis/nss_compat/compat-initgroups.c
@@ -588,15 +588,15 @@ internal_getgrent_r (struct group *gr, ent_t *ent, char *buffer,
 }
 
 enum nss_status
-_nss_compat_initgroups (const char *user, gid_t group, long int *start,
-			long int *size, gid_t *groups, long int limit,
-			int *errnop)
+_nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start,
+			    long int *size, gid_t **groupsp, int *errnop)
 {
   struct group grpbuf, *g;
   size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
   char *tmpbuf;
   enum nss_status status;
   ent_t intern = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}};
+  gid_t *groups = *groupsp;
 
   status = internal_setgrent (&intern);
   if (status != NSS_STATUS_SUCCESS)
@@ -627,22 +627,20 @@ _nss_compat_initgroups (const char *user, gid_t group, long int *start,
             if (strcmp (*m, user) == 0)
               {
                 /* Matches user.  Insert this group.  */
-                if (*start == *size && limit <= 0)
+                if (*start == *size)
                   {
                     /* Need a bigger buffer.  */
-                    groups = realloc (groups, 2 * *size * sizeof (*groups));
-                    if (groups == NULL)
+		    gid_t *newgroups;
+                    newgroups = realloc (groups, 2 * *size * sizeof (*groups));
+                    if (newgroups == NULL)
                       goto done;
+		    *groupsp = groups = newgroups;
                     *size *= 2;
                   }
 
                 groups[*start] = g->gr_gid;
                 *start += 1;
 
-                if (*start == limit)
-                  /* Can't take any more groups; stop searching.  */
-                  goto done;
-
                 break;
               }
         }
diff --git a/nis/nss_nis/nis-initgroups.c b/nis/nss_nis/nis-initgroups.c
index 9e18a2027a..ec13dbd140 100644
--- a/nis/nss_nis/nis-initgroups.c
+++ b/nis/nss_nis/nis-initgroups.c
@@ -137,15 +137,15 @@ internal_getgrent_r (struct group *grp, char *buffer, size_t buflen,
 }
 
 enum nss_status
-_nss_nis_initgroups (const char *user, gid_t group, long int *start,
-		     long int *size, gid_t *groups, long int limit,
-		     int *errnop)
+_nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
+			 long int *size, gid_t **groupsp, int *errnop)
 {
   struct group grpbuf, *g;
   size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
   char *tmpbuf;
   enum nss_status status;
   intern_t intern = { NULL, NULL };
+  gid_t *groups = *groupsp;
 
   status = internal_setgrent (&intern);
   if (status != NSS_STATUS_SUCCESS)
@@ -177,22 +177,20 @@ _nss_nis_initgroups (const char *user, gid_t group, long int *start,
             if (strcmp (*m, user) == 0)
               {
                 /* Matches user.  Insert this group.  */
-                if (*start == *size && limit <= 0)
+                if (*start == *size)
                   {
                     /* Need a bigger buffer.  */
-		    groups = realloc (groups, 2 * *size * sizeof (*groups));
-		    if (groups == NULL)
+		    gid_t *newgroups;
+		    newgroups = realloc (groups, 2 * *size * sizeof (*groups));
+		    if (newgroups == NULL)
 		      goto done;
+		    *groupsp = groups = newgroups;
                     *size *= 2;
                   }
 
                 groups[*start] = g->gr_gid;
 		*start += 1;
 
-                if (*start == limit)
-                  /* Can't take any more groups; stop searching.  */
-                  goto done;
-
                 break;
               }
         }