xref: /freebsd/libexec/revnetgroup/parse_netgroup.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
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 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid[] = "$Id: parse_netgroup.c,v 1.1.1.1 1995/10/26 16:25:29 wpaul Exp $";
39 #endif /* LIBC_SCCS and not lint */
40 
41 /*
42  * This is a specially hacked-up version of getnetgrent.c used to parse
43  * data from the stored hash table of netgroup info rather than from a
44  * file. It's used mainly for the parse_netgroup() function. All the YP
45  * stuff and file support has been stripped out since it isn't needed.
46  */
47 
48 #include <stdio.h>
49 #include <strings.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include "hash.h"
53 
54 #ifndef lint
55 static const char rcsid[] = "$Id$";
56 #endif
57 
58 /*
59  * Static Variables and functions used by setnetgrent(), getnetgrent() and
60  * __endnetgrent().
61  * There are two linked lists:
62  * - linelist is just used by setnetgrent() to parse the net group file via.
63  *   parse_netgrp()
64  * - netgrp is the list of entries for the current netgroup
65  */
66 struct linelist {
67 	struct linelist	*l_next;	/* Chain ptr. */
68 	int		l_parsed;	/* Flag for cycles */
69 	char		*l_groupname;	/* Name of netgroup */
70 	char		*l_line;	/* Netgroup entrie(s) to be parsed */
71 };
72 
73 struct netgrp {
74 	struct netgrp	*ng_next;	/* Chain ptr */
75 	char		*ng_str[3];	/* Field pointers, see below */
76 };
77 #define NG_HOST		0	/* Host name */
78 #define NG_USER		1	/* User name */
79 #define NG_DOM		2	/* and Domain name */
80 
81 static struct linelist	*linehead = (struct linelist *)0;
82 static struct netgrp	*nextgrp = (struct netgrp *)0;
83 static struct {
84 	struct netgrp	*gr;
85 	char		*grname;
86 } grouphead = {
87 	(struct netgrp *)0,
88 	(char *)0,
89 };
90 static int parse_netgrp();
91 static struct linelist *read_for_group();
92 void __setnetgrent(), __endnetgrent();
93 int __getnetgrent();
94 extern struct group_entry *gtable[];
95 extern char *lookup __P(( struct group_entry *[], char * ));
96 #define	LINSIZ	1024	/* Length of netgroup file line */
97 
98 /*
99  * setnetgrent()
100  * Parse the netgroup file looking for the netgroup and build the list
101  * of netgrp structures. Let parse_netgrp() and read_for_group() do
102  * most of the work.
103  */
104 void
105 __setnetgrent(group)
106 	char *group;
107 {
108 	/* Sanity check */
109 
110 	if (group == NULL || !strlen(group))
111 		return;
112 
113 	if (grouphead.gr == (struct netgrp *)0 ||
114 		strcmp(group, grouphead.grname)) {
115 		__endnetgrent();
116 		if (parse_netgrp(group))
117 			__endnetgrent();
118 		else {
119 			grouphead.grname = (char *)
120 				malloc(strlen(group) + 1);
121 			strcpy(grouphead.grname, group);
122 		}
123 	}
124 	nextgrp = grouphead.gr;
125 }
126 
127 /*
128  * Get the next netgroup off the list.
129  */
130 int
131 __getnetgrent(hostp, userp, domp)
132 	char **hostp, **userp, **domp;
133 {
134 	if (nextgrp) {
135 		*hostp = nextgrp->ng_str[NG_HOST];
136 		*userp = nextgrp->ng_str[NG_USER];
137 		*domp = nextgrp->ng_str[NG_DOM];
138 		nextgrp = nextgrp->ng_next;
139 		return (1);
140 	}
141 	return (0);
142 }
143 
144 /*
145  * __endnetgrent() - cleanup
146  */
147 void
148 __endnetgrent()
149 {
150 	register struct linelist *lp, *olp;
151 	register struct netgrp *gp, *ogp;
152 
153 	lp = linehead;
154 	while (lp) {
155 		olp = lp;
156 		lp = lp->l_next;
157 		free(olp->l_groupname);
158 		free(olp->l_line);
159 		free((char *)olp);
160 	}
161 	linehead = (struct linelist *)0;
162 	if (grouphead.grname) {
163 		free(grouphead.grname);
164 		grouphead.grname = (char *)0;
165 	}
166 	gp = grouphead.gr;
167 	while (gp) {
168 		ogp = gp;
169 		gp = gp->ng_next;
170 		if (ogp->ng_str[NG_HOST])
171 			free(ogp->ng_str[NG_HOST]);
172 		if (ogp->ng_str[NG_USER])
173 			free(ogp->ng_str[NG_USER]);
174 		if (ogp->ng_str[NG_DOM])
175 			free(ogp->ng_str[NG_DOM]);
176 		free((char *)ogp);
177 	}
178 	grouphead.gr = (struct netgrp *)0;
179 }
180 
181 /*
182  * Parse the netgroup file setting up the linked lists.
183  */
184 static int
185 parse_netgrp(group)
186 	char *group;
187 {
188 	register char *spos, *epos;
189 	register int len, strpos;
190 #ifdef DEBUG
191 	register int fields;
192 #endif
193 	char *pos, *gpos;
194 	struct netgrp *grp;
195 	struct linelist *lp = linehead;
196 
197 	/*
198 	 * First, see if the line has already been read in.
199 	 */
200 	while (lp) {
201 		if (!strcmp(group, lp->l_groupname))
202 			break;
203 		lp = lp->l_next;
204 	}
205 	if (lp == (struct linelist *)0 &&
206 	    (lp = read_for_group(group)) == (struct linelist *)0)
207 		return (1);
208 	if (lp->l_parsed) {
209 #ifdef DEBUG
210 		/*
211 		 * This error message is largely superflous since the
212 		 * code handles the error condition sucessfully, and
213 		 * spewing it out from inside libc can actually hose
214 		 * certain programs.
215 		 */
216 		fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);
217 #endif
218 		return (1);
219 	} else
220 		lp->l_parsed = 1;
221 	pos = lp->l_line;
222 	/* Watch for null pointer dereferences, dammit! */
223 	while (pos != NULL && *pos != '\0') {
224 		if (*pos == '(') {
225 			grp = (struct netgrp *)malloc(sizeof (struct netgrp));
226 			bzero((char *)grp, sizeof (struct netgrp));
227 			grp->ng_next = grouphead.gr;
228 			grouphead.gr = grp;
229 			pos++;
230 			gpos = strsep(&pos, ")");
231 #ifdef DEBUG
232 			fields = 0;
233 #endif
234 			for (strpos = 0; strpos < 3; strpos++) {
235 				if ((spos = strsep(&gpos, ","))) {
236 #ifdef DEBUG
237 					fields++;
238 #endif
239 					while (*spos == ' ' || *spos == '\t')
240 						spos++;
241 					if ((epos = strpbrk(spos, " \t"))) {
242 						*epos = '\0';
243 						len = epos - spos;
244 					} else
245 						len = strlen(spos);
246 					if (len > 0) {
247 						grp->ng_str[strpos] =  (char *)
248 							malloc(len + 1);
249 						bcopy(spos, grp->ng_str[strpos],
250 							len + 1);
251 					}
252 				} else {
253 					/*
254 					 * All other systems I've tested
255 					 * return NULL for empty netgroup
256 					 * fields. It's up to user programs
257 					 * to handle the NULLs appropriately.
258 					 */
259 					grp->ng_str[strpos] = NULL;
260 				}
261 			}
262 #ifdef DEBUG
263 			/*
264 			 * Note: on other platforms, malformed netgroup
265 			 * entries are not normally flagged. While we
266 			 * can catch bad entries and report them, we should
267 			 * stay silent by default for compatibility's sake.
268 			 */
269 			if (fields < 3)
270 					fprintf(stderr, "Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n",
271 						grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],
272 						grp->ng_str[NG_USER] == NULL ? "" : ",",
273 						grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],
274 						grp->ng_str[NG_DOM] == NULL ? "" : ",",
275 						grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],
276 						lp->l_groupname);
277 #endif
278 		} else {
279 			spos = strsep(&pos, ", \t");
280 			if (parse_netgrp(spos))
281 				continue;
282 		}
283 		/* Watch for null pointer dereferences, dammit! */
284 		if (pos != NULL)
285 			while (*pos == ' ' || *pos == ',' || *pos == '\t')
286 				pos++;
287 	}
288 	return (0);
289 }
290 
291 /*
292  * Read the netgroup file and save lines until the line for the netgroup
293  * is found. Return 1 if eof is encountered.
294  */
295 static struct linelist *
296 read_for_group(group)
297 	char *group;
298 {
299 	register char *pos, *spos, *linep, *olinep;
300 	register int len, olen;
301 	int cont;
302 	struct linelist *lp;
303 	char line[LINSIZ + 1];
304 	char *key = NULL, *data = NULL;
305 
306 	data = lookup (gtable, group);
307 	sprintf(line, "%s %s", group, data);
308 	pos = (char *)&line;
309 #ifdef CANT_HAPPEN
310 	if (*pos == '#')
311 		continue;
312 #endif
313 	while (*pos == ' ' || *pos == '\t')
314 		pos++;
315 	spos = pos;
316 	while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
317 		*pos != '\0')
318 		pos++;
319 	len = pos - spos;
320 	while (*pos == ' ' || *pos == '\t')
321 		pos++;
322 	if (*pos != '\n' && *pos != '\0') {
323 		lp = (struct linelist *)malloc(sizeof (*lp));
324 		lp->l_parsed = 0;
325 		lp->l_groupname = (char *)malloc(len + 1);
326 		bcopy(spos, lp->l_groupname, len);
327 		*(lp->l_groupname + len) = '\0';
328 		len = strlen(pos);
329 		olen = 0;
330 			/*
331 			 * Loop around handling line continuations.
332 			 */
333 			do {
334 				if (*(pos + len - 1) == '\n')
335 					len--;
336 				if (*(pos + len - 1) == '\\') {
337 					len--;
338 					cont = 1;
339 				} else
340 					cont = 0;
341 				if (len > 0) {
342 					linep = (char *)malloc(olen + len + 1);
343 					if (olen > 0) {
344 						bcopy(olinep, linep, olen);
345 						free(olinep);
346 					}
347 					bcopy(pos, linep + olen, len);
348 					olen += len;
349 					*(linep + olen) = '\0';
350 					olinep = linep;
351 				}
352 #ifdef CANT_HAPPEN
353 				if (cont) {
354 					if (fgets(line, LINSIZ, netf)) {
355 						pos = line;
356 						len = strlen(pos);
357 					} else
358 						cont = 0;
359 				}
360 #endif
361 			} while (cont);
362 		lp->l_line = linep;
363 		lp->l_next = linehead;
364 		linehead = lp;
365 #ifdef CANT_HAPPEN
366 		/*
367 		 * If this is the one we wanted, we are done.
368 		 */
369 		if (!strcmp(lp->l_groupname, group))
370 #endif
371 			return (lp);
372 	}
373 	return ((struct linelist *)0);
374 }
375