Home | History | Annotate | Line # | Download | only in gen
getnetgrent.c revision 1.8
      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