parse_netgroup.c revision 229780
1238405Sjkim/*
2238405Sjkim * Copyright (c) 1992, 1993
3238405Sjkim *	The Regents of the University of California.  All rights reserved.
4238405Sjkim *
5238405Sjkim * This code is derived from software contributed to Berkeley by
6238405Sjkim * Rick Macklem at The University of Guelph.
7238405Sjkim *
8238405Sjkim * Redistribution and use in source and binary forms, with or without
9238405Sjkim * modification, are permitted provided that the following conditions
10238405Sjkim * are met:
11238405Sjkim * 1. Redistributions of source code must retain the above copyright
12238405Sjkim *    notice, this list of conditions and the following disclaimer.
13238405Sjkim * 2. Redistributions in binary form must reproduce the above copyright
14238405Sjkim *    notice, this list of conditions and the following disclaimer in the
15238405Sjkim *    documentation and/or other materials provided with the distribution.
16238405Sjkim * 3. All advertising materials mentioning features or use of this software
17238405Sjkim *    must display the following acknowledgement:
18238405Sjkim *	This product includes software developed by the University of
19238405Sjkim *	California, Berkeley and its contributors.
20238405Sjkim * 4. Neither the name of the University nor the names of its contributors
21238405Sjkim *    may be used to endorse or promote products derived from this software
22238405Sjkim *    without specific prior written permission.
23238405Sjkim *
24238405Sjkim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25238405Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26238405Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27238405Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28238405Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29238405Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30238405Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31238405Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32238405Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33238405Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34238405Sjkim * SUCH DAMAGE.
35238405Sjkim */
36238405Sjkim
37238405Sjkim#ifndef lint
38238405Sjkimstatic const char rcsid[] =
39238405Sjkim  "$FreeBSD: head/libexec/revnetgroup/parse_netgroup.c 229780 2012-01-07 16:09:54Z uqs $";
40238405Sjkim#endif /* not lint */
41238405Sjkim
42238405Sjkim/*
43238405Sjkim * This is a specially hacked-up version of getnetgrent.c used to parse
44238405Sjkim * data from the stored hash table of netgroup info rather than from a
45238405Sjkim * file. It's used mainly for the parse_netgroup() function. All the YP
46238405Sjkim * stuff and file support has been stripped out since it isn't needed.
47238405Sjkim */
48238405Sjkim
49238405Sjkim#include <stdio.h>
50238405Sjkim#include <string.h>
51238405Sjkim#include <strings.h>
52238405Sjkim#include <stdlib.h>
53238405Sjkim#include <unistd.h>
54238405Sjkim#include "hash.h"
55238405Sjkim
56238405Sjkim/*
57238405Sjkim * Static Variables and functions used by setnetgrent(), getnetgrent() and
58238405Sjkim * __endnetgrent().
59238405Sjkim * There are two linked lists:
60238405Sjkim * - linelist is just used by setnetgrent() to parse the net group file via.
61238405Sjkim *   parse_netgrp()
62238405Sjkim * - netgrp is the list of entries for the current netgroup
63238405Sjkim */
64238405Sjkimstruct linelist {
65238405Sjkim	struct linelist	*l_next;	/* Chain ptr. */
66238405Sjkim	int		l_parsed;	/* Flag for cycles */
67238405Sjkim	char		*l_groupname;	/* Name of netgroup */
68238405Sjkim	char		*l_line;	/* Netgroup entrie(s) to be parsed */
69238405Sjkim};
70238405Sjkim
71238405Sjkimstruct netgrp {
72238405Sjkim	struct netgrp	*ng_next;	/* Chain ptr */
73238405Sjkim	char		*ng_str[3];	/* Field pointers, see below */
74238405Sjkim};
75238405Sjkim#define NG_HOST		0	/* Host name */
76238405Sjkim#define NG_USER		1	/* User name */
77238405Sjkim#define NG_DOM		2	/* and Domain name */
78238405Sjkim
79238405Sjkimstatic struct linelist	*linehead = (struct linelist *)0;
80238405Sjkimstatic struct netgrp	*nextgrp = (struct netgrp *)0;
81238405Sjkimstatic struct {
82238405Sjkim	struct netgrp	*gr;
83238405Sjkim	char		*grname;
84238405Sjkim} grouphead = {
85238405Sjkim	(struct netgrp *)0,
86238405Sjkim	(char *)0,
87238405Sjkim};
88238405Sjkimstatic int parse_netgrp(char *group);
89238405Sjkimstatic struct linelist *read_for_group(char *group);
90238405Sjkimextern struct group_entry *gtable[];
91238405Sjkim
92238405Sjkim/*
93238405Sjkim * setnetgrent()
94238405Sjkim * Parse the netgroup file looking for the netgroup and build the list
95238405Sjkim * of netgrp structures. Let parse_netgrp() and read_for_group() do
96238405Sjkim * most of the work.
97238405Sjkim */
98238405Sjkimvoid
99238405Sjkim__setnetgrent(char *group)
100238405Sjkim{
101238405Sjkim	/* Sanity check */
102238405Sjkim
103238405Sjkim	if (group == NULL || !strlen(group))
104238405Sjkim		return;
105238405Sjkim
106238405Sjkim	if (grouphead.gr == (struct netgrp *)0 ||
107238405Sjkim		strcmp(group, grouphead.grname)) {
108238405Sjkim		__endnetgrent();
109238405Sjkim		if (parse_netgrp(group))
110238405Sjkim			__endnetgrent();
111238405Sjkim		else {
112238405Sjkim			grouphead.grname = (char *)
113238405Sjkim				malloc(strlen(group) + 1);
114238405Sjkim			strcpy(grouphead.grname, group);
115238405Sjkim		}
116238405Sjkim	}
117238405Sjkim	nextgrp = grouphead.gr;
118238405Sjkim}
119238405Sjkim
120238405Sjkim/*
121238405Sjkim * Get the next netgroup off the list.
122238405Sjkim */
123238405Sjkimint
124238405Sjkim__getnetgrent(char **hostp, char **userp, char **domp)
125238405Sjkim{
126238405Sjkim	if (nextgrp) {
127238405Sjkim		*hostp = nextgrp->ng_str[NG_HOST];
128238405Sjkim		*userp = nextgrp->ng_str[NG_USER];
129238405Sjkim		*domp = nextgrp->ng_str[NG_DOM];
130238405Sjkim		nextgrp = nextgrp->ng_next;
131238405Sjkim		return (1);
132238405Sjkim	}
133238405Sjkim	return (0);
134238405Sjkim}
135238405Sjkim
136238405Sjkim/*
137238405Sjkim * __endnetgrent() - cleanup
138238405Sjkim */
139238405Sjkimvoid
140238405Sjkim__endnetgrent(void)
141238405Sjkim{
142238405Sjkim	struct linelist *lp, *olp;
143238405Sjkim	struct netgrp *gp, *ogp;
144238405Sjkim
145238405Sjkim	lp = linehead;
146238405Sjkim	while (lp) {
147238405Sjkim		olp = lp;
148238405Sjkim		lp = lp->l_next;
149238405Sjkim		free(olp->l_groupname);
150238405Sjkim		free(olp->l_line);
151238405Sjkim		free((char *)olp);
152238405Sjkim	}
153238405Sjkim	linehead = (struct linelist *)0;
154238405Sjkim	if (grouphead.grname) {
155238405Sjkim		free(grouphead.grname);
156238405Sjkim		grouphead.grname = (char *)0;
157238405Sjkim	}
158238405Sjkim	gp = grouphead.gr;
159238405Sjkim	while (gp) {
160238405Sjkim		ogp = gp;
161238405Sjkim		gp = gp->ng_next;
162238405Sjkim		if (ogp->ng_str[NG_HOST])
163238405Sjkim			free(ogp->ng_str[NG_HOST]);
164238405Sjkim		if (ogp->ng_str[NG_USER])
165238405Sjkim			free(ogp->ng_str[NG_USER]);
166238405Sjkim		if (ogp->ng_str[NG_DOM])
167238405Sjkim			free(ogp->ng_str[NG_DOM]);
168238405Sjkim		free((char *)ogp);
169238405Sjkim	}
170238405Sjkim	grouphead.gr = (struct netgrp *)0;
171238405Sjkim}
172238405Sjkim
173238405Sjkim/*
174238405Sjkim * Parse the netgroup file setting up the linked lists.
175238405Sjkim */
176238405Sjkimstatic int
177238405Sjkimparse_netgrp(char *group)
178238405Sjkim{
179238405Sjkim	char *spos, *epos;
180238405Sjkim	int len, strpos;
181238405Sjkim#ifdef DEBUG
182238405Sjkim	int fields;
183238405Sjkim#endif
184238405Sjkim	char *pos, *gpos;
185238405Sjkim	struct netgrp *grp;
186238405Sjkim	struct linelist *lp = linehead;
187238405Sjkim
188238405Sjkim	/*
189238405Sjkim	 * First, see if the line has already been read in.
190238405Sjkim	 */
191238405Sjkim	while (lp) {
192238405Sjkim		if (!strcmp(group, lp->l_groupname))
193238405Sjkim			break;
194238405Sjkim		lp = lp->l_next;
195238405Sjkim	}
196238405Sjkim	if (lp == (struct linelist *)0 &&
197238405Sjkim	    (lp = read_for_group(group)) == (struct linelist *)0)
198238405Sjkim		return (1);
199238405Sjkim	if (lp->l_parsed) {
200238405Sjkim#ifdef DEBUG
201238405Sjkim		/*
202238405Sjkim		 * This error message is largely superfluous since the
203238405Sjkim		 * code handles the error condition successfully, and
204238405Sjkim		 * spewing it out from inside libc can actually hose
205238405Sjkim		 * certain programs.
206238405Sjkim		 */
207238405Sjkim		warnx("cycle in netgroup %s", lp->l_groupname);
208238405Sjkim#endif
209238405Sjkim		return (1);
210238405Sjkim	} else
211238405Sjkim		lp->l_parsed = 1;
212238405Sjkim	pos = lp->l_line;
213238405Sjkim	/* Watch for null pointer dereferences, dammit! */
214238405Sjkim	while (pos != NULL && *pos != '\0') {
215238405Sjkim		if (*pos == '(') {
216238405Sjkim			grp = (struct netgrp *)malloc(sizeof (struct netgrp));
217238405Sjkim			bzero((char *)grp, sizeof (struct netgrp));
218238405Sjkim			grp->ng_next = grouphead.gr;
219238405Sjkim			grouphead.gr = grp;
220238405Sjkim			pos++;
221238405Sjkim			gpos = strsep(&pos, ")");
222238405Sjkim#ifdef DEBUG
223238405Sjkim			fields = 0;
224238405Sjkim#endif
225238405Sjkim			for (strpos = 0; strpos < 3; strpos++) {
226238405Sjkim				if ((spos = strsep(&gpos, ","))) {
227238405Sjkim#ifdef DEBUG
228238405Sjkim					fields++;
229238405Sjkim#endif
230238405Sjkim					while (*spos == ' ' || *spos == '\t')
231238405Sjkim						spos++;
232238405Sjkim					if ((epos = strpbrk(spos, " \t"))) {
233238405Sjkim						*epos = '\0';
234238405Sjkim						len = epos - spos;
235238405Sjkim					} else
236238405Sjkim						len = strlen(spos);
237238405Sjkim					if (len > 0) {
238238405Sjkim						grp->ng_str[strpos] =  (char *)
239238405Sjkim							malloc(len + 1);
240238405Sjkim						bcopy(spos, grp->ng_str[strpos],
241238405Sjkim							len + 1);
242238405Sjkim					}
243238405Sjkim				} else {
244238405Sjkim					/*
245238405Sjkim					 * All other systems I've tested
246238405Sjkim					 * return NULL for empty netgroup
247238405Sjkim					 * fields. It's up to user programs
248238405Sjkim					 * to handle the NULLs appropriately.
249238405Sjkim					 */
250238405Sjkim					grp->ng_str[strpos] = NULL;
251238405Sjkim				}
252238405Sjkim			}
253238405Sjkim#ifdef DEBUG
254238405Sjkim			/*
255238405Sjkim			 * Note: on other platforms, malformed netgroup
256238405Sjkim			 * entries are not normally flagged. While we
257238405Sjkim			 * can catch bad entries and report them, we should
258238405Sjkim			 * stay silent by default for compatibility's sake.
259238405Sjkim			 */
260238405Sjkim			if (fields < 3)
261238405Sjkim					warnx("bad entry (%s%s%s%s%s) in netgroup \"%s\"",
262238405Sjkim						grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],
263238405Sjkim						grp->ng_str[NG_USER] == NULL ? "" : ",",
264238405Sjkim						grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],
265238405Sjkim						grp->ng_str[NG_DOM] == NULL ? "" : ",",
266238405Sjkim						grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],
267238405Sjkim						lp->l_groupname);
268238405Sjkim#endif
269238405Sjkim		} else {
270238405Sjkim			spos = strsep(&pos, ", \t");
271238405Sjkim			if (parse_netgrp(spos))
272238405Sjkim				continue;
273238405Sjkim		}
274238405Sjkim		/* Watch for null pointer dereferences, dammit! */
275238405Sjkim		if (pos != NULL)
276238405Sjkim			while (*pos == ' ' || *pos == ',' || *pos == '\t')
277238405Sjkim				pos++;
278238405Sjkim	}
279238405Sjkim	return (0);
280238405Sjkim}
281238405Sjkim
282238405Sjkim/*
283238405Sjkim * Read the netgroup file and save lines until the line for the netgroup
284238405Sjkim * is found. Return 1 if eof is encountered.
285238405Sjkim */
286238405Sjkimstatic struct linelist *
287238405Sjkimread_for_group(char *group)
288238405Sjkim{
289238405Sjkim	char *pos, *spos, *linep = NULL, *olinep = NULL;
290238405Sjkim	int len, olen;
291238405Sjkim	int cont;
292238405Sjkim	struct linelist *lp;
293238405Sjkim	char line[LINSIZ + 1];
294238405Sjkim	char *data = NULL;
295238405Sjkim
296238405Sjkim	data = lookup (gtable, group);
297238405Sjkim	sprintf(line, "%s %s", group, data);
298238405Sjkim	pos = (char *)&line;
299238405Sjkim#ifdef CANT_HAPPEN
300238405Sjkim	if (*pos == '#')
301238405Sjkim		continue;
302238405Sjkim#endif
303238405Sjkim	while (*pos == ' ' || *pos == '\t')
304238405Sjkim		pos++;
305238405Sjkim	spos = pos;
306238405Sjkim	while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
307238405Sjkim		*pos != '\0')
308238405Sjkim		pos++;
309238405Sjkim	len = pos - spos;
310238405Sjkim	while (*pos == ' ' || *pos == '\t')
311238405Sjkim		pos++;
312238405Sjkim	if (*pos != '\n' && *pos != '\0') {
313238405Sjkim		lp = (struct linelist *)malloc(sizeof (*lp));
314238405Sjkim		lp->l_parsed = 0;
315238405Sjkim		lp->l_groupname = (char *)malloc(len + 1);
316238405Sjkim		bcopy(spos, lp->l_groupname, len);
317238405Sjkim		*(lp->l_groupname + len) = '\0';
318238405Sjkim		len = strlen(pos);
319238405Sjkim		olen = 0;
320238405Sjkim			/*
321238405Sjkim			 * Loop around handling line continuations.
322238405Sjkim			 */
323238405Sjkim			do {
324238405Sjkim				if (*(pos + len - 1) == '\n')
325238405Sjkim					len--;
326238405Sjkim				if (*(pos + len - 1) == '\\') {
327238405Sjkim					len--;
328238405Sjkim					cont = 1;
329238405Sjkim				} else
330238405Sjkim					cont = 0;
331238405Sjkim				if (len > 0) {
332238405Sjkim					linep = (char *)malloc(olen + len + 1);
333238405Sjkim					if (olen > 0) {
334238405Sjkim						bcopy(olinep, linep, olen);
335238405Sjkim						free(olinep);
336238405Sjkim					}
337238405Sjkim					bcopy(pos, linep + olen, len);
338238405Sjkim					olen += len;
339238405Sjkim					*(linep + olen) = '\0';
340238405Sjkim					olinep = linep;
341238405Sjkim				}
342238405Sjkim#ifdef CANT_HAPPEN
343238405Sjkim				if (cont) {
344238405Sjkim					if (fgets(line, LINSIZ, netf)) {
345238405Sjkim						pos = line;
346238405Sjkim						len = strlen(pos);
347238405Sjkim					} else
348238405Sjkim						cont = 0;
349238405Sjkim				}
350238405Sjkim#endif
351238405Sjkim			} while (cont);
352238405Sjkim		lp->l_line = linep;
353238405Sjkim		lp->l_next = linehead;
354238405Sjkim		linehead = lp;
355238405Sjkim#ifdef CANT_HAPPEN
356238405Sjkim		/*
357238405Sjkim		 * If this is the one we wanted, we are done.
358238405Sjkim		 */
359238405Sjkim		if (!strcmp(lp->l_groupname, group))
360238405Sjkim#endif
361238405Sjkim			return (lp);
362238405Sjkim	}
363238405Sjkim	return ((struct linelist *)0);
364238405Sjkim}
365238405Sjkim