1*74e12c43SGordon Ross /*
2*74e12c43SGordon Ross  * CDDL HEADER START
3*74e12c43SGordon Ross  *
4*74e12c43SGordon Ross  * The contents of this file are subject to the terms of the
5*74e12c43SGordon Ross  * Common Development and Distribution License (the "License").
6*74e12c43SGordon Ross  * You may not use this file except in compliance with the License.
7*74e12c43SGordon Ross  *
8*74e12c43SGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*74e12c43SGordon Ross  * or http://www.opensolaris.org/os/licensing.
10*74e12c43SGordon Ross  * See the License for the specific language governing permissions
11*74e12c43SGordon Ross  * and limitations under the License.
12*74e12c43SGordon Ross  *
13*74e12c43SGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14*74e12c43SGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*74e12c43SGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16*74e12c43SGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17*74e12c43SGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18*74e12c43SGordon Ross  *
19*74e12c43SGordon Ross  * CDDL HEADER END
20*74e12c43SGordon Ross  */
21*74e12c43SGordon Ross /*
22*74e12c43SGordon Ross  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
23*74e12c43SGordon Ross  *
24*74e12c43SGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25*74e12c43SGordon Ross  * Use is subject to license terms.
26*74e12c43SGordon Ross  */
27*74e12c43SGordon Ross 
28*74e12c43SGordon Ross /*
29*74e12c43SGordon Ross  *	files/getnetgrent.c -- "files" backend for nsswitch "netgroup" database
30*74e12c43SGordon Ross  *
31*74e12c43SGordon Ross  *	The API for netgroups differs sufficiently from that for the average
32*74e12c43SGordon Ross  *	getXXXbyYYY function that we use very few of the support routines in
33*74e12c43SGordon Ross  *	files_common.h.
34*74e12c43SGordon Ross  *
35*74e12c43SGordon Ross  *	The implementation of setnetgrent()/getnetgrent() here follows the
36*74e12c43SGordon Ross  *	the 4.x code, inasmuch as the setnetgrent() routine does all the work
37*74e12c43SGordon Ross  *	of traversing the netgroup graph and building a (potentially large)
38*74e12c43SGordon Ross  *	list in memory, and getnetgrent() just steps down the list.
39*74e12c43SGordon Ross  *
40*74e12c43SGordon Ross  *	An alternative, and probably better, implementation would lazy-eval
41*74e12c43SGordon Ross  *	the netgroup graph in response to getnetgrent() calls (though
42*74e12c43SGordon Ross  *	setnetgrent() should still check for the top-level netgroup name
43*74e12c43SGordon Ross  *	and return NSS_SUCCESS / NSS_NOTFOUND).
44*74e12c43SGordon Ross  */
45*74e12c43SGordon Ross 
46*74e12c43SGordon Ross #include "files_common.h"
47*74e12c43SGordon Ross #include <ctype.h>
48*74e12c43SGordon Ross #include <rpcsvc/ypclnt.h>
49*74e12c43SGordon Ross #include <malloc.h>
50*74e12c43SGordon Ross #include <string.h>
51*74e12c43SGordon Ross #include <ctype.h>
52*74e12c43SGordon Ross #include <sys/sysmacros.h>
53*74e12c43SGordon Ross 
54*74e12c43SGordon Ross /*
55*74e12c43SGordon Ross  * Tricky debug support
56*74e12c43SGordon Ross  */
57*74e12c43SGordon Ross 
58*74e12c43SGordon Ross #pragma weak __nss_files_netgr_debug
59*74e12c43SGordon Ross #pragma weak __nss_files_netgr_error
60*74e12c43SGordon Ross extern void __nss_files_netgr_debug(const char *, ...);
61*74e12c43SGordon Ross extern void __nss_files_netgr_error(const char *, ...);
62*74e12c43SGordon Ross 
63*74e12c43SGordon Ross /*
64*74e12c43SGordon Ross  * Start of stuff borrowed from getgrent.c
65*74e12c43SGordon Ross  */
66*74e12c43SGordon Ross static uint_t
hash_netgrname(nss_XbyY_args_t * argp,int keyhash,const char * line,int linelen)67*74e12c43SGordon Ross hash_netgrname(nss_XbyY_args_t *argp, int keyhash, const char *line,
68*74e12c43SGordon Ross     int linelen)
69*74e12c43SGordon Ross {
70*74e12c43SGordon Ross 	const char	*name;
71*74e12c43SGordon Ross 	uint_t		namelen, i;
72*74e12c43SGordon Ross 	uint_t		hash = 0;
73*74e12c43SGordon Ross 
74*74e12c43SGordon Ross 	if (keyhash) {
75*74e12c43SGordon Ross 		name = argp->key.name;
76*74e12c43SGordon Ross 		namelen = strlen(name);
77*74e12c43SGordon Ross 	} else {
78*74e12c43SGordon Ross 		name = line;
79*74e12c43SGordon Ross 		namelen = 0;
80*74e12c43SGordon Ross 		while (linelen-- && !isspace(*line)) {
81*74e12c43SGordon Ross 			line++;
82*74e12c43SGordon Ross 			namelen++;
83*74e12c43SGordon Ross 		}
84*74e12c43SGordon Ross 	}
85*74e12c43SGordon Ross 
86*74e12c43SGordon Ross 	for (i = 0; i < namelen; i++)
87*74e12c43SGordon Ross 		hash = hash * 15 + name[i];
88*74e12c43SGordon Ross 	return (hash);
89*74e12c43SGordon Ross }
90*74e12c43SGordon Ross 
91*74e12c43SGordon Ross static files_hash_func hash_netgr[1] = { hash_netgrname };
92*74e12c43SGordon Ross 
93*74e12c43SGordon Ross static files_hash_t hashinfo = {
94*74e12c43SGordon Ross 	DEFAULTMUTEX,
95*74e12c43SGordon Ross 	sizeof (struct nss_netgrent),
96*74e12c43SGordon Ross 	NSS_LINELEN_NETGROUP,
97*74e12c43SGordon Ross 	1,
98*74e12c43SGordon Ross 	hash_netgr
99*74e12c43SGordon Ross };
100*74e12c43SGordon Ross 
101*74e12c43SGordon Ross static int
check_netgrname(nss_XbyY_args_t * argp,const char * line,int linelen)102*74e12c43SGordon Ross check_netgrname(nss_XbyY_args_t *argp, const char *line, int linelen)
103*74e12c43SGordon Ross {
104*74e12c43SGordon Ross 	const char *linep, *limit;
105*74e12c43SGordon Ross 	const char *keyp = argp->key.name;
106*74e12c43SGordon Ross 
107*74e12c43SGordon Ross 	linep = line;
108*74e12c43SGordon Ross 	limit = line + linelen;
109*74e12c43SGordon Ross 
110*74e12c43SGordon Ross 	/* +/- entries valid for compat source only */
111*74e12c43SGordon Ross 	if (linelen == 0 || *line == '+' || *line == '-')
112*74e12c43SGordon Ross 		return (0);
113*74e12c43SGordon Ross 	while (*keyp && linep < limit && *keyp == *linep) {
114*74e12c43SGordon Ross 		keyp++;
115*74e12c43SGordon Ross 		linep++;
116*74e12c43SGordon Ross 	}
117*74e12c43SGordon Ross 	return (linep < limit && *keyp == '\0' && isspace(*linep));
118*74e12c43SGordon Ross }
119*74e12c43SGordon Ross 
120*74e12c43SGordon Ross static nss_status_t
getbyname(files_backend_ptr_t be,void * a)121*74e12c43SGordon Ross getbyname(files_backend_ptr_t be, void *a)
122*74e12c43SGordon Ross {
123*74e12c43SGordon Ross 	return (_nss_files_XY_hash(be, a, 1, &hashinfo, 0, check_netgrname));
124*74e12c43SGordon Ross }
125*74e12c43SGordon Ross 
126*74e12c43SGordon Ross /*
127*74e12c43SGordon Ross  * End of stuff borrowed from getgrent.c
128*74e12c43SGordon Ross  *
129*74e12c43SGordon Ross  * Now some "glue" functions based loosely on
130*74e12c43SGordon Ross  *   lib/libc/port/gen/getgrnam_r.c
131*74e12c43SGordon Ross  */
132*74e12c43SGordon Ross 
133*74e12c43SGordon Ross 
134*74e12c43SGordon Ross /*
135*74e12c43SGordon Ross  * This is a special purpose str2ent (parse) function used only in
136*74e12c43SGordon Ross  * the _nss_files_getbyname() below.  A general-purpose version of
137*74e12c43SGordon Ross  * this parser would copy the incoming line buffer to the passed
138*74e12c43SGordon Ross  * temporary buffer, and fill in the passed struct nss_netgrent with
139*74e12c43SGordon Ross  * pointers into that temporary buffer.  Our caller only needs the
140*74e12c43SGordon Ross  * list of members of this netgroup, and since that string already
141*74e12c43SGordon Ross  * exists in ready-to-use form in the incoming line buffer, we just
142*74e12c43SGordon Ross  * use that.  Also special here is the fact that we allocate a copy
143*74e12c43SGordon Ross  * of the member list, both because the caller wants it allocated,
144*74e12c43SGordon Ross  * and because the buffer at *instr will change after we return.
145*74e12c43SGordon Ross  * The caller passes null for a temporary buffer, which we ignore.
146*74e12c43SGordon Ross  *
147*74e12c43SGordon Ross  * See the test program: cmd/nsstest/netgr_get.c
148*74e12c43SGordon Ross  * for a more generic version of this function.
149*74e12c43SGordon Ross  */
150*74e12c43SGordon Ross static int
str2netgr(const char * instr,int lenstr,void * ent,char * buffer,int buflen)151*74e12c43SGordon Ross str2netgr(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
152*74e12c43SGordon Ross {
153*74e12c43SGordon Ross 	const char sep[] = " \t\n";
154*74e12c43SGordon Ross 	struct nss_netgrent *netgr = ent;
155*74e12c43SGordon Ross 	const char *p;
156*74e12c43SGordon Ross 
157*74e12c43SGordon Ross 	/* skip leading space */
158*74e12c43SGordon Ross 	p = instr;
159*74e12c43SGordon Ross 	while (isspace(*p))
160*74e12c43SGordon Ross 		p++;
161*74e12c43SGordon Ross 
162*74e12c43SGordon Ross 	/* should be at the key */
163*74e12c43SGordon Ross 	if (*p == '\0')
164*74e12c43SGordon Ross 		return (NSS_STR_PARSE_PARSE);
165*74e12c43SGordon Ross 	/* Full parser would set netgr_name = p here. */
166*74e12c43SGordon Ross 
167*74e12c43SGordon Ross 	/* skip the key ... */
168*74e12c43SGordon Ross 	p = strpbrk(p, sep);
169*74e12c43SGordon Ross 	if (p == NULL)
170*74e12c43SGordon Ross 		return (NSS_STR_PARSE_PARSE);
171*74e12c43SGordon Ross 	/* Full parser would store a null at *p here. */
172*74e12c43SGordon Ross 
173*74e12c43SGordon Ross 	/* skip separators */
174*74e12c43SGordon Ross 	while (isspace(*p))
175*74e12c43SGordon Ross 		p++;
176*74e12c43SGordon Ross 
177*74e12c43SGordon Ross 	/*
178*74e12c43SGordon Ross 	 * Should be at the members list, which is the
179*74e12c43SGordon Ross 	 * rest of the input line.
180*74e12c43SGordon Ross 	 */
181*74e12c43SGordon Ross 	if (*p == '\0')
182*74e12c43SGordon Ross 		return (NSS_STR_PARSE_PARSE);
183*74e12c43SGordon Ross 
184*74e12c43SGordon Ross 	/*
185*74e12c43SGordon Ross 	 * Caller wants this allocated.  Do it now,
186*74e12c43SGordon Ross 	 * before the inbuf gets re-used.
187*74e12c43SGordon Ross 	 */
188*74e12c43SGordon Ross 	netgr->netgr_members = strdup(p);
189*74e12c43SGordon Ross 	if (netgr->netgr_members == NULL)
190*74e12c43SGordon Ross 		return (NSS_STR_PARSE_PARSE);
191*74e12c43SGordon Ross 
192*74e12c43SGordon Ross 	return (NSS_STR_PARSE_SUCCESS);
193*74e12c43SGordon Ross }
194*74e12c43SGordon Ross 
195*74e12c43SGordon Ross /*
196*74e12c43SGordon Ross  * This is a compatibility "shim" used by top_down() to get
197*74e12c43SGordon Ross  * the list of members for some netgroup.  On success, the
198*74e12c43SGordon Ross  * list of members is returned in allocated memory via valp.
199*74e12c43SGordon Ross  */
200*74e12c43SGordon Ross static nss_status_t
netgr_get_members(struct files_backend * be,const char * name,char ** valp)201*74e12c43SGordon Ross netgr_get_members(struct files_backend *be,
202*74e12c43SGordon Ross     const char *name, char **valp)
203*74e12c43SGordon Ross {
204*74e12c43SGordon Ross 	struct nss_netgrent netgr;
205*74e12c43SGordon Ross 	nss_XbyY_args_t args;
206*74e12c43SGordon Ross 	nss_status_t result;
207*74e12c43SGordon Ross 
208*74e12c43SGordon Ross 	if (name == (const char *)NULL)
209*74e12c43SGordon Ross 		return (NSS_ERROR);
210*74e12c43SGordon Ross 
211*74e12c43SGordon Ross 	(void) memset(&netgr, '\0', sizeof (netgr));
212*74e12c43SGordon Ross 	(void) memset(&args, '\0', sizeof (args));
213*74e12c43SGordon Ross 	args.buf.result = &netgr;
214*74e12c43SGordon Ross 	args.str2ent = str2netgr;
215*74e12c43SGordon Ross 	args.key.name = name;
216*74e12c43SGordon Ross 	result = getbyname(be, &args);
217*74e12c43SGordon Ross 
218*74e12c43SGordon Ross 	if (result == NSS_SUCCESS) {
219*74e12c43SGordon Ross 		/* Note: allocated memory. */
220*74e12c43SGordon Ross 		*valp = netgr.netgr_members;
221*74e12c43SGordon Ross 		if (*valp == NULL)
222*74e12c43SGordon Ross 			result = NSS_UNAVAIL;
223*74e12c43SGordon Ross 	}
224*74e12c43SGordon Ross 
225*74e12c43SGordon Ross 	return (result);
226*74e12c43SGordon Ross }
227*74e12c43SGordon Ross 
228*74e12c43SGordon Ross 
229*74e12c43SGordon Ross /*
230*74e12c43SGordon Ross  * End "glue" functions
231*74e12c43SGordon Ross  *
232*74e12c43SGordon Ross  * The rest of this is based on:
233*74e12c43SGordon Ross  *  lib/nsswitch/nis/common/getnetgrent.c
234*74e12c43SGordon Ross  */
235*74e12c43SGordon Ross 
236*74e12c43SGordon Ross 
237*74e12c43SGordon Ross /*
238*74e12c43SGordon Ross  * The nss_backend_t for a getnetgrent() sequence;  we actually give the
239*74e12c43SGordon Ross  *   netgroup frontend a pointer to one of these structures in response to
240*74e12c43SGordon Ross  *   a (successful) setnetgrent() call on the files_backend backend
241*74e12c43SGordon Ross  *   described further down in this file.
242*74e12c43SGordon Ross  */
243*74e12c43SGordon Ross 
244*74e12c43SGordon Ross struct files_getnetgr_be;
245*74e12c43SGordon Ross typedef nss_status_t	(*files_getnetgr_op_t)(
246*74e12c43SGordon Ross 	struct files_getnetgr_be *, void *);
247*74e12c43SGordon Ross 
248*74e12c43SGordon Ross struct files_getnetgr_be {
249*74e12c43SGordon Ross 	files_getnetgr_op_t	*ops;
250*74e12c43SGordon Ross 	nss_dbop_t		n_ops;
251*74e12c43SGordon Ross 	/*
252*74e12c43SGordon Ross 	 * State for set/get/endnetgrent()
253*74e12c43SGordon Ross 	 */
254*74e12c43SGordon Ross 	char			*netgroup;
255*74e12c43SGordon Ross 	struct grouplist	*all_members;
256*74e12c43SGordon Ross 	struct grouplist	*next_member;
257*74e12c43SGordon Ross };
258*74e12c43SGordon Ross 
259*74e12c43SGordon Ross struct grouplist {  /* One element of the list generated by a setnetgrent() */
260*74e12c43SGordon Ross 	char			*triple[NSS_NETGR_N];
261*74e12c43SGordon Ross 	struct	grouplist	*gl_nxt;
262*74e12c43SGordon Ross };
263*74e12c43SGordon Ross 
264*74e12c43SGordon Ross static nss_status_t
getnetgr_set(struct files_getnetgr_be * be,void * a)265*74e12c43SGordon Ross getnetgr_set(struct files_getnetgr_be *be, void *a)
266*74e12c43SGordon Ross {
267*74e12c43SGordon Ross 	const char		*netgroup = (const char *) a;
268*74e12c43SGordon Ross 
269*74e12c43SGordon Ross 	if (be->netgroup != NULL &&
270*74e12c43SGordon Ross 	    strcmp(be->netgroup, netgroup) == 0) {
271*74e12c43SGordon Ross 		/* We already have the member-list;  regurgitate it */
272*74e12c43SGordon Ross 		be->next_member = be->all_members;
273*74e12c43SGordon Ross 		return (NSS_SUCCESS);
274*74e12c43SGordon Ross 	}
275*74e12c43SGordon Ross 	return (NSS_NOTFOUND);
276*74e12c43SGordon Ross }
277*74e12c43SGordon Ross 
278*74e12c43SGordon Ross static nss_status_t
getnetgr_get(struct files_getnetgr_be * be,void * a)279*74e12c43SGordon Ross getnetgr_get(struct files_getnetgr_be *be, void *a)
280*74e12c43SGordon Ross {
281*74e12c43SGordon Ross 	struct nss_getnetgrent_args *args = (struct nss_getnetgrent_args *)a;
282*74e12c43SGordon Ross 	struct grouplist	*mem;
283*74e12c43SGordon Ross 
284*74e12c43SGordon Ross 	if ((mem = be->next_member) == 0) {
285*74e12c43SGordon Ross 		args->status = NSS_NETGR_NO;
286*74e12c43SGordon Ross 	} else {
287*74e12c43SGordon Ross 		char			*buffer	= args->buffer;
288*74e12c43SGordon Ross 		int			buflen	= args->buflen;
289*74e12c43SGordon Ross 		enum nss_netgr_argn	i;
290*74e12c43SGordon Ross 
291*74e12c43SGordon Ross 		args->status = NSS_NETGR_FOUND;
292*74e12c43SGordon Ross 
293*74e12c43SGordon Ross 		for (i = 0;  i < NSS_NETGR_N;  i++) {
294*74e12c43SGordon Ross 			const char	*str;
295*74e12c43SGordon Ross 			ssize_t	len;
296*74e12c43SGordon Ross 
297*74e12c43SGordon Ross 			if ((str = mem->triple[i]) == 0) {
298*74e12c43SGordon Ross 				args->retp[i] = NULL;
299*74e12c43SGordon Ross 			} else if ((len = strlen(str) + 1) <= buflen) {
300*74e12c43SGordon Ross 				args->retp[i] = buffer;
301*74e12c43SGordon Ross 				(void) memcpy(buffer, str, len);
302*74e12c43SGordon Ross 				buffer += len;
303*74e12c43SGordon Ross 				buflen -= len;
304*74e12c43SGordon Ross 			} else {
305*74e12c43SGordon Ross 				args->status = NSS_NETGR_NOMEM;
306*74e12c43SGordon Ross 				break;
307*74e12c43SGordon Ross 			}
308*74e12c43SGordon Ross 		}
309*74e12c43SGordon Ross 		be->next_member	= mem->gl_nxt;
310*74e12c43SGordon Ross 	}
311*74e12c43SGordon Ross 	return (NSS_SUCCESS);	/* Yup, even for end-of-list, i.e. */
312*74e12c43SGordon Ross 				/* do NOT advance to next backend. */
313*74e12c43SGordon Ross }
314*74e12c43SGordon Ross 
315*74e12c43SGordon Ross static nss_status_t
getnetgr_end(struct files_getnetgr_be * be,void * dummy)316*74e12c43SGordon Ross getnetgr_end(struct files_getnetgr_be *be, void *dummy)
317*74e12c43SGordon Ross {
318*74e12c43SGordon Ross 	struct grouplist	*gl;
319*74e12c43SGordon Ross 	struct grouplist	*next;
320*74e12c43SGordon Ross 
321*74e12c43SGordon Ross 	for (gl = be->all_members; gl != NULL; gl = next) {
322*74e12c43SGordon Ross 		enum nss_netgr_argn	i;
323*74e12c43SGordon Ross 
324*74e12c43SGordon Ross 		next = gl->gl_nxt;
325*74e12c43SGordon Ross 		for (i = NSS_NETGR_MACHINE; i < NSS_NETGR_N; i++) {
326*74e12c43SGordon Ross 			free(gl->triple[i]);
327*74e12c43SGordon Ross 		}
328*74e12c43SGordon Ross 		free(gl);
329*74e12c43SGordon Ross 	}
330*74e12c43SGordon Ross 	be->all_members = NULL;
331*74e12c43SGordon Ross 	be->next_member = NULL;
332*74e12c43SGordon Ross 	free(be->netgroup);
333*74e12c43SGordon Ross 	be->netgroup = NULL;
334*74e12c43SGordon Ross 	return (NSS_SUCCESS);
335*74e12c43SGordon Ross }
336*74e12c43SGordon Ross 
337*74e12c43SGordon Ross static nss_status_t
getnetgr_destr(struct files_getnetgr_be * be,void * dummy)338*74e12c43SGordon Ross getnetgr_destr(struct files_getnetgr_be	*be, void *dummy)
339*74e12c43SGordon Ross {
340*74e12c43SGordon Ross 	if (be != NULL) {
341*74e12c43SGordon Ross 		(void) getnetgr_end(be, NULL);
342*74e12c43SGordon Ross 		free(be);
343*74e12c43SGordon Ross 	}
344*74e12c43SGordon Ross 	return (NSS_SUCCESS);
345*74e12c43SGordon Ross }
346*74e12c43SGordon Ross 
347*74e12c43SGordon Ross static files_getnetgr_op_t getnetgr_ops[] = {
348*74e12c43SGordon Ross 	getnetgr_destr,
349*74e12c43SGordon Ross 	getnetgr_end,
350*74e12c43SGordon Ross 	getnetgr_set,
351*74e12c43SGordon Ross 	getnetgr_get,	/* getnetgrent_r() */
352*74e12c43SGordon Ross };
353*74e12c43SGordon Ross 
354*74e12c43SGordon Ross 
355*74e12c43SGordon Ross /*
356*74e12c43SGordon Ross  * The nss_backend_t for innetgr() and setnetgrent().
357*74e12c43SGordon Ross  * Also getbyname(), but that's only for testing.
358*74e12c43SGordon Ross  */
359*74e12c43SGordon Ross 
360*74e12c43SGordon Ross 
361*74e12c43SGordon Ross 
362*74e12c43SGordon Ross /*
363*74e12c43SGordon Ross  * Code to do top-down search in the graph defined by the 'netgroup' YP map
364*74e12c43SGordon Ross  */
365*74e12c43SGordon Ross 
366*74e12c43SGordon Ross /*
367*74e12c43SGordon Ross  * ===> This code is now used for setnetgrent(), not just innetgr().
368*74e12c43SGordon Ross  *
369*74e12c43SGordon Ross  * If the easy way doesn't pan out, recursively search the 'netgroup' map.
370*74e12c43SGordon Ross  * In order to do this, we:
371*74e12c43SGordon Ross  *
372*74e12c43SGordon Ross  *    -	remember all the netgroup names we've seen during this search,
373*74e12c43SGordon Ross  *	whether or not we've expanded them yet (we want fast insertion
374*74e12c43SGordon Ross  *	with duplicate-detection, so use yet another chained hash table),
375*74e12c43SGordon Ross  *
376*74e12c43SGordon Ross  *    -	keep a list of all the netgroups we haven't expanded yet (we just
377*74e12c43SGordon Ross  *	want fast insertion and pop-first, so a linked list will do fine).
378*74e12c43SGordon Ross  *	If we insert at the head, we get a depth-first search;  insertion
379*74e12c43SGordon Ross  *	at the tail gives breadth-first (?), which seems preferable (?).
380*74e12c43SGordon Ross  *
381*74e12c43SGordon Ross  * A netgrnam struct contains pointers for both the hash-table and the list.
382*74e12c43SGordon Ross  * It also contains the netgroup name;  note that we embed the name at the
383*74e12c43SGordon Ross  * end of the structure rather than holding a pointer to yet another
384*74e12c43SGordon Ross  * malloc()ed region.
385*74e12c43SGordon Ross  *
386*74e12c43SGordon Ross  * A netgrtab structure contains the hash-chain heads and the head/tail
387*74e12c43SGordon Ross  * pointers for the expansion list.
388*74e12c43SGordon Ross  */
389*74e12c43SGordon Ross 
390*74e12c43SGordon Ross struct netgrnam {
391*74e12c43SGordon Ross 	struct netgrnam	*hash_chain;
392*74e12c43SGordon Ross 	struct netgrnam	*expand_next;
393*74e12c43SGordon Ross 	char		name[1];	/* Really [strlen(name) + 1] */
394*74e12c43SGordon Ross };
395*74e12c43SGordon Ross 
396*74e12c43SGordon Ross #define	HASHMOD	113
397*74e12c43SGordon Ross 
398*74e12c43SGordon Ross struct netgrtab {
399*74e12c43SGordon Ross 	struct netgrnam	*expand_first;
400*74e12c43SGordon Ross 	struct netgrnam	**expand_lastp;
401*74e12c43SGordon Ross 	struct netgrnam	*hash_heads[HASHMOD];
402*74e12c43SGordon Ross };
403*74e12c43SGordon Ross 
404*74e12c43SGordon Ross static void
ngt_init(struct netgrtab * ngt)405*74e12c43SGordon Ross ngt_init(struct netgrtab *ngt)
406*74e12c43SGordon Ross {
407*74e12c43SGordon Ross 	(void) memset((void *)ngt, '\0', sizeof (*ngt));
408*74e12c43SGordon Ross 	ngt->expand_lastp = &ngt->expand_first;
409*74e12c43SGordon Ross }
410*74e12c43SGordon Ross 
411*74e12c43SGordon Ross /* === ? Change ngt_init() and ngt_destroy() to malloc/free struct netgrtab */
412*74e12c43SGordon Ross 
413*74e12c43SGordon Ross static void
414*74e12c43SGordon Ross /* ==> ? Should return 'failed' (out-of-memory) status ? */
ngt_insert(struct netgrtab * ngt,const char * name,size_t namelen)415*74e12c43SGordon Ross ngt_insert(struct netgrtab *ngt, const char *name, size_t namelen)
416*74e12c43SGordon Ross {
417*74e12c43SGordon Ross 	unsigned	hashval;
418*74e12c43SGordon Ross 	size_t		i;
419*74e12c43SGordon Ross 	struct netgrnam	*cur;
420*74e12c43SGordon Ross 	struct netgrnam	**head;
421*74e12c43SGordon Ross 
422*74e12c43SGordon Ross 	if (__nss_files_netgr_debug != NULL) {
423*74e12c43SGordon Ross 		__nss_files_netgr_debug(
424*74e12c43SGordon Ross 		    "ngt_insert: ngt=%p names=%s", ngt, name);
425*74e12c43SGordon Ross 	}
426*74e12c43SGordon Ross 
427*74e12c43SGordon Ross 	for (hashval = 0, i = 0;  i < namelen;  i++) {
428*74e12c43SGordon Ross 		hashval = (hashval << 2) + hashval +
429*74e12c43SGordon Ross 		    ((const unsigned char *)name)[i];
430*74e12c43SGordon Ross 	}
431*74e12c43SGordon Ross 	head = &ngt->hash_heads[hashval % HASHMOD];
432*74e12c43SGordon Ross 	for (cur = *head;  cur != 0;  cur = cur->hash_chain) {
433*74e12c43SGordon Ross 		if (strncmp(cur->name, name, namelen) == 0 &&
434*74e12c43SGordon Ross 		    cur->name[namelen] == 0) {
435*74e12c43SGordon Ross 			return;		/* Already in table, do nothing */
436*74e12c43SGordon Ross 		}
437*74e12c43SGordon Ross 	}
438*74e12c43SGordon Ross 	/* Create new netgrnam struct */
439*74e12c43SGordon Ross 	cur = malloc(offsetof(struct netgrnam, name) + namelen + 1);
440*74e12c43SGordon Ross 	if (cur == NULL) {
441*74e12c43SGordon Ross 		return;			/* Out of memory, too bad */
442*74e12c43SGordon Ross 	}
443*74e12c43SGordon Ross 	(void) memcpy(cur->name, name, namelen);
444*74e12c43SGordon Ross 	cur->name[namelen] = '\0';
445*74e12c43SGordon Ross 
446*74e12c43SGordon Ross 	/* Insert in hash table */
447*74e12c43SGordon Ross 	cur->hash_chain = *head;
448*74e12c43SGordon Ross 	*head = cur;
449*74e12c43SGordon Ross 
450*74e12c43SGordon Ross 	/* Insert in expansion list (insert at end for breadth-first search */
451*74e12c43SGordon Ross 	cur->expand_next = NULL;
452*74e12c43SGordon Ross 	*ngt->expand_lastp = cur;
453*74e12c43SGordon Ross 	ngt->expand_lastp = &cur->expand_next;
454*74e12c43SGordon Ross }
455*74e12c43SGordon Ross 
456*74e12c43SGordon Ross static const char *
ngt_next(struct netgrtab * ngt)457*74e12c43SGordon Ross ngt_next(struct netgrtab *ngt)
458*74e12c43SGordon Ross {
459*74e12c43SGordon Ross 	struct netgrnam	*first;
460*74e12c43SGordon Ross 
461*74e12c43SGordon Ross 	if ((first = ngt->expand_first) == NULL) {
462*74e12c43SGordon Ross 		return (NULL);
463*74e12c43SGordon Ross 	}
464*74e12c43SGordon Ross 	if ((ngt->expand_first = first->expand_next) == NULL) {
465*74e12c43SGordon Ross 		ngt->expand_lastp = &ngt->expand_first;
466*74e12c43SGordon Ross 	}
467*74e12c43SGordon Ross 	return (first->name);
468*74e12c43SGordon Ross }
469*74e12c43SGordon Ross 
470*74e12c43SGordon Ross static void
ngt_destroy(struct netgrtab * ngt)471*74e12c43SGordon Ross ngt_destroy(struct netgrtab *ngt)
472*74e12c43SGordon Ross {
473*74e12c43SGordon Ross 	struct netgrnam	*cur;
474*74e12c43SGordon Ross 	struct netgrnam *next;
475*74e12c43SGordon Ross 	int		i;
476*74e12c43SGordon Ross 
477*74e12c43SGordon Ross 	for (i = 0;  i < HASHMOD;  i++) {
478*74e12c43SGordon Ross 		for (cur = ngt->hash_heads[i]; cur != NULL; ) {
479*74e12c43SGordon Ross 			next = cur->hash_chain;
480*74e12c43SGordon Ross 			free(cur);
481*74e12c43SGordon Ross 			cur = next;
482*74e12c43SGordon Ross 		}
483*74e12c43SGordon Ross 	}
484*74e12c43SGordon Ross 	/* Don't bother zeroing pointers;  must do init if we want to reuse */
485*74e12c43SGordon Ross }
486*74e12c43SGordon Ross 
487*74e12c43SGordon Ross typedef const char *ccp;
488*74e12c43SGordon Ross 
489*74e12c43SGordon Ross static nss_status_t
top_down(struct files_backend * be,const char ** groups,int ngroups,int (* func)(ccp triple[3],void * iter_args,nss_status_t * return_val),void * iter_args)490*74e12c43SGordon Ross top_down(struct files_backend *be, const char **groups, int ngroups,
491*74e12c43SGordon Ross     int (*func)(ccp triple[3], void *iter_args, nss_status_t *return_val),
492*74e12c43SGordon Ross     void *iter_args)
493*74e12c43SGordon Ross {
494*74e12c43SGordon Ross 	struct netgrtab		*ngt;
495*74e12c43SGordon Ross 	/* netgrtab goes on the heap, not the stack, because it's large and */
496*74e12c43SGordon Ross 	/* stacks may not be all that big in multi-threaded programs. */
497*74e12c43SGordon Ross 
498*74e12c43SGordon Ross 	const char		*group;
499*74e12c43SGordon Ross 	int			nfound;
500*74e12c43SGordon Ross 	int			done;
501*74e12c43SGordon Ross 	nss_status_t		result;
502*74e12c43SGordon Ross 
503*74e12c43SGordon Ross 	if ((ngt = malloc(sizeof (*ngt))) == NULL) {
504*74e12c43SGordon Ross 		return (NSS_UNAVAIL);
505*74e12c43SGordon Ross 	}
506*74e12c43SGordon Ross 	ngt_init(ngt);
507*74e12c43SGordon Ross 
508*74e12c43SGordon Ross 	while (ngroups > 0) {
509*74e12c43SGordon Ross 		ngt_insert(ngt, *groups, strlen(*groups));
510*74e12c43SGordon Ross 		groups++;
511*74e12c43SGordon Ross 		ngroups--;
512*74e12c43SGordon Ross 	}
513*74e12c43SGordon Ross 
514*74e12c43SGordon Ross 	done	= 0;	/* Set to 1 to indicate that we cut the iteration  */
515*74e12c43SGordon Ross 			/*   short (and 'result' holds the return value)   */
516*74e12c43SGordon Ross 	nfound	= 0;	/* Number of successful netgroup getbyname calls   */
517*74e12c43SGordon Ross 
518*74e12c43SGordon Ross 	while (!done && (group = ngt_next(ngt)) != NULL) {
519*74e12c43SGordon Ross 		char		*val = NULL;
520*74e12c43SGordon Ross 		char		*p;
521*74e12c43SGordon Ross 
522*74e12c43SGordon Ross 		result = netgr_get_members(be, group, &val);
523*74e12c43SGordon Ross 		if (result != NSS_SUCCESS) {
524*74e12c43SGordon Ross 			if (result == NSS_NOTFOUND) {
525*74e12c43SGordon Ross 				if (__nss_files_netgr_error != NULL)
526*74e12c43SGordon Ross 					__nss_files_netgr_error(
527*74e12c43SGordon Ross 			    "files netgroup lookup: %s doesn't exist",
528*74e12c43SGordon Ross 					    group);
529*74e12c43SGordon Ross 			} else {
530*74e12c43SGordon Ross 				if (__nss_files_netgr_error != NULL)
531*74e12c43SGordon Ross 					__nss_files_netgr_error(
532*74e12c43SGordon Ross 			"files netgroup lookup: getbyname returned [%s]",
533*74e12c43SGordon Ross 					    strerror(errno));
534*74e12c43SGordon Ross 				done = 1;	/* Give up, return result */
535*74e12c43SGordon Ross 			}
536*74e12c43SGordon Ross 			/* Don't need to clean up anything */
537*74e12c43SGordon Ross 			continue;
538*74e12c43SGordon Ross 		}
539*74e12c43SGordon Ross 
540*74e12c43SGordon Ross 		if (__nss_files_netgr_debug != NULL) {
541*74e12c43SGordon Ross 			__nss_files_netgr_debug(
542*74e12c43SGordon Ross 			    "ngt_top: ngt=%p grp=%s members=\"%s\"",
543*74e12c43SGordon Ross 			    ngt, group, val);
544*74e12c43SGordon Ross 		}
545*74e12c43SGordon Ross 
546*74e12c43SGordon Ross 		nfound++;
547*74e12c43SGordon Ross 
548*74e12c43SGordon Ross 		if ((p = strpbrk(val, "#\n")) != NULL) {
549*74e12c43SGordon Ross 			*p = '\0';
550*74e12c43SGordon Ross 		}
551*74e12c43SGordon Ross 		p = val;
552*74e12c43SGordon Ross 
553*74e12c43SGordon Ross 		/* Parse val into triples and recursive netgroup references */
554*74e12c43SGordon Ross 		for (;;) {
555*74e12c43SGordon Ross 			ccp			triple[NSS_NETGR_N];
556*74e12c43SGordon Ross 			int			syntax_err;
557*74e12c43SGordon Ross 			enum nss_netgr_argn	i;
558*74e12c43SGordon Ross 
559*74e12c43SGordon Ross 			while (isspace(*p))
560*74e12c43SGordon Ross 				p++;
561*74e12c43SGordon Ross 			if (*p == '\0') {
562*74e12c43SGordon Ross 				/* Finished processing this particular val */
563*74e12c43SGordon Ross 				break;
564*74e12c43SGordon Ross 			}
565*74e12c43SGordon Ross 			if (*p != '(') {
566*74e12c43SGordon Ross 				/* Doesn't look like the start of a triple, */
567*74e12c43SGordon Ross 				/*   so assume it's a recursive netgroup.   */
568*74e12c43SGordon Ross 				char *start = p;
569*74e12c43SGordon Ross 				p = strpbrk(start, " \t");
570*74e12c43SGordon Ross 				if (p == 0) {
571*74e12c43SGordon Ross 					/* Point p at the final '\0' */
572*74e12c43SGordon Ross 					p = start + strlen(start);
573*74e12c43SGordon Ross 				}
574*74e12c43SGordon Ross 				ngt_insert(ngt, start, (size_t)(p - start));
575*74e12c43SGordon Ross 				continue;
576*74e12c43SGordon Ross 			}
577*74e12c43SGordon Ross 
578*74e12c43SGordon Ross 			/* Main case:  a (machine, user, domain) triple */
579*74e12c43SGordon Ross 			p++;
580*74e12c43SGordon Ross 			syntax_err = 0;
581*74e12c43SGordon Ross 			for (i = NSS_NETGR_MACHINE; i < NSS_NETGR_N; i++) {
582*74e12c43SGordon Ross 				char		*start;
583*74e12c43SGordon Ross 				char		*limit;
584*74e12c43SGordon Ross 				const char	*terminators = ",) \t";
585*74e12c43SGordon Ross 
586*74e12c43SGordon Ross 				if (i == NSS_NETGR_DOMAIN) {
587*74e12c43SGordon Ross 					/* Don't allow comma */
588*74e12c43SGordon Ross 					terminators++;
589*74e12c43SGordon Ross 				}
590*74e12c43SGordon Ross 				while (isspace(*p))
591*74e12c43SGordon Ross 					p++;
592*74e12c43SGordon Ross 				start = p;
593*74e12c43SGordon Ross 				limit = strpbrk(start, terminators);
594*74e12c43SGordon Ross 				if (limit == 0) {
595*74e12c43SGordon Ross 					syntax_err++;
596*74e12c43SGordon Ross 					break;
597*74e12c43SGordon Ross 				}
598*74e12c43SGordon Ross 				p = limit;
599*74e12c43SGordon Ross 				while (isspace(*p))
600*74e12c43SGordon Ross 					p++;
601*74e12c43SGordon Ross 				if (*p == terminators[0]) {
602*74e12c43SGordon Ross 					/*
603*74e12c43SGordon Ross 					 * Successfully parsed this name and
604*74e12c43SGordon Ross 					 *   the separator after it (comma or
605*74e12c43SGordon Ross 					 *   right paren); leave p ready for
606*74e12c43SGordon Ross 					 *   next parse.
607*74e12c43SGordon Ross 					 */
608*74e12c43SGordon Ross 					p++;
609*74e12c43SGordon Ross 					if (start == limit) {
610*74e12c43SGordon Ross 						/* Wildcard */
611*74e12c43SGordon Ross 						triple[i] = 0;
612*74e12c43SGordon Ross 					} else {
613*74e12c43SGordon Ross 						*limit = '\0';
614*74e12c43SGordon Ross 						triple[i] = start;
615*74e12c43SGordon Ross 					}
616*74e12c43SGordon Ross 				} else {
617*74e12c43SGordon Ross 					syntax_err++;
618*74e12c43SGordon Ross 					break;
619*74e12c43SGordon Ross 				}
620*74e12c43SGordon Ross 			}
621*74e12c43SGordon Ross 
622*74e12c43SGordon Ross 			if (syntax_err) {
623*74e12c43SGordon Ross /*
624*74e12c43SGordon Ross  * ===> log it;
625*74e12c43SGordon Ross  * ===> try skipping past next ')';  failing that, abandon the line;
626*74e12c43SGordon Ross  */
627*74e12c43SGordon Ross 				break;	/* Abandon this line */
628*74e12c43SGordon Ross 			} else if ((*func)(triple, iter_args, &result) == 0) {
629*74e12c43SGordon Ross 				/* Return result, good or bad */
630*74e12c43SGordon Ross 				done = 1;
631*74e12c43SGordon Ross 				break;
632*74e12c43SGordon Ross 			}
633*74e12c43SGordon Ross 		}
634*74e12c43SGordon Ross 		/* End of inner loop over val[] */
635*74e12c43SGordon Ross 		free(val);
636*74e12c43SGordon Ross 		val = NULL;
637*74e12c43SGordon Ross 	}
638*74e12c43SGordon Ross 	/* End of outer loop (!done && ngt_next(ngt) != 0) */
639*74e12c43SGordon Ross 
640*74e12c43SGordon Ross 	ngt_destroy(ngt);
641*74e12c43SGordon Ross 	free(ngt);
642*74e12c43SGordon Ross 
643*74e12c43SGordon Ross 	if (done) {
644*74e12c43SGordon Ross 		return (result);
645*74e12c43SGordon Ross 	} else if (nfound > 0) {
646*74e12c43SGordon Ross 		/* ==== ? Should only do this if all the top-level groups */
647*74e12c43SGordon Ross 		/*	  exist in YP?					  */
648*74e12c43SGordon Ross 		return (NSS_SUCCESS);
649*74e12c43SGordon Ross 	} else {
650*74e12c43SGordon Ross 		return (NSS_NOTFOUND);
651*74e12c43SGordon Ross 	}
652*74e12c43SGordon Ross }
653*74e12c43SGordon Ross 
654*74e12c43SGordon Ross 
655*74e12c43SGordon Ross /*
656*74e12c43SGordon Ross  * Code for setnetgrent()
657*74e12c43SGordon Ross  */
658*74e12c43SGordon Ross 
659*74e12c43SGordon Ross /*
660*74e12c43SGordon Ross  * Iterator function for setnetgrent():  copy triple, add to be->all_members
661*74e12c43SGordon Ross  */
662*74e12c43SGordon Ross static int
save_triple(ccp trippp[NSS_NETGR_N],void * headp_arg,nss_status_t * return_val)663*74e12c43SGordon Ross save_triple(ccp trippp[NSS_NETGR_N], void *headp_arg,
664*74e12c43SGordon Ross     nss_status_t *return_val)
665*74e12c43SGordon Ross {
666*74e12c43SGordon Ross 	struct grouplist	**headp = headp_arg;
667*74e12c43SGordon Ross 	struct grouplist	*gl;
668*74e12c43SGordon Ross 	enum nss_netgr_argn	i;
669*74e12c43SGordon Ross 
670*74e12c43SGordon Ross 	if (__nss_files_netgr_debug != NULL) {
671*74e12c43SGordon Ross 		__nss_files_netgr_debug(
672*74e12c43SGordon Ross 		    "save_tripple: h=%s u=%s d=%s",
673*74e12c43SGordon Ross 		    trippp[0] ? trippp[0] : "*",
674*74e12c43SGordon Ross 		    trippp[1] ? trippp[1] : "*",
675*74e12c43SGordon Ross 		    trippp[2] ? trippp[2] : "*");
676*74e12c43SGordon Ross 	}
677*74e12c43SGordon Ross 
678*74e12c43SGordon Ross 	if ((gl = malloc(sizeof (*gl))) == NULL) {
679*74e12c43SGordon Ross 		/* Out of memory */
680*74e12c43SGordon Ross 		*return_val = NSS_UNAVAIL;
681*74e12c43SGordon Ross 		return (0);
682*74e12c43SGordon Ross 	}
683*74e12c43SGordon Ross 	for (i = NSS_NETGR_MACHINE;  i < NSS_NETGR_N;  i++) {
684*74e12c43SGordon Ross 		if (trippp[i] == NULL) {
685*74e12c43SGordon Ross 			/* Wildcard */
686*74e12c43SGordon Ross 			gl->triple[i] = NULL;
687*74e12c43SGordon Ross 		} else if ((gl->triple[i] = strdup(trippp[i])) == NULL) {
688*74e12c43SGordon Ross 			/* Out of memory.  Free any we've allocated */
689*74e12c43SGordon Ross 			enum nss_netgr_argn	j;
690*74e12c43SGordon Ross 
691*74e12c43SGordon Ross 			for (j = NSS_NETGR_MACHINE;  j < i;  j++) {
692*74e12c43SGordon Ross 				free(gl->triple[j]);
693*74e12c43SGordon Ross 			}
694*74e12c43SGordon Ross 			free(gl);
695*74e12c43SGordon Ross 			*return_val = NSS_UNAVAIL;
696*74e12c43SGordon Ross 			return (0);
697*74e12c43SGordon Ross 		}
698*74e12c43SGordon Ross 	}
699*74e12c43SGordon Ross 	gl->gl_nxt = *headp;
700*74e12c43SGordon Ross 	*headp = gl;
701*74e12c43SGordon Ross 	return (1);	/* Tell top_down() to keep iterating */
702*74e12c43SGordon Ross }
703*74e12c43SGordon Ross 
704*74e12c43SGordon Ross static nss_status_t
netgr_set(struct files_backend * be,void * a)705*74e12c43SGordon Ross netgr_set(struct files_backend *be, void *a)
706*74e12c43SGordon Ross {
707*74e12c43SGordon Ross 	struct nss_setnetgrent_args *args = (struct nss_setnetgrent_args *)a;
708*74e12c43SGordon Ross 	struct files_getnetgr_be	*get_be;
709*74e12c43SGordon Ross 	nss_status_t		res;
710*74e12c43SGordon Ross 
711*74e12c43SGordon Ross 	get_be = malloc(sizeof (*get_be));
712*74e12c43SGordon Ross 	if (get_be == NULL) {
713*74e12c43SGordon Ross 		return (NSS_UNAVAIL);
714*74e12c43SGordon Ross 	}
715*74e12c43SGordon Ross 
716*74e12c43SGordon Ross 	get_be->all_members = NULL;
717*74e12c43SGordon Ross 	res = top_down(be, &args->netgroup, 1, save_triple,
718*74e12c43SGordon Ross 	    &get_be->all_members);
719*74e12c43SGordon Ross 
720*74e12c43SGordon Ross 	if (res == NSS_SUCCESS) {
721*74e12c43SGordon Ross 		get_be->ops		= getnetgr_ops;
722*74e12c43SGordon Ross 		get_be->n_ops		= ARRAY_SIZE(getnetgr_ops);
723*74e12c43SGordon Ross 		get_be->netgroup	= strdup(args->netgroup);
724*74e12c43SGordon Ross 		if (get_be->netgroup == NULL) {
725*74e12c43SGordon Ross 			/* Out of memory. */
726*74e12c43SGordon Ross 			args->iterator = NULL;
727*74e12c43SGordon Ross 			free(get_be);
728*74e12c43SGordon Ross 			return (NSS_UNAVAIL);
729*74e12c43SGordon Ross 		}
730*74e12c43SGordon Ross 		get_be->next_member	= get_be->all_members;
731*74e12c43SGordon Ross 
732*74e12c43SGordon Ross 		args->iterator		= (nss_backend_t *)get_be;
733*74e12c43SGordon Ross 	} else {
734*74e12c43SGordon Ross 		args->iterator		= NULL;
735*74e12c43SGordon Ross 		free(get_be);
736*74e12c43SGordon Ross 	}
737*74e12c43SGordon Ross 	return (res);
738*74e12c43SGordon Ross }
739*74e12c43SGordon Ross 
740*74e12c43SGordon Ross 
741*74e12c43SGordon Ross /*
742*74e12c43SGordon Ross  * Code for innetgr()
743*74e12c43SGordon Ross  */
744*74e12c43SGordon Ross 
745*74e12c43SGordon Ross /*
746*74e12c43SGordon Ross  * Iterator function for innetgr():  Check whether triple matches args
747*74e12c43SGordon Ross  */
748*74e12c43SGordon Ross static int
match_triple(ccp triple[NSS_NETGR_N],void * ia_arg,nss_status_t * return_val)749*74e12c43SGordon Ross match_triple(ccp triple[NSS_NETGR_N], void *ia_arg, nss_status_t *return_val)
750*74e12c43SGordon Ross {
751*74e12c43SGordon Ross 	struct nss_innetgr_args	*ia = ia_arg;
752*74e12c43SGordon Ross 	enum nss_netgr_argn	i;
753*74e12c43SGordon Ross 
754*74e12c43SGordon Ross 	if (__nss_files_netgr_debug != NULL) {
755*74e12c43SGordon Ross 		__nss_files_netgr_debug(
756*74e12c43SGordon Ross 		    "match_triple: h=%s u=%s d=%s",
757*74e12c43SGordon Ross 		    triple[0] ? triple[0] : "*",
758*74e12c43SGordon Ross 		    triple[1] ? triple[1] : "*",
759*74e12c43SGordon Ross 		    triple[2] ? triple[2] : "*");
760*74e12c43SGordon Ross 	}
761*74e12c43SGordon Ross 
762*74e12c43SGordon Ross 	for (i = NSS_NETGR_MACHINE;  i < NSS_NETGR_N;  i++) {
763*74e12c43SGordon Ross 		int		(*cmpf)(const char *, const char *);
764*74e12c43SGordon Ross 		char		**argv;
765*74e12c43SGordon Ross 		uint_t		n;
766*74e12c43SGordon Ross 		const char	*name = triple[i];
767*74e12c43SGordon Ross 		int		argc = ia->arg[i].argc;
768*74e12c43SGordon Ross 
769*74e12c43SGordon Ross 		if (argc == 0 || name == NULL) {
770*74e12c43SGordon Ross 			/* Wildcarded on one side or t'other */
771*74e12c43SGordon Ross 			continue;
772*74e12c43SGordon Ross 		}
773*74e12c43SGordon Ross 		argv = ia->arg[i].argv;
774*74e12c43SGordon Ross 		cmpf = (i == NSS_NETGR_MACHINE) ? strcasecmp : strcmp;
775*74e12c43SGordon Ross 		for (n = 0;  n < argc;  n++) {
776*74e12c43SGordon Ross 			if ((*cmpf)(argv[n], name) == 0) {
777*74e12c43SGordon Ross 				break;
778*74e12c43SGordon Ross 			}
779*74e12c43SGordon Ross 		}
780*74e12c43SGordon Ross 		if (n >= argc) {
781*74e12c43SGordon Ross 			/* Match failed, tell top_down() to keep looking */
782*74e12c43SGordon Ross 			return (1);
783*74e12c43SGordon Ross 		}
784*74e12c43SGordon Ross 	}
785*74e12c43SGordon Ross 	/* Matched on all three, so quit looking and declare victory */
786*74e12c43SGordon Ross 
787*74e12c43SGordon Ross 	if (__nss_files_netgr_debug != NULL)
788*74e12c43SGordon Ross 		__nss_files_netgr_debug("match_triple: found");
789*74e12c43SGordon Ross 
790*74e12c43SGordon Ross 	ia->status = NSS_NETGR_FOUND;
791*74e12c43SGordon Ross 	*return_val = NSS_SUCCESS;
792*74e12c43SGordon Ross 	return (0);
793*74e12c43SGordon Ross }
794*74e12c43SGordon Ross 
795*74e12c43SGordon Ross /*
796*74e12c43SGordon Ross  * Used to have easy_way() and it's support functions here.
797*74e12c43SGordon Ross  */
798*74e12c43SGordon Ross 
799*74e12c43SGordon Ross static nss_status_t
netgr_in(struct files_backend * be,void * a)800*74e12c43SGordon Ross netgr_in(struct files_backend *be, void *a)
801*74e12c43SGordon Ross {
802*74e12c43SGordon Ross 	struct nss_innetgr_args	*ia = (struct nss_innetgr_args *)a;
803*74e12c43SGordon Ross 	nss_status_t		res;
804*74e12c43SGordon Ross 
805*74e12c43SGordon Ross 	ia->status = NSS_NETGR_NO;
806*74e12c43SGordon Ross 
807*74e12c43SGordon Ross 	/*
808*74e12c43SGordon Ross 	 * Used to have "easy_way" calls here for the cases
809*74e12c43SGordon Ross 	 * where we have just a user, or just a machine.
810*74e12c43SGordon Ross 	 *
811*74e12c43SGordon Ross 	 * That was important for NIS, where getting the list of
812*74e12c43SGordon Ross 	 * members for some netgroup was a yp_match call that may
813*74e12c43SGordon Ross 	 * need to go over-the-wire.  Here in the "files" backend,
814*74e12c43SGordon Ross 	 * getting the members of a group (getbyname) is a strictly
815*74e12c43SGordon Ross 	 * local operation, and is cached (see hashinfo above) so
816*74e12c43SGordon Ross 	 * it can normally complete with just memory operations.
817*74e12c43SGordon Ross 	 *
818*74e12c43SGordon Ross 	 * With a low-cost getbyname operation, the simple
819*74e12c43SGordon Ross 	 * top_down algorithm has acceptable performance.
820*74e12c43SGordon Ross 	 */
821*74e12c43SGordon Ross 
822*74e12c43SGordon Ross 	/* Nope, try the slow way */
823*74e12c43SGordon Ross 	ia->status = NSS_NETGR_NO;
824*74e12c43SGordon Ross 	res = top_down(be, (const char **)ia->groups.argv, ia->groups.argc,
825*74e12c43SGordon Ross 	    match_triple, ia);
826*74e12c43SGordon Ross 	return (res);
827*74e12c43SGordon Ross }
828*74e12c43SGordon Ross 
829*74e12c43SGordon Ross 
830*74e12c43SGordon Ross /*
831*74e12c43SGordon Ross  * (Almost) boilerplate for a switch backend
832*74e12c43SGordon Ross  */
833*74e12c43SGordon Ross 
834*74e12c43SGordon Ross static nss_status_t
netgr_destr(struct files_backend * be,void * dummy)835*74e12c43SGordon Ross netgr_destr(struct files_backend *be, void *dummy)
836*74e12c43SGordon Ross {
837*74e12c43SGordon Ross 	free(be);
838*74e12c43SGordon Ross 	return (NSS_SUCCESS);
839*74e12c43SGordon Ross }
840*74e12c43SGordon Ross 
841*74e12c43SGordon Ross static files_backend_op_t netgroup_ops[] = {
842*74e12c43SGordon Ross 	netgr_destr,
843*74e12c43SGordon Ross 	NULL,		/* No endent, because no setent/getent */
844*74e12c43SGordon Ross 	NULL,		/* No setent;  setnetgrent() is really a getXbyY() */
845*74e12c43SGordon Ross 	NULL,		/* No getent in the normal sense */
846*74e12c43SGordon Ross 
847*74e12c43SGordon Ross 	netgr_in,	/* innetgr(), via NSS_DBOP_NETGROUP_IN */
848*74e12c43SGordon Ross 	netgr_set,	/* setnetgrent(), via NSS_DBOP_NETGROUP_SET */
849*74e12c43SGordon Ross 	getbyname,	/* For testing, via NSS_DBOP_NETGROUP_BYNAME */
850*74e12c43SGordon Ross };
851*74e12c43SGordon Ross 
852*74e12c43SGordon Ross /*
853*74e12c43SGordon Ross  * This is the one-and-only external entry point in this file.
854*74e12c43SGordon Ross  * It's called by the NSS framework when loading this backend.
855*74e12c43SGordon Ross  */
856*74e12c43SGordon Ross nss_backend_t *
_nss_files_netgroup_constr(const char * dummy1,const char * dummy2,const char * dummy3)857*74e12c43SGordon Ross _nss_files_netgroup_constr(const char *dummy1, const char *dummy2,
858*74e12c43SGordon Ross     const char *dummy3)
859*74e12c43SGordon Ross {
860*74e12c43SGordon Ross 	nss_backend_t	*be;
861*74e12c43SGordon Ross 
862*74e12c43SGordon Ross 	be = _nss_files_constr(netgroup_ops,
863*74e12c43SGordon Ross 	    ARRAY_SIZE(netgroup_ops),
864*74e12c43SGordon Ross 	    "/etc/netgroup",
865*74e12c43SGordon Ross 	    NSS_LINELEN_NETGROUP,
866*74e12c43SGordon Ross 	    &hashinfo);
867*74e12c43SGordon Ross 
868*74e12c43SGordon Ross 	return (be);
869*74e12c43SGordon Ross }
870