11573Srgrimes/*
21573Srgrimes * Copyright (c) 1992, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Rick Macklem at The University of Guelph.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
161573Srgrimes * 4. Neither the name of the University nor the names of its contributors
171573Srgrimes *    may be used to endorse or promote products derived from this software
181573Srgrimes *    without specific prior written permission.
191573Srgrimes *
201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301573Srgrimes * SUCH DAMAGE.
311573Srgrimes */
321573Srgrimes
331573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
3423668Speterstatic char sccsid[] = "@(#)getnetgrent.c	8.2 (Berkeley) 4/27/95";
351573Srgrimes#endif /* LIBC_SCCS and not lint */
3690041Sobrien#include <sys/cdefs.h>
3790041Sobrien__FBSDID("$FreeBSD$");
381573Srgrimes
39108626Stjr#include <ctype.h>
401573Srgrimes#include <stdio.h>
417615Swpaul#include <stdlib.h>
4295459Sdes#include <string.h>
437615Swpaul#include <unistd.h>
441573Srgrimes
457615Swpaul#ifdef YP
469978Swpaul/*
479978Swpaul * Notes:
489978Swpaul * We want to be able to use NIS netgroups properly while retaining
499978Swpaul * the ability to use a local /etc/netgroup file. Unfortunately, you
509978Swpaul * can't really do both at the same time - at least, not efficiently.
519978Swpaul * NetBSD deals with this problem by creating a netgroup database
529978Swpaul * using Berkeley DB (just like the password database) that allows
539978Swpaul * for lookups using netgroup, netgroup.byuser or netgroup.byhost
549978Swpaul * searches. This is a neat idea, but I don't have time to implement
559978Swpaul * something like that now. (I think ultimately it would be nice
569978Swpaul * if we DB-fied the group and netgroup stuff all in one shot, but
579978Swpaul * for now I'm satisfied just to have something that works well
589978Swpaul * without requiring massive code changes.)
599978Swpaul *
609978Swpaul * Therefore, to still permit the use of the local file and maintain
619978Swpaul * optimum NIS performance, we allow for the following conditions:
629978Swpaul *
639978Swpaul * - If /etc/netgroup does not exist and NIS is turned on, we use
649978Swpaul *   NIS netgroups only.
659978Swpaul *
669978Swpaul * - If /etc/netgroup exists but is empty, we use NIS netgroups
679978Swpaul *   only.
689978Swpaul *
699978Swpaul * - If /etc/netgroup exists and contains _only_ a '+', we use
709978Swpaul *   NIS netgroups only.
719978Swpaul *
729978Swpaul * - If /etc/netgroup exists, contains locally defined netgroups
739978Swpaul *   and a '+', we use a mixture of NIS and the local entries.
749978Swpaul *   This method should return the same NIS data as just using
759978Swpaul *   NIS alone, but it will be slower if the NIS netgroup database
769978Swpaul *   is large (innetgr() in particular will suffer since extra
779978Swpaul *   processing has to be done in order to determine memberships
789978Swpaul *   using just the raw netgroup data).
799978Swpaul *
809978Swpaul * - If /etc/netgroup exists and contains only locally defined
819978Swpaul *   netgroup entries, we use just those local entries and ignore
829978Swpaul *   NIS (this is the original, pre-NIS behavior).
839978Swpaul */
8430288Swpaul
857615Swpaul#include <rpc/rpc.h>
867615Swpaul#include <rpcsvc/yp_prot.h>
877615Swpaul#include <rpcsvc/ypclnt.h>
889978Swpaul#include <sys/types.h>
899978Swpaul#include <sys/stat.h>
909978Swpaul#include <sys/param.h>
919978Swpaul#include <sys/errno.h>
929978Swpaulstatic char *_netgr_yp_domain;
9310521Swpaulint _use_only_yp;
947615Swpaulstatic int _netgr_yp_enabled;
959978Swpaulstatic int _yp_innetgr;
967615Swpaul#endif
977615Swpaul
989978Swpaul#ifndef _PATH_NETGROUP
991573Srgrimes#define _PATH_NETGROUP "/etc/netgroup"
1009978Swpaul#endif
1011573Srgrimes
1021573Srgrimes/*
1031573Srgrimes * Static Variables and functions used by setnetgrent(), getnetgrent() and
1041573Srgrimes * endnetgrent().
1051573Srgrimes * There are two linked lists:
1061573Srgrimes * - linelist is just used by setnetgrent() to parse the net group file via.
1071573Srgrimes *   parse_netgrp()
1081573Srgrimes * - netgrp is the list of entries for the current netgroup
1091573Srgrimes */
1101573Srgrimesstruct linelist {
1111573Srgrimes	struct linelist	*l_next;	/* Chain ptr. */
1121573Srgrimes	int		l_parsed;	/* Flag for cycles */
1131573Srgrimes	char		*l_groupname;	/* Name of netgroup */
1141573Srgrimes	char		*l_line;	/* Netgroup entrie(s) to be parsed */
1151573Srgrimes};
1161573Srgrimes
1171573Srgrimesstruct netgrp {
1181573Srgrimes	struct netgrp	*ng_next;	/* Chain ptr */
1191573Srgrimes	char		*ng_str[3];	/* Field pointers, see below */
1201573Srgrimes};
1211573Srgrimes#define NG_HOST		0	/* Host name */
1221573Srgrimes#define NG_USER		1	/* User name */
1231573Srgrimes#define NG_DOM		2	/* and Domain name */
1241573Srgrimes
1251573Srgrimesstatic struct linelist	*linehead = (struct linelist *)0;
1261573Srgrimesstatic struct netgrp	*nextgrp = (struct netgrp *)0;
1271573Srgrimesstatic struct {
1281573Srgrimes	struct netgrp	*gr;
1291573Srgrimes	char		*grname;
1301573Srgrimes} grouphead = {
1311573Srgrimes	(struct netgrp *)0,
1321573Srgrimes	(char *)0,
1331573Srgrimes};
1341573Srgrimesstatic FILE *netf = (FILE *)0;
1351573Srgrimes
136132793Sdesstatic int parse_netgrp(const char *);
137132793Sdesstatic struct linelist *read_for_group(const char *);
138132793Sdesvoid setnetgrent(const char *);
139132793Sdesvoid endnetgrent(void);
140132793Sdesint getnetgrent(char **, char **, char **);
141132793Sdesint innetgr(const char *, const char *, const char *, const char *);
142132793Sdes
1431573Srgrimes#define	LINSIZ	1024	/* Length of netgroup file line */
1441573Srgrimes
1451573Srgrimes/*
1461573Srgrimes * setnetgrent()
1471573Srgrimes * Parse the netgroup file looking for the netgroup and build the list
1481573Srgrimes * of netgrp structures. Let parse_netgrp() and read_for_group() do
1491573Srgrimes * most of the work.
1501573Srgrimes */
1511573Srgrimesvoid
152132793Sdessetnetgrent(const char *group)
1531573Srgrimes{
1549978Swpaul#ifdef YP
1559978Swpaul	struct stat _yp_statp;
1569978Swpaul	char _yp_plus;
1579978Swpaul#endif
1589978Swpaul
1597336Swpaul	/* Sanity check */
1607289Swpaul
1617336Swpaul	if (group == NULL || !strlen(group))
1627289Swpaul		return;
1637336Swpaul
164237160Skib	if (grouphead.gr == NULL || strcmp(group, grouphead.grname)) {
1651573Srgrimes		endnetgrent();
1669978Swpaul#ifdef YP
16710521Swpaul		/* Presumed guilty until proven innocent. */
16810521Swpaul		_use_only_yp = 0;
1699978Swpaul		/*
17015264Swpaul		 * If /etc/netgroup doesn't exist or is empty,
1719978Swpaul		 * use NIS exclusively.
1729978Swpaul		 */
1739978Swpaul		if (((stat(_PATH_NETGROUP, &_yp_statp) < 0) &&
174237160Skib		    errno == ENOENT) || _yp_statp.st_size == 0)
1759978Swpaul			_use_only_yp = _netgr_yp_enabled = 1;
176244092Sjilles		if ((netf = fopen(_PATH_NETGROUP,"re")) != NULL ||_use_only_yp){
1779978Swpaul		/*
1789978Swpaul		 * Icky: grab the first character of the netgroup file
1799978Swpaul		 * and turn on NIS if it's a '+'. rewind the stream
1809978Swpaul		 * afterwards so we don't goof up read_for_group() later.
1819978Swpaul		 */
1829978Swpaul			if (netf) {
1839978Swpaul				fscanf(netf, "%c", &_yp_plus);
1849978Swpaul				rewind(netf);
1859978Swpaul				if (_yp_plus == '+')
1869978Swpaul					_use_only_yp = _netgr_yp_enabled = 1;
1879978Swpaul			}
1889978Swpaul		/*
1899978Swpaul		 * If we were called specifically for an innetgr()
1909978Swpaul		 * lookup and we're in NIS-only mode, short-circuit
1919978Swpaul		 * parse_netgroup() and cut directly to the chase.
1929978Swpaul		 */
19310521Swpaul			if (_use_only_yp && _yp_innetgr) {
19410521Swpaul				/* dohw! */
19512585Swpaul				if (netf != NULL)
19612585Swpaul					fclose(netf);
1979978Swpaul				return;
19810521Swpaul			}
1999978Swpaul#else
200244092Sjilles		if ((netf = fopen(_PATH_NETGROUP, "re"))) {
2019978Swpaul#endif
2021573Srgrimes			if (parse_netgrp(group))
2031573Srgrimes				endnetgrent();
2041573Srgrimes			else {
205235740Sghelmer				grouphead.grname = strdup(group);
2061573Srgrimes			}
2079978Swpaul			if (netf)
2089978Swpaul				fclose(netf);
2091573Srgrimes		}
2101573Srgrimes	}
2111573Srgrimes	nextgrp = grouphead.gr;
2121573Srgrimes}
2131573Srgrimes
2141573Srgrimes/*
2151573Srgrimes * Get the next netgroup off the list.
2161573Srgrimes */
2171573Srgrimesint
218132793Sdesgetnetgrent(char **hostp, char **userp, char **domp)
2191573Srgrimes{
2209978Swpaul#ifdef YP
2219978Swpaul	_yp_innetgr = 0;
2229978Swpaul#endif
2231573Srgrimes
2241573Srgrimes	if (nextgrp) {
2251573Srgrimes		*hostp = nextgrp->ng_str[NG_HOST];
2261573Srgrimes		*userp = nextgrp->ng_str[NG_USER];
2271573Srgrimes		*domp = nextgrp->ng_str[NG_DOM];
2281573Srgrimes		nextgrp = nextgrp->ng_next;
2291573Srgrimes		return (1);
2301573Srgrimes	}
2311573Srgrimes	return (0);
2321573Srgrimes}
2331573Srgrimes
2341573Srgrimes/*
2351573Srgrimes * endnetgrent() - cleanup
2361573Srgrimes */
2371573Srgrimesvoid
238132793Sdesendnetgrent(void)
2391573Srgrimes{
24090041Sobrien	struct linelist *lp, *olp;
24190041Sobrien	struct netgrp *gp, *ogp;
2421573Srgrimes
2431573Srgrimes	lp = linehead;
2441573Srgrimes	while (lp) {
2451573Srgrimes		olp = lp;
2461573Srgrimes		lp = lp->l_next;
2471573Srgrimes		free(olp->l_groupname);
2481573Srgrimes		free(olp->l_line);
249237160Skib		free(olp);
2501573Srgrimes	}
251237160Skib	linehead = NULL;
2521573Srgrimes	if (grouphead.grname) {
2531573Srgrimes		free(grouphead.grname);
254237160Skib		grouphead.grname = NULL;
2551573Srgrimes	}
2561573Srgrimes	gp = grouphead.gr;
2571573Srgrimes	while (gp) {
2581573Srgrimes		ogp = gp;
2591573Srgrimes		gp = gp->ng_next;
260237160Skib		free(ogp->ng_str[NG_HOST]);
261237160Skib		free(ogp->ng_str[NG_USER]);
262237160Skib		free(ogp->ng_str[NG_DOM]);
263237160Skib		free(ogp);
2641573Srgrimes	}
265237160Skib	grouphead.gr = NULL;
266237160Skib	nextgrp = NULL;
2677149Swpaul#ifdef YP
2687223Swpaul	_netgr_yp_enabled = 0;
2697149Swpaul#endif
2701573Srgrimes}
2711573Srgrimes
2729978Swpaul#ifdef YP
273132793Sdesstatic int
274132793Sdes_listmatch(const char *list, const char *group, int len)
2759978Swpaul{
276132793Sdes	const char *ptr = list;
277132793Sdes	const char *cptr;
27831180Swpaul	int glen = strlen(group);
2799978Swpaul
28031180Swpaul	/* skip possible leading whitespace */
281237160Skib	while (isspace((unsigned char)*ptr))
28231180Swpaul		ptr++;
28315264Swpaul
28433950Ssteve	while (ptr < list + len) {
28533950Ssteve		cptr = ptr;
28652856Sache		while(*ptr != ','  && *ptr != '\0' && !isspace((unsigned char)*ptr))
28733950Ssteve			ptr++;
28833950Ssteve		if (strncmp(cptr, group, glen) == 0 && glen == (ptr - cptr))
289235739Sghelmer			return (1);
290237160Skib		while (*ptr == ','  || isspace((unsigned char)*ptr))
29133950Ssteve			ptr++;
29215839Swpaul	}
29315839Swpaul
294235739Sghelmer	return (0);
2959978Swpaul}
2969978Swpaul
297132793Sdesstatic int
298148317Sjon_revnetgr_lookup(char* lookupdom, char* map, const char* str,
299148317Sjon		 const char* dom, const char* group)
3009978Swpaul{
301148317Sjon	int y, rv, rot;
302148317Sjon	char key[MAXHOSTNAMELEN];
303148317Sjon	char *result;
304148317Sjon	int resultlen;
305148317Sjon
306148317Sjon	for (rot = 0; ; rot++) {
307148317Sjon		switch (rot) {
308236402Sghelmer		case 0:
309235739Sghelmer			snprintf(key, MAXHOSTNAMELEN, "%s.%s", str,
310235739Sghelmer			    dom ? dom : lookupdom);
311235739Sghelmer			break;
312236402Sghelmer		case 1:
313235739Sghelmer			snprintf(key, MAXHOSTNAMELEN, "%s.*", str);
314235739Sghelmer			break;
315236402Sghelmer		case 2:
316235739Sghelmer			snprintf(key, MAXHOSTNAMELEN, "*.%s",
317235739Sghelmer			    dom ? dom : lookupdom);
318235739Sghelmer			break;
319236402Sghelmer		case 3:
320235739Sghelmer			snprintf(key, MAXHOSTNAMELEN, "*.*");
321235739Sghelmer			break;
322236402Sghelmer		default:
323236402Sghelmer			return (0);
324148317Sjon		}
325148317Sjon		y = yp_match(lookupdom, map, key, strlen(key), &result,
326236402Sghelmer		    &resultlen);
327148317Sjon		if (y == 0) {
328148317Sjon			rv = _listmatch(result, group, resultlen);
329148317Sjon			free(result);
330236402Sghelmer			if (rv)
331236402Sghelmer				return (1);
332148317Sjon		} else if (y != YPERR_KEY) {
333148317Sjon			/*
334148317Sjon			 * If we get an error other than 'no
335148317Sjon			 * such key in map' then something is
336148317Sjon			 * wrong and we should stop the search.
337148317Sjon			 */
338235739Sghelmer			return (-1);
339148317Sjon		}
3409978Swpaul	}
3419978Swpaul}
3429978Swpaul#endif
3439978Swpaul
3441573Srgrimes/*
3451573Srgrimes * Search for a match in a netgroup.
3461573Srgrimes */
3471573Srgrimesint
348132793Sdesinnetgr(const char *group, const char *host, const char *user, const char *dom)
3491573Srgrimes{
3501573Srgrimes	char *hst, *usr, *dm;
3517336Swpaul	/* Sanity check */
3529287Swpaul
3537336Swpaul	if (group == NULL || !strlen(group))
3547336Swpaul		return (0);
3557336Swpaul
3569978Swpaul#ifdef YP
3579978Swpaul	_yp_innetgr = 1;
3589978Swpaul#endif
3591573Srgrimes	setnetgrent(group);
3609978Swpaul#ifdef YP
36115264Swpaul	_yp_innetgr = 0;
3629978Swpaul	/*
3639978Swpaul	 * If we're in NIS-only mode, do the search using
3649978Swpaul	 * NIS 'reverse netgroup' lookups.
365148317Sjon	 *
366148317Sjon	 * What happens with 'reverse netgroup' lookups:
367148317Sjon	 *
368148317Sjon	 * 1) try 'reverse netgroup' lookup
369148317Sjon	 *    1.a) if host is specified and user is null:
370148317Sjon	 *         look in netgroup.byhost
371148317Sjon	 *         (try host.domain, host.*, *.domain or *.*)
372148317Sjon	 *         if found, return yes
373148317Sjon	 *    1.b) if user is specified and host is null:
374148317Sjon	 *         look in netgroup.byuser
375148317Sjon	 *         (try host.domain, host.*, *.domain or *.*)
376148317Sjon	 *         if found, return yes
377148317Sjon	 *    1.c) if both host and user are specified,
378148317Sjon	 *         don't do 'reverse netgroup' lookup.  It won't work.
379148317Sjon	 *    1.d) if neither host ane user are specified (why?!?)
380148317Sjon	 *         don't do 'reverse netgroup' lookup either.
381148317Sjon	 * 2) if domain is specified and 'reverse lookup' is done:
382148317Sjon	 *    'reverse lookup' was authoritative.  bye bye.
383148317Sjon	 * 3) otherwise, too bad, try it the slow way.
3849978Swpaul	 */
385148317Sjon	if (_use_only_yp && (host == NULL) != (user == NULL)) {
386148317Sjon		int ret;
3879978Swpaul		if(yp_get_default_domain(&_netgr_yp_domain))
388235739Sghelmer			return (0);
389148317Sjon		ret = _revnetgr_lookup(_netgr_yp_domain,
390148317Sjon				      host?"netgroup.byhost":"netgroup.byuser",
391148317Sjon				      host?host:user, dom, group);
392148317Sjon		if (ret == 1)
393235739Sghelmer			return (1);
394148317Sjon		else if (ret == 0 && dom != NULL)
395235739Sghelmer			return (0);
3969978Swpaul	}
39730390Swpaul
3989978Swpaul	setnetgrent(group);
3999978Swpaul#endif /* YP */
40030390Swpaul
4011573Srgrimes	while (getnetgrent(&hst, &usr, &dm))
4029978Swpaul		if ((host == NULL || hst == NULL || !strcmp(host, hst)) &&
4039978Swpaul		    (user == NULL || usr == NULL || !strcmp(user, usr)) &&
4049978Swpaul		    ( dom == NULL ||  dm == NULL || !strcmp(dom, dm))) {
4051573Srgrimes			endnetgrent();
4061573Srgrimes			return (1);
4071573Srgrimes		}
4081573Srgrimes	endnetgrent();
4091573Srgrimes	return (0);
4101573Srgrimes}
4111573Srgrimes
4121573Srgrimes/*
4131573Srgrimes * Parse the netgroup file setting up the linked lists.
4141573Srgrimes */
4151573Srgrimesstatic int
416132793Sdesparse_netgrp(const char *group)
4171573Srgrimes{
418236402Sghelmer	struct netgrp *grp;
419236402Sghelmer	struct linelist *lp = linehead;
420236402Sghelmer	char **ng;
421236402Sghelmer	char *epos, *gpos, *pos, *spos;
422236402Sghelmer	int freepos, len, strpos;
4239287Swpaul#ifdef DEBUG
42490041Sobrien	int fields;
4259287Swpaul#endif
4261573Srgrimes
4271573Srgrimes	/*
4281573Srgrimes	 * First, see if the line has already been read in.
4291573Srgrimes	 */
4301573Srgrimes	while (lp) {
4311573Srgrimes		if (!strcmp(group, lp->l_groupname))
4321573Srgrimes			break;
4331573Srgrimes		lp = lp->l_next;
4341573Srgrimes	}
435237160Skib	if (lp == NULL && (lp = read_for_group(group)) == NULL)
4361573Srgrimes		return (1);
4371573Srgrimes	if (lp->l_parsed) {
4389287Swpaul#ifdef DEBUG
4399287Swpaul		/*
4409287Swpaul		 * This error message is largely superflous since the
4419287Swpaul		 * code handles the error condition sucessfully, and
4429287Swpaul		 * spewing it out from inside libc can actually hose
4439287Swpaul		 * certain programs.
4449287Swpaul		 */
4451573Srgrimes		fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);
4469287Swpaul#endif
4471573Srgrimes		return (1);
4481573Srgrimes	} else
4491573Srgrimes		lp->l_parsed = 1;
4501573Srgrimes	pos = lp->l_line;
4517149Swpaul	/* Watch for null pointer dereferences, dammit! */
4527149Swpaul	while (pos != NULL && *pos != '\0') {
4531573Srgrimes		if (*pos == '(') {
454236402Sghelmer			grp = malloc(sizeof(*grp));
455235740Sghelmer			if (grp == NULL)
456235740Sghelmer				return (1);
457236402Sghelmer			ng = grp->ng_str;
458236402Sghelmer			bzero(grp, sizeof(*grp));
4591573Srgrimes			pos++;
4601573Srgrimes			gpos = strsep(&pos, ")");
4619287Swpaul#ifdef DEBUG
4629287Swpaul			fields = 0;
4639287Swpaul#endif
4641573Srgrimes			for (strpos = 0; strpos < 3; strpos++) {
465236402Sghelmer				if ((spos = strsep(&gpos, ",")) == NULL) {
4669287Swpaul					/*
4679287Swpaul					 * All other systems I've tested
4689287Swpaul					 * return NULL for empty netgroup
4699287Swpaul					 * fields. It's up to user programs
4709287Swpaul					 * to handle the NULLs appropriately.
4719287Swpaul					 */
472236402Sghelmer					ng[strpos] = NULL;
473236402Sghelmer					continue;
4749287Swpaul				}
475236402Sghelmer#ifdef DEBUG
476236402Sghelmer				fields++;
477236402Sghelmer#endif
478236402Sghelmer				while (*spos == ' ' || *spos == '\t')
479236402Sghelmer					spos++;
480236402Sghelmer				if ((epos = strpbrk(spos, " \t"))) {
481236402Sghelmer					*epos = '\0';
482236402Sghelmer					len = epos - spos;
483236402Sghelmer				} else
484236402Sghelmer					len = strlen(spos);
485236402Sghelmer				if (len <= 0)
486236402Sghelmer					continue;
487236402Sghelmer				ng[strpos] = malloc(len + 1);
488236402Sghelmer				if (ng[strpos] == NULL) {
489236402Sghelmer					for (freepos = 0; freepos < strpos;
490236402Sghelmer					    freepos++)
491236402Sghelmer						free(ng[freepos]);
492236402Sghelmer					free(grp);
493236402Sghelmer					return (1);
494236402Sghelmer				}
495236402Sghelmer				bcopy(spos, ng[strpos], len + 1);
4961573Srgrimes			}
497235740Sghelmer			grp->ng_next = grouphead.gr;
498235740Sghelmer			grouphead.gr = grp;
4999287Swpaul#ifdef DEBUG
5009287Swpaul			/*
5019287Swpaul			 * Note: on other platforms, malformed netgroup
5029287Swpaul			 * entries are not normally flagged. While we
5039287Swpaul			 * can catch bad entries and report them, we should
5049287Swpaul			 * stay silent by default for compatibility's sake.
5059287Swpaul			 */
506236402Sghelmer			if (fields < 3) {
507236402Sghelmer				fprintf(stderr,
508236402Sghelmer				"Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n",
509236402Sghelmer				    ng[NG_HOST] == NULL ? "" : ng[NG_HOST],
510236402Sghelmer				    ng[NG_USER] == NULL ? "" : ",",
511236402Sghelmer				    ng[NG_USER] == NULL ? "" : ng[NG_USER],
512236402Sghelmer				    ng[NG_DOM] == NULL ? "" : ",",
513236402Sghelmer				    ng[NG_DOM] == NULL ? "" : ng[NG_DOM],
514236402Sghelmer				    lp->l_groupname);
5159287Swpaul#endif
5161573Srgrimes		} else {
5171573Srgrimes			spos = strsep(&pos, ", \t");
5181573Srgrimes			if (parse_netgrp(spos))
5197175Swpaul				continue;
5201573Srgrimes		}
52123668Speter		if (pos == NULL)
52223668Speter			break;
52323668Speter		while (*pos == ' ' || *pos == ',' || *pos == '\t')
52423668Speter			pos++;
5251573Srgrimes	}
5261573Srgrimes	return (0);
5271573Srgrimes}
5281573Srgrimes
5291573Srgrimes/*
5301573Srgrimes * Read the netgroup file and save lines until the line for the netgroup
5311573Srgrimes * is found. Return 1 if eof is encountered.
5321573Srgrimes */
5331573Srgrimesstatic struct linelist *
534132793Sdesread_for_group(const char *group)
5351573Srgrimes{
536237159Skib	char *linep, *olinep, *pos, *spos;
53790041Sobrien	int len, olen;
5381573Srgrimes	int cont;
5391573Srgrimes	struct linelist *lp;
54020957Swpaul	char line[LINSIZ + 2];
5417149Swpaul#ifdef YP
5427149Swpaul	char *result;
5437149Swpaul	int resultlen;
544235740Sghelmer	linep = NULL;
5451573Srgrimes
5467149Swpaul	while (_netgr_yp_enabled || fgets(line, LINSIZ, netf) != NULL) {
5477149Swpaul		if (_netgr_yp_enabled) {
5487149Swpaul			if(!_netgr_yp_domain)
5497223Swpaul				if(yp_get_default_domain(&_netgr_yp_domain))
5507149Swpaul					continue;
5517223Swpaul			if (yp_match(_netgr_yp_domain, "netgroup", group,
552236402Sghelmer			    strlen(group), &result, &resultlen)) {
5537223Swpaul				free(result);
5549978Swpaul				if (_use_only_yp)
5559978Swpaul					return ((struct linelist *)0);
5569978Swpaul				else {
5579978Swpaul					_netgr_yp_enabled = 0;
5589978Swpaul					continue;
5599978Swpaul				}
5607149Swpaul			}
56120957Swpaul			snprintf(line, LINSIZ, "%s %s", group, result);
5627149Swpaul			free(result);
5637149Swpaul		}
5647149Swpaul#else
565235740Sghelmer	linep = NULL;
5661573Srgrimes	while (fgets(line, LINSIZ, netf) != NULL) {
5677149Swpaul#endif
5687149Swpaul		pos = (char *)&line;
5697149Swpaul#ifdef YP
5707149Swpaul		if (*pos == '+') {
5717149Swpaul			_netgr_yp_enabled = 1;
5727149Swpaul			continue;
5737149Swpaul		}
5747149Swpaul#endif
5751573Srgrimes		if (*pos == '#')
5761573Srgrimes			continue;
5771573Srgrimes		while (*pos == ' ' || *pos == '\t')
5781573Srgrimes			pos++;
5791573Srgrimes		spos = pos;
5801573Srgrimes		while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
5811573Srgrimes			*pos != '\0')
5821573Srgrimes			pos++;
5831573Srgrimes		len = pos - spos;
5841573Srgrimes		while (*pos == ' ' || *pos == '\t')
5851573Srgrimes			pos++;
5861573Srgrimes		if (*pos != '\n' && *pos != '\0') {
5871573Srgrimes			lp = (struct linelist *)malloc(sizeof (*lp));
588235740Sghelmer			if (lp == NULL)
589235740Sghelmer				return (NULL);
5901573Srgrimes			lp->l_parsed = 0;
5911573Srgrimes			lp->l_groupname = (char *)malloc(len + 1);
592235740Sghelmer			if (lp->l_groupname == NULL) {
593235740Sghelmer				free(lp);
594235740Sghelmer				return (NULL);
595235740Sghelmer			}
5961573Srgrimes			bcopy(spos, lp->l_groupname, len);
5971573Srgrimes			*(lp->l_groupname + len) = '\0';
5981573Srgrimes			len = strlen(pos);
5991573Srgrimes			olen = 0;
6001573Srgrimes
6011573Srgrimes			/*
6021573Srgrimes			 * Loop around handling line continuations.
6031573Srgrimes			 */
6041573Srgrimes			do {
6051573Srgrimes				if (*(pos + len - 1) == '\n')
6061573Srgrimes					len--;
6071573Srgrimes				if (*(pos + len - 1) == '\\') {
6081573Srgrimes					len--;
6091573Srgrimes					cont = 1;
6101573Srgrimes				} else
6111573Srgrimes					cont = 0;
6121573Srgrimes				if (len > 0) {
613237159Skib					linep = malloc(olen + len + 1);
614235740Sghelmer					if (linep == NULL) {
615235740Sghelmer						free(lp->l_groupname);
616235740Sghelmer						free(lp);
617235740Sghelmer						return (NULL);
6181573Srgrimes					}
619237159Skib					if (olen > 0) {
620237159Skib						bcopy(olinep, linep, olen);
621237159Skib						free(olinep);
622237159Skib					}
6231573Srgrimes					bcopy(pos, linep + olen, len);
6241573Srgrimes					olen += len;
6251573Srgrimes					*(linep + olen) = '\0';
626237159Skib					olinep = linep;
6271573Srgrimes				}
6281573Srgrimes				if (cont) {
6291573Srgrimes					if (fgets(line, LINSIZ, netf)) {
6301573Srgrimes						pos = line;
6311573Srgrimes						len = strlen(pos);
6321573Srgrimes					} else
6331573Srgrimes						cont = 0;
6341573Srgrimes				}
6351573Srgrimes			} while (cont);
6361573Srgrimes			lp->l_line = linep;
6371573Srgrimes			lp->l_next = linehead;
6381573Srgrimes			linehead = lp;
6391573Srgrimes
6401573Srgrimes			/*
6411573Srgrimes			 * If this is the one we wanted, we are done.
6421573Srgrimes			 */
6431573Srgrimes			if (!strcmp(lp->l_groupname, group))
6441573Srgrimes				return (lp);
6451573Srgrimes		}
6461573Srgrimes	}
6479978Swpaul#ifdef YP
6489978Swpaul	/*
6499978Swpaul	 * Yucky. The recursive nature of this whole mess might require
6509978Swpaul	 * us to make more than one pass through the netgroup file.
6519978Swpaul	 * This might be best left outside the #ifdef YP, but YP is
6529978Swpaul	 * defined by default anyway, so I'll leave it like this
6539978Swpaul	 * until I know better.
6549978Swpaul	 */
6559978Swpaul	rewind(netf);
6569978Swpaul#endif
657235740Sghelmer	return (NULL);
6581573Srgrimes}
659