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