diff options
| -rw-r--r-- | lib/libc/gen/getnetgrent.c | 201 | ||||
| -rw-r--r-- | lib/libc/net/ether_addr.c | 31 | ||||
| -rw-r--r-- | lib/libc/net/rcmd.c | 20 | ||||
| -rw-r--r-- | sbin/mountd/netgroup.5 | 69 | ||||
| -rw-r--r-- | usr.sbin/mountd/netgroup.5 | 69 | 
5 files changed, 350 insertions, 40 deletions
| diff --git a/lib/libc/gen/getnetgrent.c b/lib/libc/gen/getnetgrent.c index 658cf6330513..b26af50f66e2 100644 --- a/lib/libc/gen/getnetgrent.c +++ b/lib/libc/gen/getnetgrent.c @@ -44,13 +44,60 @@ static char sccsid[] = "@(#)getnetgrent.c	8.1 (Berkeley) 6/4/93";  #include <unistd.h>  #ifdef YP +/* + * Notes: + * We want to be able to use NIS netgroups properly while retaining + * the ability to use a local /etc/netgroup file. Unfortunately, you + * can't really do both at the same time - at least, not efficiently. + * NetBSD deals with this problem by creating a netgroup database + * using Berkeley DB (just like the password database) that allows + * for lookups using netgroup, netgroup.byuser or netgroup.byhost + * searches. This is a neat idea, but I don't have time to implement + * something like that now. (I think ultimately it would be nice + * if we DB-fied the group and netgroup stuff all in one shot, but + * for now I'm satisfied just to have something that works well + * without requiring massive code changes.) + *  + * Therefore, to still permit the use of the local file and maintain + * optimum NIS performance, we allow for the following conditions: + * + * - If /etc/netgroup does not exist and NIS is turned on, we use + *   NIS netgroups only. + * + * - If /etc/netgroup exists but is empty, we use NIS netgroups + *   only. + * + * - If /etc/netgroup exists and contains _only_ a '+', we use + *   NIS netgroups only. + * + * - If /etc/netgroup exists, contains locally defined netgroups + *   and a '+', we use a mixture of NIS and the local entries. + *   This method should return the same NIS data as just using + *   NIS alone, but it will be slower if the NIS netgroup database + *   is large (innetgr() in particular will suffer since extra + *   processing has to be done in order to determine memberships + *   using just the raw netgroup data). + * + * - If /etc/netgroup exists and contains only locally defined + *   netgroup entries, we use just those local entries and ignore + *   NIS (this is the original, pre-NIS behavior). + */  #include <rpc/rpc.h>  #include <rpcsvc/yp_prot.h>  #include <rpcsvc/ypclnt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <sys/errno.h> +static char *_netgr_yp_domain; +static int _use_only_yp;  static int _netgr_yp_enabled; +static int _yp_innetgr;  #endif +#ifndef _PATH_NETGROUP  #define _PATH_NETGROUP "/etc/netgroup" +#endif  /*   * Static Variables and functions used by setnetgrent(), getnetgrent() and @@ -102,6 +149,11 @@ void  setnetgrent(group)  	char *group;  { +#ifdef YP +	struct stat _yp_statp; +	char _yp_plus; +#endif +  	/* Sanity check */  	if (group == NULL || !strlen(group)) @@ -110,7 +162,36 @@ setnetgrent(group)  	if (grouphead.gr == (struct netgrp *)0 ||  		strcmp(group, grouphead.grname)) {  		endnetgrent(); +#ifdef YP +		/* +		 * IF /etc/netgroup doesn't exist or is empty, +		 * use NIS exclusively. +		 */ +		if (((stat(_PATH_NETGROUP, &_yp_statp) < 0) && +			errno == ENOENT) || _yp_statp.st_size == 0) +			_use_only_yp = _netgr_yp_enabled = 1; +		if ((netf = fopen(_PATH_NETGROUP,"r")) != NULL ||_use_only_yp){ +		/* +		 * Icky: grab the first character of the netgroup file +		 * and turn on NIS if it's a '+'. rewind the stream +		 * afterwards so we don't goof up read_for_group() later. +		 */ +			if (netf) { +				fscanf(netf, "%c", &_yp_plus); +				rewind(netf); +				if (_yp_plus == '+') +					_use_only_yp = _netgr_yp_enabled = 1; +			} +		/* +		 * If we were called specifically for an innetgr() +		 * lookup and we're in NIS-only mode, short-circuit +		 * parse_netgroup() and cut directly to the chase. +		 */ +			if (_use_only_yp && _yp_innetgr) +				return; +#else  		if (netf = fopen(_PATH_NETGROUP, "r")) { +#endif  			if (parse_netgrp(group))  				endnetgrent();  			else { @@ -118,7 +199,8 @@ setnetgrent(group)  					malloc(strlen(group) + 1);  				strcpy(grouphead.grname, group);  			} -			fclose(netf); +			if (netf) +				fclose(netf);  		}  	}  	nextgrp = grouphead.gr; @@ -131,6 +213,9 @@ int  getnetgrent(hostp, userp, domp)  	char **hostp, **userp, **domp;  { +#ifdef YP +	_yp_innetgr = 0; +#endif  	if (nextgrp) {  		*hostp = nextgrp->ng_str[NG_HOST]; @@ -182,6 +267,43 @@ endnetgrent()  #endif  } +#ifdef YP +static int _listmatch(list, group) +char *list, *group; +{ +	char *ptr = list; + +	while (ptr != NULL) { +		if (!strncmp(ptr, group, strlen(group)) &&  +			(*(ptr+strlen(group)) == ',' || +			*(ptr+strlen(group)) == '\n')) +			return(1); +		ptr++; +	} +	return(0); +} + +static int _buildkey(key, str, dom, rotation) +char *key, *str, *dom; +int *rotation; +{ +	(*rotation)++; +	if (*rotation > 4) +		return(0); +	switch(*rotation) { +		case(1): sprintf((char *)key, "%s.%s", str, dom ? dom : "*"); +			 break; +		case(2): sprintf((char *)key, "%s.*", str); +			 break; +		case(3): sprintf((char *)key, "*.%s", dom ? dom : "*"); +			 break; +		case(4): sprintf((char *)key, "*.*"); +			 break; +	} +	return(1); +} +#endif +  /*   * Search for a match in a netgroup.   */ @@ -190,17 +312,60 @@ innetgr(group, host, user, dom)  	char *group, *host, *user, *dom;  {  	char *hst, *usr, *dm; - +#ifdef YP +	char *result; +	int resultlen; +#endif  	/* Sanity check */  	if (group == NULL || !strlen(group))  		return (0); +#ifdef YP +	_yp_innetgr = 1; +#endif +	setnetgrent(group); +#ifdef YP +	/* +	 * If we're in NIS-only mode, do the search using +	 * NIS 'reverse netgroup' lookups. +	 */ +	if (_use_only_yp) { +		char _key[MAXHOSTNAMELEN]; +		int rot = 0; + +		if(yp_get_default_domain(&_netgr_yp_domain)) +			return(0); +		while(_buildkey(&_key, user ? user : host, dom, &rot)) { +			if (yp_match(_netgr_yp_domain, user? "netgroup.byuser": +			    "netgroup.byhost", _key, strlen(_key), &result, +			    &resultlen)) +				free(result); +			else { +				if (_listmatch(result, group)) { +					free(result); +					return(1); +				} +			} +		} +		free(result); +#ifdef CHARITABLE +	} +	/* +	 * Couldn't match using NIS-exclusive mode -- try +	 * standard mode. +	 */ +	_yp_innetgr = 0;  	setnetgrent(group); +#else +		return(0); +	} +#endif /* CHARITABLE */ +#endif /* YP */  	while (getnetgrent(&hst, &usr, &dm)) -		if ((host == (char *)0 || !strcmp(host, hst)) && -		    (user == (char *)0 || !strcmp(user, usr)) && -		    (dom == (char *)0 || !strcmp(dom, dm))) { +		if ((host == NULL || hst == NULL || !strcmp(host, hst)) && +		    (user == NULL || usr == NULL || !strcmp(user, usr)) && +		    ( dom == NULL ||  dm == NULL || !strcmp(dom, dm))) {  			endnetgrent();  			return (1);  		} @@ -262,13 +427,13 @@ parse_netgrp(group)  			fields = 0;  #endif  			for (strpos = 0; strpos < 3; strpos++) { -				if (spos = strsep(&gpos, ",")) { +				if ((spos = strsep(&gpos, ","))) {  #ifdef DEBUG  					fields++;  #endif  					while (*spos == ' ' || *spos == '\t')  						spos++; -					if (epos = strpbrk(spos, " \t")) { +					if ((epos = strpbrk(spos, " \t"))) {  						*epos = '\0';  						len = epos - spos;  					} else @@ -332,7 +497,6 @@ read_for_group(group)  	struct linelist *lp;  	char line[LINSIZ + 1];  #ifdef YP -	static char *_netgr_yp_domain;  	char *result;  	int resultlen; @@ -344,7 +508,12 @@ read_for_group(group)  			if (yp_match(_netgr_yp_domain, "netgroup", group,  					strlen(group), &result, &resultlen)) {  				free(result); -				return ((struct linelist *)0); +				if (_use_only_yp) +					return ((struct linelist *)0); +				else { +					_netgr_yp_enabled = 0; +					continue; +				}  			}  			sprintf(line, "%s %s", group, result);  			free(result); @@ -354,10 +523,6 @@ read_for_group(group)  #endif  		pos = (char *)&line;  #ifdef YP -		/* -		 * Once we default over to NIS, only -		 * endnetgrent() can get us out again. -		 */  		if (*pos == '+') {  			_netgr_yp_enabled = 1;  			continue; @@ -424,5 +589,15 @@ read_for_group(group)  				return (lp);  		}  	} +#ifdef YP +	/* +	 * Yucky. The recursive nature of this whole mess might require +	 * us to make more than one pass through the netgroup file. +	 * This might be best left outside the #ifdef YP, but YP is +	 * defined by default anyway, so I'll leave it like this +	 * until I know better. +	 */ +	rewind(netf); +#endif  	return ((struct linelist *)0);  } diff --git a/lib/libc/net/ether_addr.c b/lib/libc/net/ether_addr.c index c6288261ebe9..711bb7d93a05 100644 --- a/lib/libc/net/ether_addr.c +++ b/lib/libc/net/ether_addr.c @@ -35,7 +35,7 @@   * Center for Telecommunications Research   * Columbia University, New York City   * - *	$Id: ether_addr.c,v 1.5 1995/03/26 02:37:00 wpaul Exp $ + *	$Id: ether_addr.c,v 1.1 1995/04/02 01:31:17 wpaul Exp $   */ @@ -142,23 +142,16 @@ int ether_ntohost(hostname, e)  			continue;  #ifdef YP  		if (buf[0] == '+') { -			fclose(fp);  /* Can ignore /etc/ethers from here on. */  			if (yp_get_default_domain(&yp_domain)) -				return(1); +				continue;  			ether_a = ether_ntoa(e);  			if (yp_match(yp_domain, "ethers.byaddr", ether_a,  				strlen(ether_a), &result, &resultlen)) {  				free(result); -				return(1); +				continue;  			} -			if (!ether_line(result, &local_ether, &local_host)) { -				strcpy(hostname, (char *)&local_host); -				free(result); -				return(0); -			} else { +			strncpy((char *)&buf, result, resultlen);  				free(result); -				return(1); -			}  		}  #endif  		if (!ether_line(&buf, &local_ether, &local_host)) { @@ -200,23 +193,15 @@ int ether_hostton(hostname, e)  			continue;  #ifdef YP  		if (buf[0] == '+') { -			fclose(fp);  /* Can ignore /etc/ethers from here on. */  			if (yp_get_default_domain(&yp_domain)) -				return(1); +				continue;  			if (yp_match(yp_domain, "ethers.byname", hostname,  				strlen(hostname), &result, &resultlen)) {  				free(result); -				return(1); -			} -			if (!ether_line(result, &local_ether, &local_host)) { -				bcopy((char *)&local_ether.octet[0], -					(char *)&e->octet[0], 6); -				free(result); -				return(0); -			} else { -				free(result); -				return(1); +				continue;  			} +			strncpy((char *)&buf, result, resultlen); +			free(result);  		}  #endif  		if (!ether_line(&buf, &local_ether, &local_host)) { diff --git a/lib/libc/net/rcmd.c b/lib/libc/net/rcmd.c index 34ac18bf9f2f..f0d756ceeb78 100644 --- a/lib/libc/net/rcmd.c +++ b/lib/libc/net/rcmd.c @@ -51,6 +51,11 @@ static char sccsid[] = "@(#)rcmd.c	8.3 (Berkeley) 3/26/94";  #include <stdio.h>  #include <ctype.h>  #include <string.h> +#ifdef YP +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif  #define max(a, b)	((a > b) ? a : b) @@ -359,7 +364,14 @@ __ivaliduser(hostf, raddr, luser, ruser)  	struct hostent *hp;  	/* Presumed guilty until proven innocent. */  	int userok = 0, hostok = 0; +#ifdef YP +	char *ypdomain; +	if (yp_get_default_domain(&ypdomain)) +		ypdomain = NULL; +#else +#define	ypdomain NULL +#endif  	/* We need to get the damn hostname back for netgroup matching. */  	if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_long),  							AF_INET)) == NULL) @@ -403,14 +415,14 @@ __ivaliduser(hostf, raddr, luser, ruser)  			}  			if (buf[1] == '@')  /* match a host by netgroup */  				hostok = innetgr((char *)&buf[2], hp->h_name, -						NULL, NULL); +						NULL, ypdomain);  			else		/* match a host by addr */  				hostok = __icheckhost(raddr,(char *)&buf[1]);  			break;  		case '-':     /* reject '-' hosts and all their users */  			if (buf[1] == '@') {  				if (innetgr((char *)&buf[2], -					      hp->h_name, NULL, NULL)) +					      hp->h_name, NULL, ypdomain))  					return(-1);  			} else {  				if (__icheckhost(raddr,(char *)&buf[1])) @@ -428,7 +440,7 @@ __ivaliduser(hostf, raddr, luser, ruser)  				break;  			}  			if (*(user+1) == '@')  /* match a user by netgroup */ -				userok = innetgr(user+2, NULL, ruser, NULL); +				userok = innetgr(user+2, NULL, ruser, ypdomain);  			else	   /* match a user by direct specification */  				userok = !(strcmp(ruser, user+1));  			break; @@ -438,7 +450,7 @@ __ivaliduser(hostf, raddr, luser, ruser)  					return(-1);  				if (*(user+1) == '@') {  					if (innetgr(user+2, NULL, -							ruser, NULL)) +							ruser, ypdomain))  						return(-1);  				} else {  					if (!strcmp(ruser, user+1)) diff --git a/sbin/mountd/netgroup.5 b/sbin/mountd/netgroup.5 index 9ad8c48258a7..711e04f8295b 100644 --- a/sbin/mountd/netgroup.5 +++ b/sbin/mountd/netgroup.5 @@ -73,6 +73,66 @@ should normally be used to access the  database.  .Pp  Lines that begin with a # are treated as comments. +.Sh NIS/YP INTERACTION +On most other platforms, +.Nm netgroups +are only used in conjunction with +NIS and local +.Pa /etc/netgroup +files are ignored. With FreeBSD, +.Nm netgroups +can be used with either NIS or local files, but there are certain +caveats to consider. The existing +.Nm netgroup +system is extremely inefficient where +.Fn innetgr 3 +lookups are concerned since +.Nm netgroup +memberships are computed on the fly. By contrast, the NIS +.Nm netgroup +database consists of three seperate maps (netgroup, netgroup.byuser +and netgroup.byhost) that are keyed to allow +.Fn innetgr 3 +lookups to be done quickly. The FreeBSD +.Nm netgroup +system can interact with the NIS +.Nm netgroup +maps in the following ways: +.Bl -bullet -offset indent +.It +If the +.Pa /etc/netgroup +file does not exist, or it exists and is empty, or +it exists and contains only a '+', and NIS is running, +.Nm netgroup +lookups will be done exclusively through NIS, with +.Fn innetgr 3 +taking advantage of the netgroup.byuser and +netgroup.byhost maps to speed up searches. (This +is more or less compatible with the behavior of SunOS and +similar platforms.) +.It +If the +.Pa /etc/netgroup +exists and contains only local  +.Nm netgroup +information (with no NIS '+' token), then only the local +.Nm netgroup +information will be processed (and NIS will be ingored). +.It +If +.Pa /etc/netgroup +exists and contains both local netgroup data +.Pa and +the NIS '+' token, the local data and the NIS netgroup +map will be processed as a single combined +.Nm netgroup +database. While this configuration is the most flexible, it +is also the least efficient: in particular, +.Fn innetgr 3 +lookups will be especially slow if the +database is large. +.El  .Sh FILES  .Bl -tag -width /etc/netgroup -compact  .It Pa /etc/netgroup @@ -89,3 +149,12 @@ The interpretation of access restrictions based on the member tuples of a  netgroup is left up to the various network applications.  Also, it is not obvious how the domain specification  applies to the BSD environment. +.Pp +The +.Nm netgroup +database should be stored in the form of a +hashed +.Xr db 3 +database just like the +.Xr passwd 5 +database to speed up reverse lookups. diff --git a/usr.sbin/mountd/netgroup.5 b/usr.sbin/mountd/netgroup.5 index 9ad8c48258a7..711e04f8295b 100644 --- a/usr.sbin/mountd/netgroup.5 +++ b/usr.sbin/mountd/netgroup.5 @@ -73,6 +73,66 @@ should normally be used to access the  database.  .Pp  Lines that begin with a # are treated as comments. +.Sh NIS/YP INTERACTION +On most other platforms, +.Nm netgroups +are only used in conjunction with +NIS and local +.Pa /etc/netgroup +files are ignored. With FreeBSD, +.Nm netgroups +can be used with either NIS or local files, but there are certain +caveats to consider. The existing +.Nm netgroup +system is extremely inefficient where +.Fn innetgr 3 +lookups are concerned since +.Nm netgroup +memberships are computed on the fly. By contrast, the NIS +.Nm netgroup +database consists of three seperate maps (netgroup, netgroup.byuser +and netgroup.byhost) that are keyed to allow +.Fn innetgr 3 +lookups to be done quickly. The FreeBSD +.Nm netgroup +system can interact with the NIS +.Nm netgroup +maps in the following ways: +.Bl -bullet -offset indent +.It +If the +.Pa /etc/netgroup +file does not exist, or it exists and is empty, or +it exists and contains only a '+', and NIS is running, +.Nm netgroup +lookups will be done exclusively through NIS, with +.Fn innetgr 3 +taking advantage of the netgroup.byuser and +netgroup.byhost maps to speed up searches. (This +is more or less compatible with the behavior of SunOS and +similar platforms.) +.It +If the +.Pa /etc/netgroup +exists and contains only local  +.Nm netgroup +information (with no NIS '+' token), then only the local +.Nm netgroup +information will be processed (and NIS will be ingored). +.It +If +.Pa /etc/netgroup +exists and contains both local netgroup data +.Pa and +the NIS '+' token, the local data and the NIS netgroup +map will be processed as a single combined +.Nm netgroup +database. While this configuration is the most flexible, it +is also the least efficient: in particular, +.Fn innetgr 3 +lookups will be especially slow if the +database is large. +.El  .Sh FILES  .Bl -tag -width /etc/netgroup -compact  .It Pa /etc/netgroup @@ -89,3 +149,12 @@ The interpretation of access restrictions based on the member tuples of a  netgroup is left up to the various network applications.  Also, it is not obvious how the domain specification  applies to the BSD environment. +.Pp +The +.Nm netgroup +database should be stored in the form of a +hashed +.Xr db 3 +database just like the +.Xr passwd 5 +database to speed up reverse lookups. | 
