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