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