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