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