xref: /netbsd-src/lib/libc/gen/getnetgrent.c (revision f2575a3983a395b7f367ba835a6dece653f75fea)
1 /*	$NetBSD: getnetgrent.c,v 1.40 2008/04/05 08:01:54 rtr Exp $	*/
2 
3 /*
4  * Copyright (c) 1994 Christos Zoulas
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Christos Zoulas.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 #if defined(LIBC_SCCS) && !defined(lint)
36 __RCSID("$NetBSD: getnetgrent.c,v 1.40 2008/04/05 08:01:54 rtr Exp $");
37 #endif /* LIBC_SCCS and not lint */
38 
39 #include "namespace.h"
40 #include <sys/types.h>
41 
42 #include <assert.h>
43 #include <ctype.h>
44 #include <db.h>
45 #include <err.h>
46 #include <fcntl.h>
47 #define _NETGROUP_PRIVATE
48 #include <stringlist.h>
49 #include <netgroup.h>
50 #include <nsswitch.h>
51 #include <stdarg.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 
56 #ifdef YP
57 #include <rpc/rpc.h>
58 #include <rpcsvc/ypclnt.h>
59 #include <rpcsvc/yp_prot.h>
60 #endif
61 
62 #ifdef __weak_alias
63 __weak_alias(endnetgrent,_endnetgrent)
64 __weak_alias(getnetgrent,_getnetgrent)
65 __weak_alias(innetgr,_innetgr)
66 __weak_alias(setnetgrent,_setnetgrent)
67 #endif
68 
69 #define _NG_STAR(s)	(((s) == NULL || *(s) == '\0') ? _ngstar : s)
70 #define _NG_EMPTY(s)	((s) == NULL ? "" : s)
71 #define _NG_ISSPACE(p)	(isspace((unsigned char) (p)) || (p) == '\n')
72 
73 static const char _ngstar[] = "*";
74 static struct netgroup *_nghead = NULL;
75 static struct netgroup *_nglist = NULL;
76 static DB *_ng_db;
77 
78 static int getstring(char **, int, __aconst char **);
79 static struct netgroup *getnetgroup(char **);
80 static int lookup(char *, char **, int);
81 static int addgroup(StringList *, char *);
82 static int in_check(const char *, const char *, const char *,
83     struct netgroup *);
84 static int in_find(StringList *, char *, const char *, const char *,
85     const char *);
86 static char *in_lookup1(const char *, const char *, int);
87 static int in_lookup(const char *, const char *, const char *, int);
88 
89 #ifdef NSSRC_FILES
90 static const ns_src default_files_nis[] = {
91 	{ NSSRC_FILES,	NS_SUCCESS | NS_NOTFOUND },
92 #ifdef YP
93 	{ NSSRC_NIS,	NS_SUCCESS },
94 #endif
95 	{ 0, 0 },
96 };
97 #endif
98 
99 /*
100  * getstring(): Get a string delimited by the character, skipping leading and
101  * trailing blanks and advancing the pointer
102  */
103 static int
104 getstring(char **pp, int del, char __aconst **str)
105 {
106 	size_t len;
107 	char *sp, *ep, *dp;
108 
109 	_DIAGASSERT(pp != NULL);
110 	_DIAGASSERT(str != NULL);
111 
112 	/* skip leading blanks */
113 	for (sp = *pp; *sp && _NG_ISSPACE(*sp); sp++)
114 		continue;
115 
116 	/* accumulate till delimiter or space */
117 	for (ep = sp; *ep && *ep != del && !_NG_ISSPACE(*ep); ep++)
118 		continue;
119 
120 	/* hunt for the delimiter */
121 	for (dp = ep; *dp && *dp != del && _NG_ISSPACE(*dp); dp++)
122 		continue;
123 
124 	if (*dp != del) {
125 		*str = NULL;
126 		return 0;
127 	}
128 
129 	*pp = ++dp;
130 
131 	len = (ep - sp) + 1;
132 	if (len > 1) {
133 		dp = malloc(len);
134 		if (dp == NULL)
135 			return 0;
136 		(void)memcpy(dp, sp, len);
137 		dp[len - 1] = '\0';
138 	} else
139 		dp = NULL;
140 
141 	*str = dp;
142 	return 1;
143 }
144 
145 
146 /*
147  * getnetgroup(): Parse a netgroup, and advance the pointer
148  */
149 static struct netgroup *
150 getnetgroup(pp)
151 	char	**pp;
152 {
153 	struct netgroup *ng;
154 
155 	_DIAGASSERT(pp != NULL);
156 	_DIAGASSERT(*pp != NULL);
157 
158 	ng = malloc(sizeof(struct netgroup));
159 	if (ng == NULL)
160 		return NULL;
161 
162 	(*pp)++;	/* skip '(' */
163 	if (!getstring(pp, ',', &ng->ng_host))
164 		goto badhost;
165 
166 	if (!getstring(pp, ',', &ng->ng_user))
167 		goto baduser;
168 
169 	if (!getstring(pp, ')', &ng->ng_domain))
170 		goto baddomain;
171 
172 #ifdef DEBUG_NG
173 	{
174 		char buf[1024];
175 		(void) fprintf(stderr, "netgroup %s\n",
176 		    _ng_print(buf, sizeof(buf), ng));
177 	}
178 #endif
179 	return ng;
180 
181 baddomain:
182 	if (ng->ng_user)
183 		free(ng->ng_user);
184 baduser:
185 	if (ng->ng_host)
186 		free(ng->ng_host);
187 badhost:
188 	free(ng);
189 	return NULL;
190 }
191 
192 void
193 _ng_cycle(const char *grp, const StringList *sl)
194 {
195 	size_t i;
196 	warnx("netgroup: Cycle in group `%s'", grp);
197 	(void)fprintf(stderr, "groups: ");
198 	for (i = 0; i < sl->sl_cur; i++)
199 		(void)fprintf(stderr, "%s ", sl->sl_str[i]);
200 	(void)fprintf(stderr, "\n");
201 }
202 
203 static int _local_lookup(void *, void *, va_list);
204 
205 /*ARGSUSED*/
206 static int
207 _local_lookup(void *rv, void *cb_data, va_list ap)
208 {
209 	char	 *name = va_arg(ap, char *);
210 	char	**line = va_arg(ap, char **);
211 	int	  bywhat = va_arg(ap, int);
212 
213 	DBT	 key, data;
214 	size_t	 len;
215 	char	*ks;
216 	int	 r;
217 
218 	if (_ng_db == NULL)
219 		return NS_UNAVAIL;
220 
221 	len = strlen(name) + 2;
222 	ks = malloc(len);
223 	if (ks == NULL)
224 		return NS_UNAVAIL;
225 
226 	ks[0] = bywhat;
227 	(void)memcpy(&ks[1], name, len - 1);
228 
229 	key.data = (u_char *)ks;
230 	key.size = len;
231 
232 	r = (*_ng_db->get)(_ng_db, &key, &data, 0);
233 	free(ks);
234 	switch (r) {
235 	case 0:
236 		break;
237 	case 1:
238 		return NS_NOTFOUND;
239 	case -1:
240 			/* XXX: call endnetgrent() here ? */
241 		return NS_UNAVAIL;
242 	}
243 
244 	*line = strdup(data.data);
245 	if (*line == NULL)
246 		return NS_UNAVAIL;
247 	return NS_SUCCESS;
248 }
249 
250 #ifdef YP
251 static int _nis_lookup(void *, void *, va_list);
252 
253 /*ARGSUSED*/
254 static int
255 _nis_lookup(void *rv, void *cb_data, va_list ap)
256 {
257 	char	 *name = va_arg(ap, char *);
258 	char	**line = va_arg(ap, char **);
259 	int	  bywhat = va_arg(ap, int);
260 
261 	static char	*__ypdomain;
262 	int              i;
263 	const char      *map = NULL;
264 
265 	if(__ypdomain == NULL) {
266 		switch (yp_get_default_domain(&__ypdomain)) {
267 		case 0:
268 			break;
269 		case YPERR_RESRC:
270 			return NS_TRYAGAIN;
271 		default:
272 			return NS_UNAVAIL;
273 		}
274 	}
275 
276 	switch (bywhat) {
277 	case _NG_KEYBYNAME:
278 		map = "netgroup";
279 		break;
280 
281 	case _NG_KEYBYUSER:
282 		map = "netgroup.byuser";
283 		break;
284 
285 	case _NG_KEYBYHOST:
286 		map = "netgroup.byhost";
287 		break;
288 
289 	default:
290 		abort();
291 	}
292 
293 	*line = NULL;
294 	switch (yp_match(__ypdomain, map, name, (int)strlen(name), line, &i)) {
295 	case 0:
296 		return NS_SUCCESS;
297 	case YPERR_KEY:
298 		if (*line)
299 			free(*line);
300 		return NS_NOTFOUND;
301 	default:
302 		if (*line)
303 			free(*line);
304 		return NS_UNAVAIL;
305 	}
306 	/* NOTREACHED */
307 }
308 #endif
309 
310 #ifdef NSSRC_FILES
311 /*
312  * lookup(): Find the given key in the database or yp, and return its value
313  * in *line; returns 1 if key was found, 0 otherwise
314  */
315 static int
316 lookup(char *name, char	**line, int bywhat)
317 {
318 	int		r;
319 	static const ns_dtab dtab[] = {
320 		NS_FILES_CB(_local_lookup, NULL)
321 		NS_NIS_CB(_nis_lookup, NULL)
322 		NS_NULL_CB
323 	};
324 
325 	_DIAGASSERT(name != NULL);
326 	_DIAGASSERT(line != NULL);
327 
328 	r = nsdispatch(NULL, dtab, NSDB_NETGROUP, "lookup", default_files_nis,
329 	    name, line, bywhat);
330 	return (r == NS_SUCCESS) ? 1 : 0;
331 }
332 #else
333 static int
334 _local_lookupv(int *rv, void *cbdata, ...)
335 {
336 	int e;
337 	va_list ap;
338 	va_start(ap, cbdata);
339 	e = _local_lookup(rv, cbdata, ap);
340 	va_end(ap);
341 	return e;
342 }
343 
344 static int
345 lookup(name, line, bywhat)
346 	char	 *name;
347 	char	**line;
348 	int	  bywhat;
349 {
350 	return _local_lookupv(NULL, NULL, name, line, bywhat) == NS_SUCCESS;
351 }
352 #endif
353 
354 /*
355  * _ng_parse(): Parse a line and return: _NG_ERROR: Syntax Error _NG_NONE:
356  * line was empty or a comment _NG_GROUP: line had a netgroup definition,
357  * returned in ng _NG_NAME:  line had a netgroup name, returned in name
358  *
359  * Public since used by netgroup_mkdb
360  */
361 int
362 _ng_parse(char **p, char **name, struct netgroup **ng)
363 {
364 
365 	_DIAGASSERT(p != NULL);
366 	_DIAGASSERT(*p != NULL);
367 	_DIAGASSERT(name != NULL);
368 	_DIAGASSERT(ng != NULL);
369 
370 	while (**p) {
371 		if (**p == '#')
372 			/* comment */
373 			return _NG_NONE;
374 
375 		while (**p && _NG_ISSPACE(**p))
376 			/* skipblank */
377 			(*p)++;
378 
379 		if (**p == '(') {
380 			if ((*ng = getnetgroup(p)) == NULL)
381 				return _NG_ERROR;
382 			return _NG_GROUP;
383 		} else {
384 			char	*np;
385 			size_t	i;
386 
387 			for (np = *p; **p && !_NG_ISSPACE(**p); (*p)++)
388 				continue;
389 			if (np != *p) {
390 				i = (*p - np) + 1;
391 				*name = malloc(i);
392 				if (*name == NULL)
393 					return _NG_ERROR;
394 				(void)memcpy(*name, np, i);
395 				(*name)[i - 1] = '\0';
396 				return _NG_NAME;
397 			}
398 		}
399 	}
400 	return _NG_NONE;
401 }
402 
403 
404 /*
405  * addgroup(): Recursively add all the members of the netgroup to this group.
406  * returns 0 upon failure, nonzero upon success.
407  * grp is not a valid pointer after return (either free(3)ed or allocated
408  * to a stringlist). in either case, it shouldn't be used again.
409  */
410 static int
411 addgroup(StringList *sl, char *grp)
412 {
413 	char		*line, *p;
414 	struct netgroup	*ng;
415 	char		*name;
416 
417 	_DIAGASSERT(sl != NULL);
418 	_DIAGASSERT(grp != NULL);
419 
420 #ifdef DEBUG_NG
421 	(void)fprintf(stderr, "addgroup(%s)\n", grp);
422 #endif
423 	/* check for cycles */
424 	if (sl_find(sl, grp) != NULL) {
425 		_ng_cycle(grp, sl);
426 		free(grp);
427 		return 0;
428 	}
429 	if (sl_add(sl, grp) == -1) {
430 		free(grp);
431 		return 0;
432 	}
433 
434 	/* Lookup this netgroup */
435 	line = NULL;
436 	if (!lookup(grp, &line, _NG_KEYBYNAME)) {
437 		if (line)
438 			free(line);
439 		return 0;
440 	}
441 
442 	p = line;
443 
444 	for (;;) {
445 		switch (_ng_parse(&p, &name, &ng)) {
446 		case _NG_NONE:
447 			/* Done with the line */
448 			free(line);
449 			return 1;
450 
451 		case _NG_GROUP:
452 			/* new netgroup */
453 			/* add to the list */
454 			ng->ng_next = _nglist;
455 			_nglist = ng;
456 			break;
457 
458 		case _NG_NAME:
459 			/* netgroup name */
460 			if (!addgroup(sl, name))
461 				return 0;
462 			break;
463 
464 		case _NG_ERROR:
465 			return 0;
466 
467 		default:
468 			abort();
469 		}
470 	}
471 }
472 
473 
474 /*
475  * in_check(): Compare the spec with the netgroup
476  */
477 static int
478 in_check(const char *host, const char *user, const char *domain,
479     struct netgroup *ng)
480 {
481 
482 	/* host may be NULL */
483 	/* user may be NULL */
484 	/* domain may be NULL */
485 	_DIAGASSERT(ng != NULL);
486 
487 	if ((host != NULL) && (ng->ng_host != NULL)
488 	    && strcmp(ng->ng_host, host) != 0)
489 		return 0;
490 
491 	if ((user != NULL) && (ng->ng_user != NULL)
492 	    && strcmp(ng->ng_user, user) != 0)
493 		return 0;
494 
495 	if ((domain != NULL) && (ng->ng_domain != NULL)
496 	    && strcmp(ng->ng_domain, domain) != 0)
497 		return 0;
498 
499 	return 1;
500 }
501 
502 
503 /*
504  * in_find(): Find a match for the host, user, domain spec.
505  * grp is not a valid pointer after return (either free(3)ed or allocated
506  * to a stringlist). in either case, it shouldn't be used again.
507  */
508 static int
509 in_find(StringList *sl, char *grp, const char *host, const char *user,
510     const char *domain)
511 {
512 	char		*line, *p;
513 	int		 i;
514 	struct netgroup	*ng;
515 	char		*name;
516 
517 	_DIAGASSERT(sl != NULL);
518 	_DIAGASSERT(grp != NULL);
519 	/* host may be NULL */
520 	/* user may be NULL */
521 	/* domain may be NULL */
522 
523 #ifdef DEBUG_NG
524 	(void)fprintf(stderr, "in_find(%s)\n", grp);
525 #endif
526 	/* check for cycles */
527 	if (sl_find(sl, grp) != NULL) {
528 		_ng_cycle(grp, sl);
529 		free(grp);
530 		return 0;
531 	}
532 	if (sl_add(sl, grp) == -1) {
533 		free(grp);
534 		return 0;
535 	}
536 
537 	/* Lookup this netgroup */
538 	line = NULL;
539 	if (!lookup(grp, &line, _NG_KEYBYNAME)) {
540 		if (line)
541 			free(line);
542 		return 0;
543 	}
544 
545 	p = line;
546 
547 	for (;;) {
548 		switch (_ng_parse(&p, &name, &ng)) {
549 		case _NG_NONE:
550 			/* Done with the line */
551 			free(line);
552 			return 0;
553 
554 		case _NG_GROUP:
555 			/* new netgroup */
556 			i = in_check(host, user, domain, ng);
557 			if (ng->ng_host != NULL)
558 				free(ng->ng_host);
559 			if (ng->ng_user != NULL)
560 				free(ng->ng_user);
561 			if (ng->ng_domain != NULL)
562 				free(ng->ng_domain);
563 			free(ng);
564 			if (i) {
565 				free(line);
566 				return 1;
567 			}
568 			break;
569 
570 		case _NG_NAME:
571 			/* netgroup name */
572 			if (in_find(sl, name, host, user, domain)) {
573 				free(line);
574 				return 1;
575 			}
576 			break;
577 
578 		case _NG_ERROR:
579 			free(line);
580 			return 0;
581 
582 		default:
583 			abort();
584 		}
585 	}
586 }
587 
588 /*
589  * _ng_makekey(): Make a key from the two names given. The key is of the form
590  * <name1>.<name2> Names strings are replaced with * if they are empty;
591  * Returns NULL if there's a problem.
592  */
593 char *
594 _ng_makekey(const char *s1, const char *s2, size_t len)
595 {
596 	char *buf;
597 
598 	/* s1 may be NULL */
599 	/* s2 may be NULL */
600 
601 	buf = malloc(len);
602 	if (buf != NULL)
603 		(void)snprintf(buf, len, "%s.%s", _NG_STAR(s1), _NG_STAR(s2));
604 	return buf;
605 }
606 
607 void
608 _ng_print(char *buf, size_t len, const struct netgroup *ng)
609 {
610 	_DIAGASSERT(buf != NULL);
611 	_DIAGASSERT(ng != NULL);
612 
613 	(void)snprintf(buf, len, "(%s,%s,%s)", _NG_EMPTY(ng->ng_host),
614 	    _NG_EMPTY(ng->ng_user), _NG_EMPTY(ng->ng_domain));
615 }
616 
617 
618 /*
619  * in_lookup1(): Fast lookup for a key in the appropriate map
620  */
621 static char *
622 in_lookup1(const char *key, const char *domain, int map)
623 {
624 	char	*line;
625 	size_t	 len;
626 	char	*ptr;
627 	int	 res;
628 
629 	/* key may be NULL */
630 	/* domain may be NULL */
631 
632 	len = (key ? strlen(key) : 1) + (domain ? strlen(domain) : 1) + 2;
633 	ptr = _ng_makekey(key, domain, len);
634 	if (ptr == NULL)
635 		return NULL;
636 	res = lookup(ptr, &line, map);
637 	free(ptr);
638 	return res ? line : NULL;
639 }
640 
641 
642 /*
643  * in_lookup(): Fast lookup for a key in the appropriate map
644  */
645 static int
646 in_lookup(const char *group, const char *key, const char *domain, int map)
647 {
648 	size_t	 len;
649 	char	*ptr, *line;
650 
651 	_DIAGASSERT(group != NULL);
652 	/* key may be NULL */
653 	/* domain may be NULL */
654 
655 	if (domain != NULL) {
656 		/* Domain specified; look in "group.domain" and "*.domain" */
657 		if ((line = in_lookup1(key, domain, map)) == NULL)
658 			line = in_lookup1(NULL, domain, map);
659 	} else
660 		line = NULL;
661 
662 	if (line == NULL) {
663 	    /*
664 	     * domain not specified or domain lookup failed; look in
665 	     * "group.*" and "*.*"
666 	     */
667 	    if (((line = in_lookup1(key, NULL, map)) == NULL) &&
668 		((line = in_lookup1(NULL, NULL, map)) == NULL))
669 		return 0;
670 	}
671 
672 	len = strlen(group);
673 
674 	for (ptr = line; (ptr = strstr(ptr, group)) != NULL;)
675 		/* Make sure we did not find a substring */
676 		if ((ptr != line && ptr[-1] != ',') ||
677 		    (ptr[len] != '\0' && strchr("\n\t ,", ptr[len]) == NULL))
678 			ptr++;
679 		else {
680 			free(line);
681 			return 1;
682 		}
683 
684 	free(line);
685 	return 0;
686 }
687 
688 /*ARGSUSED*/
689 static int
690 _local_endnetgrent(void *rv, void *cb_data, va_list ap)
691 {
692 	for (_nglist = _nghead; _nglist != NULL; _nglist = _nghead) {
693 		_nghead = _nglist->ng_next;
694 		if (_nglist->ng_host != NULL)
695 			free(_nglist->ng_host);
696 		if (_nglist->ng_user != NULL)
697 			free(_nglist->ng_user);
698 		if (_nglist->ng_domain != NULL)
699 			free(_nglist->ng_domain);
700 		free(_nglist);
701 	}
702 
703 	if (_ng_db) {
704 		(void)(*_ng_db->close)(_ng_db);
705 		_ng_db = NULL;
706 	}
707 
708 	return NS_SUCCESS;
709 }
710 
711 /*ARGSUSED*/
712 static int
713 _local_setnetgrent(void *rv, void *cb_data, va_list ap)
714 {
715 	const char	*ng = va_arg(ap, const char *);
716 	StringList	*sl;
717 	char		*ng_copy;
718 
719 	_DIAGASSERT(ng != NULL);
720 
721 	sl = sl_init();
722 	if (sl == NULL)
723 		return NS_TRYAGAIN;
724 
725 	/* Cleanup any previous storage */
726 	if (_nghead != NULL)
727 		endnetgrent();
728 
729 	if (_ng_db == NULL)
730 		_ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
731 
732 	ng_copy = strdup(ng);
733 	if (ng_copy != NULL)
734 		addgroup(sl, ng_copy);
735 	_nghead = _nglist;
736 	sl_free(sl, 1);
737 
738 	return NS_SUCCESS;
739 }
740 
741 /*ARGSUSED*/
742 static int
743 _local_getnetgrent(void *rv, void *cb_data, va_list ap)
744 {
745 	int *retval = va_arg(ap, int *);
746 	const char **host = va_arg(ap, const char **);
747 	const char **user = va_arg(ap, const char **);
748 	const char **domain = va_arg(ap, const char **);
749 
750 	_DIAGASSERT(host != NULL);
751 	_DIAGASSERT(user != NULL);
752 	_DIAGASSERT(domain != NULL);
753 
754 	*retval = 0;
755 
756 	if (_nglist == NULL)
757 		return NS_TRYAGAIN;
758 
759 	*host   = _nglist->ng_host;
760 	*user   = _nglist->ng_user;
761 	*domain = _nglist->ng_domain;
762 
763 	_nglist = _nglist->ng_next;
764 
765 	*retval = 1;
766 
767 	return NS_SUCCESS;
768 }
769 
770 /*ARGSUSED*/
771 static int
772 _local_innetgr(void *rv, void *cb_data, va_list ap)
773 {
774 	int *retval = va_arg(ap, int *);
775 	const char *grp = va_arg(ap, const char *);
776 	const char *host = va_arg(ap, const char *);
777 	const char *user = va_arg(ap, const char *);
778 	const char *domain = va_arg(ap, const char *);
779 
780 	int	 found;
781 	StringList *sl;
782 	char *grcpy;
783 
784 	_DIAGASSERT(grp != NULL);
785 	/* host may be NULL */
786 	/* user may be NULL */
787 	/* domain may be NULL */
788 
789 	if (_ng_db == NULL)
790 		_ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
791 
792 	/* Try the fast lookup first */
793 	if (host != NULL && user == NULL) {
794 		if (in_lookup(grp, host, domain, _NG_KEYBYHOST)) {
795 			*retval = 1;
796 			return NS_SUCCESS;
797 		}
798 	} else if (host == NULL && user != NULL) {
799 		if (in_lookup(grp, user, domain, _NG_KEYBYUSER)) {
800 			*retval = 1;
801 			return NS_SUCCESS;
802 		}
803 	}
804 	/* If a domainname is given, we would have found a match */
805 	if (domain != NULL) {
806 		*retval = 0;
807 		return NS_SUCCESS;
808 	}
809 
810 	/* Too bad need the slow recursive way */
811 	sl = sl_init();
812 	if (sl == NULL) {
813 		*retval = 0;
814 		return NS_SUCCESS;
815 	}
816 	if ((grcpy = strdup(grp)) == NULL) {
817 		sl_free(sl, 1);
818 		*retval = 0;
819 		return NS_SUCCESS;
820 	}
821 	found = in_find(sl, grcpy, host, user, domain);
822 	sl_free(sl, 1);
823 
824 	*retval = found;
825 	return NS_SUCCESS;
826 }
827 
828 #ifdef YP
829 
830 /*ARGSUSED*/
831 static int
832 _nis_endnetgrent(void *rv, void *cb_data, va_list ap)
833 {
834 	return _local_endnetgrent(rv, cb_data, ap);
835 }
836 
837 /*ARGSUSED*/
838 static int
839 _nis_setnetgrent(void *rv, void *cb_data, va_list ap)
840 {
841 	return _local_setnetgrent(rv, cb_data, ap);
842 }
843 
844 /*ARGSUSED*/
845 static int
846 _nis_getnetgrent(void *rv, void *cb_data, va_list ap)
847 {
848 	return _local_getnetgrent(rv, cb_data, ap);
849 }
850 
851 /*ARGSUSED*/
852 static int
853 _nis_innetgr(void *rv, void *cb_data, va_list ap)
854 {
855 	return _local_innetgr(rv, cb_data, ap);
856 }
857 
858 #endif
859 
860 
861 #ifdef NSSRC_FILES
862 void
863 endnetgrent(void)
864 {
865 	static const ns_dtab dtab[] = {
866 		NS_FILES_CB(_local_endnetgrent, NULL)
867 		NS_NIS_CB(_nis_endnetgrent, NULL)
868 		NS_NULL_CB
869 	};
870 
871 	(void) nsdispatch(NULL, dtab, NSDB_NETGROUP, "endnetgrent",
872 			  __nsdefaultcompat);
873 }
874 #else
875 static int
876 _local_endnetgrentv(int *rv, void *cbdata, ...)
877 {
878 	int e;
879 	va_list ap;
880 	va_start(ap, cbdata);
881 	e = _local_endnetgrent(rv, cbdata, ap);
882 	va_end(ap);
883 	return e;
884 }
885 
886 void
887 endnetgrent(void)
888 {
889 	(void)_local_endnetgrentv(NULL, NULL, NULL);
890 }
891 #endif
892 
893 #ifdef NSSRC_FILES
894 void
895 setnetgrent(const char *ng)
896 {
897 	static const ns_dtab dtab[] = {
898 		NS_FILES_CB(_local_setnetgrent, NULL)
899 		NS_NIS_CB(_nis_setnetgrent, NULL)
900 		NS_NULL_CB
901 	};
902 
903 	(void) nsdispatch(NULL, dtab, NSDB_NETGROUP, "setnetgrent",
904 			   __nsdefaultnis, ng);
905 }
906 #else
907 static int
908 _local_setnetgrentv(int *rv, void *cbdata, ...)
909 {
910 	int e;
911 	va_list ap;
912 	va_start(ap, cbdata);
913 	e = _local_setnetgrent(rv, cbdata, ap);
914 	va_end(ap);
915 	return e;
916 }
917 
918 void
919 setnetgrent(const char *ng)
920 {
921 	(void) _local_setnetgrentv(NULL, NULL,ng);
922 }
923 
924 #endif
925 
926 #ifdef NSSRC_FILES
927 int
928 getnetgrent(const char **host, const char **user, const char **domain)
929 {
930 	int     r, retval;
931 	static const ns_dtab dtab[] = {
932 		NS_FILES_CB(_local_getnetgrent, NULL)
933 		NS_NIS_CB(_nis_getnetgrent, NULL)
934 		NS_NULL_CB
935 	};
936 
937 	r = nsdispatch(NULL, dtab, NSDB_NETGROUP, "getnetgrent",
938 		       __nsdefaultnis, &retval, host, user, domain);
939 
940 	return (r == NS_SUCCESS) ? retval : 0;
941 }
942 #else
943 static int
944 _local_getnetgrentv(int *rv, void *cbdata, ...)
945 {
946 	int e;
947 	va_list ap;
948 	va_start(ap, cbdata);
949 	e = _local_getnetgrent(rv, cbdata, ap);
950 	va_end(ap);
951 	return e;
952 }
953 
954 int
955 getnetgrent(const char **host, const char **user, const char **domain)
956 {
957 	return _local_getnetgrentv(NULL, NULL, host, user, domain) == NS_SUCCESS;
958 }
959 #endif
960 
961 #ifdef NSSRC_FILES
962 int
963 innetgr(const char *grp, const char *host, const char *user,
964 	const char *domain)
965 {
966 	int     r, retval;
967 	static const ns_dtab dtab[] = {
968 		NS_FILES_CB(_local_innetgr, NULL)
969 		NS_NIS_CB(_nis_innetgr, NULL)
970 		NS_NULL_CB
971 	};
972 
973 	r = nsdispatch(NULL, dtab, NSDB_NETGROUP, "innetgr",
974 		       __nsdefaultnis, &retval, grp, host, user, domain);
975 
976 	return (r == NS_SUCCESS) ? retval : 0;
977 }
978 #else
979 static int
980 _local_innetgrv(int *rv, void *cbdata, ...)
981 {
982 	int e;
983 	va_list ap;
984 	va_start(ap, cbdata);
985 	e = _local_innetgr(rv, cbdata, ap);
986 	va_end(ap);
987 	return e;
988 }
989 
990 int
991 innetgr(const char *grp, const char *host, const char *user,
992 	const char *domain)
993 {
994 	return _local_innetgrv(NULL, NULL, grp, host, user, domain) == NS_SUCCESS;
995 }
996 #endif
997