11556Srgrimes/*
21556Srgrimes * Copyright (c) 1992, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Rick Macklem at The University of Guelph.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 4. Neither the name of the University nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
3436150Scharnierstatic char sccsid[] = "@(#)getnetgrent.c	8.2 (Berkeley) 4/27/95";
3536150Scharnier#endif /* LIBC_SCCS and not lint */
3636150Scharnier#include <sys/cdefs.h>
371556Srgrimes__FBSDID("$FreeBSD$");
3899110Sobrien
3999110Sobrien#include <ctype.h>
401556Srgrimes#include <stdio.h>
41109627Stjr#include <stdlib.h>
421556Srgrimes#include <string.h>
43109627Stjr#include <unistd.h>
4417987Speter
4559437Scracauer#ifdef YP
4617987Speter/*
471556Srgrimes * Notes:
481556Srgrimes * We want to be able to use NIS netgroups properly while retaining
491556Srgrimes * the ability to use a local /etc/netgroup file. Unfortunately, you
501556Srgrimes * can't really do both at the same time - at least, not efficiently.
5117987Speter * NetBSD deals with this problem by creating a netgroup database
521556Srgrimes * using Berkeley DB (just like the password database) that allows
531556Srgrimes * for lookups using netgroup, netgroup.byuser or netgroup.byhost
541556Srgrimes * searches. This is a neat idea, but I don't have time to implement
55213811Sobrien * something like that now. (I think ultimately it would be nice
56213811Sobrien * if we DB-fied the group and netgroup stuff all in one shot, but
57213811Sobrien * for now I'm satisfied just to have something that works well
58213811Sobrien * without requiring massive code changes.)
59213811Sobrien *
601556Srgrimes * Therefore, to still permit the use of the local file and maintain
611556Srgrimes * optimum NIS performance, we allow for the following conditions:
6217987Speter *
6390111Simp * - If /etc/netgroup does not exist and NIS is turned on, we use
6417987Speter *   NIS netgroups only.
651556Srgrimes *
661556Srgrimes * - If /etc/netgroup exists but is empty, we use NIS netgroups
671556Srgrimes *   only.
681556Srgrimes *
691556Srgrimes * - If /etc/netgroup exists and contains _only_ a '+', we use
70213811Sobrien *   NIS netgroups only.
7190111Simp *
7217987Speter * - If /etc/netgroup exists, contains locally defined netgroups
731556Srgrimes *   and a '+', we use a mixture of NIS and the local entries.
741556Srgrimes *   This method should return the same NIS data as just using
751556Srgrimes *   NIS alone, but it will be slower if the NIS netgroup database
7617987Speter *   is large (innetgr() in particular will suffer since extra
7717987Speter *   processing has to be done in order to determine memberships
7817987Speter *   using just the raw netgroup data).
791556Srgrimes *
801556Srgrimes * - If /etc/netgroup exists and contains only locally defined
811556Srgrimes *   netgroup entries, we use just those local entries and ignore
821556Srgrimes *   NIS (this is the original, pre-NIS behavior).
831556Srgrimes */
841556Srgrimes
851556Srgrimes#include <rpc/rpc.h>
861556Srgrimes#include <rpcsvc/yp_prot.h>
871556Srgrimes#include <rpcsvc/ypclnt.h>
881556Srgrimes#include <sys/types.h>
891556Srgrimes#include <sys/stat.h>
901556Srgrimes#include <sys/param.h>
911556Srgrimes#include <sys/errno.h>
921556Srgrimesstatic char *_netgr_yp_domain;
931556Srgrimesint _use_only_yp;
941556Srgrimesstatic int _netgr_yp_enabled;
951556Srgrimesstatic int _yp_innetgr;
961556Srgrimes#endif
971556Srgrimes
981556Srgrimes#ifndef _PATH_NETGROUP
991556Srgrimes#define _PATH_NETGROUP "/etc/netgroup"
1001556Srgrimes#endif
1011556Srgrimes
1021556Srgrimes/*
1031556Srgrimes * Static Variables and functions used by setnetgrent(), getnetgrent() and
1041556Srgrimes * endnetgrent().
1051556Srgrimes * There are two linked lists:
1061556Srgrimes * - linelist is just used by setnetgrent() to parse the net group file via.
1071556Srgrimes *   parse_netgrp()
1081556Srgrimes * - netgrp is the list of entries for the current netgroup
1091556Srgrimes */
1101556Srgrimesstruct linelist {
1111556Srgrimes	struct linelist	*l_next;	/* Chain ptr. */
1121556Srgrimes	int		l_parsed;	/* Flag for cycles */
1131556Srgrimes	char		*l_groupname;	/* Name of netgroup */
1141556Srgrimes	char		*l_line;	/* Netgroup entrie(s) to be parsed */
1151556Srgrimes};
1161556Srgrimes
1171556Srgrimesstruct netgrp {
1181556Srgrimes	struct netgrp	*ng_next;	/* Chain ptr */
1191556Srgrimes	char		*ng_str[3];	/* Field pointers, see below */
1201556Srgrimes};
121213811Sobrien#define NG_HOST		0	/* Host name */
12290111Simp#define NG_USER		1	/* User name */
12317987Speter#define NG_DOM		2	/* and Domain name */
1241556Srgrimes
1251556Srgrimesstatic struct linelist	*linehead = (struct linelist *)0;
1261556Srgrimesstatic struct netgrp	*nextgrp = (struct netgrp *)0;
1271556Srgrimesstatic struct {
1281556Srgrimes	struct netgrp	*gr;
1291556Srgrimes	char		*grname;
1301556Srgrimes} grouphead = {
1311556Srgrimes	(struct netgrp *)0,
1321556Srgrimes	(char *)0,
1331556Srgrimes};
1341556Srgrimesstatic FILE *netf = (FILE *)0;
1351556Srgrimes
1361556Srgrimesstatic int parse_netgrp(const char *);
1371556Srgrimesstatic struct linelist *read_for_group(const char *);
1381556Srgrimesvoid setnetgrent(const char *);
1391556Srgrimesvoid endnetgrent(void);
1401556Srgrimesint getnetgrent(char **, char **, char **);
1411556Srgrimesint innetgr(const char *, const char *, const char *, const char *);
1421556Srgrimes
14396922Stjr#define	LINSIZ	1024	/* Length of netgroup file line */
1441556Srgrimes
14566612Sbrian/*
1461556Srgrimes * setnetgrent()
147157750Sschweikh * Parse the netgroup file looking for the netgroup and build the list
148157750Sschweikh * of netgrp structures. Let parse_netgrp() and read_for_group() do
14917987Speter * most of the work.
1501556Srgrimes */
1511556Srgrimesvoid
1521556Srgrimessetnetgrent(const char *group)
1531556Srgrimes{
1541556Srgrimes#ifdef YP
15599634Stjr	struct stat _yp_statp;
15699634Stjr	char _yp_plus;
15799634Stjr#endif
15899634Stjr
159157750Sschweikh	/* Sanity check */
160157750Sschweikh
161157750Sschweikh	if (group == NULL || !strlen(group))
162157750Sschweikh		return;
1631556Srgrimes
1641556Srgrimes	if (grouphead.gr == NULL || strcmp(group, grouphead.grname)) {
1651556Srgrimes		endnetgrent();
1661556Srgrimes#ifdef YP
1671556Srgrimes		/* Presumed guilty until proven innocent. */
1681556Srgrimes		_use_only_yp = 0;
1691556Srgrimes		/*
1701556Srgrimes		 * If /etc/netgroup doesn't exist or is empty,
1711556Srgrimes		 * use NIS exclusively.
172213811Sobrien		 */
17390111Simp		if (((stat(_PATH_NETGROUP, &_yp_statp) < 0) &&
17490111Simp		    errno == ENOENT) || _yp_statp.st_size == 0)
1751556Srgrimes			_use_only_yp = _netgr_yp_enabled = 1;
1761556Srgrimes		if ((netf = fopen(_PATH_NETGROUP,"re")) != NULL ||_use_only_yp){
1771556Srgrimes		/*
1781556Srgrimes		 * Icky: grab the first character of the netgroup file
1791556Srgrimes		 * and turn on NIS if it's a '+'. rewind the stream
1801556Srgrimes		 * afterwards so we don't goof up read_for_group() later.
1811556Srgrimes		 */
1821556Srgrimes			if (netf) {
1831556Srgrimes				fscanf(netf, "%c", &_yp_plus);
1841556Srgrimes				rewind(netf);
1851556Srgrimes				if (_yp_plus == '+')
1861556Srgrimes					_use_only_yp = _netgr_yp_enabled = 1;
1871556Srgrimes			}
1881556Srgrimes		/*
1891556Srgrimes		 * If we were called specifically for an innetgr()
1901556Srgrimes		 * lookup and we're in NIS-only mode, short-circuit
1911556Srgrimes		 * parse_netgroup() and cut directly to the chase.
1921556Srgrimes		 */
1931556Srgrimes			if (_use_only_yp && _yp_innetgr) {
19417987Speter				/* dohw! */
19517987Speter				if (netf != NULL)
19617987Speter					fclose(netf);
1971556Srgrimes				return;
1981556Srgrimes			}
19917987Speter#else
2001556Srgrimes		if ((netf = fopen(_PATH_NETGROUP, "re"))) {
2011556Srgrimes#endif
20217987Speter			if (parse_netgrp(group))
2031556Srgrimes				endnetgrent();
2041556Srgrimes			else {
2051556Srgrimes				grouphead.grname = strdup(group);
2061556Srgrimes			}
2071556Srgrimes			if (netf)
2081556Srgrimes				fclose(netf);
2091556Srgrimes		}
2101556Srgrimes	}
2111556Srgrimes	nextgrp = grouphead.gr;
2121556Srgrimes}
2131556Srgrimes
2141556Srgrimes/*
2151556Srgrimes * Get the next netgroup off the list.
2161556Srgrimes */
2171556Srgrimesint
2181556Srgrimesgetnetgrent(char **hostp, char **userp, char **domp)
21917987Speter{
22017987Speter#ifdef YP
22117987Speter	_yp_innetgr = 0;
22217987Speter#endif
22317987Speter
22417987Speter	if (nextgrp) {
22517987Speter		*hostp = nextgrp->ng_str[NG_HOST];
22617987Speter		*userp = nextgrp->ng_str[NG_USER];
22717987Speter		*domp = nextgrp->ng_str[NG_DOM];
22817987Speter		nextgrp = nextgrp->ng_next;
22917987Speter		return (1);
23017987Speter	}
23117987Speter	return (0);
23217987Speter}
23317987Speter
23417987Speter/*
2351556Srgrimes * endnetgrent() - cleanup
2361556Srgrimes */
2371556Srgrimesvoid
2381556Srgrimesendnetgrent(void)
2391556Srgrimes{
2401556Srgrimes	struct linelist *lp, *olp;
2411556Srgrimes	struct netgrp *gp, *ogp;
2421556Srgrimes
2431556Srgrimes	lp = linehead;
2441556Srgrimes	while (lp) {
2451556Srgrimes		olp = lp;
2461556Srgrimes		lp = lp->l_next;
2471556Srgrimes		free(olp->l_groupname);
2481556Srgrimes		free(olp->l_line);
2491556Srgrimes		free(olp);
2501556Srgrimes	}
2511556Srgrimes	linehead = NULL;
2521556Srgrimes	if (grouphead.grname) {
2531556Srgrimes		free(grouphead.grname);
2541556Srgrimes		grouphead.grname = NULL;
2551556Srgrimes	}
2561556Srgrimes	gp = grouphead.gr;
257213811Sobrien	while (gp) {
25890111Simp		ogp = gp;
25917987Speter		gp = gp->ng_next;
2601556Srgrimes		free(ogp->ng_str[NG_HOST]);
2611556Srgrimes		free(ogp->ng_str[NG_USER]);
2621556Srgrimes		free(ogp->ng_str[NG_DOM]);
2631556Srgrimes		free(ogp);
2641556Srgrimes	}
2651556Srgrimes	grouphead.gr = NULL;
2661556Srgrimes	nextgrp = NULL;
2671556Srgrimes#ifdef YP
2681556Srgrimes	_netgr_yp_enabled = 0;
2691556Srgrimes#endif
2701556Srgrimes}
2711556Srgrimes
2721556Srgrimes#ifdef YP
2731556Srgrimesstatic int
2741556Srgrimes_listmatch(const char *list, const char *group, int len)
2751556Srgrimes{
2761556Srgrimes	const char *ptr = list;
277213744Sobrien	const char *cptr;
2781556Srgrimes	int glen = strlen(group);
2791556Srgrimes
2801556Srgrimes	/* skip possible leading whitespace */
2811556Srgrimes	while (isspace((unsigned char)*ptr))
2821556Srgrimes		ptr++;
2831556Srgrimes
28417987Speter	while (ptr < list + len) {
28590111Simp		cptr = ptr;
28617987Speter		while(*ptr != ','  && *ptr != '\0' && !isspace((unsigned char)*ptr))
2871556Srgrimes			ptr++;
2881556Srgrimes		if (strncmp(cptr, group, glen) == 0 && glen == (ptr - cptr))
2891556Srgrimes			return (1);
2901556Srgrimes		while (*ptr == ','  || isspace((unsigned char)*ptr))
2911556Srgrimes			ptr++;
2921556Srgrimes	}
2931556Srgrimes
29420425Ssteve	return (0);
29517987Speter}
29659438Scracauer
29717987Speterstatic int
29817987Speter_revnetgr_lookup(char* lookupdom, char* map, const char* str,
29917987Speter		 const char* dom, const char* group)
30017987Speter{
30117987Speter	int y, rv, rot;
30217987Speter	char key[MAXHOSTNAMELEN];
30317987Speter	char *result;
30417987Speter	int resultlen;
30517987Speter
3061556Srgrimes	for (rot = 0; ; rot++) {
3071556Srgrimes		switch (rot) {
3081556Srgrimes		case 0:
30917987Speter			snprintf(key, MAXHOSTNAMELEN, "%s.%s", str,
310200956Sjilles			    dom ? dom : lookupdom);
31117987Speter			break;
3121556Srgrimes		case 1:
3131556Srgrimes			snprintf(key, MAXHOSTNAMELEN, "%s.*", str);
3141556Srgrimes			break;
3151556Srgrimes		case 2:
3161556Srgrimes			snprintf(key, MAXHOSTNAMELEN, "*.%s",
3171556Srgrimes			    dom ? dom : lookupdom);
3181556Srgrimes			break;
3191556Srgrimes		case 3:
320213811Sobrien			snprintf(key, MAXHOSTNAMELEN, "*.*");
32190111Simp			break;
32217987Speter		default:
32325222Ssteve			return (0);
3241556Srgrimes		}
3251556Srgrimes		y = yp_match(lookupdom, map, key, strlen(key), &result,
3261556Srgrimes		    &resultlen);
3271556Srgrimes		if (y == 0) {
3281556Srgrimes			rv = _listmatch(result, group, resultlen);
3291556Srgrimes			free(result);
3301556Srgrimes			if (rv)
3311556Srgrimes				return (1);
3321556Srgrimes		} else if (y != YPERR_KEY) {
3331556Srgrimes			/*
3341556Srgrimes			 * If we get an error other than 'no
3351556Srgrimes			 * such key in map' then something is
3361556Srgrimes			 * wrong and we should stop the search.
3371556Srgrimes			 */
3381556Srgrimes			return (-1);
3391556Srgrimes		}
3401556Srgrimes	}
3411556Srgrimes}
3421556Srgrimes#endif
3431556Srgrimes
3441556Srgrimes/*
3451556Srgrimes * Search for a match in a netgroup.
3461556Srgrimes */
3471556Srgrimesint
3481556Srgrimesinnetgr(const char *group, const char *host, const char *user, const char *dom)
3491556Srgrimes{
3501556Srgrimes	char *hst, *usr, *dm;
3511556Srgrimes	/* Sanity check */
3521556Srgrimes
3531556Srgrimes	if (group == NULL || !strlen(group))
3541556Srgrimes		return (0);
3551556Srgrimes
3561556Srgrimes#ifdef YP
35718018Speter	_yp_innetgr = 1;
3581556Srgrimes#endif
3591556Srgrimes	setnetgrent(group);
36017987Speter#ifdef YP
36190111Simp	_yp_innetgr = 0;
36217987Speter	/*
3631556Srgrimes	 * If we're in NIS-only mode, do the search using
3641556Srgrimes	 * NIS 'reverse netgroup' lookups.
3651556Srgrimes	 *
3661556Srgrimes	 * What happens with 'reverse netgroup' lookups:
3671556Srgrimes	 *
3681556Srgrimes	 * 1) try 'reverse netgroup' lookup
3691556Srgrimes	 *    1.a) if host is specified and user is null:
3701556Srgrimes	 *         look in netgroup.byhost
3711556Srgrimes	 *         (try host.domain, host.*, *.domain or *.*)
3721556Srgrimes	 *         if found, return yes
3731556Srgrimes	 *    1.b) if user is specified and host is null:
3741556Srgrimes	 *         look in netgroup.byuser
3751556Srgrimes	 *         (try host.domain, host.*, *.domain or *.*)
37617987Speter	 *         if found, return yes
37790111Simp	 *    1.c) if both host and user are specified,
37890111Simp	 *         don't do 'reverse netgroup' lookup.  It won't work.
3791556Srgrimes	 *    1.d) if neither host ane user are specified (why?!?)
3801556Srgrimes	 *         don't do 'reverse netgroup' lookup either.
3811556Srgrimes	 * 2) if domain is specified and 'reverse lookup' is done:
3821556Srgrimes	 *    'reverse lookup' was authoritative.  bye bye.
3831556Srgrimes	 * 3) otherwise, too bad, try it the slow way.
3841556Srgrimes	 */
38517987Speter	if (_use_only_yp && (host == NULL) != (user == NULL)) {
38617987Speter		int ret;
38717987Speter		if(yp_get_default_domain(&_netgr_yp_domain))
38817987Speter			return (0);
38917987Speter		ret = _revnetgr_lookup(_netgr_yp_domain,
39017987Speter				      host?"netgroup.byhost":"netgroup.byuser",
39117987Speter				      host?host:user, dom, group);
39217987Speter		if (ret == 1)
393262951Sjmmv			return (1);
39417987Speter		else if (ret == 0 && dom != NULL)
3951556Srgrimes			return (0);
3961556Srgrimes	}
397262951Sjmmv
3981556Srgrimes	setnetgrent(group);
3991556Srgrimes#endif /* YP */
40053891Scracauer
4011556Srgrimes	while (getnetgrent(&hst, &usr, &dm))
4021556Srgrimes		if ((host == NULL || hst == NULL || !strcmp(host, hst)) &&
4031556Srgrimes		    (user == NULL || usr == NULL || !strcmp(user, usr)) &&
4041556Srgrimes		    ( dom == NULL ||  dm == NULL || !strcmp(dom, dm))) {
4051556Srgrimes			endnetgrent();
4061556Srgrimes			return (1);
40720425Ssteve		}
4081556Srgrimes	endnetgrent();
409	return (0);
410}
411
412/*
413 * Parse the netgroup file setting up the linked lists.
414 */
415static int
416parse_netgrp(const char *group)
417{
418	struct netgrp *grp;
419	struct linelist *lp = linehead;
420	char **ng;
421	char *epos, *gpos, *pos, *spos;
422	int freepos, len, strpos;
423#ifdef DEBUG
424	int fields;
425#endif
426
427	/*
428	 * First, see if the line has already been read in.
429	 */
430	while (lp) {
431		if (!strcmp(group, lp->l_groupname))
432			break;
433		lp = lp->l_next;
434	}
435	if (lp == NULL && (lp = read_for_group(group)) == NULL)
436		return (1);
437	if (lp->l_parsed) {
438#ifdef DEBUG
439		/*
440		 * This error message is largely superflous since the
441		 * code handles the error condition sucessfully, and
442		 * spewing it out from inside libc can actually hose
443		 * certain programs.
444		 */
445		fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);
446#endif
447		return (1);
448	} else
449		lp->l_parsed = 1;
450	pos = lp->l_line;
451	/* Watch for null pointer dereferences, dammit! */
452	while (pos != NULL && *pos != '\0') {
453		if (*pos == '(') {
454			grp = malloc(sizeof(*grp));
455			if (grp == NULL)
456				return (1);
457			ng = grp->ng_str;
458			bzero(grp, sizeof(*grp));
459			pos++;
460			gpos = strsep(&pos, ")");
461#ifdef DEBUG
462			fields = 0;
463#endif
464			for (strpos = 0; strpos < 3; strpos++) {
465				if ((spos = strsep(&gpos, ",")) == NULL) {
466					/*
467					 * All other systems I've tested
468					 * return NULL for empty netgroup
469					 * fields. It's up to user programs
470					 * to handle the NULLs appropriately.
471					 */
472					ng[strpos] = NULL;
473					continue;
474				}
475#ifdef DEBUG
476				fields++;
477#endif
478				while (*spos == ' ' || *spos == '\t')
479					spos++;
480				if ((epos = strpbrk(spos, " \t"))) {
481					*epos = '\0';
482					len = epos - spos;
483				} else
484					len = strlen(spos);
485				if (len <= 0)
486					continue;
487				ng[strpos] = malloc(len + 1);
488				if (ng[strpos] == NULL) {
489					for (freepos = 0; freepos < strpos;
490					    freepos++)
491						free(ng[freepos]);
492					free(grp);
493					return (1);
494				}
495				bcopy(spos, ng[strpos], len + 1);
496			}
497			grp->ng_next = grouphead.gr;
498			grouphead.gr = grp;
499#ifdef DEBUG
500			/*
501			 * Note: on other platforms, malformed netgroup
502			 * entries are not normally flagged. While we
503			 * can catch bad entries and report them, we should
504			 * stay silent by default for compatibility's sake.
505			 */
506			if (fields < 3) {
507				fprintf(stderr,
508				"Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n",
509				    ng[NG_HOST] == NULL ? "" : ng[NG_HOST],
510				    ng[NG_USER] == NULL ? "" : ",",
511				    ng[NG_USER] == NULL ? "" : ng[NG_USER],
512				    ng[NG_DOM] == NULL ? "" : ",",
513				    ng[NG_DOM] == NULL ? "" : ng[NG_DOM],
514				    lp->l_groupname);
515			}
516#endif
517		} else {
518			spos = strsep(&pos, ", \t");
519			if (parse_netgrp(spos))
520				continue;
521		}
522		if (pos == NULL)
523			break;
524		while (*pos == ' ' || *pos == ',' || *pos == '\t')
525			pos++;
526	}
527	return (0);
528}
529
530/*
531 * Read the netgroup file and save lines until the line for the netgroup
532 * is found. Return 1 if eof is encountered.
533 */
534static struct linelist *
535read_for_group(const char *group)
536{
537	char *linep, *olinep, *pos, *spos;
538	int len, olen;
539	int cont;
540	struct linelist *lp;
541	char line[LINSIZ + 2];
542#ifdef YP
543	char *result;
544	int resultlen;
545	linep = NULL;
546
547	while (_netgr_yp_enabled || fgets(line, LINSIZ, netf) != NULL) {
548		if (_netgr_yp_enabled) {
549			if(!_netgr_yp_domain)
550				if(yp_get_default_domain(&_netgr_yp_domain))
551					continue;
552			if (yp_match(_netgr_yp_domain, "netgroup", group,
553			    strlen(group), &result, &resultlen)) {
554				free(result);
555				if (_use_only_yp)
556					return ((struct linelist *)0);
557				else {
558					_netgr_yp_enabled = 0;
559					continue;
560				}
561			}
562			if (strlen(result) == 0) {
563				free(result);
564				return (NULL);
565			}
566			snprintf(line, LINSIZ, "%s %s", group, result);
567			free(result);
568		}
569#else
570	linep = NULL;
571	while (fgets(line, LINSIZ, netf) != NULL) {
572#endif
573		pos = (char *)&line;
574#ifdef YP
575		if (*pos == '+') {
576			_netgr_yp_enabled = 1;
577			continue;
578		}
579#endif
580		if (*pos == '#')
581			continue;
582		while (*pos == ' ' || *pos == '\t')
583			pos++;
584		spos = pos;
585		while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
586			*pos != '\0')
587			pos++;
588		len = pos - spos;
589		while (*pos == ' ' || *pos == '\t')
590			pos++;
591		if (*pos != '\n' && *pos != '\0') {
592			lp = (struct linelist *)malloc(sizeof (*lp));
593			if (lp == NULL)
594				return (NULL);
595			lp->l_parsed = 0;
596			lp->l_groupname = (char *)malloc(len + 1);
597			if (lp->l_groupname == NULL) {
598				free(lp);
599				return (NULL);
600			}
601			bcopy(spos, lp->l_groupname, len);
602			*(lp->l_groupname + len) = '\0';
603			len = strlen(pos);
604			olen = 0;
605
606			/*
607			 * Loop around handling line continuations.
608			 */
609			do {
610				if (*(pos + len - 1) == '\n')
611					len--;
612				if (*(pos + len - 1) == '\\') {
613					len--;
614					cont = 1;
615				} else
616					cont = 0;
617				if (len > 0) {
618					linep = malloc(olen + len + 1);
619					if (linep == NULL) {
620						free(lp->l_groupname);
621						free(lp);
622						if (olen > 0)
623							free(olinep);
624						return (NULL);
625					}
626					if (olen > 0) {
627						bcopy(olinep, linep, olen);
628						free(olinep);
629					}
630					bcopy(pos, linep + olen, len);
631					olen += len;
632					*(linep + olen) = '\0';
633					olinep = linep;
634				}
635				if (cont) {
636					if (fgets(line, LINSIZ, netf)) {
637						pos = line;
638						len = strlen(pos);
639					} else
640						cont = 0;
641				}
642			} while (cont);
643			lp->l_line = linep;
644			lp->l_next = linehead;
645			linehead = lp;
646
647			/*
648			 * If this is the one we wanted, we are done.
649			 */
650			if (!strcmp(lp->l_groupname, group))
651				return (lp);
652		}
653	}
654#ifdef YP
655	/*
656	 * Yucky. The recursive nature of this whole mess might require
657	 * us to make more than one pass through the netgroup file.
658	 * This might be best left outside the #ifdef YP, but YP is
659	 * defined by default anyway, so I'll leave it like this
660	 * until I know better.
661	 */
662	rewind(netf);
663#endif
664	return (NULL);
665}
666