xref: /minix3/lib/libc/gen/getgroupmembership.c (revision 2fe8fb192fe7e8720e3e7a77f928da545e872a6a)
1*2fe8fb19SBen Gras /*	$NetBSD: getgroupmembership.c,v 1.4 2008/04/28 20:22:59 martin Exp $	*/
2*2fe8fb19SBen Gras 
3*2fe8fb19SBen Gras /*-
4*2fe8fb19SBen Gras  * Copyright (c) 2004-2005 The NetBSD Foundation, Inc.
5*2fe8fb19SBen Gras  * All rights reserved.
6*2fe8fb19SBen Gras  *
7*2fe8fb19SBen Gras  * This code is derived from software contributed to The NetBSD Foundation
8*2fe8fb19SBen Gras  * by Luke Mewburn.
9*2fe8fb19SBen Gras  *
10*2fe8fb19SBen Gras  * Redistribution and use in source and binary forms, with or without
11*2fe8fb19SBen Gras  * modification, are permitted provided that the following conditions
12*2fe8fb19SBen Gras  * are met:
13*2fe8fb19SBen Gras  * 1. Redistributions of source code must retain the above copyright
14*2fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer.
15*2fe8fb19SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
16*2fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer in the
17*2fe8fb19SBen Gras  *    documentation and/or other materials provided with the distribution.
18*2fe8fb19SBen Gras  *
19*2fe8fb19SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*2fe8fb19SBen Gras  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*2fe8fb19SBen Gras  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*2fe8fb19SBen Gras  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*2fe8fb19SBen Gras  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*2fe8fb19SBen Gras  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*2fe8fb19SBen Gras  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*2fe8fb19SBen Gras  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*2fe8fb19SBen Gras  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*2fe8fb19SBen Gras  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*2fe8fb19SBen Gras  * POSSIBILITY OF SUCH DAMAGE.
30*2fe8fb19SBen Gras  */
31*2fe8fb19SBen Gras 
32*2fe8fb19SBen Gras #include <sys/cdefs.h>
33*2fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
34*2fe8fb19SBen Gras __RCSID("$NetBSD: getgroupmembership.c,v 1.4 2008/04/28 20:22:59 martin Exp $");
35*2fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
36*2fe8fb19SBen Gras 
37*2fe8fb19SBen Gras /*
38*2fe8fb19SBen Gras  * calculate group access list
39*2fe8fb19SBen Gras  */
40*2fe8fb19SBen Gras 
41*2fe8fb19SBen Gras #include "namespace.h"
42*2fe8fb19SBen Gras #include "reentrant.h"
43*2fe8fb19SBen Gras 
44*2fe8fb19SBen Gras #include <sys/param.h>
45*2fe8fb19SBen Gras 
46*2fe8fb19SBen Gras #include <assert.h>
47*2fe8fb19SBen Gras #include <errno.h>
48*2fe8fb19SBen Gras #include <grp.h>
49*2fe8fb19SBen Gras #include <limits.h>
50*2fe8fb19SBen Gras #include <nsswitch.h>
51*2fe8fb19SBen Gras #include <stdarg.h>
52*2fe8fb19SBen Gras #include <stdio.h>
53*2fe8fb19SBen Gras #include <stdlib.h>
54*2fe8fb19SBen Gras #include <string.h>
55*2fe8fb19SBen Gras #include <unistd.h>
56*2fe8fb19SBen Gras 
57*2fe8fb19SBen Gras #ifdef HESIOD
58*2fe8fb19SBen Gras #include <hesiod.h>
59*2fe8fb19SBen Gras #endif
60*2fe8fb19SBen Gras 
61*2fe8fb19SBen Gras #include "gr_private.h"
62*2fe8fb19SBen Gras 
63*2fe8fb19SBen Gras #ifdef __weak_alias
__weak_alias(getgroupmembership,_getgroupmembership)64*2fe8fb19SBen Gras __weak_alias(getgroupmembership,_getgroupmembership)
65*2fe8fb19SBen Gras #endif
66*2fe8fb19SBen Gras 
67*2fe8fb19SBen Gras /*
68*2fe8fb19SBen Gras  * __gr_addgid
69*2fe8fb19SBen Gras  *	Add gid to the groups array (of maxgrp size) at the position
70*2fe8fb19SBen Gras  *	indicated by *groupc, unless it already exists or *groupc is
71*2fe8fb19SBen Gras  *	past &groups[maxgrp].
72*2fe8fb19SBen Gras  *	Returns 1 upon success (including duplicate suppression), 0 otherwise.
73*2fe8fb19SBen Gras  */
74*2fe8fb19SBen Gras static int
75*2fe8fb19SBen Gras __gr_addgid(gid_t gid, gid_t *groups, int maxgrp, int *groupc)
76*2fe8fb19SBen Gras {
77*2fe8fb19SBen Gras 	int	ret, dupc;
78*2fe8fb19SBen Gras 
79*2fe8fb19SBen Gras 	_DIAGASSERT(groupc != NULL);
80*2fe8fb19SBen Gras 	_DIAGASSERT(groups != NULL);
81*2fe8fb19SBen Gras 
82*2fe8fb19SBen Gras 						/* skip duplicates */
83*2fe8fb19SBen Gras 	for (dupc = 0; dupc < MIN(maxgrp, *groupc); dupc++) {
84*2fe8fb19SBen Gras 		if (groups[dupc] == gid)
85*2fe8fb19SBen Gras 			return 1;
86*2fe8fb19SBen Gras 	}
87*2fe8fb19SBen Gras 
88*2fe8fb19SBen Gras 	ret = 1;
89*2fe8fb19SBen Gras 	if (*groupc < maxgrp)			/* add this gid */
90*2fe8fb19SBen Gras 		groups[*groupc] = gid;
91*2fe8fb19SBen Gras 	else
92*2fe8fb19SBen Gras 		ret = 0;
93*2fe8fb19SBen Gras 	(*groupc)++;
94*2fe8fb19SBen Gras 	return ret;
95*2fe8fb19SBen Gras }
96*2fe8fb19SBen Gras 
97*2fe8fb19SBen Gras 
98*2fe8fb19SBen Gras /*ARGSUSED*/
99*2fe8fb19SBen Gras static int
_files_getgroupmembership(void * retval,void * cb_data,va_list ap)100*2fe8fb19SBen Gras _files_getgroupmembership(void *retval, void *cb_data, va_list ap)
101*2fe8fb19SBen Gras {
102*2fe8fb19SBen Gras 	int		*result	= va_arg(ap, int *);
103*2fe8fb19SBen Gras 	const char 	*uname	= va_arg(ap, const char *);
104*2fe8fb19SBen Gras 	gid_t		 agroup	= va_arg(ap, gid_t);
105*2fe8fb19SBen Gras 	gid_t		*groups	= va_arg(ap, gid_t *);
106*2fe8fb19SBen Gras 	int		 maxgrp	= va_arg(ap, int);
107*2fe8fb19SBen Gras 	int		*groupc	= va_arg(ap, int *);
108*2fe8fb19SBen Gras 
109*2fe8fb19SBen Gras 	struct __grstate_files	state;
110*2fe8fb19SBen Gras 	struct group		grp;
111*2fe8fb19SBen Gras 	char			grpbuf[_GETGR_R_SIZE_MAX];
112*2fe8fb19SBen Gras 	int			rv, i;
113*2fe8fb19SBen Gras 
114*2fe8fb19SBen Gras 	_DIAGASSERT(result != NULL);
115*2fe8fb19SBen Gras 	_DIAGASSERT(uname != NULL);
116*2fe8fb19SBen Gras 	/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
117*2fe8fb19SBen Gras 	_DIAGASSERT(groupc != NULL);
118*2fe8fb19SBen Gras 
119*2fe8fb19SBen Gras 						/* install primary group */
120*2fe8fb19SBen Gras 	(void) __gr_addgid(agroup, groups, maxgrp, groupc);
121*2fe8fb19SBen Gras 
122*2fe8fb19SBen Gras 	memset(&state, 0, sizeof(state));
123*2fe8fb19SBen Gras 	while (__grscan_files(&rv, &grp, grpbuf, sizeof(grpbuf), &state,
124*2fe8fb19SBen Gras 				0, NULL, 0) == NS_SUCCESS) {
125*2fe8fb19SBen Gras 						/* scan members */
126*2fe8fb19SBen Gras 		for (i = 0; grp.gr_mem[i]; i++) {
127*2fe8fb19SBen Gras 			if (strcmp(grp.gr_mem[i], uname) != 0)
128*2fe8fb19SBen Gras 				continue;
129*2fe8fb19SBen Gras 			if (! __gr_addgid(grp.gr_gid, groups, maxgrp, groupc))
130*2fe8fb19SBen Gras 				*result = -1;
131*2fe8fb19SBen Gras 			break;
132*2fe8fb19SBen Gras 		}
133*2fe8fb19SBen Gras 	}
134*2fe8fb19SBen Gras 	__grend_files(&state);
135*2fe8fb19SBen Gras 	return NS_NOTFOUND;
136*2fe8fb19SBen Gras }
137*2fe8fb19SBen Gras 
138*2fe8fb19SBen Gras 
139*2fe8fb19SBen Gras #ifdef HESIOD
140*2fe8fb19SBen Gras 
141*2fe8fb19SBen Gras /*ARGSUSED*/
142*2fe8fb19SBen Gras static int
_dns_getgroupmembership(void * retval,void * cb_data,va_list ap)143*2fe8fb19SBen Gras _dns_getgroupmembership(void *retval, void *cb_data, va_list ap)
144*2fe8fb19SBen Gras {
145*2fe8fb19SBen Gras 	int		*result	= va_arg(ap, int *);
146*2fe8fb19SBen Gras 	const char 	*uname	= va_arg(ap, const char *);
147*2fe8fb19SBen Gras 	gid_t		 agroup	= va_arg(ap, gid_t);
148*2fe8fb19SBen Gras 	gid_t		*groups	= va_arg(ap, gid_t *);
149*2fe8fb19SBen Gras 	int		 maxgrp	= va_arg(ap, int);
150*2fe8fb19SBen Gras 	int		*groupc	= va_arg(ap, int *);
151*2fe8fb19SBen Gras 
152*2fe8fb19SBen Gras 	struct __grstate_dns	state;
153*2fe8fb19SBen Gras 	struct group		grp;
154*2fe8fb19SBen Gras 	char			grpbuf[_GETGR_R_SIZE_MAX];
155*2fe8fb19SBen Gras 	unsigned long		id;
156*2fe8fb19SBen Gras 	void			*context;
157*2fe8fb19SBen Gras 	char			**hp, *cp, *ep;
158*2fe8fb19SBen Gras 	int			rv, i;
159*2fe8fb19SBen Gras 
160*2fe8fb19SBen Gras 	_DIAGASSERT(result != NULL);
161*2fe8fb19SBen Gras 	_DIAGASSERT(uname != NULL);
162*2fe8fb19SBen Gras 	/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
163*2fe8fb19SBen Gras 	_DIAGASSERT(groupc != NULL);
164*2fe8fb19SBen Gras 
165*2fe8fb19SBen Gras 						/* install primary group */
166*2fe8fb19SBen Gras 	(void) __gr_addgid(agroup, groups, maxgrp, groupc);
167*2fe8fb19SBen Gras 
168*2fe8fb19SBen Gras 	hp = NULL;
169*2fe8fb19SBen Gras 	rv = NS_NOTFOUND;
170*2fe8fb19SBen Gras 
171*2fe8fb19SBen Gras 	if (hesiod_init(&context) == -1)		/* setup hesiod */
172*2fe8fb19SBen Gras 		return NS_UNAVAIL;
173*2fe8fb19SBen Gras 
174*2fe8fb19SBen Gras 	hp = hesiod_resolve(context, uname, "grplist");	/* find grplist */
175*2fe8fb19SBen Gras 	if (hp == NULL) {
176*2fe8fb19SBen Gras 		if (errno != ENOENT) {			/* wasn't "not found"*/
177*2fe8fb19SBen Gras 			rv = NS_UNAVAIL;
178*2fe8fb19SBen Gras 			goto dnsgroupmembers_out;
179*2fe8fb19SBen Gras 		}
180*2fe8fb19SBen Gras 			/* grplist not found, fallback to _dns_grscan */
181*2fe8fb19SBen Gras 		memset(&state, 0, sizeof(state));
182*2fe8fb19SBen Gras 		while (__grscan_dns(&rv, &grp, grpbuf, sizeof(grpbuf), &state,
183*2fe8fb19SBen Gras 					0, NULL, 0) == NS_SUCCESS) {
184*2fe8fb19SBen Gras 							/* scan members */
185*2fe8fb19SBen Gras 			for (i = 0; grp.gr_mem[i]; i++) {
186*2fe8fb19SBen Gras 				if (strcmp(grp.gr_mem[i], uname) != 0)
187*2fe8fb19SBen Gras 					continue;
188*2fe8fb19SBen Gras 				if (! __gr_addgid(grp.gr_gid, groups, maxgrp,
189*2fe8fb19SBen Gras 				    groupc))
190*2fe8fb19SBen Gras 					*result = -1;
191*2fe8fb19SBen Gras 				break;
192*2fe8fb19SBen Gras 			}
193*2fe8fb19SBen Gras 		}
194*2fe8fb19SBen Gras 		__grend_dns(&state);
195*2fe8fb19SBen Gras 		rv = NS_NOTFOUND;
196*2fe8fb19SBen Gras 		goto dnsgroupmembers_out;
197*2fe8fb19SBen Gras 	}
198*2fe8fb19SBen Gras 
199*2fe8fb19SBen Gras 	if ((ep = strchr(hp[0], '\n')) != NULL)
200*2fe8fb19SBen Gras 		*ep = '\0';				/* clear trailing \n */
201*2fe8fb19SBen Gras 
202*2fe8fb19SBen Gras 	for (cp = hp[0]; *cp != '\0'; ) {		/* parse grplist */
203*2fe8fb19SBen Gras 		if ((cp = strchr(cp, ':')) == NULL)	/* skip grpname */
204*2fe8fb19SBen Gras 			break;
205*2fe8fb19SBen Gras 		cp++;
206*2fe8fb19SBen Gras 		id = strtoul(cp, &ep, 10);		/* parse gid */
207*2fe8fb19SBen Gras 		if (id > GID_MAX || (*ep != ':' && *ep != '\0')) {
208*2fe8fb19SBen Gras 			rv = NS_UNAVAIL;
209*2fe8fb19SBen Gras 			goto dnsgroupmembers_out;
210*2fe8fb19SBen Gras 		}
211*2fe8fb19SBen Gras 		cp = ep;
212*2fe8fb19SBen Gras 		if (*cp == ':')
213*2fe8fb19SBen Gras 			cp++;
214*2fe8fb19SBen Gras 
215*2fe8fb19SBen Gras 							/* add gid */
216*2fe8fb19SBen Gras 		if (! __gr_addgid((gid_t)id, groups, maxgrp, groupc))
217*2fe8fb19SBen Gras 			*result = -1;
218*2fe8fb19SBen Gras 	}
219*2fe8fb19SBen Gras 
220*2fe8fb19SBen Gras 	rv = NS_NOTFOUND;
221*2fe8fb19SBen Gras 
222*2fe8fb19SBen Gras  dnsgroupmembers_out:
223*2fe8fb19SBen Gras 	if (hp)
224*2fe8fb19SBen Gras 		hesiod_free_list(context, hp);
225*2fe8fb19SBen Gras 	hesiod_end(context);
226*2fe8fb19SBen Gras 	return rv;
227*2fe8fb19SBen Gras }
228*2fe8fb19SBen Gras 
229*2fe8fb19SBen Gras #endif /* HESIOD */
230*2fe8fb19SBen Gras 
231*2fe8fb19SBen Gras 
232*2fe8fb19SBen Gras #ifdef YP
233*2fe8fb19SBen Gras 
234*2fe8fb19SBen Gras /*ARGSUSED*/
235*2fe8fb19SBen Gras static int
_nis_getgroupmembership(void * retval,void * cb_data,va_list ap)236*2fe8fb19SBen Gras _nis_getgroupmembership(void *retval, void *cb_data, va_list ap)
237*2fe8fb19SBen Gras {
238*2fe8fb19SBen Gras 	int		*result	= va_arg(ap, int *);
239*2fe8fb19SBen Gras 	const char 	*uname	= va_arg(ap, const char *);
240*2fe8fb19SBen Gras 	gid_t		 agroup	= va_arg(ap, gid_t);
241*2fe8fb19SBen Gras 	gid_t		*groups	= va_arg(ap, gid_t *);
242*2fe8fb19SBen Gras 	int		 maxgrp	= va_arg(ap, int);
243*2fe8fb19SBen Gras 	int		*groupc	= va_arg(ap, int *);
244*2fe8fb19SBen Gras 
245*2fe8fb19SBen Gras 	struct __grstate_nis	state;
246*2fe8fb19SBen Gras 	struct group		grp;
247*2fe8fb19SBen Gras 	char			grpbuf[_GETGR_R_SIZE_MAX];
248*2fe8fb19SBen Gras 	int			rv, i;
249*2fe8fb19SBen Gras 
250*2fe8fb19SBen Gras 	_DIAGASSERT(result != NULL);
251*2fe8fb19SBen Gras 	_DIAGASSERT(uname != NULL);
252*2fe8fb19SBen Gras 	/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
253*2fe8fb19SBen Gras 	_DIAGASSERT(groupc != NULL);
254*2fe8fb19SBen Gras 
255*2fe8fb19SBen Gras 						/* install primary group */
256*2fe8fb19SBen Gras 	(void) __gr_addgid(agroup, groups, maxgrp, groupc);
257*2fe8fb19SBen Gras 
258*2fe8fb19SBen Gras 	memset(&state, 0, sizeof(state));
259*2fe8fb19SBen Gras 	while (__grscan_nis(&rv, &grp, grpbuf, sizeof(grpbuf), &state,
260*2fe8fb19SBen Gras 				0, NULL, 0) == NS_SUCCESS) {
261*2fe8fb19SBen Gras 						/* scan members */
262*2fe8fb19SBen Gras 		for (i = 0; grp.gr_mem[i]; i++) {
263*2fe8fb19SBen Gras 			if (strcmp(grp.gr_mem[i], uname) != 0)
264*2fe8fb19SBen Gras 				continue;
265*2fe8fb19SBen Gras 			if (! __gr_addgid(grp.gr_gid, groups, maxgrp, groupc))
266*2fe8fb19SBen Gras 				*result = -1;
267*2fe8fb19SBen Gras 			break;
268*2fe8fb19SBen Gras 		}
269*2fe8fb19SBen Gras 	}
270*2fe8fb19SBen Gras 	__grend_nis(&state);
271*2fe8fb19SBen Gras 
272*2fe8fb19SBen Gras 	return NS_NOTFOUND;
273*2fe8fb19SBen Gras }
274*2fe8fb19SBen Gras 
275*2fe8fb19SBen Gras #endif /* YP */
276*2fe8fb19SBen Gras 
277*2fe8fb19SBen Gras 
278*2fe8fb19SBen Gras #ifdef _GROUP_COMPAT
279*2fe8fb19SBen Gras 
280*2fe8fb19SBen Gras struct __compatggm {
281*2fe8fb19SBen Gras 	const char	*uname;		/* user to search for */
282*2fe8fb19SBen Gras 	gid_t		*groups;
283*2fe8fb19SBen Gras 	gid_t		 agroup;
284*2fe8fb19SBen Gras 	int		 maxgrp;
285*2fe8fb19SBen Gras 	int		*groupc;
286*2fe8fb19SBen Gras };
287*2fe8fb19SBen Gras 
288*2fe8fb19SBen Gras static int
_compat_ggm_search(void * cookie,struct group ** groupres)289*2fe8fb19SBen Gras _compat_ggm_search(void *cookie, struct group **groupres)
290*2fe8fb19SBen Gras {
291*2fe8fb19SBen Gras 	struct __compatggm	*cp;
292*2fe8fb19SBen Gras 	int			rerror, crv;
293*2fe8fb19SBen Gras 
294*2fe8fb19SBen Gras 	static const ns_dtab dtab[] = {
295*2fe8fb19SBen Gras 		NS_FILES_CB(__grbad_compat, "files")
296*2fe8fb19SBen Gras 		NS_DNS_CB(_dns_getgroupmembership, NULL)
297*2fe8fb19SBen Gras 		NS_NIS_CB(_nis_getgroupmembership, NULL)
298*2fe8fb19SBen Gras 		NS_COMPAT_CB(__grbad_compat, "compat")
299*2fe8fb19SBen Gras 		NS_NULL_CB
300*2fe8fb19SBen Gras 	};
301*2fe8fb19SBen Gras 
302*2fe8fb19SBen Gras 	*groupres = NULL;	/* we don't care about this */
303*2fe8fb19SBen Gras 	cp = (struct __compatggm *)cookie;
304*2fe8fb19SBen Gras 
305*2fe8fb19SBen Gras 	crv = nsdispatch(NULL, dtab,
306*2fe8fb19SBen Gras 	    NSDB_GROUP_COMPAT, "getgroupmembership",
307*2fe8fb19SBen Gras 	    __nsdefaultnis,
308*2fe8fb19SBen Gras 	    &rerror, cp->uname, cp->agroup, cp->groups, cp->maxgrp, cp->groupc);
309*2fe8fb19SBen Gras 
310*2fe8fb19SBen Gras 	if (crv == NS_SUCCESS)
311*2fe8fb19SBen Gras 		crv = NS_NOTFOUND;	/* indicate "no more +: entries" */
312*2fe8fb19SBen Gras 
313*2fe8fb19SBen Gras 	return crv;
314*2fe8fb19SBen Gras }
315*2fe8fb19SBen Gras 
316*2fe8fb19SBen Gras /* ARGSUSED */
317*2fe8fb19SBen Gras static int
_compat_getgroupmembership(void * retval,void * cb_data,va_list ap)318*2fe8fb19SBen Gras _compat_getgroupmembership(void *retval, void *cb_data, va_list ap)
319*2fe8fb19SBen Gras {
320*2fe8fb19SBen Gras 	int		*result	= va_arg(ap, int *);
321*2fe8fb19SBen Gras 	const char 	*uname	= va_arg(ap, const char *);
322*2fe8fb19SBen Gras 	gid_t		 agroup	= va_arg(ap, gid_t);
323*2fe8fb19SBen Gras 	gid_t		*groups	= va_arg(ap, gid_t *);
324*2fe8fb19SBen Gras 	int		 maxgrp	= va_arg(ap, int);
325*2fe8fb19SBen Gras 	int		*groupc	= va_arg(ap, int *);
326*2fe8fb19SBen Gras 
327*2fe8fb19SBen Gras 	struct __grstate_compat	state;
328*2fe8fb19SBen Gras 	struct __compatggm	ggmstate;
329*2fe8fb19SBen Gras 	struct group		grp;
330*2fe8fb19SBen Gras 	char			grpbuf[_GETGR_R_SIZE_MAX];
331*2fe8fb19SBen Gras 	int			rv, i;
332*2fe8fb19SBen Gras 
333*2fe8fb19SBen Gras 	_DIAGASSERT(result != NULL);
334*2fe8fb19SBen Gras 	_DIAGASSERT(uname != NULL);
335*2fe8fb19SBen Gras 	/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
336*2fe8fb19SBen Gras 	_DIAGASSERT(groupc != NULL);
337*2fe8fb19SBen Gras 
338*2fe8fb19SBen Gras 						/* install primary group */
339*2fe8fb19SBen Gras 	(void) __gr_addgid(agroup, groups, maxgrp, groupc);
340*2fe8fb19SBen Gras 
341*2fe8fb19SBen Gras 	memset(&state, 0, sizeof(state));
342*2fe8fb19SBen Gras 	memset(&ggmstate, 0, sizeof(ggmstate));
343*2fe8fb19SBen Gras 	ggmstate.uname = uname;
344*2fe8fb19SBen Gras 	ggmstate.groups = groups;
345*2fe8fb19SBen Gras 	ggmstate.agroup = agroup;
346*2fe8fb19SBen Gras 	ggmstate.maxgrp = maxgrp;
347*2fe8fb19SBen Gras 	ggmstate.groupc = groupc;
348*2fe8fb19SBen Gras 
349*2fe8fb19SBen Gras 	while (__grscan_compat(&rv, &grp, grpbuf, sizeof(grpbuf), &state,
350*2fe8fb19SBen Gras 				0, NULL, 0, _compat_ggm_search, &ggmstate)
351*2fe8fb19SBen Gras 		== NS_SUCCESS) {
352*2fe8fb19SBen Gras 						/* scan members */
353*2fe8fb19SBen Gras 		for (i = 0; grp.gr_mem[i]; i++) {
354*2fe8fb19SBen Gras 			if (strcmp(grp.gr_mem[i], uname) != 0)
355*2fe8fb19SBen Gras 				continue;
356*2fe8fb19SBen Gras 			if (! __gr_addgid(grp.gr_gid, groups, maxgrp, groupc))
357*2fe8fb19SBen Gras 				*result = -1;
358*2fe8fb19SBen Gras 			break;
359*2fe8fb19SBen Gras 		}
360*2fe8fb19SBen Gras 	}
361*2fe8fb19SBen Gras 
362*2fe8fb19SBen Gras 	__grend_compat(&state);
363*2fe8fb19SBen Gras 	return NS_NOTFOUND;
364*2fe8fb19SBen Gras }
365*2fe8fb19SBen Gras 
366*2fe8fb19SBen Gras #endif	/* _GROUP_COMPAT */
367*2fe8fb19SBen Gras 
368*2fe8fb19SBen Gras 
369*2fe8fb19SBen Gras int
getgroupmembership(const char * uname,gid_t agroup,gid_t * groups,int maxgrp,int * groupc)370*2fe8fb19SBen Gras getgroupmembership(const char *uname, gid_t agroup,
371*2fe8fb19SBen Gras     gid_t *groups, int maxgrp, int *groupc)
372*2fe8fb19SBen Gras {
373*2fe8fb19SBen Gras 	int	rerror;
374*2fe8fb19SBen Gras 
375*2fe8fb19SBen Gras 	static const ns_dtab dtab[] = {
376*2fe8fb19SBen Gras 		NS_FILES_CB(_files_getgroupmembership, NULL)
377*2fe8fb19SBen Gras 		NS_DNS_CB(_dns_getgroupmembership, NULL)
378*2fe8fb19SBen Gras 		NS_NIS_CB(_nis_getgroupmembership, NULL)
379*2fe8fb19SBen Gras 		NS_COMPAT_CB(_compat_getgroupmembership, NULL)
380*2fe8fb19SBen Gras 		NS_NULL_CB
381*2fe8fb19SBen Gras 	};
382*2fe8fb19SBen Gras 
383*2fe8fb19SBen Gras 	_DIAGASSERT(uname != NULL);
384*2fe8fb19SBen Gras 	/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
385*2fe8fb19SBen Gras 	_DIAGASSERT(groupc != NULL);
386*2fe8fb19SBen Gras 
387*2fe8fb19SBen Gras 	*groupc = 0;
388*2fe8fb19SBen Gras 
389*2fe8fb19SBen Gras 	mutex_lock(&__grmutex);
390*2fe8fb19SBen Gras 			/*
391*2fe8fb19SBen Gras 			 * Call each backend.
392*2fe8fb19SBen Gras 			 * For compatibility with getgrent(3) semantics,
393*2fe8fb19SBen Gras 			 * a backend should return NS_NOTFOUND even upon
394*2fe8fb19SBen Gras 			 * completion, to allow result merging to occur.
395*2fe8fb19SBen Gras 			 */
396*2fe8fb19SBen Gras 	(void) nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership",
397*2fe8fb19SBen Gras 	    __nsdefaultcompat,
398*2fe8fb19SBen Gras 	    &rerror, uname, agroup, groups, maxgrp, groupc);
399*2fe8fb19SBen Gras 	mutex_unlock(&__grmutex);
400*2fe8fb19SBen Gras 
401*2fe8fb19SBen Gras 	if (*groupc > maxgrp)			/* too many groups found */
402*2fe8fb19SBen Gras 		return -1;
403*2fe8fb19SBen Gras 	else
404*2fe8fb19SBen Gras 		return 0;
405*2fe8fb19SBen Gras }
406