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