Blob Blame Raw
--- 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 <config.h>
@@ -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;
 }