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