--- cyrus/lib/auth_unix.c 2007/02/13 16:42:49 1.41 +++ cyrus/lib/auth_unix.c 2007/09/17 14:36:40 1.45 @@ -41,7 +41,7 @@ */ /* - * $Id: auth_unix.c,v 1.41 2007/02/13 16:42:49 murch Exp $ + * $Id: auth_unix.c,v 1.45 2007/09/17 14:36:40 murch Exp $ */ #include @@ -224,6 +224,10 @@ static struct auth_state *mynewstate(con struct passwd *pwd; struct group *grp; char **mem; +#ifdef HAVE_GETGROUPLIST + gid_t gid, *groupids = NULL; + int ret, ngroups = 0; +#endif identifier = mycanonifyid(identifier, 0); if (!identifier) return 0; @@ -239,7 +243,48 @@ static struct auth_state *mynewstate(con return newstate; pwd = getpwnam(identifier); - + +#ifdef HAVE_GETGROUPLIST + gid = pwd ? pwd->pw_gid : (gid_t) -1; + + /* get number of groups user is member of into ngroups */ + getgrouplist(identifier, gid, NULL, &ngroups); + + /* get the actual group ids */ + do { + groupids = (gid_t *)xrealloc((gid_t *)groupids, + ngroups * sizeof(gid_t)); + + newstate->ngroups = ngroups; /* copy of ngroups for comparision */ + ret = getgrouplist(identifier, gid, groupids, &ngroups); + /* + * This is tricky. We do this as long as getgrouplist tells us to + * realloc _and_ the number of groups changes. It tells us to realloc + * also in the case of failure... + */ + } while (ret != -1 && ngroups != newstate->ngroups); + + if (ret == -1) { + newstate->ngroups = 0; + newstate->group = NULL; + goto err; + } + + newstate->ngroups = 0; + newstate->group = (char **)xmalloc(ngroups * sizeof(char *)); + while (ngroups--) { + if (pwd || groupids[ngroups] != gid) { + if ((grp = getgrgid(groupids[ngroups]))) { + newstate->ngroups++; + newstate->group[newstate->ngroups-1] = xstrdup(grp->gr_name); + } + } + } + +err: + if (groupids) free(groupids); + +#else /* !HAVE_GETGROUPLIST */ setgrent(); while ((grp = getgrent())) { for (mem = grp->gr_mem; *mem; mem++) { @@ -254,6 +299,8 @@ static struct auth_state *mynewstate(con } } endgrent(); +#endif /* HAVE_GETGROUPLIST */ + return newstate; }