parse_netgroup.c revision 90377
1/*
2 * Copyright (c) 1992, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static const char rcsid[] =
39  "$FreeBSD: head/libexec/revnetgroup/parse_netgroup.c 90377 2002-02-07 23:57:01Z imp $";
40#endif /* not lint */
41
42/*
43 * This is a specially hacked-up version of getnetgrent.c used to parse
44 * data from the stored hash table of netgroup info rather than from a
45 * file. It's used mainly for the parse_netgroup() function. All the YP
46 * stuff and file support has been stripped out since it isn't needed.
47 */
48
49#include <stdio.h>
50#include <strings.h>
51#include <stdlib.h>
52#include <unistd.h>
53#include "hash.h"
54
55/*
56 * Static Variables and functions used by setnetgrent(), getnetgrent() and
57 * __endnetgrent().
58 * There are two linked lists:
59 * - linelist is just used by setnetgrent() to parse the net group file via.
60 *   parse_netgrp()
61 * - netgrp is the list of entries for the current netgroup
62 */
63struct linelist {
64	struct linelist	*l_next;	/* Chain ptr. */
65	int		l_parsed;	/* Flag for cycles */
66	char		*l_groupname;	/* Name of netgroup */
67	char		*l_line;	/* Netgroup entrie(s) to be parsed */
68};
69
70struct netgrp {
71	struct netgrp	*ng_next;	/* Chain ptr */
72	char		*ng_str[3];	/* Field pointers, see below */
73};
74#define NG_HOST		0	/* Host name */
75#define NG_USER		1	/* User name */
76#define NG_DOM		2	/* and Domain name */
77
78static struct linelist	*linehead = (struct linelist *)0;
79static struct netgrp	*nextgrp = (struct netgrp *)0;
80static struct {
81	struct netgrp	*gr;
82	char		*grname;
83} grouphead = {
84	(struct netgrp *)0,
85	(char *)0,
86};
87static int parse_netgrp(char *group);
88static struct linelist *read_for_group(char *group);
89extern struct group_entry *gtable[];
90
91/*
92 * setnetgrent()
93 * Parse the netgroup file looking for the netgroup and build the list
94 * of netgrp structures. Let parse_netgrp() and read_for_group() do
95 * most of the work.
96 */
97void
98__setnetgrent(char *group)
99{
100	/* Sanity check */
101
102	if (group == NULL || !strlen(group))
103		return;
104
105	if (grouphead.gr == (struct netgrp *)0 ||
106		strcmp(group, grouphead.grname)) {
107		__endnetgrent();
108		if (parse_netgrp(group))
109			__endnetgrent();
110		else {
111			grouphead.grname = (char *)
112				malloc(strlen(group) + 1);
113			strcpy(grouphead.grname, group);
114		}
115	}
116	nextgrp = grouphead.gr;
117}
118
119/*
120 * Get the next netgroup off the list.
121 */
122int
123__getnetgrent(char **hostp, char **userp, char **domp)
124{
125	if (nextgrp) {
126		*hostp = nextgrp->ng_str[NG_HOST];
127		*userp = nextgrp->ng_str[NG_USER];
128		*domp = nextgrp->ng_str[NG_DOM];
129		nextgrp = nextgrp->ng_next;
130		return (1);
131	}
132	return (0);
133}
134
135/*
136 * __endnetgrent() - cleanup
137 */
138void
139__endnetgrent(void)
140{
141	struct linelist *lp, *olp;
142	struct netgrp *gp, *ogp;
143
144	lp = linehead;
145	while (lp) {
146		olp = lp;
147		lp = lp->l_next;
148		free(olp->l_groupname);
149		free(olp->l_line);
150		free((char *)olp);
151	}
152	linehead = (struct linelist *)0;
153	if (grouphead.grname) {
154		free(grouphead.grname);
155		grouphead.grname = (char *)0;
156	}
157	gp = grouphead.gr;
158	while (gp) {
159		ogp = gp;
160		gp = gp->ng_next;
161		if (ogp->ng_str[NG_HOST])
162			free(ogp->ng_str[NG_HOST]);
163		if (ogp->ng_str[NG_USER])
164			free(ogp->ng_str[NG_USER]);
165		if (ogp->ng_str[NG_DOM])
166			free(ogp->ng_str[NG_DOM]);
167		free((char *)ogp);
168	}
169	grouphead.gr = (struct netgrp *)0;
170}
171
172/*
173 * Parse the netgroup file setting up the linked lists.
174 */
175static int
176parse_netgrp(char *group)
177{
178	char *spos, *epos;
179	int len, strpos;
180#ifdef DEBUG
181	int fields;
182#endif
183	char *pos, *gpos;
184	struct netgrp *grp;
185	struct linelist *lp = linehead;
186
187	/*
188	 * First, see if the line has already been read in.
189	 */
190	while (lp) {
191		if (!strcmp(group, lp->l_groupname))
192			break;
193		lp = lp->l_next;
194	}
195	if (lp == (struct linelist *)0 &&
196	    (lp = read_for_group(group)) == (struct linelist *)0)
197		return (1);
198	if (lp->l_parsed) {
199#ifdef DEBUG
200		/*
201		 * This error message is largely superflous since the
202		 * code handles the error condition sucessfully, and
203		 * spewing it out from inside libc can actually hose
204		 * certain programs.
205		 */
206		warnx("cycle in netgroup %s", lp->l_groupname);
207#endif
208		return (1);
209	} else
210		lp->l_parsed = 1;
211	pos = lp->l_line;
212	/* Watch for null pointer dereferences, dammit! */
213	while (pos != NULL && *pos != '\0') {
214		if (*pos == '(') {
215			grp = (struct netgrp *)malloc(sizeof (struct netgrp));
216			bzero((char *)grp, sizeof (struct netgrp));
217			grp->ng_next = grouphead.gr;
218			grouphead.gr = grp;
219			pos++;
220			gpos = strsep(&pos, ")");
221#ifdef DEBUG
222			fields = 0;
223#endif
224			for (strpos = 0; strpos < 3; strpos++) {
225				if ((spos = strsep(&gpos, ","))) {
226#ifdef DEBUG
227					fields++;
228#endif
229					while (*spos == ' ' || *spos == '\t')
230						spos++;
231					if ((epos = strpbrk(spos, " \t"))) {
232						*epos = '\0';
233						len = epos - spos;
234					} else
235						len = strlen(spos);
236					if (len > 0) {
237						grp->ng_str[strpos] =  (char *)
238							malloc(len + 1);
239						bcopy(spos, grp->ng_str[strpos],
240							len + 1);
241					}
242				} else {
243					/*
244					 * All other systems I've tested
245					 * return NULL for empty netgroup
246					 * fields. It's up to user programs
247					 * to handle the NULLs appropriately.
248					 */
249					grp->ng_str[strpos] = NULL;
250				}
251			}
252#ifdef DEBUG
253			/*
254			 * Note: on other platforms, malformed netgroup
255			 * entries are not normally flagged. While we
256			 * can catch bad entries and report them, we should
257			 * stay silent by default for compatibility's sake.
258			 */
259			if (fields < 3)
260					warnx("bad entry (%s%s%s%s%s) in netgroup \"%s\"",
261						grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],
262						grp->ng_str[NG_USER] == NULL ? "" : ",",
263						grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],
264						grp->ng_str[NG_DOM] == NULL ? "" : ",",
265						grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],
266						lp->l_groupname);
267#endif
268		} else {
269			spos = strsep(&pos, ", \t");
270			if (parse_netgrp(spos))
271				continue;
272		}
273		/* Watch for null pointer dereferences, dammit! */
274		if (pos != NULL)
275			while (*pos == ' ' || *pos == ',' || *pos == '\t')
276				pos++;
277	}
278	return (0);
279}
280
281/*
282 * Read the netgroup file and save lines until the line for the netgroup
283 * is found. Return 1 if eof is encountered.
284 */
285static struct linelist *
286read_for_group(char *group)
287{
288	char *pos, *spos, *linep = NULL, *olinep = NULL;
289	int len, olen;
290	int cont;
291	struct linelist *lp;
292	char line[LINSIZ + 1];
293	char *data = NULL;
294
295	data = lookup (gtable, group);
296	sprintf(line, "%s %s", group, data);
297	pos = (char *)&line;
298#ifdef CANT_HAPPEN
299	if (*pos == '#')
300		continue;
301#endif
302	while (*pos == ' ' || *pos == '\t')
303		pos++;
304	spos = pos;
305	while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
306		*pos != '\0')
307		pos++;
308	len = pos - spos;
309	while (*pos == ' ' || *pos == '\t')
310		pos++;
311	if (*pos != '\n' && *pos != '\0') {
312		lp = (struct linelist *)malloc(sizeof (*lp));
313		lp->l_parsed = 0;
314		lp->l_groupname = (char *)malloc(len + 1);
315		bcopy(spos, lp->l_groupname, len);
316		*(lp->l_groupname + len) = '\0';
317		len = strlen(pos);
318		olen = 0;
319			/*
320			 * Loop around handling line continuations.
321			 */
322			do {
323				if (*(pos + len - 1) == '\n')
324					len--;
325				if (*(pos + len - 1) == '\\') {
326					len--;
327					cont = 1;
328				} else
329					cont = 0;
330				if (len > 0) {
331					linep = (char *)malloc(olen + len + 1);
332					if (olen > 0) {
333						bcopy(olinep, linep, olen);
334						free(olinep);
335					}
336					bcopy(pos, linep + olen, len);
337					olen += len;
338					*(linep + olen) = '\0';
339					olinep = linep;
340				}
341#ifdef CANT_HAPPEN
342				if (cont) {
343					if (fgets(line, LINSIZ, netf)) {
344						pos = line;
345						len = strlen(pos);
346					} else
347						cont = 0;
348				}
349#endif
350			} while (cont);
351		lp->l_line = linep;
352		lp->l_next = linehead;
353		linehead = lp;
354#ifdef CANT_HAPPEN
355		/*
356		 * If this is the one we wanted, we are done.
357		 */
358		if (!strcmp(lp->l_groupname, group))
359#endif
360			return (lp);
361	}
362	return ((struct linelist *)0);
363}
364