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