about summary refs log tree commit diff
path: root/grp/initgroups.c
diff options
context:
space:
mode:
Diffstat (limited to 'grp/initgroups.c')
-rw-r--r--grp/initgroups.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/grp/initgroups.c b/grp/initgroups.c
index 9e79273f3e..d052cf48f7 100644
--- a/grp/initgroups.c
+++ b/grp/initgroups.c
@@ -73,7 +73,7 @@ internal_getgrouplist (const char *user, gid_t group, long int *size,
   /* Start is one, because we have the first group as parameter.  */
   long int start = 1;
 
-  *groupsp[0] = group;
+  (*groupsp)[0] = group;
 
   if (__nss_group_database != NULL)
     {
@@ -86,6 +86,8 @@ internal_getgrouplist (const char *user, gid_t group, long int *size,
 
   while (! no_more)
     {
+      long int prev_start = start;
+
       fct = __nss_lookup_function (nip, "initgroups_dyn");
 
       if (fct == NULL)
@@ -100,6 +102,21 @@ internal_getgrouplist (const char *user, gid_t group, long int *size,
 	status = DL_CALL_FCT (fct, (user, group, &start, size, groupsp,
 				    limit, &errno));
 
+      /* Remove duplicates.  */
+      long int cnt = prev_start;
+      while (cnt < start)
+	{
+	  long int inner;
+	  for (inner = 0; inner < prev_start; ++inner)
+	    if ((*groupsp)[inner] == (*groupsp)[cnt])
+	      break;
+
+	  if (inner < prev_start)
+	    (*groupsp)[cnt] = (*groupsp)[--start];
+	  else
+	    ++cnt;
+	}
+
       /* This is really only for debugging.  */
       if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
 	__libc_fatal ("illegal status in internal_getgrouplist");
@@ -124,10 +141,10 @@ int
 getgrouplist (const char *user, gid_t group, gid_t *groups, int *ngroups)
 {
   gid_t *newgroups;
-  long int size = *ngroups;
+  long int size = MAX (1, *ngroups);
   int result;
 
-  newgroups = (gid_t *) malloc (size * sizeof (gid_t));
+  newgroups = (gid_t *) malloc ((size + 1) * sizeof (gid_t));
   if (__builtin_expect (newgroups == NULL, 0))
     /* No more memory.  */
     // XXX This is wrong.  The user provided memory, we have to use