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