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