111814Swpaul/*
211814Swpaul * Copyright (c) 1992, 1993
311814Swpaul *	The Regents of the University of California.  All rights reserved.
411814Swpaul *
511814Swpaul * This code is derived from software contributed to Berkeley by
611814Swpaul * Rick Macklem at The University of Guelph.
711814Swpaul *
811814Swpaul * Redistribution and use in source and binary forms, with or without
911814Swpaul * modification, are permitted provided that the following conditions
1011814Swpaul * are met:
1111814Swpaul * 1. Redistributions of source code must retain the above copyright
1211814Swpaul *    notice, this list of conditions and the following disclaimer.
1311814Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1411814Swpaul *    notice, this list of conditions and the following disclaimer in the
1511814Swpaul *    documentation and/or other materials provided with the distribution.
1611814Swpaul * 3. All advertising materials mentioning features or use of this software
1711814Swpaul *    must display the following acknowledgement:
1811814Swpaul *	This product includes software developed by the University of
1911814Swpaul *	California, Berkeley and its contributors.
2011814Swpaul * 4. Neither the name of the University nor the names of its contributors
2111814Swpaul *    may be used to endorse or promote products derived from this software
2211814Swpaul *    without specific prior written permission.
2311814Swpaul *
2411814Swpaul * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2511814Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2611814Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2711814Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2811814Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2911814Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3011814Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3111814Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3211814Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3311814Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3411814Swpaul * SUCH DAMAGE.
3511814Swpaul */
3611814Swpaul
3731404Scharnier#ifndef lint
3831404Scharnierstatic const char rcsid[] =
3950476Speter  "$FreeBSD$";
4031404Scharnier#endif /* not lint */
4111814Swpaul
4211814Swpaul/*
4311814Swpaul * This is a specially hacked-up version of getnetgrent.c used to parse
4411814Swpaul * data from the stored hash table of netgroup info rather than from a
4511814Swpaul * file. It's used mainly for the parse_netgroup() function. All the YP
4611814Swpaul * stuff and file support has been stripped out since it isn't needed.
4711814Swpaul */
4811814Swpaul
4911814Swpaul#include <stdio.h>
5093590Smike#include <string.h>
5111814Swpaul#include <strings.h>
5211814Swpaul#include <stdlib.h>
5311814Swpaul#include <unistd.h>
5411814Swpaul#include "hash.h"
5511814Swpaul
5611814Swpaul/*
5711814Swpaul * Static Variables and functions used by setnetgrent(), getnetgrent() and
5811814Swpaul * __endnetgrent().
5911814Swpaul * There are two linked lists:
6011814Swpaul * - linelist is just used by setnetgrent() to parse the net group file via.
6111814Swpaul *   parse_netgrp()
6211814Swpaul * - netgrp is the list of entries for the current netgroup
6311814Swpaul */
6411814Swpaulstruct linelist {
6511814Swpaul	struct linelist	*l_next;	/* Chain ptr. */
6611814Swpaul	int		l_parsed;	/* Flag for cycles */
6711814Swpaul	char		*l_groupname;	/* Name of netgroup */
6811814Swpaul	char		*l_line;	/* Netgroup entrie(s) to be parsed */
6911814Swpaul};
7011814Swpaul
7111814Swpaulstruct netgrp {
7211814Swpaul	struct netgrp	*ng_next;	/* Chain ptr */
7311814Swpaul	char		*ng_str[3];	/* Field pointers, see below */
7411814Swpaul};
7511814Swpaul#define NG_HOST		0	/* Host name */
7611814Swpaul#define NG_USER		1	/* User name */
7711814Swpaul#define NG_DOM		2	/* and Domain name */
7811814Swpaul
7911814Swpaulstatic struct linelist	*linehead = (struct linelist *)0;
8011814Swpaulstatic struct netgrp	*nextgrp = (struct netgrp *)0;
8111814Swpaulstatic struct {
8211814Swpaul	struct netgrp	*gr;
8311814Swpaul	char		*grname;
8411814Swpaul} grouphead = {
8511814Swpaul	(struct netgrp *)0,
8611814Swpaul	(char *)0,
8711814Swpaul};
8890377Simpstatic int parse_netgrp(char *group);
8990377Simpstatic struct linelist *read_for_group(char *group);
9011814Swpaulextern struct group_entry *gtable[];
9111814Swpaul
9211814Swpaul/*
9311814Swpaul * setnetgrent()
9411814Swpaul * Parse the netgroup file looking for the netgroup and build the list
9511814Swpaul * of netgrp structures. Let parse_netgrp() and read_for_group() do
9611814Swpaul * most of the work.
9711814Swpaul */
9811814Swpaulvoid
9990377Simp__setnetgrent(char *group)
10011814Swpaul{
10111814Swpaul	/* Sanity check */
10211814Swpaul
10311814Swpaul	if (group == NULL || !strlen(group))
10411814Swpaul		return;
10511814Swpaul
10611814Swpaul	if (grouphead.gr == (struct netgrp *)0 ||
10711814Swpaul		strcmp(group, grouphead.grname)) {
10811814Swpaul		__endnetgrent();
10911814Swpaul		if (parse_netgrp(group))
11011814Swpaul			__endnetgrent();
11111814Swpaul		else {
11211814Swpaul			grouphead.grname = (char *)
11311814Swpaul				malloc(strlen(group) + 1);
11411814Swpaul			strcpy(grouphead.grname, group);
11511814Swpaul		}
11611814Swpaul	}
11711814Swpaul	nextgrp = grouphead.gr;
11811814Swpaul}
11911814Swpaul
12011814Swpaul/*
12111814Swpaul * Get the next netgroup off the list.
12211814Swpaul */
12311814Swpaulint
12490377Simp__getnetgrent(char **hostp, char **userp, char **domp)
12511814Swpaul{
12611814Swpaul	if (nextgrp) {
12711814Swpaul		*hostp = nextgrp->ng_str[NG_HOST];
12811814Swpaul		*userp = nextgrp->ng_str[NG_USER];
12911814Swpaul		*domp = nextgrp->ng_str[NG_DOM];
13011814Swpaul		nextgrp = nextgrp->ng_next;
13111814Swpaul		return (1);
13211814Swpaul	}
13311814Swpaul	return (0);
13411814Swpaul}
13511814Swpaul
13611814Swpaul/*
13711814Swpaul * __endnetgrent() - cleanup
13811814Swpaul */
13911814Swpaulvoid
14090377Simp__endnetgrent(void)
14111814Swpaul{
14290377Simp	struct linelist *lp, *olp;
14390377Simp	struct netgrp *gp, *ogp;
14411814Swpaul
14511814Swpaul	lp = linehead;
14611814Swpaul	while (lp) {
14711814Swpaul		olp = lp;
14811814Swpaul		lp = lp->l_next;
14911814Swpaul		free(olp->l_groupname);
15011814Swpaul		free(olp->l_line);
15111814Swpaul		free((char *)olp);
15211814Swpaul	}
15311814Swpaul	linehead = (struct linelist *)0;
15411814Swpaul	if (grouphead.grname) {
15511814Swpaul		free(grouphead.grname);
15611814Swpaul		grouphead.grname = (char *)0;
15711814Swpaul	}
15811814Swpaul	gp = grouphead.gr;
15911814Swpaul	while (gp) {
16011814Swpaul		ogp = gp;
16111814Swpaul		gp = gp->ng_next;
16211814Swpaul		if (ogp->ng_str[NG_HOST])
16311814Swpaul			free(ogp->ng_str[NG_HOST]);
16411814Swpaul		if (ogp->ng_str[NG_USER])
16511814Swpaul			free(ogp->ng_str[NG_USER]);
16611814Swpaul		if (ogp->ng_str[NG_DOM])
16711814Swpaul			free(ogp->ng_str[NG_DOM]);
16811814Swpaul		free((char *)ogp);
16911814Swpaul	}
17011814Swpaul	grouphead.gr = (struct netgrp *)0;
17111814Swpaul}
17211814Swpaul
17311814Swpaul/*
17411814Swpaul * Parse the netgroup file setting up the linked lists.
17511814Swpaul */
17611814Swpaulstatic int
17790377Simpparse_netgrp(char *group)
17811814Swpaul{
17990377Simp	char *spos, *epos;
18090377Simp	int len, strpos;
18111814Swpaul#ifdef DEBUG
18290377Simp	int fields;
18311814Swpaul#endif
18411814Swpaul	char *pos, *gpos;
18511814Swpaul	struct netgrp *grp;
18611814Swpaul	struct linelist *lp = linehead;
18711814Swpaul
18811814Swpaul	/*
18911814Swpaul	 * First, see if the line has already been read in.
19011814Swpaul	 */
19111814Swpaul	while (lp) {
19211814Swpaul		if (!strcmp(group, lp->l_groupname))
19311814Swpaul			break;
19411814Swpaul		lp = lp->l_next;
19511814Swpaul	}
19611814Swpaul	if (lp == (struct linelist *)0 &&
19711814Swpaul	    (lp = read_for_group(group)) == (struct linelist *)0)
19811814Swpaul		return (1);
19911814Swpaul	if (lp->l_parsed) {
20011814Swpaul#ifdef DEBUG
20111814Swpaul		/*
20211814Swpaul		 * This error message is largely superflous since the
20311814Swpaul		 * code handles the error condition sucessfully, and
20411814Swpaul		 * spewing it out from inside libc can actually hose
20511814Swpaul		 * certain programs.
20611814Swpaul		 */
20731404Scharnier		warnx("cycle in netgroup %s", lp->l_groupname);
20811814Swpaul#endif
20911814Swpaul		return (1);
21011814Swpaul	} else
21111814Swpaul		lp->l_parsed = 1;
21211814Swpaul	pos = lp->l_line;
21311814Swpaul	/* Watch for null pointer dereferences, dammit! */
21411814Swpaul	while (pos != NULL && *pos != '\0') {
21511814Swpaul		if (*pos == '(') {
21611814Swpaul			grp = (struct netgrp *)malloc(sizeof (struct netgrp));
21711814Swpaul			bzero((char *)grp, sizeof (struct netgrp));
21811814Swpaul			grp->ng_next = grouphead.gr;
21911814Swpaul			grouphead.gr = grp;
22011814Swpaul			pos++;
22111814Swpaul			gpos = strsep(&pos, ")");
22211814Swpaul#ifdef DEBUG
22311814Swpaul			fields = 0;
22411814Swpaul#endif
22511814Swpaul			for (strpos = 0; strpos < 3; strpos++) {
22611814Swpaul				if ((spos = strsep(&gpos, ","))) {
22711814Swpaul#ifdef DEBUG
22811814Swpaul					fields++;
22911814Swpaul#endif
23011814Swpaul					while (*spos == ' ' || *spos == '\t')
23111814Swpaul						spos++;
23211814Swpaul					if ((epos = strpbrk(spos, " \t"))) {
23311814Swpaul						*epos = '\0';
23411814Swpaul						len = epos - spos;
23511814Swpaul					} else
23611814Swpaul						len = strlen(spos);
23711814Swpaul					if (len > 0) {
23811814Swpaul						grp->ng_str[strpos] =  (char *)
23911814Swpaul							malloc(len + 1);
24011814Swpaul						bcopy(spos, grp->ng_str[strpos],
24111814Swpaul							len + 1);
24211814Swpaul					}
24311814Swpaul				} else {
24411814Swpaul					/*
24511814Swpaul					 * All other systems I've tested
24611814Swpaul					 * return NULL for empty netgroup
24711814Swpaul					 * fields. It's up to user programs
24811814Swpaul					 * to handle the NULLs appropriately.
24911814Swpaul					 */
25011814Swpaul					grp->ng_str[strpos] = NULL;
25111814Swpaul				}
25211814Swpaul			}
25311814Swpaul#ifdef DEBUG
25411814Swpaul			/*
25511814Swpaul			 * Note: on other platforms, malformed netgroup
25611814Swpaul			 * entries are not normally flagged. While we
25711814Swpaul			 * can catch bad entries and report them, we should
25811814Swpaul			 * stay silent by default for compatibility's sake.
25911814Swpaul			 */
26011814Swpaul			if (fields < 3)
26131404Scharnier					warnx("bad entry (%s%s%s%s%s) in netgroup \"%s\"",
26211814Swpaul						grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],
26311814Swpaul						grp->ng_str[NG_USER] == NULL ? "" : ",",
26411814Swpaul						grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],
26511814Swpaul						grp->ng_str[NG_DOM] == NULL ? "" : ",",
26611814Swpaul						grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],
26711814Swpaul						lp->l_groupname);
26811814Swpaul#endif
26911814Swpaul		} else {
27011814Swpaul			spos = strsep(&pos, ", \t");
27111814Swpaul			if (parse_netgrp(spos))
27211814Swpaul				continue;
27311814Swpaul		}
27411814Swpaul		/* Watch for null pointer dereferences, dammit! */
27511814Swpaul		if (pos != NULL)
27611814Swpaul			while (*pos == ' ' || *pos == ',' || *pos == '\t')
27711814Swpaul				pos++;
27811814Swpaul	}
27911814Swpaul	return (0);
28011814Swpaul}
28111814Swpaul
28211814Swpaul/*
28311814Swpaul * Read the netgroup file and save lines until the line for the netgroup
28411814Swpaul * is found. Return 1 if eof is encountered.
28511814Swpaul */
28611814Swpaulstatic struct linelist *
28790377Simpread_for_group(char *group)
28811814Swpaul{
28990377Simp	char *pos, *spos, *linep = NULL, *olinep = NULL;
29090377Simp	int len, olen;
29111814Swpaul	int cont;
29211814Swpaul	struct linelist *lp;
29311814Swpaul	char line[LINSIZ + 1];
29420387Swpaul	char *data = NULL;
29511814Swpaul
29611814Swpaul	data = lookup (gtable, group);
29711814Swpaul	sprintf(line, "%s %s", group, data);
29811814Swpaul	pos = (char *)&line;
29911814Swpaul#ifdef CANT_HAPPEN
30011814Swpaul	if (*pos == '#')
30111814Swpaul		continue;
30211814Swpaul#endif
30311814Swpaul	while (*pos == ' ' || *pos == '\t')
30411814Swpaul		pos++;
30511814Swpaul	spos = pos;
30611814Swpaul	while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
30711814Swpaul		*pos != '\0')
30811814Swpaul		pos++;
30911814Swpaul	len = pos - spos;
31011814Swpaul	while (*pos == ' ' || *pos == '\t')
31111814Swpaul		pos++;
31211814Swpaul	if (*pos != '\n' && *pos != '\0') {
31311814Swpaul		lp = (struct linelist *)malloc(sizeof (*lp));
31411814Swpaul		lp->l_parsed = 0;
31511814Swpaul		lp->l_groupname = (char *)malloc(len + 1);
31611814Swpaul		bcopy(spos, lp->l_groupname, len);
31711814Swpaul		*(lp->l_groupname + len) = '\0';
31811814Swpaul		len = strlen(pos);
31911814Swpaul		olen = 0;
32011814Swpaul			/*
32111814Swpaul			 * Loop around handling line continuations.
32211814Swpaul			 */
32311814Swpaul			do {
32411814Swpaul				if (*(pos + len - 1) == '\n')
32511814Swpaul					len--;
32611814Swpaul				if (*(pos + len - 1) == '\\') {
32711814Swpaul					len--;
32811814Swpaul					cont = 1;
32911814Swpaul				} else
33011814Swpaul					cont = 0;
33111814Swpaul				if (len > 0) {
33211814Swpaul					linep = (char *)malloc(olen + len + 1);
33311814Swpaul					if (olen > 0) {
33411814Swpaul						bcopy(olinep, linep, olen);
33511814Swpaul						free(olinep);
33611814Swpaul					}
33711814Swpaul					bcopy(pos, linep + olen, len);
33811814Swpaul					olen += len;
33911814Swpaul					*(linep + olen) = '\0';
34011814Swpaul					olinep = linep;
34111814Swpaul				}
34211814Swpaul#ifdef CANT_HAPPEN
34311814Swpaul				if (cont) {
34411814Swpaul					if (fgets(line, LINSIZ, netf)) {
34511814Swpaul						pos = line;
34611814Swpaul						len = strlen(pos);
34711814Swpaul					} else
34811814Swpaul						cont = 0;
34911814Swpaul				}
35011814Swpaul#endif
35111814Swpaul			} while (cont);
35211814Swpaul		lp->l_line = linep;
35311814Swpaul		lp->l_next = linehead;
35411814Swpaul		linehead = lp;
35511814Swpaul#ifdef CANT_HAPPEN
35611814Swpaul		/*
35711814Swpaul		 * If this is the one we wanted, we are done.
35811814Swpaul		 */
35911814Swpaul		if (!strcmp(lp->l_groupname, group))
36011814Swpaul#endif
36111814Swpaul			return (lp);
36211814Swpaul	}
36311814Swpaul	return ((struct linelist *)0);
36411814Swpaul}
365