Home | History | Annotate | Line # | Download | only in gen
getnetgrent.c revision 1.11.2.1
      1 /*	$NetBSD: getnetgrent.c,v 1.11.2.1 1997/05/24 04:51:54 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.1 1997/05/24 04:51:54 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 	NS_FILES_CB(dtab, _local_lookup, NULL);
    290 	NS_NIS_CB(dtab, _nis_lookup, NULL);
    291 
    292 	r = nsdispatch(NULL, dtab, NSDB_NETGROUP, name, line, bywhat);
    293 	return (r == NS_SUCCESS) ? 1 : 0;
    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(sl, grp)
    350 	StringList	*sl;
    351 	char		*grp;
    352 {
    353 	char		*line, *p;
    354 	struct netgroup	*ng;
    355 	char		*name;
    356 
    357 #ifdef DEBUG_NG
    358 	(void) fprintf(stderr, "addgroup(%s)\n", grp);
    359 #endif
    360 	/* check for cycles */
    361 	if (sl_find(sl, grp) != NULL) {
    362 		free(grp);
    363 		_warnx("netgroup: Cycle in group `%s'", grp);
    364 		return;
    365 	}
    366 	sl_add(sl, grp);
    367 
    368 	/* Lookup this netgroup */
    369 	line = NULL;
    370 	if (!lookup(grp, &line, _NG_KEYBYNAME)) {
    371 		if (line != NULL)
    372 			free(line);
    373 		return;
    374 	}
    375 
    376 	p = line;
    377 
    378 	for (;;) {
    379 		switch (_ng_parse(&p, &name, &ng)) {
    380 		case _NG_NONE:
    381 			/* Done with the line */
    382 			free(line);
    383 			return;
    384 
    385 		case _NG_GROUP:
    386 			/* new netgroup */
    387 			/* add to the list */
    388 			ng->ng_next = _nglist;
    389 			_nglist = ng;
    390 			break;
    391 
    392 		case _NG_NAME:
    393 			/* netgroup name */
    394 			addgroup(sl, name);
    395 			break;
    396 
    397 		case _NG_ERROR:
    398 			return;
    399 
    400 		default:
    401 			abort();
    402 			return;
    403 		}
    404 	}
    405 }
    406 
    407 
    408 /*
    409  * in_check(): Compare the spec with the netgroup
    410  */
    411 static int
    412 in_check(host, user, domain, ng)
    413 	const char	*host;
    414 	const char	*user;
    415 	const char	*domain;
    416 	struct netgroup	*ng;
    417 {
    418 	if ((host != NULL) && (ng->ng_host != NULL)
    419 	    && strcmp(ng->ng_host, host) != 0)
    420 		return 0;
    421 
    422 	if ((user != NULL) && (ng->ng_user != NULL)
    423 	    && strcmp(ng->ng_user, user) != 0)
    424 		return 0;
    425 
    426 	if ((domain != NULL) && (ng->ng_domain != NULL)
    427 	    && strcmp(ng->ng_domain, domain) != 0)
    428 		return 0;
    429 
    430 	return 1;
    431 }
    432 
    433 
    434 /*
    435  * in_find(): Find a match for the host, user, domain spec
    436  */
    437 static int
    438 in_find(sl, grp, host, user, domain)
    439 	StringList	*sl;
    440 	char		*grp;
    441 	const char	*host;
    442 	const char	*user;
    443 	const char	*domain;
    444 {
    445 	char		*line, *p;
    446 	int		 i;
    447 	struct netgroup	*ng;
    448 	char		*name;
    449 
    450 #ifdef DEBUG_NG
    451 	(void) fprintf(stderr, "in_find(%s)\n", grp);
    452 #endif
    453 	/* check for cycles */
    454 	if (sl_find(sl, grp) != NULL) {
    455 		free(grp);
    456 		_warnx("netgroup: Cycle in group `%s'", grp);
    457 		return 0;
    458 	}
    459 	sl_add(sl, grp);
    460 
    461 	/* Lookup this netgroup */
    462 	line = NULL;
    463 	if (!lookup(grp, &line, _NG_KEYBYNAME)) {
    464 		if (line)
    465 			free(line);
    466 		return 0;
    467 	}
    468 
    469 	p = line;
    470 
    471 	for (;;) {
    472 		switch (_ng_parse(&p, &name, &ng)) {
    473 		case _NG_NONE:
    474 			/* Done with the line */
    475 			free(line);
    476 			return 0;
    477 
    478 		case _NG_GROUP:
    479 			/* new netgroup */
    480 			i = in_check(host, user, domain, ng);
    481 			if (ng->ng_host != NULL)
    482 				free(ng->ng_host);
    483 			if (ng->ng_user != NULL)
    484 				free(ng->ng_user);
    485 			if (ng->ng_domain != NULL)
    486 				free(ng->ng_domain);
    487 			free(ng);
    488 			if (i) {
    489 				free(line);
    490 				return 1;
    491 			}
    492 			break;
    493 
    494 		case _NG_NAME:
    495 			/* netgroup name */
    496 			if (in_find(sl, name, host, user, domain)) {
    497 				free(line);
    498 				return 1;
    499 			}
    500 			break;
    501 
    502 		case _NG_ERROR:
    503 			free(line);
    504 			return 0;
    505 
    506 		default:
    507 			abort();
    508 			return 0;
    509 		}
    510 	}
    511 }
    512 
    513 
    514 /*
    515  * _ng_makekey(): Make a key from the two names given. The key is of the form
    516  * <name1>.<name2> Names strings are replaced with * if they are empty;
    517  */
    518 char *
    519 _ng_makekey(s1, s2, len)
    520 	const char	*s1, *s2;
    521 	size_t		 len;
    522 {
    523 	char *buf = malloc(len);
    524 	if (buf == NULL)
    525 		_err(1, _ngoomem);
    526 	(void) snprintf(buf, len, "%s.%s", _NG_STAR(s1), _NG_STAR(s2));
    527 	return buf;
    528 }
    529 
    530 void
    531 _ng_print(buf, len, ng)
    532 	char *buf;
    533 	size_t len;
    534 	const struct netgroup *ng;
    535 {
    536 	(void) snprintf(buf, len, "(%s,%s,%s)", _NG_EMPTY(ng->ng_host),
    537 	    _NG_EMPTY(ng->ng_user), _NG_EMPTY(ng->ng_domain));
    538 }
    539 
    540 
    541 /*
    542  * in_lookup1(): Fast lookup for a key in the appropriate map
    543  */
    544 static char *
    545 in_lookup1(key, domain, map)
    546 	const char	*key;
    547 	const char	*domain;
    548 	int		 map;
    549 {
    550 	char	*line;
    551 	size_t	 len;
    552 	char	*ptr;
    553 	int	 res;
    554 
    555 	len = (key ? strlen(key) : 1) + (domain ? strlen(domain) : 1) + 2;
    556 	ptr = _ng_makekey(key, domain, len);
    557 	res = lookup(ptr, &line, map);
    558 	free(ptr);
    559 	return res ? line : NULL;
    560 }
    561 
    562 
    563 /*
    564  * in_lookup(): Fast lookup for a key in the appropriate map
    565  */
    566 static int
    567 in_lookup(group, key, domain, map)
    568 	const char	*group;
    569 	const char	*key;
    570 	const char	*domain;
    571 	int		 map;
    572 {
    573 	size_t	 len;
    574 	char	*ptr, *line;
    575 
    576 	if (domain != NULL) {
    577 		/* Domain specified; look in "group.domain" and "*.domain" */
    578 		if ((line = in_lookup1(key, domain, map)) == NULL)
    579 			line = in_lookup1(NULL, domain, map);
    580 	}
    581 	else
    582 		line = NULL;
    583 
    584 	if (line == NULL) {
    585 		/*
    586 		 * domain not specified or domain lookup failed; look in
    587 		 * "group.*" and "*.*"
    588 		 */
    589 	    if (((line = in_lookup1(key, NULL, map)) == NULL) &&
    590 		((line = in_lookup1(NULL, NULL, map)) == NULL))
    591 		return 0;
    592 	}
    593 
    594 	len = strlen(group);
    595 
    596 	for (ptr = line; (ptr = strstr(ptr, group)) != NULL;)
    597 		/* Make sure we did not find a substring */
    598 		if ((ptr != line && ptr[-1] != ',') ||
    599 		    (ptr[len] != '\0' && strchr("\n\t ,", ptr[len]) == NULL))
    600 			ptr++;
    601 		else {
    602 			free(line);
    603 			return 1;
    604 		}
    605 
    606 	free(line);
    607 	return 0;
    608 }
    609 
    610 
    611 void
    612 endnetgrent()
    613 {
    614 	for (_nglist = _nghead; _nglist != NULL; _nglist = _nghead) {
    615 		_nghead = _nglist->ng_next;
    616 		if (_nglist->ng_host != NULL)
    617 			free(_nglist->ng_host);
    618 		if (_nglist->ng_user != NULL)
    619 			free(_nglist->ng_user);
    620 		if (_nglist->ng_domain != NULL)
    621 			free(_nglist->ng_domain);
    622 		free(_nglist);
    623 	}
    624 
    625 	if (_ng_db) {
    626 		(void) (_ng_db->close) (_ng_db);
    627 		_ng_db = NULL;
    628 	}
    629 }
    630 
    631 
    632 void
    633 setnetgrent(ng)
    634 	const char	*ng;
    635 {
    636 	StringList	*sl = sl_init();
    637 	char		*ng_copy;
    638 
    639 	/* Cleanup any previous storage */
    640 	if (_nghead != NULL)
    641 		endnetgrent();
    642 
    643 	if (_ng_db == NULL)
    644 		_ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
    645 
    646 	ng_copy = strdup(ng);
    647 	if (ng_copy == NULL)
    648 		_err(1, _ngoomem);
    649 	addgroup(sl, ng_copy);
    650 	_nghead = _nglist;
    651 	sl_free(sl, 1);
    652 }
    653 
    654 
    655 int
    656 getnetgrent(host, user, domain)
    657 	const char	**host;
    658 	const char	**user;
    659 	const char	**domain;
    660 {
    661 	if (_nglist == NULL)
    662 		return 0;
    663 
    664 	*host   = _nglist->ng_host;
    665 	*user   = _nglist->ng_user;
    666 	*domain = _nglist->ng_domain;
    667 
    668 	_nglist = _nglist->ng_next;
    669 
    670 	return 1;
    671 }
    672 
    673 
    674 int
    675 innetgr(grp, host, user, domain)
    676 	const char	*grp, *host, *user, *domain;
    677 {
    678 	int	 found;
    679 	StringList *sl;
    680 
    681 	if (_ng_db == NULL)
    682 		_ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
    683 
    684 	/* Try the fast lookup first */
    685 	if (host != NULL && user == NULL) {
    686 		if (in_lookup(grp, host, domain, _NG_KEYBYHOST))
    687 			return 1;
    688 	} else if (host == NULL && user != NULL) {
    689 		if (in_lookup(grp, user, domain, _NG_KEYBYUSER))
    690 			return 1;
    691 	}
    692 	/* If a domainname is given, we would have found a match */
    693 	if (domain != NULL)
    694 		return 0;
    695 
    696 	/* Too bad need the slow recursive way */
    697 	sl = sl_init();
    698 	found = in_find(sl, strdup(grp), host, user, domain);
    699 	sl_free(sl, 1);
    700 
    701 	return found;
    702 }
    703