Home | History | Annotate | Line # | Download | only in gen
getnetgrent.c revision 1.11.2.2
      1 /*	$NetBSD: getnetgrent.c,v 1.11.2.2 1997/05/26 16:33:34 lukem Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1994 Christos Zoulas
      5  * All rights reserved.
      6  * Portions Copyright (c) 1997 Luke Mewburn. All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by Christos Zoulas.
     19  * 4. The name of the author may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     23  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #if defined(LIBC_SCCS) && !defined(lint)
     36 static char *rcsid = "$NetBSD: getnetgrent.c,v 1.11.2.2 1997/05/26 16:33:34 lukem Exp $";
     37 #endif /* LIBC_SCCS and not lint */
     38 
     39 #include <sys/types.h>
     40 #include <stdio.h>
     41 #define _NETGROUP_PRIVATE
     42 #include <netgroup.h>
     43 #include <string.h>
     44 #include <fcntl.h>
     45 #include <err.h>
     46 #include <ctype.h>
     47 #include <nsswitch.h>
     48 #include <stdlib.h>
     49 #include <stringlist.h>
     50 #include <db.h>
     51 #ifdef YP
     52 #include <rpc/rpc.h>
     53 #include <rpcsvc/ypclnt.h>
     54 #include <rpcsvc/yp_prot.h>
     55 #endif
     56 
     57 #define _NG_STAR(s)	(((s) == NULL || *(s) == '\0') ? _ngstar : s)
     58 #define _NG_EMPTY(s)	((s) == NULL ? "" : s)
     59 #define _NG_ISSPACE(p)	(isspace((unsigned char) (p)) || (p) == '\n')
     60 
     61 static const char _ngstar[] = "*";
     62 static const char _ngoomem[] = "netgroup: %m";
     63 static struct netgroup *_nghead = (struct netgroup *)NULL;
     64 static struct netgroup *_nglist = (struct netgroup *)NULL;
     65 static DB *_ng_db;
     66 
     67 static int		getstring __P((char **, int, char **));
     68 static struct netgroup	*getnetgroup __P((char **));
     69 static int		 lookup __P((char *, char **, int));
     70 static void		 addgroup __P((StringList *, char *));
     71 static int		 in_check __P((const char *, const char *,
     72 				       const char *, struct netgroup *));
     73 static int		 in_find __P((StringList *, char *, const char *,
     74 				      const char *, const char *));
     75 static char		*in_lookup1 __P((const char *, const char *, int));
     76 static int		 in_lookup __P((const char *, const char *,
     77 					const char *, int));
     78 
     79 /*
     80  * getstring(): Get a string delimited by the character, skipping leading and
     81  * trailing blanks and advancing the pointer
     82  */
     83 static int
     84 getstring(pp, del, str)
     85 	char	**pp;
     86 	int	  del;
     87 	char	**str;
     88 {
     89 	char *sp, *ep, *dp;
     90 
     91 	/* skip leading blanks */
     92 	for (sp = *pp; *sp && _NG_ISSPACE(*sp); sp++)
     93 		continue;
     94 
     95 	/* accumulate till delimiter or space */
     96 	for (ep = sp; *ep && *ep != del && !_NG_ISSPACE(*ep); ep++)
     97 		continue;
     98 
     99 	/* hunt for the delimiter */
    100 	for (dp = ep; *dp && *dp != del && _NG_ISSPACE(*dp); dp++)
    101 		continue;
    102 
    103 	if (*dp != del) {
    104 		*str = NULL;
    105 		return 0;
    106 	}
    107 
    108 	*pp = ++dp;
    109 
    110 	del = (ep - sp) + 1;
    111 	if (del > 1) {
    112 		dp = malloc(del);
    113 		if (dp == NULL)
    114 			_err(1, _ngoomem);
    115 		memcpy(dp, sp, del);
    116 		dp[del - 1] = '\0';
    117 	} else
    118 		dp = NULL;
    119 
    120 	*str = dp;
    121 	return 1;
    122 }
    123 
    124 
    125 /*
    126  * getnetgroup(): Parse a netgroup, and advance the pointer
    127  */
    128 static struct netgroup *
    129 getnetgroup(pp)
    130 	char	**pp;
    131 {
    132 	struct netgroup *ng = malloc(sizeof(struct netgroup));
    133 
    134 	if (ng == NULL)
    135 		_err(1, _ngoomem);
    136 
    137 	(*pp)++;	/* skip '(' */
    138 	if (!getstring(pp, ',', &ng->ng_host))
    139 		goto badhost;
    140 
    141 	if (!getstring(pp, ',', &ng->ng_user))
    142 		goto baduser;
    143 
    144 	if (!getstring(pp, ')', &ng->ng_domain))
    145 		goto baddomain;
    146 
    147 #ifdef DEBUG_NG
    148 	{
    149 		char buf[1024];
    150 		(void) fprintf(stderr, "netgroup %s\n",
    151 		    _ng_print(buf, sizeof(buf), ng));
    152 	}
    153 #endif
    154 	return ng;
    155 
    156 baddomain:
    157 	if (ng->ng_user)
    158 		free(ng->ng_user);
    159 baduser:
    160 	if (ng->ng_host)
    161 		free(ng->ng_host);
    162 badhost:
    163 	free(ng);
    164 	return NULL;
    165 }
    166 
    167 
    168 static int
    169 _local_lookup(rv, cb_data, ap)
    170 	void	*rv;
    171 	void	*cb_data;
    172 	va_list	ap;
    173 {
    174 	char	 *name = va_arg(ap, char *);
    175 	char	**line = va_arg(ap, char **);
    176 	int	  bywhat = va_arg(ap, int);
    177 
    178 	DBT	 key, data;
    179 	size_t	 len;
    180 	char	*ks;
    181 	int	 r;
    182 
    183 	if (_ng_db == NULL)
    184 		return NS_UNAVAIL;
    185 
    186 	len = strlen(name) + 2;
    187 	ks = malloc(len);
    188 	if (ks == NULL)
    189 		_err(1, _ngoomem);
    190 
    191 	ks[0] = bywhat;
    192 	memcpy(&ks[1], name, len - 1);
    193 
    194 	key.data = (u_char *) ks;
    195 	key.size = len;
    196 
    197 	r = (_ng_db->get) (_ng_db, &key, &data, 0);
    198 	free(ks);
    199 	switch (r) {
    200 	case 0:
    201 		break;
    202 	case 1:
    203 		return NS_NOTFOUND;
    204 	case -1:
    205 		return NS_UNAVAIL;
    206 	}
    207 
    208 	*line = strdup(data.data);
    209 	if (*line == NULL)
    210 		return NS_UNAVAIL;
    211 	return NS_SUCCESS;
    212 }
    213 
    214 #ifdef YP
    215 static int
    216 _nis_lookup(rv, cb_data, ap)
    217 	void	*rv;
    218 	void	*cb_data;
    219 	va_list	 ap;
    220 {
    221 	char	 *name = va_arg(ap, char *);
    222 	char	**line = va_arg(ap, char **);
    223 	int	  bywhat = va_arg(ap, int);
    224 
    225 	static char	*__ypdomain;
    226 	int              i;
    227 	char            *map = NULL;
    228 
    229 	if(__ypdomain == NULL) {
    230 		switch (yp_get_default_domain(&__ypdomain)) {
    231 		case 0:
    232 			break;
    233 		case YPERR_RESRC:
    234 			return NS_TRYAGAIN;
    235 		default:
    236 			return NS_UNAVAIL;
    237 		}
    238 	}
    239 
    240 	switch (bywhat) {
    241 	case _NG_KEYBYNAME:
    242 		map = "netgroup";
    243 		break;
    244 
    245 	case _NG_KEYBYUSER:
    246 		map = "netgroup.byuser";
    247 		break;
    248 
    249 	case _NG_KEYBYHOST:
    250 		map = "netgroup.byhost";
    251 		break;
    252 
    253 	default:
    254 		abort();
    255 		break;
    256 	}
    257 
    258 
    259 	*line = NULL;
    260 	switch (yp_match(__ypdomain, map, name, strlen(name), line, &i)) {
    261 	case 0:
    262 		return NS_SUCCESS;
    263 	case YPERR_KEY:
    264 		if (*line)
    265 			free(*line);
    266 		return NS_NOTFOUND;
    267 	default:
    268 		if (*line)
    269 			free(*line);
    270 		return NS_UNAVAIL;
    271 	}
    272 	/* NOTREACHED */
    273 }
    274 #endif
    275 
    276 /*
    277  * lookup(): Find the given key in the database or yp, and return its value
    278  * in *line; returns 1 if key was found, 0 otherwise
    279  */
    280 static int
    281 lookup(name, line, bywhat)
    282 	char	 *name;
    283 	char	**line;
    284 	int	  bywhat;
    285 {
    286 	int		r;
    287 	static ns_dtab	dtab;
    288 
    289 	if (dtab[NS_FILES].cb == NULL) {
    290 		NS_FILES_CB(dtab, _local_lookup, NULL);
    291 		NS_NIS_CB(dtab, _nis_lookup, NULL);
    292 	}
    293 
    294 	r = nsdispatch(NULL, dtab, NSDB_NETGROUP, name, line, bywhat);
    295 	return (r == NS_SUCCESS) ? 1 : 0;
    296 }
    297 
    298 /*
    299  * _ng_parse(): Parse a line and return: _NG_ERROR: Syntax Error _NG_NONE:
    300  * line was empty or a comment _NG_GROUP: line had a netgroup definition,
    301  * returned in ng _NG_NAME:  line had a netgroup name, returned in name
    302  *
    303  * Public since used by netgroup_mkdb
    304  */
    305 int
    306 _ng_parse(p, name, ng)
    307 	char		**p;
    308 	char		**name;
    309 	struct netgroup	**ng;
    310 {
    311 	while (**p) {
    312 		if (**p == '#')
    313 			/* comment */
    314 			return _NG_NONE;
    315 
    316 		while (**p && _NG_ISSPACE(**p))
    317 			/* skipblank */
    318 			(*p)++;
    319 
    320 		if (**p == '(') {
    321 			if ((*ng = getnetgroup(p)) == NULL) {
    322 				_warnx("netgroup: Syntax error `%s'", *p);
    323 				return _NG_ERROR;
    324 			}
    325 			return _NG_GROUP;
    326 		} else {
    327 			char           *np;
    328 			int             i;
    329 
    330 			for (np = *p; **p && !_NG_ISSPACE(**p); (*p)++)
    331 				continue;
    332 			if (np != *p) {
    333 				i = (*p - np) + 1;
    334 				*name = malloc(i);
    335 				if (*name == NULL)
    336 					_err(1, _ngoomem);
    337 				memcpy(*name, np, i);
    338 				(*name)[i - 1] = '\0';
    339 				return _NG_NAME;
    340 			}
    341 		}
    342 	}
    343 	return _NG_NONE;
    344 }
    345 
    346 
    347 /*
    348  * addgroup(): Recursively add all the members of the netgroup to this group
    349  */
    350 static void
    351 addgroup(sl, grp)
    352 	StringList	*sl;
    353 	char		*grp;
    354 {
    355 	char		*line, *p;
    356 	struct netgroup	*ng;
    357 	char		*name;
    358 
    359 #ifdef DEBUG_NG
    360 	(void) fprintf(stderr, "addgroup(%s)\n", grp);
    361 #endif
    362 	/* check for cycles */
    363 	if (sl_find(sl, grp) != NULL) {
    364 		free(grp);
    365 		_warnx("netgroup: Cycle in group `%s'", grp);
    366 		return;
    367 	}
    368 	sl_add(sl, grp);
    369 
    370 	/* Lookup this netgroup */
    371 	line = NULL;
    372 	if (!lookup(grp, &line, _NG_KEYBYNAME)) {
    373 		if (line != NULL)
    374 			free(line);
    375 		return;
    376 	}
    377 
    378 	p = line;
    379 
    380 	for (;;) {
    381 		switch (_ng_parse(&p, &name, &ng)) {
    382 		case _NG_NONE:
    383 			/* Done with the line */
    384 			free(line);
    385 			return;
    386 
    387 		case _NG_GROUP:
    388 			/* new netgroup */
    389 			/* add to the list */
    390 			ng->ng_next = _nglist;
    391 			_nglist = ng;
    392 			break;
    393 
    394 		case _NG_NAME:
    395 			/* netgroup name */
    396 			addgroup(sl, name);
    397 			break;
    398 
    399 		case _NG_ERROR:
    400 			return;
    401 
    402 		default:
    403 			abort();
    404 			return;
    405 		}
    406 	}
    407 }
    408 
    409 
    410 /*
    411  * in_check(): Compare the spec with the netgroup
    412  */
    413 static int
    414 in_check(host, user, domain, ng)
    415 	const char	*host;
    416 	const char	*user;
    417 	const char	*domain;
    418 	struct netgroup	*ng;
    419 {
    420 	if ((host != NULL) && (ng->ng_host != NULL)
    421 	    && strcmp(ng->ng_host, host) != 0)
    422 		return 0;
    423 
    424 	if ((user != NULL) && (ng->ng_user != NULL)
    425 	    && strcmp(ng->ng_user, user) != 0)
    426 		return 0;
    427 
    428 	if ((domain != NULL) && (ng->ng_domain != NULL)
    429 	    && strcmp(ng->ng_domain, domain) != 0)
    430 		return 0;
    431 
    432 	return 1;
    433 }
    434 
    435 
    436 /*
    437  * in_find(): Find a match for the host, user, domain spec
    438  */
    439 static int
    440 in_find(sl, grp, host, user, domain)
    441 	StringList	*sl;
    442 	char		*grp;
    443 	const char	*host;
    444 	const char	*user;
    445 	const char	*domain;
    446 {
    447 	char		*line, *p;
    448 	int		 i;
    449 	struct netgroup	*ng;
    450 	char		*name;
    451 
    452 #ifdef DEBUG_NG
    453 	(void) fprintf(stderr, "in_find(%s)\n", grp);
    454 #endif
    455 	/* check for cycles */
    456 	if (sl_find(sl, grp) != NULL) {
    457 		free(grp);
    458 		_warnx("netgroup: Cycle in group `%s'", grp);
    459 		return 0;
    460 	}
    461 	sl_add(sl, grp);
    462 
    463 	/* Lookup this netgroup */
    464 	line = NULL;
    465 	if (!lookup(grp, &line, _NG_KEYBYNAME)) {
    466 		if (line)
    467 			free(line);
    468 		return 0;
    469 	}
    470 
    471 	p = line;
    472 
    473 	for (;;) {
    474 		switch (_ng_parse(&p, &name, &ng)) {
    475 		case _NG_NONE:
    476 			/* Done with the line */
    477 			free(line);
    478 			return 0;
    479 
    480 		case _NG_GROUP:
    481 			/* new netgroup */
    482 			i = in_check(host, user, domain, ng);
    483 			if (ng->ng_host != NULL)
    484 				free(ng->ng_host);
    485 			if (ng->ng_user != NULL)
    486 				free(ng->ng_user);
    487 			if (ng->ng_domain != NULL)
    488 				free(ng->ng_domain);
    489 			free(ng);
    490 			if (i) {
    491 				free(line);
    492 				return 1;
    493 			}
    494 			break;
    495 
    496 		case _NG_NAME:
    497 			/* netgroup name */
    498 			if (in_find(sl, name, host, user, domain)) {
    499 				free(line);
    500 				return 1;
    501 			}
    502 			break;
    503 
    504 		case _NG_ERROR:
    505 			free(line);
    506 			return 0;
    507 
    508 		default:
    509 			abort();
    510 			return 0;
    511 		}
    512 	}
    513 }
    514 
    515 
    516 /*
    517  * _ng_makekey(): Make a key from the two names given. The key is of the form
    518  * <name1>.<name2> Names strings are replaced with * if they are empty;
    519  */
    520 char *
    521 _ng_makekey(s1, s2, len)
    522 	const char	*s1, *s2;
    523 	size_t		 len;
    524 {
    525 	char *buf = malloc(len);
    526 	if (buf == NULL)
    527 		_err(1, _ngoomem);
    528 	(void) snprintf(buf, len, "%s.%s", _NG_STAR(s1), _NG_STAR(s2));
    529 	return buf;
    530 }
    531 
    532 void
    533 _ng_print(buf, len, ng)
    534 	char *buf;
    535 	size_t len;
    536 	const struct netgroup *ng;
    537 {
    538 	(void) snprintf(buf, len, "(%s,%s,%s)", _NG_EMPTY(ng->ng_host),
    539 	    _NG_EMPTY(ng->ng_user), _NG_EMPTY(ng->ng_domain));
    540 }
    541 
    542 
    543 /*
    544  * in_lookup1(): Fast lookup for a key in the appropriate map
    545  */
    546 static char *
    547 in_lookup1(key, domain, map)
    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(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(group, key, domain, map)
    570 	const char	*group;
    571 	const char	*key;
    572 	const char	*domain;
    573 	int		 map;
    574 {
    575 	size_t	 len;
    576 	char	*ptr, *line;
    577 
    578 	if (domain != NULL) {
    579 		/* Domain specified; look in "group.domain" and "*.domain" */
    580 		if ((line = in_lookup1(key, domain, map)) == NULL)
    581 			line = in_lookup1(NULL, domain, map);
    582 	}
    583 	else
    584 		line = NULL;
    585 
    586 	if (line == NULL) {
    587 		/*
    588 		 * domain not specified or domain lookup failed; look in
    589 		 * "group.*" and "*.*"
    590 		 */
    591 	    if (((line = in_lookup1(key, NULL, map)) == NULL) &&
    592 		((line = in_lookup1(NULL, NULL, map)) == NULL))
    593 		return 0;
    594 	}
    595 
    596 	len = strlen(group);
    597 
    598 	for (ptr = line; (ptr = strstr(ptr, group)) != NULL;)
    599 		/* Make sure we did not find a substring */
    600 		if ((ptr != line && ptr[-1] != ',') ||
    601 		    (ptr[len] != '\0' && strchr("\n\t ,", ptr[len]) == NULL))
    602 			ptr++;
    603 		else {
    604 			free(line);
    605 			return 1;
    606 		}
    607 
    608 	free(line);
    609 	return 0;
    610 }
    611 
    612 
    613 void
    614 endnetgrent()
    615 {
    616 	for (_nglist = _nghead; _nglist != NULL; _nglist = _nghead) {
    617 		_nghead = _nglist->ng_next;
    618 		if (_nglist->ng_host != NULL)
    619 			free(_nglist->ng_host);
    620 		if (_nglist->ng_user != NULL)
    621 			free(_nglist->ng_user);
    622 		if (_nglist->ng_domain != NULL)
    623 			free(_nglist->ng_domain);
    624 		free(_nglist);
    625 	}
    626 
    627 	if (_ng_db) {
    628 		(void) (_ng_db->close) (_ng_db);
    629 		_ng_db = NULL;
    630 	}
    631 }
    632 
    633 
    634 void
    635 setnetgrent(ng)
    636 	const char	*ng;
    637 {
    638 	StringList	*sl = sl_init();
    639 	char		*ng_copy;
    640 
    641 	/* Cleanup any previous storage */
    642 	if (_nghead != NULL)
    643 		endnetgrent();
    644 
    645 	if (_ng_db == NULL)
    646 		_ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
    647 
    648 	ng_copy = strdup(ng);
    649 	if (ng_copy == NULL)
    650 		_err(1, _ngoomem);
    651 	addgroup(sl, ng_copy);
    652 	_nghead = _nglist;
    653 	sl_free(sl, 1);
    654 }
    655 
    656 
    657 int
    658 getnetgrent(host, user, domain)
    659 	const char	**host;
    660 	const char	**user;
    661 	const char	**domain;
    662 {
    663 	if (_nglist == NULL)
    664 		return 0;
    665 
    666 	*host   = _nglist->ng_host;
    667 	*user   = _nglist->ng_user;
    668 	*domain = _nglist->ng_domain;
    669 
    670 	_nglist = _nglist->ng_next;
    671 
    672 	return 1;
    673 }
    674 
    675 
    676 int
    677 innetgr(grp, host, user, domain)
    678 	const char	*grp, *host, *user, *domain;
    679 {
    680 	int	 found;
    681 	StringList *sl;
    682 
    683 	if (_ng_db == NULL)
    684 		_ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
    685 
    686 	/* Try the fast lookup first */
    687 	if (host != NULL && user == NULL) {
    688 		if (in_lookup(grp, host, domain, _NG_KEYBYHOST))
    689 			return 1;
    690 	} else if (host == NULL && user != NULL) {
    691 		if (in_lookup(grp, user, domain, _NG_KEYBYUSER))
    692 			return 1;
    693 	}
    694 	/* If a domainname is given, we would have found a match */
    695 	if (domain != NULL)
    696 		return 0;
    697 
    698 	/* Too bad need the slow recursive way */
    699 	sl = sl_init();
    700 	found = in_find(sl, strdup(grp), host, user, domain);
    701 	sl_free(sl, 1);
    702 
    703 	return found;
    704 }
    705