xref: /netbsd-src/lib/libc/gen/getnetgrent.c (revision 1ca5c1b28139779176bd5c13ad7c5f25c0bcd5f8)
1 /*	$NetBSD: getnetgrent.c,v 1.28 2000/01/22 22:40:58 mycroft 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.28 2000/01/22 22:40:58 mycroft 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 <netgroup.h>
49 #include <nsswitch.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <stringlist.h>
54 
55 #ifdef YP
56 #include <rpc/rpc.h>
57 #include <rpcsvc/ypclnt.h>
58 #include <rpcsvc/yp_prot.h>
59 #endif
60 
61 #ifdef __STDC__
62 #include <stdarg.h>
63 #else
64 #include <varargs.h>
65 #endif
66 
67 #ifdef __weak_alias
68 __weak_alias(endnetgrent,_endnetgrent)
69 __weak_alias(getnetgrent,_getnetgrent)
70 __weak_alias(innetgr,_innetgr)
71 __weak_alias(setnetgrent,_setnetgrent)
72 #endif
73 
74 #define _NG_STAR(s)	(((s) == NULL || *(s) == '\0') ? _ngstar : s)
75 #define _NG_EMPTY(s)	((s) == NULL ? "" : s)
76 #define _NG_ISSPACE(p)	(isspace((unsigned char) (p)) || (p) == '\n')
77 
78 static const char _ngstar[] = "*";
79 static struct netgroup *_nghead = (struct netgroup *)NULL;
80 static struct netgroup *_nglist = (struct netgroup *)NULL;
81 static DB *_ng_db;
82 
83 static int		 getstring __P((char **, int, __aconst char **));
84 static struct netgroup	*getnetgroup __P((char **));
85 static int		 lookup __P((char *, char **, int));
86 static int		 addgroup __P((StringList *, char *));
87 static int		 in_check __P((const char *, const char *,
88 				       const char *, struct netgroup *));
89 static int		 in_find __P((StringList *, char *, const char *,
90 				      const char *, const char *));
91 static char		*in_lookup1 __P((const char *, const char *, int));
92 static int		 in_lookup __P((const char *, const char *,
93 					const char *, int));
94 
95 static const ns_src default_files_nis[] = {
96 	{ NSSRC_FILES,	NS_SUCCESS | NS_NOTFOUND },
97 #ifdef YP
98 	{ NSSRC_NIS,	NS_SUCCESS },
99 #endif
100 	{ 0 }
101 };
102 
103 /*
104  * getstring(): Get a string delimited by the character, skipping leading and
105  * trailing blanks and advancing the pointer
106  */
107 static int
108 getstring(pp, del, str)
109 	char	**pp;
110 	int	  del;
111 	char	__aconst **str;
112 {
113 	size_t len;
114 	char *sp, *ep, *dp;
115 
116 	_DIAGASSERT(pp != NULL);
117 	_DIAGASSERT(str != NULL);
118 
119 	/* skip leading blanks */
120 	for (sp = *pp; *sp && _NG_ISSPACE(*sp); sp++)
121 		continue;
122 
123 	/* accumulate till delimiter or space */
124 	for (ep = sp; *ep && *ep != del && !_NG_ISSPACE(*ep); ep++)
125 		continue;
126 
127 	/* hunt for the delimiter */
128 	for (dp = ep; *dp && *dp != del && _NG_ISSPACE(*dp); dp++)
129 		continue;
130 
131 	if (*dp != del) {
132 		*str = NULL;
133 		return 0;
134 	}
135 
136 	*pp = ++dp;
137 
138 	len = (ep - sp) + 1;
139 	if (len > 1) {
140 		dp = malloc(len);
141 		if (dp == NULL)
142 			return 0;
143 		memcpy(dp, sp, len);
144 		dp[len - 1] = '\0';
145 	} else
146 		dp = NULL;
147 
148 	*str = dp;
149 	return 1;
150 }
151 
152 
153 /*
154  * getnetgroup(): Parse a netgroup, and advance the pointer
155  */
156 static struct netgroup *
157 getnetgroup(pp)
158 	char	**pp;
159 {
160 	struct netgroup *ng;
161 
162 	_DIAGASSERT(pp != NULL);
163 	_DIAGASSERT(*pp != NULL);
164 
165 	ng = malloc(sizeof(struct netgroup));
166 	if (ng == NULL)
167 		return NULL;
168 
169 	(*pp)++;	/* skip '(' */
170 	if (!getstring(pp, ',', &ng->ng_host))
171 		goto badhost;
172 
173 	if (!getstring(pp, ',', &ng->ng_user))
174 		goto baduser;
175 
176 	if (!getstring(pp, ')', &ng->ng_domain))
177 		goto baddomain;
178 
179 #ifdef DEBUG_NG
180 	{
181 		char buf[1024];
182 		(void) fprintf(stderr, "netgroup %s\n",
183 		    _ng_print(buf, sizeof(buf), ng));
184 	}
185 #endif
186 	return ng;
187 
188 baddomain:
189 	if (ng->ng_user)
190 		free((char *)ng->ng_user);
191 baduser:
192 	if (ng->ng_host)
193 		free((char *)ng->ng_host);
194 badhost:
195 	free(ng);
196 	return NULL;
197 }
198 
199 
200 static int _local_lookup __P((void *, void *, va_list));
201 
202 /*ARGSUSED*/
203 static int
204 _local_lookup(rv, cb_data, ap)
205 	void	*rv;
206 	void	*cb_data;
207 	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 	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 __P((void *, void *, va_list));
252 
253 /*ARGSUSED*/
254 static int
255 _nis_lookup(rv, cb_data, ap)
256 	void	*rv;
257 	void	*cb_data;
258 	va_list	 ap;
259 {
260 	char	 *name = va_arg(ap, char *);
261 	char	**line = va_arg(ap, char **);
262 	int	  bywhat = va_arg(ap, int);
263 
264 	static char	*__ypdomain;
265 	int              i;
266 	char            *map = NULL;
267 
268 	if(__ypdomain == NULL) {
269 		switch (yp_get_default_domain(&__ypdomain)) {
270 		case 0:
271 			break;
272 		case YPERR_RESRC:
273 			return NS_TRYAGAIN;
274 		default:
275 			return NS_UNAVAIL;
276 		}
277 	}
278 
279 	switch (bywhat) {
280 	case _NG_KEYBYNAME:
281 		map = "netgroup";
282 		break;
283 
284 	case _NG_KEYBYUSER:
285 		map = "netgroup.byuser";
286 		break;
287 
288 	case _NG_KEYBYHOST:
289 		map = "netgroup.byhost";
290 		break;
291 
292 	default:
293 		abort();
294 	}
295 
296 	*line = NULL;
297 	switch (yp_match(__ypdomain, map, name, (int)strlen(name), line, &i)) {
298 	case 0:
299 		return NS_SUCCESS;
300 	case YPERR_KEY:
301 		if (*line)
302 			free(*line);
303 		return NS_NOTFOUND;
304 	default:
305 		if (*line)
306 			free(*line);
307 		return NS_UNAVAIL;
308 	}
309 	/* NOTREACHED */
310 }
311 #endif
312 
313 
314 /*
315  * lookup(): Find the given key in the database or yp, and return its value
316  * in *line; returns 1 if key was found, 0 otherwise
317  */
318 static int
319 lookup(name, line, bywhat)
320 	char	 *name;
321 	char	**line;
322 	int	  bywhat;
323 {
324 	int		r;
325 	static const ns_dtab dtab[] = {
326 		NS_FILES_CB(_local_lookup, NULL)
327 		NS_NIS_CB(_nis_lookup, NULL)
328 		{ 0 }
329 	};
330 
331 	_DIAGASSERT(name != NULL);
332 	_DIAGASSERT(line != NULL);
333 
334 	r = nsdispatch(NULL, dtab, NSDB_NETGROUP, "lookup", default_files_nis,
335 	    name, line, bywhat);
336 	return (r == NS_SUCCESS) ? 1 : 0;
337 }
338 
339 /*
340  * _ng_parse(): Parse a line and return: _NG_ERROR: Syntax Error _NG_NONE:
341  * line was empty or a comment _NG_GROUP: line had a netgroup definition,
342  * returned in ng _NG_NAME:  line had a netgroup name, returned in name
343  *
344  * Public since used by netgroup_mkdb
345  */
346 int
347 _ng_parse(p, name, ng)
348 	char		**p;
349 	char		**name;
350 	struct netgroup	**ng;
351 {
352 
353 	_DIAGASSERT(p != NULL);
354 	_DIAGASSERT(*p != NULL);
355 	_DIAGASSERT(name != NULL);
356 	_DIAGASSERT(ng != NULL);
357 
358 	while (**p) {
359 		if (**p == '#')
360 			/* comment */
361 			return _NG_NONE;
362 
363 		while (**p && _NG_ISSPACE(**p))
364 			/* skipblank */
365 			(*p)++;
366 
367 		if (**p == '(') {
368 			if ((*ng = getnetgroup(p)) == NULL)
369 				return _NG_ERROR;
370 			return _NG_GROUP;
371 		} else {
372 			char	*np;
373 			size_t	i;
374 
375 			for (np = *p; **p && !_NG_ISSPACE(**p); (*p)++)
376 				continue;
377 			if (np != *p) {
378 				i = (*p - np) + 1;
379 				*name = malloc(i);
380 				if (*name == NULL)
381 					return _NG_ERROR;
382 				memcpy(*name, np, i);
383 				(*name)[i - 1] = '\0';
384 				return _NG_NAME;
385 			}
386 		}
387 	}
388 	return _NG_NONE;
389 }
390 
391 
392 /*
393  * addgroup(): Recursively add all the members of the netgroup to this group.
394  * returns 0 upon failure, nonzero upon success.
395  * grp is not a valid pointer after return (either free(3)ed or allocated
396  * to a stringlist). in either case, it shouldn't be used again.
397  */
398 static int
399 addgroup(sl, grp)
400 	StringList	*sl;
401 	char		*grp;
402 {
403 	char		*line, *p;
404 	struct netgroup	*ng;
405 	char		*name;
406 
407 	_DIAGASSERT(sl != NULL);
408 	_DIAGASSERT(grp != NULL);
409 
410 #ifdef DEBUG_NG
411 	(void) fprintf(stderr, "addgroup(%s)\n", grp);
412 #endif
413 	/* check for cycles */
414 	if (sl_find(sl, grp) != NULL) {
415 		free(grp);
416 		warnx("netgroup: Cycle in group `%s'", grp);
417 		return 0;
418 	}
419 	if (sl_add(sl, grp) == -1) {
420 		free(grp);
421 		return 0;
422 	}
423 
424 	/* Lookup this netgroup */
425 	line = NULL;
426 	if (!lookup(grp, &line, _NG_KEYBYNAME)) {
427 		if (line != NULL)
428 			free(line);
429 		return 0;
430 	}
431 
432 	p = line;
433 
434 	for (;;) {
435 		switch (_ng_parse(&p, &name, &ng)) {
436 		case _NG_NONE:
437 			/* Done with the line */
438 			free(line);
439 			return 1;
440 
441 		case _NG_GROUP:
442 			/* new netgroup */
443 			/* add to the list */
444 			ng->ng_next = _nglist;
445 			_nglist = ng;
446 			break;
447 
448 		case _NG_NAME:
449 			/* netgroup name */
450 			if (!addgroup(sl, name))
451 				return 0;
452 			break;
453 
454 		case _NG_ERROR:
455 			return 0;
456 
457 		default:
458 			abort();
459 		}
460 	}
461 }
462 
463 
464 /*
465  * in_check(): Compare the spec with the netgroup
466  */
467 static int
468 in_check(host, user, domain, ng)
469 	const char	*host;
470 	const char	*user;
471 	const char	*domain;
472 	struct netgroup	*ng;
473 {
474 
475 	/* host may be NULL */
476 	/* user may be NULL */
477 	/* domain may be NULL */
478 	_DIAGASSERT(ng != NULL);
479 
480 	if ((host != NULL) && (ng->ng_host != NULL)
481 	    && strcmp(ng->ng_host, host) != 0)
482 		return 0;
483 
484 	if ((user != NULL) && (ng->ng_user != NULL)
485 	    && strcmp(ng->ng_user, user) != 0)
486 		return 0;
487 
488 	if ((domain != NULL) && (ng->ng_domain != NULL)
489 	    && strcmp(ng->ng_domain, domain) != 0)
490 		return 0;
491 
492 	return 1;
493 }
494 
495 
496 /*
497  * in_find(): Find a match for the host, user, domain spec.
498  * grp is not a valid pointer after return (either free(3)ed or allocated
499  * to a stringlist). in either case, it shouldn't be used again.
500  */
501 static int
502 in_find(sl, grp, host, user, domain)
503 	StringList	*sl;
504 	char		*grp;
505 	const char	*host;
506 	const char	*user;
507 	const char	*domain;
508 {
509 	char		*line, *p;
510 	int		 i;
511 	struct netgroup	*ng;
512 	char		*name;
513 
514 	_DIAGASSERT(sl != NULL);
515 	_DIAGASSERT(grp != NULL);
516 	/* host may be NULL */
517 	/* user may be NULL */
518 	/* domain may be NULL */
519 
520 #ifdef DEBUG_NG
521 	(void) fprintf(stderr, "in_find(%s)\n", grp);
522 #endif
523 	/* check for cycles */
524 	if (sl_find(sl, grp) != NULL) {
525 		free(grp);
526 		warnx("netgroup: Cycle in group `%s'", grp);
527 		return 0;
528 	}
529 	if (sl_add(sl, grp) == -1) {
530 		free(grp);
531 		return 0;
532 	}
533 
534 	/* Lookup this netgroup */
535 	line = NULL;
536 	if (!lookup(grp, &line, _NG_KEYBYNAME)) {
537 		if (line)
538 			free(line);
539 		return 0;
540 	}
541 
542 	p = line;
543 
544 	for (;;) {
545 		switch (_ng_parse(&p, &name, &ng)) {
546 		case _NG_NONE:
547 			/* Done with the line */
548 			free(line);
549 			return 0;
550 
551 		case _NG_GROUP:
552 			/* new netgroup */
553 			i = in_check(host, user, domain, ng);
554 			if (ng->ng_host != NULL)
555 				free((char *)ng->ng_host);
556 			if (ng->ng_user != NULL)
557 				free((char *)ng->ng_user);
558 			if (ng->ng_domain != NULL)
559 				free((char *)ng->ng_domain);
560 			free(ng);
561 			if (i) {
562 				free(line);
563 				return 1;
564 			}
565 			break;
566 
567 		case _NG_NAME:
568 			/* netgroup name */
569 			if (in_find(sl, name, host, user, domain)) {
570 				free(line);
571 				return 1;
572 			}
573 			break;
574 
575 		case _NG_ERROR:
576 			free(line);
577 			return 0;
578 
579 		default:
580 			abort();
581 		}
582 	}
583 }
584 
585 /*
586  * _ng_makekey(): Make a key from the two names given. The key is of the form
587  * <name1>.<name2> Names strings are replaced with * if they are empty;
588  * Returns NULL if there's a problem.
589  */
590 char *
591 _ng_makekey(s1, s2, len)
592 	const char	*s1, *s2;
593 	size_t		 len;
594 {
595 	char *buf;
596 
597 	/* s1 may be NULL */
598 	/* s2 may be NULL */
599 
600 	buf = malloc(len);
601 	if (buf != NULL)
602 		(void) snprintf(buf, len, "%s.%s", _NG_STAR(s1), _NG_STAR(s2));
603 	return buf;
604 }
605 
606 void
607 _ng_print(buf, len, ng)
608 	char *buf;
609 	size_t len;
610 	const struct netgroup *ng;
611 {
612 	_DIAGASSERT(buf != NULL);
613 	_DIAGASSERT(ng != NULL);
614 
615 	(void) snprintf(buf, len, "(%s,%s,%s)", _NG_EMPTY(ng->ng_host),
616 	    _NG_EMPTY(ng->ng_user), _NG_EMPTY(ng->ng_domain));
617 }
618 
619 
620 /*
621  * in_lookup1(): Fast lookup for a key in the appropriate map
622  */
623 static char *
624 in_lookup1(key, domain, map)
625 	const char	*key;
626 	const char	*domain;
627 	int		 map;
628 {
629 	char	*line;
630 	size_t	 len;
631 	char	*ptr;
632 	int	 res;
633 
634 	/* key may be NULL */
635 	/* domain may be NULL */
636 
637 	len = (key ? strlen(key) : 1) + (domain ? strlen(domain) : 1) + 2;
638 	ptr = _ng_makekey(key, domain, len);
639 	if (ptr == NULL)
640 		return NULL;
641 	res = lookup(ptr, &line, map);
642 	free(ptr);
643 	return res ? line : NULL;
644 }
645 
646 
647 /*
648  * in_lookup(): Fast lookup for a key in the appropriate map
649  */
650 static int
651 in_lookup(group, key, domain, map)
652 	const char	*group;
653 	const char	*key;
654 	const char	*domain;
655 	int		 map;
656 {
657 	size_t	 len;
658 	char	*ptr, *line;
659 
660 	_DIAGASSERT(group != NULL);
661 	/* key may be NULL */
662 	/* domain may be NULL */
663 
664 	if (domain != NULL) {
665 		/* Domain specified; look in "group.domain" and "*.domain" */
666 		if ((line = in_lookup1(key, domain, map)) == NULL)
667 			line = in_lookup1(NULL, domain, map);
668 	} else
669 		line = NULL;
670 
671 	if (line == NULL) {
672 		/*
673 		 * domain not specified or domain lookup failed; look in
674 		 * "group.*" and "*.*"
675 		 */
676 	    if (((line = in_lookup1(key, NULL, map)) == NULL) &&
677 		((line = in_lookup1(NULL, NULL, map)) == NULL))
678 		return 0;
679 	}
680 
681 	len = strlen(group);
682 
683 	for (ptr = line; (ptr = strstr(ptr, group)) != NULL;)
684 		/* Make sure we did not find a substring */
685 		if ((ptr != line && ptr[-1] != ',') ||
686 		    (ptr[len] != '\0' && strchr("\n\t ,", ptr[len]) == NULL))
687 			ptr++;
688 		else {
689 			free(line);
690 			return 1;
691 		}
692 
693 	free(line);
694 	return 0;
695 }
696 
697 
698 void
699 endnetgrent()
700 {
701 	for (_nglist = _nghead; _nglist != NULL; _nglist = _nghead) {
702 		_nghead = _nglist->ng_next;
703 		if (_nglist->ng_host != NULL)
704 			free((char *)_nglist->ng_host);
705 		if (_nglist->ng_user != NULL)
706 			free((char *)_nglist->ng_user);
707 		if (_nglist->ng_domain != NULL)
708 			free((char *)_nglist->ng_domain);
709 		free(_nglist);
710 	}
711 
712 	if (_ng_db) {
713 		(void) (_ng_db->close) (_ng_db);
714 		_ng_db = NULL;
715 	}
716 }
717 
718 
719 void
720 setnetgrent(ng)
721 	const char	*ng;
722 {
723 	StringList	*sl;
724 	char		*ng_copy;
725 
726 	_DIAGASSERT(ng != NULL);
727 
728 	sl = sl_init();
729 	if (sl == NULL)
730 		return;
731 
732 	/* Cleanup any previous storage */
733 	if (_nghead != NULL)
734 		endnetgrent();
735 
736 	if (_ng_db == NULL)
737 		_ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
738 
739 	ng_copy = strdup(ng);
740 	if (ng_copy != NULL)
741 		addgroup(sl, ng_copy);
742 	_nghead = _nglist;
743 	sl_free(sl, 1);
744 }
745 
746 
747 int
748 getnetgrent(host, user, domain)
749 	const char	**host;
750 	const char	**user;
751 	const char	**domain;
752 {
753 	_DIAGASSERT(host != NULL);
754 	_DIAGASSERT(user != NULL);
755 	_DIAGASSERT(domain != NULL);
756 
757 	if (_nglist == NULL)
758 		return 0;
759 
760 	*host   = _nglist->ng_host;
761 	*user   = _nglist->ng_user;
762 	*domain = _nglist->ng_domain;
763 
764 	_nglist = _nglist->ng_next;
765 
766 	return 1;
767 }
768 
769 
770 int
771 innetgr(grp, host, user, domain)
772 	const char	*grp, *host, *user, *domain;
773 {
774 	int	 found;
775 	StringList *sl;
776 
777 	_DIAGASSERT(grp != NULL);
778 	/* host may be NULL */
779 	/* user may be NULL */
780 	/* domain may be NULL */
781 
782 	if (_ng_db == NULL)
783 		_ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
784 
785 	/* Try the fast lookup first */
786 	if (host != NULL && user == NULL) {
787 		if (in_lookup(grp, host, domain, _NG_KEYBYHOST))
788 			return 1;
789 	} else if (host == NULL && user != NULL) {
790 		if (in_lookup(grp, user, domain, _NG_KEYBYUSER))
791 			return 1;
792 	}
793 	/* If a domainname is given, we would have found a match */
794 	if (domain != NULL)
795 		return 0;
796 
797 	/* Too bad need the slow recursive way */
798 	sl = sl_init();
799 	if (sl == NULL)
800 		return 0;
801 	found = in_find(sl, strdup(grp), host, user, domain);
802 	sl_free(sl, 1);
803 
804 	return found;
805 }
806