about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--grp/compat-initgroups.c61
-rw-r--r--grp/initgroups.c23
-rw-r--r--nscd/initgrcache.c16
4 files changed, 78 insertions, 28 deletions
diff --git a/ChangeLog b/ChangeLog
index 6edd7c3c84..a97d986f6f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2004-10-05  Ulrich Drepper  <drepper@redhat.com>
+
+	* grp/initgroups.c: Remove duplicate group IDs.
+	* grp/compat-initgroups.c: Likewise.
+	* nscd/initgrcache.c: Likewise.
+
 2004-10-05  Jakub Jelinek  <jakub@redhat.com>
 
 	* sysdeps/unix/sysv/linux/x86_64/sysconf.c (__sysconf): Return 200112L
diff --git a/grp/compat-initgroups.c b/grp/compat-initgroups.c
index 585c4aecbb..efd875a689 100644
--- a/grp/compat-initgroups.c
+++ b/grp/compat-initgroups.c
@@ -58,31 +58,42 @@ compat_call (service_user *nip, const char *user, gid_t group, long int *start,
           for (m = grpbuf.gr_mem; *m != NULL; ++m)
             if (strcmp (*m, user) == 0)
               {
-                /* Matches user.  Insert this group.  */
-                if (__builtin_expect (*start == *size, 0))
-                  {
-                    /* Need a bigger buffer.  */
-		    gid_t *newgroups;
-		    long int newsize;
-
-		    if (limit > 0 && *size == limit)
-		      /* We reached the maximum.  */
-		      goto done;
-
-		    if (limit <= 0)
-		      newsize = 2 * *size;
-		    else
-		      newsize = MIN (limit, 2 * *size);
-
-                    newgroups = realloc (groups, newsize * sizeof (*groups));
-                    if (newgroups == NULL)
-                      goto done;
-		    *groupsp = groups = newgroups;
-                    *size = newsize;
-                  }
-
-                groups[*start] = grpbuf.gr_gid;
-                *start += 1;
+		/* Check whether the group is already on the list.  */
+		long int cnt;
+		for (cnt = 0; cnt < *start; ++cnt)
+		  if (groups[cnt] == grpbuf.gr_gid)
+		    break;
+
+		if (cnt == *start)
+		  {
+		    /* Matches user and not yet on the list.  Insert
+		       this group.  */
+		    if (__builtin_expect (*start == *size, 0))
+		      {
+			/* Need a bigger buffer.  */
+			gid_t *newgroups;
+			long int newsize;
+
+			if (limit > 0 && *size == limit)
+			  /* We reached the maximum.  */
+			  goto done;
+
+			if (limit <= 0)
+			  newsize = 2 * *size;
+			else
+			  newsize = MIN (limit, 2 * *size);
+
+			newgroups = realloc (groups,
+					     newsize * sizeof (*groups));
+			if (newgroups == NULL)
+			  goto done;
+			*groupsp = groups = newgroups;
+			*size = newsize;
+		      }
+
+		    groups[*start] = grpbuf.gr_gid;
+		    *start += 1;
+		  }
 
                 break;
               }
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
diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c
index 124b4bae62..b46433716b 100644
--- a/nscd/initgrcache.c
+++ b/nscd/initgrcache.c
@@ -117,6 +117,7 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
   /* Nothing added yet.  */
   while (! no_more)
     {
+      long int prev_start = start;
       enum nss_status status;
       initgroups_dyn_function fct;
       fct = __nss_lookup_function (nip, "initgroups_dyn");
@@ -133,6 +134,21 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
 	status = DL_CALL_FCT (fct, (key, -1, &start, &size, &groups,
 				    limit, &errno));
 
+      /* Remove duplicates.  */
+      long int cnt = prev_start;
+      while (cnt < start)
+	{
+	  long int inner;
+	  for (inner = 0; inner < prev_start; ++inner)
+	    if (groups[inner] == groups[cnt])
+	      break;
+
+	  if (inner < prev_start)
+	    groups[cnt] = groups[--start];
+	  else
+	    ++cnt;
+	}
+
       if (status != NSS_STATUS_TRYAGAIN)
 	all_tryagain = false;