xref: /aosp_15_r20/external/musl/src/misc/initgroups.c (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
1*c9945492SAndroid Build Coastguard Worker #define _GNU_SOURCE
2*c9945492SAndroid Build Coastguard Worker #include <grp.h>
3*c9945492SAndroid Build Coastguard Worker #include <limits.h>
4*c9945492SAndroid Build Coastguard Worker #include <stdlib.h>
5*c9945492SAndroid Build Coastguard Worker 
initgroups(const char * user,gid_t gid)6*c9945492SAndroid Build Coastguard Worker int initgroups(const char *user, gid_t gid)
7*c9945492SAndroid Build Coastguard Worker {
8*c9945492SAndroid Build Coastguard Worker 	gid_t buf[32], *groups = buf;
9*c9945492SAndroid Build Coastguard Worker 	int count = sizeof buf / sizeof *buf, prev_count = count;
10*c9945492SAndroid Build Coastguard Worker 	while (getgrouplist(user, gid, groups, &count) < 0) {
11*c9945492SAndroid Build Coastguard Worker 		if (groups != buf) free(groups);
12*c9945492SAndroid Build Coastguard Worker 
13*c9945492SAndroid Build Coastguard Worker 		/* Return if failure isn't buffer size */
14*c9945492SAndroid Build Coastguard Worker 		if (count <= prev_count)
15*c9945492SAndroid Build Coastguard Worker 			return -1;
16*c9945492SAndroid Build Coastguard Worker 
17*c9945492SAndroid Build Coastguard Worker 		/* Always increase by at least 50% to limit to
18*c9945492SAndroid Build Coastguard Worker 		 * logarithmically many retries on TOCTOU races. */
19*c9945492SAndroid Build Coastguard Worker 		if (count < prev_count + (prev_count>>1))
20*c9945492SAndroid Build Coastguard Worker 			count = prev_count + (prev_count>>1);
21*c9945492SAndroid Build Coastguard Worker 
22*c9945492SAndroid Build Coastguard Worker 		groups = calloc(count, sizeof *groups);
23*c9945492SAndroid Build Coastguard Worker 		if (!groups) return -1;
24*c9945492SAndroid Build Coastguard Worker 		prev_count = count;
25*c9945492SAndroid Build Coastguard Worker 	}
26*c9945492SAndroid Build Coastguard Worker 	int ret = setgroups(count, groups);
27*c9945492SAndroid Build Coastguard Worker 	if (groups != buf) free(groups);
28*c9945492SAndroid Build Coastguard Worker 	return ret;
29*c9945492SAndroid Build Coastguard Worker }
30