about summary refs log tree commit diff
path: root/hesiod
diff options
context:
space:
mode:
Diffstat (limited to 'hesiod')
-rw-r--r--hesiod/Versions2
-rw-r--r--hesiod/nss_hesiod/hesiod-grp.c41
2 files changed, 35 insertions, 8 deletions
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);