Just a heads-up, because this bug took me absolutely ages to chase down,
and I want to save others the same pain.

Samba is perhaps the most prominent reason why you might find a user in
more than 16 groups on a Unix system, and so this bug may at first
appear to be a 'Samba issue' (that certainly is why it found it's way to
my attention :-)

https://www.illumos.org/issues/3691

In short, unless the group list we supply to setgroups() is sorted, if
there are more than 16 groups, the Illumos kernel fails to honour some
of the groups.  Presumably there is a bisection search being done. 

The symptom for Samba users is that as a user is added to more groups,
they loose access to folders they previously had access too. 

Attached is a total hack that appears to resolve the issue, but the real
fix needs to be in glibc or the kernel. 

Andrew Bartlett
-- 
Andrew Bartlett                                http://samba.org/~abartlet/
Authentication Developer, Samba Team           http://samba.org

diff --git a/source3/lib/system.c b/source3/lib/system.c
index 7c0bb3f..be7d94d 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -1174,14 +1174,14 @@ int groups_max(void)
  returning an array of gid_t, but actuall return an array of int.
 ****************************************************************************/
 
-#if defined(HAVE_BROKEN_GETGROUPS)
-
 #ifdef HAVE_BROKEN_GETGROUPS
 #define GID_T int
 #else
 #define GID_T gid_t
 #endif
 
+#if defined(HAVE_BROKEN_GETGROUPS)
+
 static int sys_broken_getgroups(int setlen, gid_t *gidset)
 {
 	GID_T gid;
@@ -1224,6 +1224,13 @@ static int sys_broken_getgroups(int setlen, gid_t *gidset)
 	return ngroups;
 }
 
+#endif /* HAVE_BROKEN_GETGROUPS */
+
+static int gid_compare(void *gid_1, void *gid_2)
+{
+	return (*(GID_T *)gid_1 - *(GID_T *)gid_2);
+}
+
 static int sys_broken_setgroups(int setlen, gid_t *gidset)
 {
 	GID_T *group_list;
@@ -1250,6 +1257,8 @@ static int sys_broken_setgroups(int setlen, gid_t *gidset)
 	for(i = 0; i < setlen; i++) 
 		group_list[i] = (GID_T) gidset[i]; 
 
+	TYPESAFE_QSORT(group_list, setlen, gid_compare);
+
 	if(setgroups(setlen, group_list) != 0) {
 		int saved_errno = errno;
 		SAFE_FREE(group_list);
@@ -1261,8 +1270,6 @@ static int sys_broken_setgroups(int setlen, gid_t *gidset)
 	return 0 ;
 }
 
-#endif /* HAVE_BROKEN_GETGROUPS */
-
 /* This is a list of systems that require the first GID passed to setgroups(2)
  * to be the effective GID. If your system is one of these, add it here.
  */
@@ -1353,11 +1360,8 @@ int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
 
 #if defined(USE_BSD_SETGROUPS)
 	return sys_bsd_setgroups(primary_gid, setlen, gidset);
-#elif defined(HAVE_BROKEN_GETGROUPS)
-	return sys_broken_setgroups(setlen, gidset);
-#else
-	return setgroups(setlen, gidset);
 #endif
+	return sys_broken_setgroups(setlen, gidset);
 }
 
 /**************************************************************************
-- 
To unsubscribe from this list go to the following URL and read the
instructions:  https://lists.samba.org/mailman/options/samba

Reply via email to