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