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