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