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