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