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
38 static const char rcsid[] =
39   "$FreeBSD: src/libexec/revnetgroup/parse_netgroup.c,v 1.7 1999/08/28 00:09:48 peter Exp $";
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  */
63 struct 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 
70 struct 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 
78 static struct linelist	*linehead = (struct linelist *)0;
79 static struct netgrp	*nextgrp = (struct netgrp *)0;
80 static struct {
81 	struct netgrp	*gr;
82 	char		*grname;
83 } grouphead = {
84 	(struct netgrp *)0,
85 	(char *)0,
86 };
87 static int parse_netgrp();
88 static struct linelist *read_for_group();
89 void __setnetgrent(), __endnetgrent();
90 int __getnetgrent();
91 extern 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  */
99 void
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  */
125 int
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  */
142 void
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  */
179 static int
180 parse_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  */
290 static struct linelist *
291 read_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