NGROUPS_MAX on Linux
Tim Hockin
thockin at sun.com
Fri Feb 20 11:19:53 EST 2004
Linux has just raised the NGROUPS_MAX limit from 32 to 64k. In doing an
audit of various tools, openssh turned up as having incorrect groups
handling. Almost no user-space apps really care about NGROUPS_MAX.
A proposed patch (untested, since the CVS build won't compile on my RH box..
:-/) :
What think?
Index: uidswap.c
===================================================================
RCS file: /cvs/openssh/uidswap.c,v
retrieving revision 1.42
diff -u -u -r1.42 uidswap.c
--- uidswap.c 17 Dec 2003 07:53:26 -0000 1.42
+++ uidswap.c 19 Feb 2004 23:50:38 -0000
@@ -38,7 +38,7 @@
/* Saved effective uid. */
static int privileged = 0;
static int temporarily_use_uid_effective = 0;
-static gid_t saved_egroups[NGROUPS_MAX], user_groups[NGROUPS_MAX];
+static gid_t *saved_egroups, *user_groups;
static int saved_egroupslen = -1, user_groupslen = -1;
/*
@@ -68,17 +68,27 @@
privileged = 1;
temporarily_use_uid_effective = 1;
- saved_egroupslen = getgroups(NGROUPS_MAX, saved_egroups);
+
+ saved_egroupslen = getgroups(0, NULL);
if (saved_egroupslen < 0)
fatal("getgroups: %.100s", strerror(errno));
+ saved_egroups = xrealloc(saved_egroups,
+ saved_egroupslen * sizeof(*saved_egroups));
+ if (getgroups(saved_egroupslen, saved_egroups) < 0)
+ fatal("getgroups: %.100s", strerror(errno));
/* set and save the user's groups */
if (user_groupslen == -1) {
if (initgroups(pw->pw_name, pw->pw_gid) < 0)
fatal("initgroups: %s: %.100s", pw->pw_name,
strerror(errno));
- user_groupslen = getgroups(NGROUPS_MAX, user_groups);
+
+ user_groupslen = getgroups(0, NULL);
if (user_groupslen < 0)
+ fatal("getgroups: %.100s", strerror(errno));
+ user_groups = xrealloc(user_groups,
+ user_groupslena * sizeof(*user_groups));
+ if (getgroups(user_groupslen, user_groups) < 0)
fatal("getgroups: %.100s", strerror(errno));
}
/* Set the effective uid to the given (unprivileged) uid. */
Index: groupaccess.c
===================================================================
RCS file: /cvs/openssh/groupaccess.c,v
retrieving revision 1.7
diff -u -u -r1.7 groupaccess.c
--- groupaccess.c 14 May 2003 03:40:07 -0000 1.7
+++ groupaccess.c 19 Feb 2004 23:50:38 -0000
@@ -31,7 +31,7 @@
#include "log.h"
static int ngroups;
-static char *groups_byname[NGROUPS_MAX + 1]; /* +1 for base/primary group */
+static char **groups_byname;
/*
* Initialize group access list for user with primary (base) and
@@ -40,20 +40,33 @@
int
ga_init(const char *user, gid_t base)
{
- gid_t groups_bygid[NGROUPS_MAX + 1];
- int i, j;
+ gid_t *groups_bygid;
+ int i;
struct group *gr;
if (ngroups > 0)
ga_free();
- ngroups = sizeof(groups_bygid) / sizeof(gid_t);
+ getgrouplist(user, base, NULL, &ngroups);
+ groups_bygid = xmalloc(ngroups * sizeof(*groups_bygid));
+ groups_byname = xmalloc(ngroups * sizeof(*groups_byname));
+
if (getgrouplist(user, base, groups_bygid, &ngroups) == -1)
logit("getgrouplist: groups list too small");
- for (i = 0, j = 0; i < ngroups; i++)
- if ((gr = getgrgid(groups_bygid[i])) != NULL)
- groups_byname[j++] = xstrdup(gr->gr_name);
- return (ngroups = j);
+ for (i = 0; i < ngroups; i++) {
+ if ((gr = getgrgid(groups_bygid[i])) != NULL) {
+ groups_byname[i] = xstrdup(gr->gr_name);
+ } else {
+ char gidstr[32];
+
+ logit("getgrgid: unknown group id: %d",
+ (int)groups_bygid[i]);
+ snprintf(gidstr, sizeof(gidstr), "%d",
+ (int)groups_bygid[i]);
+ groups_byname[i] = xstrdup(gidstr);
+ }
+ }
+ return ngroups;
}
/*
@@ -84,5 +97,7 @@
for (i = 0; i < ngroups; i++)
xfree(groups_byname[i]);
ngroups = 0;
+ xfree(groups_byname);
+ xfree(groups_bygid);
}
}
--
Tim Hockin
Sun Microsystems, Linux Software Engineering
thockin at sun.com
All opinions are my own, not Sun's
More information about the openssh-unix-dev
mailing list