Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 5 Jun 2009 17:36:36 -0500
From:      Brooks Davis <brooks@freebsd.org>
To:        arch@freebsd.org, current@freebsd.org
Subject:   RFT: Allow large values of NGROUPS_MAX
Message-ID:  <20090605223636.GA24364@lor.one-eyed-alien.net>

next in thread | raw e-mail | index | archive | help

--i9LlY+UWpKt15+FH
Content-Type: multipart/mixed; boundary="sdtB3X0nJg68CQEu"
Content-Disposition: inline


--sdtB3X0nJg68CQEu
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

I've been working on fixing the limit of 15 groups per user.  This has
primarily consisted of merging a patch from Isilon Systems which breaks
the group array out of struct ucred and stores in in malloc'd storage.

I've attached a patch which includes that change and increases the value
of NGROUPS_MAX to 32767.  It also changes references to cr_groups[0] to
use the cr_gid macro and introduces a new crsetgroups() function for use
by random bits of code that fill in credentials (usually partial ones)
Additionally, a number of arrays that used to be of length NGROUPS have
been changed to use XU_NGROUPS (from xucred) or their own definition
which is 16 to avoid excessive bloat.  Most of these should probably be
change to use dynamic allocation.

In general, when something could not take more groups, I have chosen to
truncate the list rather than fail.  This may raise issues with negative
permissions, but complete failure is likely to cause problems for more
people.  If it's a major issue this can be made tunable.  As I mentioned
above, many thing should be redone to support dynamic allocation, but
all the RPC related things can not.

I'd like people to test and review this patch with the aim of getting it
and some of the other work I've been doing in subversion in to 8.0.  You
can find all of it at http://svn.freebsd.org/base/projects/ngroups.

Before any merge a couple decisions need to be made:

 - How large should NGROUPS_MAX be?  Linux uses 65536 and we could
   extend things to support that, but it's probably unnecessary. =20

 - Should we make any attempt to support old binaries when there
   are more than 16 groups?  The POSIX getgroups/setgroups APIs did not
   anticipate this change and thus either will fail outright.  We can't
   fix setgroups, but we might want to make an optional accommodation for
   getgroups to allow for truncated returns to old code.

-- Brooks

--sdtB3X0nJg68CQEu
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="ngroups-nosysconf.diff"
Content-Transfer-Encoding: quoted-printable

diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/lib/libc/rpc/netname.c ngroups/lib/libc/=
rpc/netname.c
--- /usr/src/lib/libc/rpc/netname.c	2009-01-22 10:05:44.000000000 -0600
+++ ngroups/lib/libc/rpc/netname.c	2009-05-14 01:48:22.000000000 -0500
@@ -61,9 +61,6 @@
 #ifndef MAXHOSTNAMELEN
 #define MAXHOSTNAMELEN 256
 #endif
-#ifndef NGROUPS
-#define NGROUPS 16
-#endif
=20
 #define TYPE_BIT(type)  (sizeof (type) * CHAR_BIT)
=20
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/lib/libc/rpc/netnamer.c ngroups/lib/libc=
/rpc/netnamer.c
--- /usr/src/lib/libc/rpc/netnamer.c	2009-01-22 10:05:44.000000000 -0600
+++ ngroups/lib/libc/rpc/netnamer.c	2009-05-13 22:51:38.000000000 -0500
@@ -66,10 +66,6 @@
 static int getnetid( char *, char * );
 static int _getgroups( char *, gid_t * );
=20
-#ifndef NGROUPS
-#define NGROUPS 16
-#endif
-
 /*
  * Convert network-name into unix credential
  */
@@ -104,7 +100,7 @@
 			return (0);
 		}
 		*gidp =3D (gid_t) atol(p);
-		for (gidlen =3D 0; gidlen < NGROUPS; gidlen++) {
+		for (gidlen =3D 0; gidlen < NGRPS; gidlen++) {
 			p =3D strsep(&res, "\n,");
 			if (p =3D=3D NULL)
 				break;
@@ -157,7 +153,7 @@
 static int
 _getgroups(uname, groups)
 	char           *uname;
-	gid_t          groups[NGROUPS];
+	gid_t          groups[NGRPS];
 {
 	gid_t           ngroups =3D 0;
 	struct group *grp;
@@ -169,7 +165,7 @@
 	while ((grp =3D getgrent())) {
 		for (i =3D 0; grp->gr_mem[i]; i++)
 			if (!strcmp(grp->gr_mem[i], uname)) {
-				if (ngroups =3D=3D NGROUPS) {
+				if (ngroups =3D=3D NGRPS) {
 #ifdef DEBUG
 					fprintf(stderr,
 				"initgroups: %s is in too many groups\n", uname);
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/contrib/pf/net/pf.c ngroups/sys/cont=
rib/pf/net/pf.c
--- /usr/src/sys/contrib/pf/net/pf.c	2009-06-05 15:33:53.000000000 -0500
+++ ngroups/sys/contrib/pf/net/pf.c	2009-06-05 16:02:32.000000000 -0500
@@ -2945,7 +2945,7 @@
 	if (inp_arg !=3D NULL) {
 		INP_LOCK_ASSERT(inp_arg);
 		pd->lookup.uid =3D inp_arg->inp_cred->cr_uid;
-		pd->lookup.gid =3D inp_arg->inp_cred->cr_groups[0];
+		pd->lookup.gid =3D inp_arg->inp_cred->cr_gid;
 		return (1);
 	}
 #endif
@@ -3043,7 +3043,7 @@
 	}
 #ifdef __FreeBSD__
 	pd->lookup.uid =3D inp->inp_cred->cr_uid;
-	pd->lookup.gid =3D inp->inp_cred->cr_groups[0];
+	pd->lookup.gid =3D inp->inp_cred->cr_gid;
 	INP_INFO_RUNLOCK(pi);
 #else
 	pd->lookup.uid =3D inp->inp_socket->so_euid;
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/fs/nfs/nfs_commonport.c ngroups/sys/=
fs/nfs/nfs_commonport.c
--- /usr/src/sys/fs/nfs/nfs_commonport.c	2009-05-29 12:48:03.000000000 -0500
+++ ngroups/sys/fs/nfs/nfs_commonport.c	2009-06-05 15:33:54.000000000 -0500
@@ -220,14 +220,9 @@
 void
 newnfs_copycred(struct nfscred *nfscr, struct ucred *cr)
 {
-	int ngroups, i;
=20
 	cr->cr_uid =3D nfscr->nfsc_uid;
-	ngroups =3D (nfscr->nfsc_ngroups < NGROUPS) ?
-	    nfscr->nfsc_ngroups : NGROUPS;
-	for (i =3D 0; i < ngroups; i++)
-		cr->cr_groups[i] =3D nfscr->nfsc_groups[i];
-	cr->cr_ngroups =3D ngroups;
+	crsetgroups(cr, nfscr->nfsc_ngroups, nfscr->nfsc_groups);
 }
=20
 /*
@@ -295,15 +290,13 @@
=20
 /*
  * Set the credentials to refer to root.
- * If only the various BSDen could agree on whether cr_gid is a separate
- * field or cr_groups[0]...
  */
 void
 newnfs_setroot(struct ucred *cred)
 {
=20
 	cred->cr_uid =3D 0;
-	cred->cr_groups[0] =3D 0;
+	cred->cr_gid =3D 0;
 	cred->cr_ngroups =3D 1;
 }
=20
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/fs/nfsclient/nfs_clport.c ngroups/sy=
s/fs/nfsclient/nfs_clport.c
--- /usr/src/sys/fs/nfsclient/nfs_clport.c	2009-05-29 12:48:03.000000000 -0=
500
+++ ngroups/sys/fs/nfsclient/nfs_clport.c	2009-06-05 15:33:54.000000000 -05=
00
@@ -976,14 +976,12 @@
 void
 newnfs_copyincred(struct ucred *cr, struct nfscred *nfscr)
 {
-	int ngroups, i;
+	int i;
=20
 	nfscr->nfsc_uid =3D cr->cr_uid;
-	ngroups =3D (cr->cr_ngroups > NGROUPS) ? NGROUPS :
-	    cr->cr_ngroups;
-	for (i =3D 0; i < ngroups; i++)
+	nfscr->nfsc_ngroups =3D MIN(cr->cr_ngroups, XU_NGROUPS);
+	for (i =3D 0; i < nfscr->nfsc_ngroups; i++)
 		nfscr->nfsc_groups[i] =3D cr->cr_groups[i];
-	nfscr->nfsc_ngroups =3D ngroups;
 }
=20
=20
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/fs/nfsserver/nfs_nfsdport.c ngroups/=
sys/fs/nfsserver/nfs_nfsdport.c
--- /usr/src/sys/fs/nfsserver/nfs_nfsdport.c	2009-06-05 15:33:50.000000000 =
-0500
+++ ngroups/sys/fs/nfsserver/nfs_nfsdport.c	2009-06-05 16:02:29.000000000 -=
0500
@@ -2360,7 +2360,6 @@
 nfsd_excred(struct nfsrv_descript *nd, struct nfsexstuff *exp,
     struct ucred *credanon)
 {
-	int i;
 	int error =3D 0;
=20
 	/*
@@ -2403,9 +2402,8 @@
 	     (nd->nd_flag & ND_AUTHNONE))) {
 		nd->nd_cred->cr_uid =3D credanon->cr_uid;
 		nd->nd_cred->cr_gid =3D credanon->cr_gid;
-		for (i =3D 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
-			nd->nd_cred->cr_groups[i] =3D credanon->cr_groups[i];
-		nd->nd_cred->cr_ngroups =3D i;
+		crsetgroups(nd->nd_cred, credanon->cr_ngroups,
+		    credanon->cr_groups);
 	}
 	return (0);
 }
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/fs/nfsserver/nfs_nfsdstate.c ngroups=
/sys/fs/nfsserver/nfs_nfsdstate.c
--- /usr/src/sys/fs/nfsserver/nfs_nfsdstate.c	2009-05-29 12:48:03.000000000=
 -0500
+++ ngroups/sys/fs/nfsserver/nfs_nfsdstate.c	2009-06-05 15:33:54.000000000 =
-0500
@@ -3577,7 +3577,6 @@
 	nd->nd_repstat =3D 0;
 	cred->cr_uid =3D clp->lc_uid;
 	cred->cr_gid =3D clp->lc_gid;
-	cred->cr_groups[0] =3D clp->lc_gid;
 	callback =3D clp->lc_callback;
 	NFSUNLOCKSTATE();
 	cred->cr_ngroups =3D 1;
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/fs/portalfs/portal.h ngroups/sys/fs/=
portalfs/portal.h
--- /usr/src/sys/fs/portalfs/portal.h	2009-01-22 10:06:01.000000000 -0600
+++ ngroups/sys/fs/portalfs/portal.h	2009-06-05 15:33:54.000000000 -0500
@@ -43,7 +43,7 @@
 	int		pcr_flag;		/* File open mode */
 	uid_t		pcr_uid;		/* From ucred */
 	short		pcr_ngroups;		/* From ucred */
-	gid_t		pcr_groups[NGROUPS];	/* From ucred */
+	gid_t		pcr_groups[XU_NGROUPS];	/* From ucred */
 };
=20
 #ifdef _KERNEL
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/fs/portalfs/portal_vnops.c ngroups/s=
ys/fs/portalfs/portal_vnops.c
--- /usr/src/sys/fs/portalfs/portal_vnops.c	2009-01-22 10:06:01.000000000 -=
0600
+++ ngroups/sys/fs/portalfs/portal_vnops.c	2009-06-05 15:33:54.000000000 -0=
500
@@ -311,8 +311,9 @@
=20
 	pcred.pcr_flag =3D ap->a_mode;
 	pcred.pcr_uid =3D ap->a_cred->cr_uid;
-	pcred.pcr_ngroups =3D ap->a_cred->cr_ngroups;
-	bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t));
+	pcred.pcr_ngroups =3D MIN(ap->a_cred->cr_ngroups, XU_NGROUPS);
+	bcopy(ap->a_cred->cr_groups, pcred.pcr_groups,
+	    pcred.pcr_ngroups * sizeof(gid_t));
 	aiov[0].iov_base =3D (caddr_t) &pcred;
 	aiov[0].iov_len =3D sizeof(pcred);
 	aiov[1].iov_base =3D pt->pt_arg;
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/fs/unionfs/union_vnops.c ngroups/sys=
/fs/unionfs/union_vnops.c
--- /usr/src/sys/fs/unionfs/union_vnops.c	2009-04-12 15:26:52.000000000 -05=
00
+++ ngroups/sys/fs/unionfs/union_vnops.c	2009-06-05 15:33:54.000000000 -0500
@@ -638,7 +638,6 @@
 	uid_t		uid;	/* upper side vnode's uid */
 	gid_t		gid;	/* upper side vnode's gid */
 	u_short		vmode;	/* upper side vnode's mode */
-	gid_t          *gp;
 	u_short		mask;
=20
 	mask =3D 0;
@@ -659,17 +658,14 @@
=20
 	/* check group */
 	count =3D 0;
-	gp =3D cred->cr_groups;
-	for (; count < cred->cr_ngroups; count++, gp++) {
-		if (gid =3D=3D *gp) {
-			if (accmode & VEXEC)
-				mask |=3D S_IXGRP;
-			if (accmode & VREAD)
-				mask |=3D S_IRGRP;
-			if (accmode & VWRITE)
-				mask |=3D S_IWGRP;
-			return ((vmode & mask) =3D=3D mask ? 0 : EACCES);
-		}
+	if (groupmember(gid, cred)) {
+		if (accmode & VEXEC)
+			mask |=3D S_IXGRP;
+		if (accmode & VREAD)
+			mask |=3D S_IRGRP;
+		if (accmode & VWRITE)
+			mask |=3D S_IWGRP;
+		return ((vmode & mask) =3D=3D mask ? 0 : EACCES);
 	}
=20
 	/* check other */
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/gnu/fs/xfs/FreeBSD/xfs_compat.h ngro=
ups/sys/gnu/fs/xfs/FreeBSD/xfs_compat.h
--- /usr/src/sys/gnu/fs/xfs/FreeBSD/xfs_compat.h	2009-02-28 13:28:12.000000=
000 -0600
+++ ngroups/sys/gnu/fs/xfs/FreeBSD/xfs_compat.h	2009-06-05 15:33:54.0000000=
00 -0500
@@ -163,7 +163,7 @@
  * Cedentials manipulation.
  */
 #define current_fsuid(credp)	(credp)->cr_uid
-#define current_fsgid(credp)	(credp)->cr_groups[0]
+#define current_fsgid(credp)	(credp)->cr_gid
=20
 #define PAGE_CACHE_SIZE PAGE_SIZE
=20
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/gnu/fs/xfs/xfs_inode.c ngroups/sys/g=
nu/fs/xfs/xfs_inode.c
--- /usr/src/sys/gnu/fs/xfs/xfs_inode.c	2009-01-21 12:45:49.000000000 -0600
+++ ngroups/sys/gnu/fs/xfs/xfs_inode.c	2009-06-05 15:33:54.000000000 -0500
@@ -1124,7 +1124,7 @@
 	ip->i_d.di_nlink =3D nlink;
 	ASSERT(ip->i_d.di_nlink =3D=3D nlink);
 	ip->i_d.di_uid =3D curthread->td_ucred->cr_uid;
-	ip->i_d.di_gid =3D curthread->td_ucred->cr_groups[0];
+	ip->i_d.di_gid =3D curthread->td_ucred->cr_gid;
 	ip->i_d.di_projid =3D prid;
 	memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
=20
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/gnu/fs/xfs/xfs_vnodeops.c ngroups/sy=
s/gnu/fs/xfs/xfs_vnodeops.c
--- /usr/src/sys/gnu/fs/xfs/xfs_vnodeops.c	2009-01-21 12:45:49.000000000 -0=
600
+++ ngroups/sys/gnu/fs/xfs/xfs_vnodeops.c	2009-06-05 15:33:54.000000000 -05=
00
@@ -3379,7 +3379,7 @@
 	 */
 	error =3D XFS_QM_DQVOPALLOC(mp, dp,
 				  current->td_ucred->cr_uid,
-				  current->td_ucred->cr_groups[0],
+				  current->td_ucred->cr_gid,
 				  prid,
 				  XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
 	if (error)
Only in /usr/src/sys/i386/ibcs2: ibcs2_misc.c.orig
Only in /usr/src/sys/kern: kern_exec.c.orig
Only in /usr/src/sys/kern: kern_proc.c.orig
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/kern/kern_prot.c ngroups/sys/kern/ke=
rn_prot.c
--- /usr/src/sys/kern/kern_prot.c	2009-06-05 15:33:50.000000000 -0500
+++ ngroups/sys/kern/kern_prot.c	2009-06-05 16:02:28.000000000 -0500
@@ -82,6 +82,9 @@
=20
 SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy"=
);
=20
+static __inline void crsetgroups_locked(struct ucred *cr, int ngrp,
+    gid_t *groups);
+
 #ifndef _SYS_SYSPROTO_H_
 struct getpid_args {
 	int	dummy;
@@ -243,16 +246,11 @@
=20
 	td->td_retval[0] =3D td->td_ucred->cr_rgid;
 #if defined(COMPAT_43)
-	td->td_retval[1] =3D td->td_ucred->cr_groups[0];
+	td->td_retval[1] =3D td->td_ucred->cr_gid;
 #endif
 	return (0);
 }
=20
-/*
- * Get effective group ID.  The "egid" is groups[0], and could be obtained
- * via getgroups.  This syscall exists because it is somewhat painful to do
- * correctly in a library function.
- */
 #ifndef _SYS_SYSPROTO_H_
 struct getegid_args {
         int     dummy;
@@ -263,7 +261,7 @@
 getegid(struct thread *td, struct getegid_args *uap)
 {
=20
-	td->td_retval[0] =3D td->td_ucred->cr_groups[0];
+	td->td_retval[0] =3D td->td_ucred->cr_gid;
 	return (0);
 }
=20
@@ -679,7 +677,7 @@
 	    gid !=3D oldcred->cr_svgid &&		/* allow setgid(saved gid) */
 #endif
 #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
-	    gid !=3D oldcred->cr_groups[0] && /* allow setgid(getegid()) */
+	    gid !=3D oldcred->cr_gid && /* allow setgid(getegid()) */
 #endif
 	    (error =3D priv_check_cred(oldcred, PRIV_CRED_SETGID, 0)) !=3D 0)
 		goto fail;
@@ -691,7 +689,7 @@
 	 */
 	if (
 #ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
-	    gid =3D=3D oldcred->cr_groups[0] ||
+	    gid =3D=3D oldcred->cr_gid ||
 #endif
 	    /* We are using privs. */
 	    priv_check_cred(oldcred, PRIV_CRED_SETGID, 0) =3D=3D 0)
@@ -720,7 +718,7 @@
 	 * In all cases permitted cases, we are changing the egid.
 	 * Copy credentials so other references do not see our changes.
 	 */
-	if (oldcred->cr_groups[0] !=3D gid) {
+	if (oldcred->cr_gid !=3D gid) {
 		change_egid(newcred, gid);
 		setsugid(p);
 	}
@@ -766,7 +764,7 @@
 	    (error =3D priv_check_cred(oldcred, PRIV_CRED_SETEGID, 0)) !=3D 0)
 		goto fail;
=20
-	if (oldcred->cr_groups[0] !=3D egid) {
+	if (oldcred->cr_gid !=3D egid) {
 		change_egid(newcred, egid);
 		setsugid(p);
 	}
@@ -811,7 +809,6 @@
 {
 	struct proc *p =3D td->td_proc;
 	struct ucred *newcred, *oldcred;
-	int newgroups;
 	int error;
=20
 	if (ngrp > NGROUPS)
@@ -820,16 +817,7 @@
 	newcred =3D crget();
 	crextend(newcred, ngrp);
 	PROC_LOCK(p);
-	oldcred =3D p->p_ucred;
-	newgroups =3D MAX(oldcred->cr_agroups, ngrp);
-	while (newcred->cr_agroups < newgroups) {
-		PROC_UNLOCK(p);
-		crextend(newcred, newgroups);
-		PROC_LOCK(p);
-		oldcred =3D p->p_ucred;
-		newgroups =3D MAX(oldcred->cr_agroups, ngrp);
-	}
-
+	oldcred =3D crcopysafe(p, newcred);
=20
 #ifdef MAC
 	error =3D mac_cred_check_setgroups(oldcred, ngrp, groups);
@@ -841,7 +829,6 @@
 	if (error)
 		goto fail;
=20
-	crcopy(newcred, oldcred);
 	if (ngrp < 1) {
 		/*
 		 * setgroups(0, NULL) is a legitimate way of clearing the
@@ -851,8 +838,7 @@
 		 */
 		newcred->cr_ngroups =3D 1;
 	} else {
-		bcopy(groups, newcred->cr_groups, ngrp * sizeof(gid_t));
-		newcred->cr_ngroups =3D ngrp;
+		crsetgroups_locked(newcred, ngrp, groups);
 	}
 	setsugid(p);
 	p->p_ucred =3D newcred;
@@ -964,12 +950,12 @@
=20
 	if (((rgid !=3D (gid_t)-1 && rgid !=3D oldcred->cr_rgid &&
 	    rgid !=3D oldcred->cr_svgid) ||
-	     (egid !=3D (gid_t)-1 && egid !=3D oldcred->cr_groups[0] &&
+	     (egid !=3D (gid_t)-1 && egid !=3D oldcred->cr_gid &&
 	     egid !=3D oldcred->cr_rgid && egid !=3D oldcred->cr_svgid)) &&
 	    (error =3D priv_check_cred(oldcred, PRIV_CRED_SETREGID, 0)) !=3D 0)
 		goto fail;
=20
-	if (egid !=3D (gid_t)-1 && oldcred->cr_groups[0] !=3D egid) {
+	if (egid !=3D (gid_t)-1 && oldcred->cr_gid !=3D egid) {
 		change_egid(newcred, egid);
 		setsugid(p);
 	}
@@ -977,9 +963,9 @@
 		change_rgid(newcred, rgid);
 		setsugid(p);
 	}
-	if ((rgid !=3D (gid_t)-1 || newcred->cr_groups[0] !=3D newcred->cr_rgid) =
&&
-	    newcred->cr_svgid !=3D newcred->cr_groups[0]) {
-		change_svgid(newcred, newcred->cr_groups[0]);
+	if ((rgid !=3D (gid_t)-1 || newcred->cr_gid !=3D newcred->cr_rgid) &&
+	    newcred->cr_svgid !=3D newcred->cr_gid) {
+		change_svgid(newcred, newcred->cr_gid);
 		setsugid(p);
 	}
 	p->p_ucred =3D newcred;
@@ -1110,17 +1096,17 @@
=20
 	if (((rgid !=3D (gid_t)-1 && rgid !=3D oldcred->cr_rgid &&
 	      rgid !=3D oldcred->cr_svgid &&
-	      rgid !=3D oldcred->cr_groups[0]) ||
+	      rgid !=3D oldcred->cr_gid) ||
 	     (egid !=3D (gid_t)-1 && egid !=3D oldcred->cr_rgid &&
 	      egid !=3D oldcred->cr_svgid &&
-	      egid !=3D oldcred->cr_groups[0]) ||
+	      egid !=3D oldcred->cr_gid) ||
 	     (sgid !=3D (gid_t)-1 && sgid !=3D oldcred->cr_rgid &&
 	      sgid !=3D oldcred->cr_svgid &&
-	      sgid !=3D oldcred->cr_groups[0])) &&
+	      sgid !=3D oldcred->cr_gid)) &&
 	    (error =3D priv_check_cred(oldcred, PRIV_CRED_SETRESGID, 0)) !=3D 0)
 		goto fail;
=20
-	if (egid !=3D (gid_t)-1 && oldcred->cr_groups[0] !=3D egid) {
+	if (egid !=3D (gid_t)-1 && oldcred->cr_gid !=3D egid) {
 		change_egid(newcred, egid);
 		setsugid(p);
 	}
@@ -1189,8 +1175,8 @@
 		error1 =3D copyout(&cred->cr_rgid,
 		    uap->rgid, sizeof(cred->cr_rgid));
 	if (uap->egid)
-		error2 =3D copyout(&cred->cr_groups[0],
-		    uap->egid, sizeof(cred->cr_groups[0]));
+		error2 =3D copyout(&cred->cr_gid,
+		    uap->egid, sizeof(cred->cr_gid));
 	if (uap->sgid)
 		error3 =3D copyout(&cred->cr_svgid,
 		    uap->sgid, sizeof(cred->cr_svgid));
@@ -1911,7 +1897,7 @@
 	ngroups =3D min(cr->cr_ngroups, XU_NGROUPS);
 	xcr->cr_ngroups =3D ngroups;
 	bcopy(cr->cr_groups, xcr->cr_groups,
-	    ngroups * sizeof(cr->cr_groups[0]));
+	    ngroups * sizeof(*cr->cr_groups));
 }
=20
 /*
@@ -1969,6 +1955,8 @@
 	/*
 	 * We extend by 2 each time since we're using a power of two
 	 * allocator.
+	 * XXX: it probably makes more sense to right-size the
+	 * allocation if we need more than a page.
 	 */
 	if (cr->cr_agroups)
 		cnt =3D cr->cr_agroups * 2;
@@ -1987,6 +1975,36 @@
 }
=20
 /*
+ * Copy groups in to a credential, preserving any necessicary invariants
+ * (i.e. sorting in the future).  crextend() must have been called
+ * before hand to ensure sufficient space is available.  If=20
+ */
+static inline void
+crsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups)
+{
+=09
+	KASSERT(cr->cr_agroups >=3D ngrp, ("cr_ngroups is too small"));
+
+	bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t));
+	cr->cr_ngroups =3D ngrp;
+}
+
+/*
+ * Copy groups in to a credential after expanding it if required.
+ * Truncate the list to NGROUPS if it is too large.
+ */
+void
+crsetgroups(struct ucred *cr, int ngrp, gid_t *groups)
+{
+
+	if (ngrp > NGROUPS)
+		ngrp =3D NGROUPS;
+
+	crextend(cr, ngrp);
+	crsetgroups_locked(cr, ngrp, groups);
+}
+
+/*
  * Get login name, if available.
  */
 #ifndef _SYS_SYSPROTO_H_
@@ -2083,7 +2101,7 @@
 change_egid(struct ucred *newcred, gid_t egid)
 {
=20
-	newcred->cr_groups[0] =3D egid;
+	newcred->cr_gid =3D egid;
 }
=20
 /*-
Only in /usr/src/sys/kern: kern_prot.c.orig
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/kern/vfs_export.c ngroups/sys/kern/v=
fs_export.c
--- /usr/src/sys/kern/vfs_export.c	2009-05-29 12:48:02.000000000 -0500
+++ ngroups/sys/kern/vfs_export.c	2009-06-05 15:33:54.000000000 -0500
@@ -120,9 +120,8 @@
 		np->netc_exflags =3D argp->ex_flags;
 		np->netc_anon =3D crget();
 		np->netc_anon->cr_uid =3D argp->ex_anon.cr_uid;
-		np->netc_anon->cr_ngroups =3D argp->ex_anon.cr_ngroups;
-		bcopy(argp->ex_anon.cr_groups, np->netc_anon->cr_groups,
-		    sizeof(np->netc_anon->cr_groups));
+		crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups,
+		    argp->ex_anon.cr_groups);
 		np->netc_numsecflavors =3D argp->ex_numsecflavors;
 		bcopy(argp->ex_secflavors, np->netc_secflavors,
 		    sizeof(np->netc_secflavors));
@@ -205,9 +204,8 @@
 	np->netc_exflags =3D argp->ex_flags;
 	np->netc_anon =3D crget();
 	np->netc_anon->cr_uid =3D argp->ex_anon.cr_uid;
-	np->netc_anon->cr_ngroups =3D argp->ex_anon.cr_ngroups;
-	bcopy(argp->ex_anon.cr_groups, np->netc_anon->cr_groups,
-	    sizeof(np->netc_anon->cr_groups));
+	crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups,
+	    np->netc_anon->cr_groups);
 	np->netc_numsecflavors =3D argp->ex_numsecflavors;
 	bcopy(argp->ex_secflavors, np->netc_secflavors,
 	    sizeof(np->netc_secflavors));
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/kern/vfs_syscalls.c ngroups/sys/kern=
/vfs_syscalls.c
--- /usr/src/sys/kern/vfs_syscalls.c	2009-06-05 15:33:50.000000000 -0500
+++ ngroups/sys/kern/vfs_syscalls.c	2009-06-05 16:02:28.000000000 -0500
@@ -2128,7 +2128,7 @@
 		cred =3D td->td_ucred;
 		tmpcred =3D crdup(cred);
 		tmpcred->cr_uid =3D cred->cr_ruid;
-		tmpcred->cr_groups[0] =3D cred->cr_rgid;
+		tmpcred->cr_gid =3D cred->cr_rgid;
 		td->td_ucred =3D tmpcred;
 	} else
 		cred =3D tmpcred =3D td->td_ucred;
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/netinet/ipfw/ip_fw2.c ngroups/sys/ne=
tinet/ipfw/ip_fw2.c
--- /usr/src/sys/netinet/ipfw/ip_fw2.c	2009-06-05 15:33:50.000000000 -0500
+++ ngroups/sys/netinet/ipfw/ip_fw2.c	2009-06-05 16:02:28.000000000 -0500
@@ -139,8 +139,9 @@
  * the user specified UID/GID based constraints in
  * a firewall rule.
  */
+#define	FW_NGROUPS	16
 struct ip_fw_ugid {
-	gid_t		fw_groups[NGROUPS];
+	gid_t		fw_groups[FW_NGROUPS];	/* XXX: should be dynamic */
 	int		fw_ngroups;
 	uid_t		fw_uid;
 	int		fw_prid;
@@ -2016,8 +2017,8 @@
 	cr =3D inp->inp_cred;
 	ugp->fw_prid =3D jailed(cr) ? cr->cr_prison->pr_id : -1;
 	ugp->fw_uid =3D cr->cr_uid;
-	ugp->fw_ngroups =3D cr->cr_ngroups;
-	bcopy(cr->cr_groups, ugp->fw_groups, sizeof(ugp->fw_groups));
+	ugp->fw_ngroups =3D MIN(cr->cr_ngroups, FW_NGROUPS);
+	bcopy(cr->cr_groups, ugp->fw_groups, sizeof(gid_t) * ugp->fw_ngroups);
 }
=20
 static int
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/netncp/ncp_conn.c ngroups/sys/netncp=
/ncp_conn.c
--- /usr/src/sys/netncp/ncp_conn.c	2009-01-22 10:06:17.000000000 -0600
+++ ngroups/sys/netncp/ncp_conn.c	2009-06-05 15:33:54.000000000 -0500
@@ -249,7 +249,7 @@
 	ncp->connid =3D 0xFFFF;
 	ncp->li =3D *cap;
 	ncp->nc_group =3D (cap->group !=3D NCP_DEFAULT_GROUP) ?
-		cap->group : cred->cr_groups[0];
+		cap->group : cred->cr_gid;
=20
 	if (cap->retry_count =3D=3D 0)
 		ncp->li.retry_count =3D NCP_RETRY_COUNT;
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/netsmb/smb_conn.c ngroups/sys/netsmb=
/smb_conn.c
--- /usr/src/sys/netsmb/smb_conn.c	2009-01-22 10:06:17.000000000 -0600
+++ ngroups/sys/netsmb/smb_conn.c	2009-06-05 15:33:54.000000000 -0500
@@ -416,7 +416,7 @@
 	if (uid =3D=3D SMBM_ANY_OWNER)
 		uid =3D realuid;
 	if (gid =3D=3D SMBM_ANY_GROUP)
-		gid =3D cred->cr_groups[0];
+		gid =3D cred->cr_gid;
 	vcp->vc_uid =3D uid;
 	vcp->vc_grp =3D gid;
=20
@@ -714,7 +714,7 @@
 	if (uid =3D=3D SMBM_ANY_OWNER)
 		uid =3D realuid;
 	if (gid =3D=3D SMBM_ANY_GROUP)
-		gid =3D cred->cr_groups[0];
+		gid =3D cred->cr_gid;
 	ssp =3D smb_zmalloc(sizeof(*ssp), M_SMBCONN, M_WAITOK);
 	smb_co_init(SSTOCP(ssp), SMBL_SHARE, "smbss ilock", "smbss");
 	ssp->obj.co_free =3D smb_share_free;
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/nfsclient/nfs_subs.c ngroups/sys/nfs=
client/nfs_subs.c
--- /usr/src/sys/nfsclient/nfs_subs.c	2009-05-29 12:48:02.000000000 -0500
+++ ngroups/sys/nfsclient/nfs_subs.c	2009-06-05 15:33:54.000000000 -0500
@@ -253,7 +253,7 @@
 		*tl++ =3D 0;		/* stamp ?? */
 		*tl++ =3D 0;		/* NULL hostname */
 		*tl++ =3D txdr_unsigned(cr->cr_uid);
-		*tl++ =3D txdr_unsigned(cr->cr_groups[0]);
+		*tl++ =3D txdr_unsigned(cr->cr_gid);
 		grpsiz =3D (auth_len >> 2) - 5;
 		*tl++ =3D txdr_unsigned(grpsiz);
 		for (i =3D 1; i <=3D grpsiz; i++)
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/nfsserver/nfs_srvsock.c ngroups/sys/=
nfsserver/nfs_srvsock.c
--- /usr/src/sys/nfsserver/nfs_srvsock.c	2009-06-05 15:33:51.000000000 -0500
+++ ngroups/sys/nfsserver/nfs_srvsock.c	2009-06-05 16:02:29.000000000 -0500
@@ -358,7 +358,7 @@
 		tl =3D nfsm_dissect_nonblock(u_int32_t *, 3 * NFSX_UNSIGNED);
 		nd->nd_cr->cr_uid =3D nd->nd_cr->cr_ruid =3D
 		    nd->nd_cr->cr_svuid =3D fxdr_unsigned(uid_t, *tl++);
-		nd->nd_cr->cr_groups[0] =3D nd->nd_cr->cr_rgid =3D
+		nd->nd_cr->cr_gid =3D nd->nd_cr->cr_rgid =3D
 		    nd->nd_cr->cr_svgid =3D fxdr_unsigned(gid_t, *tl++);
 #ifdef MAC
 		mac_cred_associate_nfsd(nd->nd_cr);
@@ -374,7 +374,7 @@
 			nd->nd_cr->cr_groups[i] =3D fxdr_unsigned(gid_t, *tl++);
 		    else
 			tl++;
-		nd->nd_cr->cr_ngroups =3D (len >=3D XU_NGROUPS) ? XU_NGROUPS : (len + 1);
+		nd->nd_cr->cr_ngroups =3D MIN(XU_NGROUPS, len + 1);
 		if (nd->nd_cr->cr_ngroups > 1)
 		    nfsrvw_sort(nd->nd_cr->cr_groups, nd->nd_cr->cr_ngroups);
 		len =3D fxdr_unsigned(int, *++tl);
Only in /usr/src/sys/nfsserver: nfs_srvsock.c.orig
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/nfsserver/nfs_srvsubs.c ngroups/sys/=
nfsserver/nfs_srvsubs.c
--- /usr/src/sys/nfsserver/nfs_srvsubs.c	2009-05-29 12:48:04.000000000 -0500
+++ ngroups/sys/nfsserver/nfs_srvsubs.c	2009-06-05 15:33:54.000000000 -0500
@@ -1181,9 +1181,7 @@
 	cred =3D nfsd->nd_cr;
 	if (cred->cr_uid =3D=3D 0 || (exflags & MNT_EXPORTANON)) {
 		cred->cr_uid =3D credanon->cr_uid;
-		for (i =3D 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
-			cred->cr_groups[i] =3D credanon->cr_groups[i];
-		cred->cr_ngroups =3D i;
+		crsetgroups(cred, credanon->cr_ngroups, credanon->cr_groups);
 	}
 	if (exflags & MNT_EXRDONLY)
 		*rdonlyp =3D 1;
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/rpc/authunix_prot.c ngroups/sys/rpc/=
authunix_prot.c
--- /usr/src/sys/rpc/authunix_prot.c	2009-06-05 15:33:49.000000000 -0500
+++ ngroups/sys/rpc/authunix_prot.c	2009-06-05 16:02:28.000000000 -0500
@@ -98,7 +98,7 @@
=20
 	if (!xdr_uint32_t(xdrs, &cred->cr_uid))
 		return (FALSE);
-	if (!xdr_uint32_t(xdrs, &cred->cr_groups[0]))
+	if (!xdr_uint32_t(xdrs, &cred->cr_gid))
 		return (FALSE);
=20
 	if (xdrs->x_op =3D=3D XDR_ENCODE) {
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c ngro=
ups/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c
--- /usr/src/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c	2009-01-22 10:05:57.000000=
000 -0600
+++ ngroups/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c	2009-06-05 15:33:54.0000000=
00 -0500
@@ -447,11 +447,7 @@
 	cr =3D client->cl_cred =3D crget();
 	cr->cr_uid =3D cr->cr_ruid =3D cr->cr_svuid =3D uc->uid;
 	cr->cr_rgid =3D cr->cr_svgid =3D uc->gid;
-	cr->cr_ngroups =3D uc->gidlen;
-	if (cr->cr_ngroups > NGROUPS)
-		cr->cr_ngroups =3D NGROUPS;
-	for (i =3D 0; i < cr->cr_ngroups; i++)
-		cr->cr_groups[i] =3D uc->gidlist[i];
+	crsetgroups(cr, uc->gidlen, uc->gidlist);
 	*crp =3D crhold(cr);
=20
 	return (TRUE);
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/rpc/svc_auth.c ngroups/sys/rpc/svc_a=
uth.c
--- /usr/src/sys/rpc/svc_auth.c	2009-01-22 10:05:57.000000000 -0600
+++ ngroups/sys/rpc/svc_auth.c	2009-06-05 15:33:54.000000000 -0500
@@ -165,7 +165,7 @@
 svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp)
 {
 	struct ucred *cr =3D NULL;
-	int flavor, i;
+	int flavor;
 	struct xucred *xcr;
=20
 	flavor =3D rqst->rq_cred.oa_flavor;
@@ -177,10 +177,8 @@
 		xcr =3D (struct xucred *) rqst->rq_clntcred;
 		cr =3D crget();
 		cr->cr_uid =3D cr->cr_ruid =3D cr->cr_svuid =3D xcr->cr_uid;
-		cr->cr_ngroups =3D xcr->cr_ngroups;
-		for (i =3D 0; i < xcr->cr_ngroups; i++)
-			cr->cr_groups[i] =3D xcr->cr_groups[i];
-		cr->cr_rgid =3D cr->cr_svgid =3D cr->cr_groups[0];
+		crsetgroups(cr, xcr->cr_ngroups, xcr->cr_groups);
+		cr->cr_rgid =3D cr->cr_svgid =3D cr->cr_gid;
 		*crp =3D cr;
 		return (TRUE);
=20
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/rpc/svc_auth_unix.c ngroups/sys/rpc/=
svc_auth_unix.c
--- /usr/src/sys/rpc/svc_auth_unix.c	2009-01-22 10:05:57.000000000 -0600
+++ ngroups/sys/rpc/svc_auth_unix.c	2009-06-05 15:33:54.000000000 -0500
@@ -88,20 +88,20 @@
 		str_len =3D RNDUP(str_len);
 		buf +=3D str_len / sizeof (int32_t);
 		xcr->cr_uid =3D IXDR_GET_UINT32(buf);
-		xcr->cr_groups[0] =3D IXDR_GET_UINT32(buf);
+		xcr->cr_gid =3D IXDR_GET_UINT32(buf);
 		gid_len =3D (size_t)IXDR_GET_UINT32(buf);
 		if (gid_len > NGRPS) {
 			stat =3D AUTH_BADCRED;
 			goto done;
 		}
 		for (i =3D 0; i < gid_len; i++) {
-			if (i + 1 < NGROUPS)
+			if (i + 1 < XU_NGROUPS)
 				xcr->cr_groups[i + 1] =3D IXDR_GET_INT32(buf);
 			else
 				buf++;
 		}
-		if (gid_len + 1 > NGROUPS)
-			xcr->cr_ngroups =3D NGROUPS;
+		if (gid_len + 1 > XU_NGROUPS)
+			xcr->cr_ngroups =3D XU_NGROUPS;
 		else
 			xcr->cr_ngroups =3D gid_len + 1;
=20
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/security/audit/audit.c ngroups/sys/s=
ecurity/audit/audit.c
--- /usr/src/sys/security/audit/audit.c	2009-04-24 10:41:08.000000000 -0500
+++ ngroups/sys/security/audit/audit.c	2009-06-05 15:33:54.000000000 -0500
@@ -224,7 +224,7 @@
 	cru2x(cred, &ar->k_ar.ar_subj_cred);
 	ar->k_ar.ar_subj_ruid =3D cred->cr_ruid;
 	ar->k_ar.ar_subj_rgid =3D cred->cr_rgid;
-	ar->k_ar.ar_subj_egid =3D cred->cr_groups[0];
+	ar->k_ar.ar_subj_egid =3D cred->cr_gid;
 	ar->k_ar.ar_subj_auid =3D cred->cr_audit.ai_auid;
 	ar->k_ar.ar_subj_asid =3D cred->cr_audit.ai_asid;
 	ar->k_ar.ar_subj_pid =3D td->td_proc->p_pid;
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/security/audit/audit_arg.c ngroups/s=
ys/security/audit/audit_arg.c
--- /usr/src/sys/security/audit/audit_arg.c	2009-01-22 10:06:21.000000000 -=
0600
+++ ngroups/sys/security/audit/audit_arg.c	2009-06-05 15:33:54.000000000 -0=
500
@@ -369,7 +369,7 @@
 	cred =3D p->p_ucred;
 	ar->k_ar.ar_arg_auid =3D cred->cr_audit.ai_auid;
 	ar->k_ar.ar_arg_euid =3D cred->cr_uid;
-	ar->k_ar.ar_arg_egid =3D cred->cr_groups[0];
+	ar->k_ar.ar_arg_egid =3D cred->cr_gid;
 	ar->k_ar.ar_arg_ruid =3D cred->cr_ruid;
 	ar->k_ar.ar_arg_rgid =3D cred->cr_rgid;
 	ar->k_ar.ar_arg_asid =3D cred->cr_audit.ai_asid;
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/sys/syslimits.h ngroups/sys/sys/sysl=
imits.h
--- /usr/src/sys/sys/syslimits.h	2009-01-22 10:06:22.000000000 -0600
+++ ngroups/sys/sys/syslimits.h	2009-06-05 15:34:15.000000000 -0500
@@ -54,7 +54,7 @@
 #define	MAX_CANON		  255	/* max bytes in term canon input line */
 #define	MAX_INPUT		  255	/* max bytes in terminal input */
 #define	NAME_MAX		  255	/* max bytes in a file name */
-#define	NGROUPS_MAX		   16	/* max supplemental group id's */
+#define	NGROUPS_MAX	 	32767	/* max supplemental group id's */
 #ifndef OPEN_MAX
 #define	OPEN_MAX		   64	/* max open files per process */
 #endif
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/sys/ucred.h ngroups/sys/sys/ucred.h
--- /usr/src/sys/sys/ucred.h	2009-06-05 15:33:54.000000000 -0500
+++ ngroups/sys/sys/ucred.h	2009-06-05 16:02:34.000000000 -0500
@@ -48,7 +48,7 @@
 	uid_t	cr_uid;			/* effective user id */
 	uid_t	cr_ruid;		/* real user id */
 	uid_t	cr_svuid;		/* saved user id */
-	short	cr_ngroups;		/* number of groups */
+	int	cr_ngroups;		/* number of groups */
 	gid_t	cr_rgid;		/* real group id */
 	gid_t	cr_svgid;		/* saved group id */
 	struct uidinfo	*cr_uidinfo;	/* per euid resource consumption */
@@ -61,7 +61,7 @@
 	struct label	*cr_label;	/* MAC label */
 	struct auditinfo_addr	cr_audit;	/* Audit properties. */
 	gid_t	*cr_groups;		/* groups */
-	short	cr_agroups;		/* Available groups */
+	int	cr_agroups;		/* Available groups */
 };
 #define	NOCRED	((struct ucred *)0)	/* no credential available */
 #define	FSCRED	((struct ucred *)-1)	/* filesystem credential */
@@ -77,11 +77,9 @@
 	uid_t	cr_uid;			/* effective user id */
 	short	cr_ngroups;		/* number of groups */
 	gid_t	cr_groups[XU_NGROUPS];	/* groups */
+	void	*_cr_unused1;		/* compatibility with old ucred */
 };
-#define	XUCRED_VERSION	2
-
-#define XUCRED_SIZE(n)        \
-	(sizeof(struct xucred) + (MAX((n)-XU_NGROUPS, 0) * sizeof(gid_t)))
+#define	XUCRED_VERSION	0
=20
 /* This can be used for both ucred and xucred structures. */
 #define	cr_gid cr_groups[0]
@@ -97,7 +95,7 @@
 void	change_svgid(struct ucred *newcred, gid_t svgid);
 void	change_svuid(struct ucred *newcred, uid_t svuid);
 void	crcopy(struct ucred *dest, struct ucred *src);
-struct ucred	*crcopysafe(struct proc *, struct ucred *);
+struct ucred	*crcopysafe(struct proc *p, struct ucred *cr);
 struct ucred	*crdup(struct ucred *cr);
 void	cred_update_thread(struct thread *td);
 void	crfree(struct ucred *cr);
@@ -106,6 +104,7 @@
 int	crshared(struct ucred *cr);
 void	cru2x(struct ucred *cr, struct xucred *xcr);
 void	crextend(struct ucred *cr, int n);
+void	crsetgroups(struct ucred *cr, int n, gid_t *groups);
 int	groupmember(gid_t gid, struct ucred *cred);
 #endif /* _KERNEL */
=20
Only in /usr/src/sys/sys: ucred.h.orig
Only in /usr/src/sys/sys: user.h.diff
Only in /usr/src/sys/sys: user.h.orig
Only in /usr/src/sys/sys: user.h.rej.orig
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/sys/ufs/ufs/ufs_vnops.c ngroups/sys/ufs/=
ufs/ufs_vnops.c
--- /usr/src/sys/ufs/ufs/ufs_vnops.c	2009-06-05 15:33:49.000000000 -0500
+++ ngroups/sys/ufs/ufs/ufs_vnops.c	2009-06-05 16:02:28.000000000 -0500
@@ -1475,7 +1475,7 @@
 				refcount_init(&ucred.cr_ref, 1);
 				ucred.cr_uid =3D ip->i_uid;
 				ucred.cr_ngroups =3D 1;
-				ucred.cr_groups[0] =3D dp->i_gid;
+				ucred.cr_gid =3D dp->i_gid;
 				ucp =3D &ucred;
 			}
 #endif
@@ -2266,6 +2266,7 @@
 	{
 #ifdef QUOTA
 		struct ucred ucred, *ucp;
+		gid_t ucred_group;
 		ucp =3D cnp->cn_cred;
 #endif
 		/*
@@ -2292,7 +2293,8 @@
 			refcount_init(&ucred.cr_ref, 1);
 			ucred.cr_uid =3D ip->i_uid;
 			ucred.cr_ngroups =3D 1;
-			ucred.cr_groups[0] =3D pdir->i_gid;
+			ucred.cr_groups =3D &ucred_group;
+			ucred.cr_gid =3D pdir->i_gid;
 			ucp =3D &ucred;
 #endif
 		} else {
diff -ru --exclude=3D'.glimpse*' --exclude=3D.svn --exclude=3Dcompile --ign=
ore-matching=3D'$FreeBSD' /usr/src/usr.sbin/mountd/mountd.c ngroups/usr.sbi=
n/mountd/mountd.c
--- /usr/src/usr.sbin/mountd/mountd.c	2009-05-29 12:47:59.000000000 -0500
+++ ngroups/usr.sbin/mountd/mountd.c	2009-05-28 17:11:49.000000000 -0500
@@ -174,7 +174,7 @@
 int	do_mount(struct exportlist *, struct grouplist *, int,
 		struct xucred *, char *, int, struct statfs *);
 int	do_opt(char **, char **, struct exportlist *, struct grouplist *,
-				int *, int *, struct xucred **);
+				int *, int *, struct xucred *);
 struct	exportlist *ex_search(fsid_t *);
 struct	exportlist *get_exp(void);
 void	free_dir(struct dirlist *);
@@ -196,7 +196,7 @@
 void	mntsrv(struct svc_req *, SVCXPRT *);
 void	nextfield(char **, char **);
 void	out_of_mem(void);
-void	parsecred(char *, struct xucred **);
+void	parsecred(char *, struct xucred *);
 int	put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int);
 void	*sa_rawaddr(struct sockaddr *sa, int *nbytes);
 int	sacmp(struct sockaddr *sa1, struct sockaddr *sa2,
@@ -221,6 +221,7 @@
 	(uid_t)-2,
 	1,
 	{ (gid_t)-2 },
+	NULL
 };
 int force_v2 =3D 0;
 int resvport_only =3D 1;
@@ -1167,7 +1168,7 @@
 	struct exportlist **epp;
 	struct dirlist *dirhead;
 	struct statfs fsb;
-	struct xucred *anon;
+	struct xucred anon;
 	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
 	int len, has_host, exflags, got_nondir, dirplen, netgrp;
=20
@@ -1185,7 +1186,7 @@
 		 * Set defaults.
 		 */
 		has_host =3D FALSE;
-		anon =3D &def_anon;
+		anon =3D def_anon;
 		exflags =3D MNT_EXPORTED;
 		got_nondir =3D 0;
 		opt_flags =3D 0;
@@ -1403,7 +1404,7 @@
 		 */
 		grp =3D tgrp;
 		do {
-			if (do_mount(ep, grp, exflags, anon, dirp, dirplen,
+			if (do_mount(ep, grp, exflags, &anon, dirp, dirplen,
 			    &fsb)) {
 				getexp_err(ep, tgrp);
 				goto nextline;
@@ -1956,7 +1957,7 @@
 	struct grouplist *grp;
 	int *has_hostp;
 	int *exflagsp;
-	struct xucred **cr;
+	struct xucred *cr;
 {
 	char *cpoptarg, *cpoptend;
 	char *cp, *endcp, *cpopt, savedc, savedc2;
@@ -2420,33 +2421,6 @@
 	return (ret);
 }
=20
-static void
-xcr_grow(struct xucred **cr, int *cr_ngroups, int desired_groups)
-{
-	struct xucred *in =3D *cr, *out;
-	int n;
-
-	if (in && *cr_ngroups > desired_groups)
-		return;
-
-	n =3D MAX(XU_NGROUPS, *cr_ngroups);
-	while (n < desired_groups)
-		n *=3D 2;
-
-	out =3D malloc(XUCRED_SIZE(n));
-	if (out =3D=3D NULL)
-		out_of_mem();
-
-	if (in) {
-		memcpy(out, in, XUCRED_SIZE(*cr_ngroups));
-		if (in !=3D &def_anon)
-			free(in);
-	}
-
-	*cr =3D out;
-	*cr_ngroups =3D n;
-}
-
 /*
  * Translate a net address.
  *
@@ -2654,20 +2628,18 @@
  * Parse a description of a credential.
  */
 void
-parsecred(namelist, cr_out)
+parsecred(namelist, cr)
 	char *namelist;
-	struct xucred **cr_out;
+	struct xucred *cr;
 {
 	char *name;
+	int cnt;
 	char *names;
 	struct passwd *pw;
 	struct group *gr;
+	gid_t groups[NGRPS + 1];
 	int ngroups;
-	struct xucred *cr =3D NULL;
-	int cr_ngroups =3D 0;
-	int error;
=20
-	xcr_grow(&cr, &cr_ngroups, 0);
 	cr->cr_version =3D XUCRED_VERSION;
 	/*
 	 * Set up the unprivileged user.
@@ -2690,20 +2662,20 @@
 	if (names =3D=3D NULL) {
 		if (pw =3D=3D NULL) {
 			syslog(LOG_ERR, "unknown user: %s", name);
-			goto out;
+			return;
 		}
 		cr->cr_uid =3D pw->pw_uid;
-		for (;;) {
-			ngroups =3D cr_ngroups;
-			error =3D getgrouplist(pw->pw_name, pw->pw_gid,
-			    cr->cr_groups, &ngroups);
-			if (!error)
-				break;
-			xcr_grow(&cr, &cr_ngroups, ngroups);
-		}
-		cr->cr_ngroups =3D ngroups;
-
-		goto out;
+		ngroups =3D NGRPS + 1;
+		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
+			syslog(LOG_ERR, "too many groups");
+		/*
+		 * Compress out duplicate.
+		 */
+		cr->cr_ngroups =3D ngroups - 1;
+		cr->cr_groups[0] =3D groups[0];
+		for (cnt =3D 2; cnt < ngroups; cnt++)
+			cr->cr_groups[cnt - 1] =3D groups[cnt];
+		return;
 	}
 	/*
 	 * Explicit credential specified as a colon separated list:
@@ -2715,11 +2687,10 @@
 		cr->cr_uid =3D atoi(name);
 	else {
 		syslog(LOG_ERR, "unknown user: %s", name);
-		goto out;
+		return;
 	}
 	cr->cr_ngroups =3D 0;
-	while (names !=3D NULL && *names !=3D '\0') {
-		xcr_grow(&cr, &cr_ngroups, cr->cr_ngroups + 1);
+	while (names !=3D NULL && *names !=3D '\0' && cr->cr_ngroups < NGRPS) {
 		name =3D strsep(&names, ":");
 		if (isdigit(*name) || *name =3D=3D '-') {
 			cr->cr_groups[cr->cr_ngroups++] =3D atoi(name);
@@ -2731,9 +2702,8 @@
 			cr->cr_groups[cr->cr_ngroups++] =3D gr->gr_gid;
 		}
 	}
-
- out:
-	*cr_out =3D cr;
+	if (names !=3D NULL && *names !=3D '\0' && cr->cr_ngroups =3D=3D NGRPS)
+		syslog(LOG_ERR, "too many groups");
 }
=20
 #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)

--sdtB3X0nJg68CQEu--

--i9LlY+UWpKt15+FH
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (FreeBSD)

iD8DBQFKKZ3zXY6L6fI4GtQRAmZIAJ9vmvoOMbiS30WRBzsHqpjAx+fdMQCg21bB
l7/uY3WXqja2MHK21xWk4a4=
=acSA
-----END PGP SIGNATURE-----

--i9LlY+UWpKt15+FH--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090605223636.GA24364>