parse_netgroup.c revision 31404
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	"$Id$";
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();
88static struct linelist *read_for_group();
89void __setnetgrent(), __endnetgrent();
90int __getnetgrent();
91extern struct group_entry *gtable[];
92
93/*
94 * setnetgrent()
95 * Parse the netgroup file looking for the netgroup and build the list
96 * of netgrp structures. Let parse_netgrp() and read_for_group() do
97 * most of the work.
98 */
99void
100__setnetgrent(group)
101	char *group;
102{
103	/* Sanity check */
104
105	if (group == NULL || !strlen(group))
106		return;
107
108	if (grouphead.gr == (struct netgrp *)0 ||
109		strcmp(group, grouphead.grname)) {
110		__endnetgrent();
111		if (parse_netgrp(group))
112			__endnetgrent();
113		else {
114			grouphead.grname = (char *)
115				malloc(strlen(group) + 1);
116			strcpy(grouphead.grname, group);
117		}
118	}
119	nextgrp = grouphead.gr;
120}
121
122/*
123 * Get the next netgroup off the list.
124 */
125int
126__getnetgrent(hostp, userp, domp)
127	char **hostp, **userp, **domp;
128{
129	if (nextgrp) {
130		*hostp = nextgrp->ng_str[NG_HOST];
131		*userp = nextgrp->ng_str[NG_USER];
132		*domp = nextgrp->ng_str[NG_DOM];
133		nextgrp = nextgrp->ng_next;
134		return (1);
135	}
136	return (0);
137}
138
139/*
140 * __endnetgrent() - cleanup
141 */
142void
143__endnetgrent()
144{
145	register struct linelist *lp, *olp;
146	register struct netgrp *gp, *ogp;
147
148	lp = linehead;
149	while (lp) {
150		olp = lp;
151		lp = lp->l_next;
152		free(olp->l_groupname);
153		free(olp->l_line);
154		free((char *)olp);
155	}
156	linehead = (struct linelist *)0;
157	if (grouphead.grname) {
158		free(grouphead.grname);
159		grouphead.grname = (char *)0;
160	}
161	gp = grouphead.gr;
162	while (gp) {
163		ogp = gp;
164		gp = gp->ng_next;
165		if (ogp->ng_str[NG_HOST])
166			free(ogp->ng_str[NG_HOST]);
167		if (ogp->ng_str[NG_USER])
168			free(ogp->ng_str[NG_USER]);
169		if (ogp->ng_str[NG_DOM])
170			free(ogp->ng_str[NG_DOM]);
171		free((char *)ogp);
172	}
173	grouphead.gr = (struct netgrp *)0;
174}
175
176/*
177 * Parse the netgroup file setting up the linked lists.
178 */
179static int
180parse_netgrp(group)
181	char *group;
182{
183	register char *spos, *epos;
184	register int len, strpos;
185#ifdef DEBUG
186	register int fields;
187#endif
188	char *pos, *gpos;
189	struct netgrp *grp;
190	struct linelist *lp = linehead;
191
192	/*
193	 * First, see if the line has already been read in.
194	 */
195	while (lp) {
196		if (!strcmp(group, lp->l_groupname))
197			break;
198		lp = lp->l_next;
199	}
200	if (lp == (struct linelist *)0 &&
201	    (lp = read_for_group(group)) == (struct linelist *)0)
202		return (1);
203	if (lp->l_parsed) {
204#ifdef DEBUG
205		/*
206		 * This error message is largely superflous since the
207		 * code handles the error condition sucessfully, and
208		 * spewing it out from inside libc can actually hose
209		 * certain programs.
210		 */
211		warnx("cycle in netgroup %s", lp->l_groupname);
212#endif
213		return (1);
214	} else
215		lp->l_parsed = 1;
216	pos = lp->l_line;
217	/* Watch for null pointer dereferences, dammit! */
218	while (pos != NULL && *pos != '\0') {
219		if (*pos == '(') {
220			grp = (struct netgrp *)malloc(sizeof (struct netgrp));
221			bzero((char *)grp, sizeof (struct netgrp));
222			grp->ng_next = grouphead.gr;
223			grouphead.gr = grp;
224			pos++;
225			gpos = strsep(&pos, ")");
226#ifdef DEBUG
227			fields = 0;
228#endif
229			for (strpos = 0; strpos < 3; strpos++) {
230				if ((spos = strsep(&gpos, ","))) {
231#ifdef DEBUG
232					fields++;
233#endif
234					while (*spos == ' ' || *spos == '\t')
235						spos++;
236					if ((epos = strpbrk(spos, " \t"))) {
237						*epos = '\0';
238						len = epos - spos;
239					} else
240						len = strlen(spos);
241					if (len > 0) {
242						grp->ng_str[strpos] =  (char *)
243							malloc(len + 1);
244						bcopy(spos, grp->ng_str[strpos],
245							len + 1);
246					}
247				} else {
248					/*
249					 * All other systems I've tested
250					 * return NULL for empty netgroup
251					 * fields. It's up to user programs
252					 * to handle the NULLs appropriately.
253					 */
254					grp->ng_str[strpos] = NULL;
255				}
256			}
257#ifdef DEBUG
258			/*
259			 * Note: on other platforms, malformed netgroup
260			 * entries are not normally flagged. While we
261			 * can catch bad entries and report them, we should
262			 * stay silent by default for compatibility's sake.
263			 */
264			if (fields < 3)
265					warnx("bad entry (%s%s%s%s%s) in netgroup \"%s\"",
266						grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],
267						grp->ng_str[NG_USER] == NULL ? "" : ",",
268						grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],
269						grp->ng_str[NG_DOM] == NULL ? "" : ",",
270						grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],
271						lp->l_groupname);
272#endif
273		} else {
274			spos = strsep(&pos, ", \t");
275			if (parse_netgrp(spos))
276				continue;
277		}
278		/* Watch for null pointer dereferences, dammit! */
279		if (pos != NULL)
280			while (*pos == ' ' || *pos == ',' || *pos == '\t')
281				pos++;
282	}
283	return (0);
284}
285
286/*
287 * Read the netgroup file and save lines until the line for the netgroup
288 * is found. Return 1 if eof is encountered.
289 */
290static struct linelist *
291read_for_group(group)
292	char *group;
293{
294	register char *pos, *spos, *linep = NULL, *olinep = NULL;
295	register int len, olen;
296	int cont;
297	struct linelist *lp;
298	char line[LINSIZ + 1];
299	char *data = NULL;
300
301	data = lookup (gtable, group);
302	sprintf(line, "%s %s", group, data);
303	pos = (char *)&line;
304#ifdef CANT_HAPPEN
305	if (*pos == '#')
306		continue;
307#endif
308	while (*pos == ' ' || *pos == '\t')
309		pos++;
310	spos = pos;
311	while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
312		*pos != '\0')
313		pos++;
314	len = pos - spos;
315	while (*pos == ' ' || *pos == '\t')
316		pos++;
317	if (*pos != '\n' && *pos != '\0') {
318		lp = (struct linelist *)malloc(sizeof (*lp));
319		lp->l_parsed = 0;
320		lp->l_groupname = (char *)malloc(len + 1);
321		bcopy(spos, lp->l_groupname, len);
322		*(lp->l_groupname + len) = '\0';
323		len = strlen(pos);
324		olen = 0;
325			/*
326			 * Loop around handling line continuations.
327			 */
328			do {
329				if (*(pos + len - 1) == '\n')
330					len--;
331				if (*(pos + len - 1) == '\\') {
332					len--;
333					cont = 1;
334				} else
335					cont = 0;
336				if (len > 0) {
337					linep = (char *)malloc(olen + len + 1);
338					if (olen > 0) {
339						bcopy(olinep, linep, olen);
340						free(olinep);
341					}
342					bcopy(pos, linep + olen, len);
343					olen += len;
344					*(linep + olen) = '\0';
345					olinep = linep;
346				}
347#ifdef CANT_HAPPEN
348				if (cont) {
349					if (fgets(line, LINSIZ, netf)) {
350						pos = line;
351						len = strlen(pos);
352					} else
353						cont = 0;
354				}
355#endif
356			} while (cont);
357		lp->l_line = linep;
358		lp->l_next = linehead;
359		linehead = lp;
360#ifdef CANT_HAPPEN
361		/*
362		 * If this is the one we wanted, we are done.
363		 */
364		if (!strcmp(lp->l_groupname, group))
365#endif
366			return (lp);
367	}
368	return ((struct linelist *)0);
369}
370