xref: /netbsd-src/external/bsd/libbind/dist/irs/lcl_ng.c (revision 5bbd2a12505d72a8177929a37b5cee489d0a1cfd)
1 /*	$NetBSD: lcl_ng.c,v 1.1.1.2 2012/09/09 16:07:54 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (c) 1996-1999 by Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #if !defined(LINT) && !defined(CODECENTER)
21 static const char rcsid[] = "Id: lcl_ng.c,v 1.3 2005/04/27 04:56:31 sra Exp ";
22 #endif
23 
24 /* Imports */
25 
26 #include "port_before.h"
27 
28 #include <sys/types.h>
29 #include <netinet/in.h>
30 #include <arpa/nameser.h>
31 #include <resolv.h>
32 #include <errno.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 #include <irs.h>
39 #include <isc/memcluster.h>
40 
41 #include "port_after.h"
42 
43 #include "irs_p.h"
44 #include "lcl_p.h"
45 
46 /* Definitions */
47 
48 #define NG_HOST         0       /*%< Host name */
49 #define NG_USER         1       /*%< User name */
50 #define NG_DOM          2       /*%< and Domain name */
51 #define LINSIZ		1024    /*%< Length of netgroup file line */
52 /*
53  * XXX Warning XXX
54  * This code is a hack-and-slash special.  It realy needs to be
55  * rewritten with things like strdup, and realloc in mind.
56  * More reasonable data structures would not be a bad thing.
57  */
58 
59 /*%
60  * Static Variables and functions used by setnetgrent(), getnetgrent() and
61  * endnetgrent().
62  *
63  * There are two linked lists:
64  * \li linelist is just used by setnetgrent() to parse the net group file via.
65  *   parse_netgrp()
66  * \li 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 ng_old_struct {
76 	struct ng_old_struct *ng_next;	/*%< Chain ptr */
77 	char *		ng_str[3];	/*%< Field pointers, see below */
78 };
79 
80 struct pvt {
81 	FILE			*fp;
82 	struct linelist		*linehead;
83 	struct ng_old_struct    *nextgrp;
84 	struct {
85 		struct ng_old_struct	*gr;
86 		char			*grname;
87 	} grouphead;
88 };
89 
90 /* Forward */
91 
92 static void 		ng_rewind(struct irs_ng *, const char*);
93 static void 		ng_close(struct irs_ng *);
94 static int		ng_next(struct irs_ng *, const char **,
95 				const char **, const char **);
96 static int 		ng_test(struct irs_ng *, const char *,
97 				const char *, const char *,
98 				const char *);
99 static void		ng_minimize(struct irs_ng *);
100 
101 static int 		parse_netgrp(struct irs_ng *, const char*);
102 static struct linelist *read_for_group(struct irs_ng *, const char *);
103 static void		freelists(struct irs_ng *);
104 
105 /* Public */
106 
107 struct irs_ng *
irs_lcl_ng(struct irs_acc * this)108 irs_lcl_ng(struct irs_acc *this) {
109 	struct irs_ng *ng;
110 	struct pvt *pvt;
111 
112 	UNUSED(this);
113 
114 	if (!(ng = memget(sizeof *ng))) {
115 		errno = ENOMEM;
116 		return (NULL);
117 	}
118 	memset(ng, 0x5e, sizeof *ng);
119 	if (!(pvt = memget(sizeof *pvt))) {
120 		memput(ng, sizeof *ng);
121 		errno = ENOMEM;
122 		return (NULL);
123 	}
124 	memset(pvt, 0, sizeof *pvt);
125 	ng->private = pvt;
126 	ng->close = ng_close;
127 	ng->next = ng_next;
128 	ng->test = ng_test;
129 	ng->rewind = ng_rewind;
130 	ng->minimize = ng_minimize;
131 	return (ng);
132 }
133 
134 /* Methods */
135 
136 static void
ng_close(struct irs_ng * this)137 ng_close(struct irs_ng *this) {
138 	struct pvt *pvt = (struct pvt *)this->private;
139 
140 	if (pvt->fp != NULL)
141 		fclose(pvt->fp);
142 	freelists(this);
143 	memput(pvt, sizeof *pvt);
144 	memput(this, sizeof *this);
145 }
146 
147 /*%
148  * Parse the netgroup file looking for the netgroup and build the list
149  * of netgrp structures. Let parse_netgrp() and read_for_group() do
150  * most of the work.
151  */
152 static void
ng_rewind(struct irs_ng * this,const char * group)153 ng_rewind(struct irs_ng *this, const char *group) {
154 	struct pvt *pvt = (struct pvt *)this->private;
155 
156 	if (pvt->fp != NULL && fseek(pvt->fp, SEEK_CUR, 0L) == -1) {
157 		fclose(pvt->fp);
158 		pvt->fp = NULL;
159 	}
160 
161 	if (pvt->fp == NULL || pvt->grouphead.gr == NULL ||
162 	    strcmp(group, pvt->grouphead.grname)) {
163 		freelists(this);
164 		if (pvt->fp != NULL)
165 			fclose(pvt->fp);
166 		pvt->fp = fopen(_PATH_NETGROUP, "r");
167 		if (pvt->fp != NULL) {
168 			if (parse_netgrp(this, group))
169 				freelists(this);
170 			if (!(pvt->grouphead.grname = strdup(group)))
171 				freelists(this);
172 			fclose(pvt->fp);
173 			pvt->fp = NULL;
174 		}
175 	}
176 	pvt->nextgrp = pvt->grouphead.gr;
177 }
178 
179 /*%
180  * Get the next netgroup off the list.
181  */
182 static int
ng_next(struct irs_ng * this,const char ** host,const char ** user,const char ** domain)183 ng_next(struct irs_ng *this, const char **host, const char **user,
184 	const char **domain)
185 {
186 	struct pvt *pvt = (struct pvt *)this->private;
187 
188 	if (pvt->nextgrp) {
189 		*host = pvt->nextgrp->ng_str[NG_HOST];
190 		*user = pvt->nextgrp->ng_str[NG_USER];
191 		*domain = pvt->nextgrp->ng_str[NG_DOM];
192 		pvt->nextgrp = pvt->nextgrp->ng_next;
193 		return (1);
194 	}
195 	return (0);
196 }
197 
198 /*%
199  * Search for a match in a netgroup.
200  */
201 static int
ng_test(struct irs_ng * this,const char * name,const char * host,const char * user,const char * domain)202 ng_test(struct irs_ng *this, const char *name,
203 	const char *host, const char *user, const char *domain)
204 {
205 	const char *ng_host, *ng_user, *ng_domain;
206 
207 	ng_rewind(this, name);
208 	while (ng_next(this, &ng_host, &ng_user, &ng_domain))
209 		if ((host == NULL || ng_host == NULL ||
210 		     !strcmp(host, ng_host)) &&
211 		    (user ==  NULL || ng_user == NULL ||
212 		     !strcmp(user, ng_user)) &&
213 		    (domain == NULL || ng_domain == NULL ||
214 		     !strcmp(domain, ng_domain))) {
215 			freelists(this);
216 			return (1);
217 		}
218 	freelists(this);
219 	return (0);
220 }
221 
222 static void
ng_minimize(struct irs_ng * this)223 ng_minimize(struct irs_ng *this) {
224 	struct pvt *pvt = (struct pvt *)this->private;
225 
226 	if (pvt->fp != NULL) {
227 		(void)fclose(pvt->fp);
228 		pvt->fp = NULL;
229 	}
230 }
231 
232 /* Private */
233 
234 /*%
235  * endnetgrent() - cleanup
236  */
237 static void
freelists(struct irs_ng * this)238 freelists(struct irs_ng *this) {
239 	struct pvt *pvt = (struct pvt *)this->private;
240 	struct linelist *lp, *olp;
241 	struct ng_old_struct *gp, *ogp;
242 
243 	lp = pvt->linehead;
244 	while (lp) {
245 		olp = lp;
246 		lp = lp->l_next;
247 		free(olp->l_groupname);
248 		free(olp->l_line);
249 		free((char *)olp);
250 	}
251 	pvt->linehead = NULL;
252 	if (pvt->grouphead.grname) {
253 		free(pvt->grouphead.grname);
254 		pvt->grouphead.grname = NULL;
255 	}
256 	gp = pvt->grouphead.gr;
257 	while (gp) {
258 		ogp = gp;
259 		gp = gp->ng_next;
260 		if (ogp->ng_str[NG_HOST])
261 			free(ogp->ng_str[NG_HOST]);
262 		if (ogp->ng_str[NG_USER])
263 			free(ogp->ng_str[NG_USER]);
264 		if (ogp->ng_str[NG_DOM])
265 			free(ogp->ng_str[NG_DOM]);
266 		free((char *)ogp);
267 	}
268 	pvt->grouphead.gr = NULL;
269 }
270 
271 /*%
272  * Parse the netgroup file setting up the linked lists.
273  */
274 static int
parse_netgrp(struct irs_ng * this,const char * group)275 parse_netgrp(struct irs_ng *this, const char *group) {
276 	struct pvt *pvt = (struct pvt *)this->private;
277 	char *spos, *epos;
278 	int len, strpos;
279 	char *pos, *gpos;
280 	struct ng_old_struct *grp;
281 	struct linelist *lp = pvt->linehead;
282 
283         /*
284          * First, see if the line has already been read in.
285          */
286 	while (lp) {
287 		if (!strcmp(group, lp->l_groupname))
288 			break;
289 		lp = lp->l_next;
290 	}
291 	if (lp == NULL &&
292 	    (lp = read_for_group(this, group)) == NULL)
293 		return (1);
294 	if (lp->l_parsed) {
295 		/*fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);*/
296 		return (1);
297 	} else
298 		lp->l_parsed = 1;
299 	pos = lp->l_line;
300 	while (*pos != '\0') {
301 		if (*pos == '(') {
302 			if (!(grp = malloc(sizeof (struct ng_old_struct)))) {
303 				freelists(this);
304 				errno = ENOMEM;
305 				return (1);
306 			}
307 			memset(grp, 0, sizeof (struct ng_old_struct));
308 			grp->ng_next = pvt->grouphead.gr;
309 			pvt->grouphead.gr = grp;
310 			pos++;
311 			gpos = strsep(&pos, ")");
312 			for (strpos = 0; strpos < 3; strpos++) {
313 				if ((spos = strsep(&gpos, ","))) {
314 					while (*spos == ' ' || *spos == '\t')
315 						spos++;
316 					if ((epos = strpbrk(spos, " \t"))) {
317 						*epos = '\0';
318 						len = epos - spos;
319 					} else
320 						len = strlen(spos);
321 					if (len > 0) {
322 						if(!(grp->ng_str[strpos]
323 						   =  (char *)
324 						   malloc(len + 1))) {
325 							freelists(this);
326 							return (1);
327 						}
328 						memcpy(grp->ng_str[strpos],
329 						       spos,
330 						       len + 1);
331 					}
332 				} else
333 					goto errout;
334 			}
335 		} else {
336 			spos = strsep(&pos, ", \t");
337 			if (spos != NULL && parse_netgrp(this, spos)) {
338 				freelists(this);
339 				return (1);
340 			}
341 		}
342 		if (pos == NULL)
343 			break;
344 		while (*pos == ' ' || *pos == ',' || *pos == '\t')
345 			pos++;
346 	}
347 	return (0);
348  errout:
349 	/*fprintf(stderr, "Bad netgroup %s at ..%s\n", lp->l_groupname,
350 		  spos);*/
351 	return (1);
352 }
353 
354 /*%
355  * Read the netgroup file and save lines until the line for the netgroup
356  * is found. Return 1 if eof is encountered.
357  */
358 static struct linelist *
read_for_group(struct irs_ng * this,const char * group)359 read_for_group(struct irs_ng *this, const char *group) {
360 	struct pvt *pvt = (struct pvt *)this->private;
361 	char *pos, *spos, *linep = NULL, *olinep;
362 	int len, olen, cont;
363 	struct linelist *lp;
364 	char line[LINSIZ + 1];
365 
366 	while (fgets(line, LINSIZ, pvt->fp) != NULL) {
367 		pos = line;
368 		if (*pos == '#')
369 			continue;
370 		while (*pos == ' ' || *pos == '\t')
371 			pos++;
372 		spos = pos;
373 		while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
374 			*pos != '\0')
375 			pos++;
376 		len = pos - spos;
377 		while (*pos == ' ' || *pos == '\t')
378 			pos++;
379 		if (*pos != '\n' && *pos != '\0') {
380 			if (!(lp = malloc(sizeof (*lp)))) {
381 				freelists(this);
382 				return (NULL);
383 			}
384 			lp->l_parsed = 0;
385 			if (!(lp->l_groupname = malloc(len + 1))) {
386 				free(lp);
387 				freelists(this);
388 				return (NULL);
389 			}
390 			memcpy(lp->l_groupname, spos,  len);
391 			*(lp->l_groupname + len) = '\0';
392 			len = strlen(pos);
393 			olen = 0;
394 			olinep = NULL;
395 
396 			/*
397 			 * Loop around handling line continuations.
398 			 */
399 			do {
400 				if (*(pos + len - 1) == '\n')
401 					len--;
402 				if (*(pos + len - 1) == '\\') {
403 					len--;
404 					cont = 1;
405 				} else
406 					cont = 0;
407 				if (len > 0) {
408 					if (!(linep = malloc(olen + len + 1))){
409 						if (olen > 0)
410 							free(olinep);
411 						free(lp->l_groupname);
412 						free(lp);
413 						freelists(this);
414 						errno = ENOMEM;
415 						return (NULL);
416 					}
417 					if (olen > 0) {
418 						memcpy(linep, olinep, olen);
419 						free(olinep);
420 					}
421 					memcpy(linep + olen, pos, len);
422 					olen += len;
423 					*(linep + olen) = '\0';
424 					olinep = linep;
425 				}
426 				if (cont) {
427 					if (fgets(line, LINSIZ, pvt->fp)) {
428 						pos = line;
429 						len = strlen(pos);
430 					} else
431 						cont = 0;
432 				}
433 			} while (cont);
434 			lp->l_line = linep;
435 			lp->l_next = pvt->linehead;
436 			pvt->linehead = lp;
437 
438 			/*
439 			 * If this is the one we wanted, we are done.
440 			 */
441 			if (!strcmp(lp->l_groupname, group))
442 				return (lp);
443 		}
444 	}
445 	return (NULL);
446 }
447 
448 /*! \file */
449