xref: /netbsd-src/external/bsd/libbind/dist/irs/gen_gr.c (revision 5bbd2a12505d72a8177929a37b5cee489d0a1cfd)
1 /*	$NetBSD: gen_gr.c,v 1.1.1.2 2012/09/09 16:07:58 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: gen_gr.c,v 1.8 2005/04/27 04:56:23 sra Exp ";
22 #endif
23 
24 /* Imports */
25 
26 #include "port_before.h"
27 
28 #ifndef WANT_IRS_GR
29 static int __bind_irs_gr_unneeded;
30 #else
31 
32 #include <sys/types.h>
33 
34 #include <isc/assertions.h>
35 #include <errno.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include <netinet/in.h>
41 #include <arpa/nameser.h>
42 #include <resolv.h>
43 
44 #include <isc/memcluster.h>
45 #include <irs.h>
46 
47 #include "port_after.h"
48 
49 #include "irs_p.h"
50 #include "gen_p.h"
51 
52 /* Definitions */
53 
54 struct pvt {
55 	struct irs_rule *	rules;
56 	struct irs_rule *	rule;
57 	struct irs_gr *		gr;
58 	/*
59 	 * Need space to store the entries read from the group file.
60 	 * The members list also needs space per member, and the
61 	 * strings making up the user names must be allocated
62 	 * somewhere.  Rather than doing lots of small allocations,
63 	 * we keep one buffer and resize it as needed.
64 	 */
65 	struct group		group;
66 	size_t			nmemb;    /*%< Malloc'd max index of gr_mem[]. */
67 	char *			membuf;
68 	size_t			membufsize;
69 	struct __res_state *	res;
70 	void			(*free_res)(void *);
71 };
72 
73 /* Forward */
74 
75 static void		gr_close(struct irs_gr *);
76 static struct group *	gr_next(struct irs_gr *);
77 static struct group *	gr_byname(struct irs_gr *, const char *);
78 static struct group *	gr_bygid(struct irs_gr *, gid_t);
79 static void		gr_rewind(struct irs_gr *);
80 static int		gr_list(struct irs_gr *, const char *,
81 				gid_t, gid_t *, int *);
82 static void		gr_minimize(struct irs_gr *);
83 static struct __res_state * gr_res_get(struct irs_gr *);
84 static void		gr_res_set(struct irs_gr *,
85 				      struct __res_state *,
86 				      void (*)(void *));
87 
88 static int		grmerge(struct irs_gr *gr, const struct group *src,
89 				int preserve);
90 
91 static int		countvec(char **vec);
92 static int		isnew(char **old, char *new);
93 static int		countnew(char **old, char **new);
94 static size_t		sizenew(char **old, char **new);
95 static int		newgid(int, gid_t *, gid_t);
96 
97 /* Macros */
98 
99 #define FREE_IF(x) do { if ((x) != NULL) { free(x); (x) = NULL; } } while (0)
100 
101 /* Public */
102 
103 struct irs_gr *
irs_gen_gr(struct irs_acc * this)104 irs_gen_gr(struct irs_acc *this) {
105 	struct gen_p *accpvt = (struct gen_p *)this->private;
106 	struct irs_gr *gr;
107 	struct pvt *pvt;
108 
109 	if (!(gr = memget(sizeof *gr))) {
110 		errno = ENOMEM;
111 		return (NULL);
112 	}
113 	memset(gr, 0x5e, sizeof *gr);
114 	if (!(pvt = memget(sizeof *pvt))) {
115 		memput(gr, sizeof *gr);
116 		errno = ENOMEM;
117 		return (NULL);
118 	}
119 	memset(pvt, 0, sizeof *pvt);
120 	pvt->rules = accpvt->map_rules[irs_gr];
121 	pvt->rule = pvt->rules;
122 	gr->private = pvt;
123 	gr->close = gr_close;
124 	gr->next = gr_next;
125 	gr->byname = gr_byname;
126 	gr->bygid = gr_bygid;
127 	gr->rewind = gr_rewind;
128 	gr->list = gr_list;
129 	gr->minimize = gr_minimize;
130 	gr->res_get = gr_res_get;
131 	gr->res_set = gr_res_set;
132 	return (gr);
133 }
134 
135 /* Methods. */
136 
137 static void
gr_close(struct irs_gr * this)138 gr_close(struct irs_gr *this) {
139 	struct pvt *pvt = (struct pvt *)this->private;
140 
141 	memput(pvt, sizeof *pvt);
142 	memput(this, sizeof *this);
143 }
144 
145 static struct group *
gr_next(struct irs_gr * this)146 gr_next(struct irs_gr *this) {
147 	struct pvt *pvt = (struct pvt *)this->private;
148 	struct group *rval;
149 	struct irs_gr *gr;
150 
151 	while (pvt->rule) {
152 		gr = pvt->rule->inst->gr;
153 		rval = (*gr->next)(gr);
154 		if (rval)
155 			return (rval);
156 		if (!(pvt->rule->flags & IRS_CONTINUE))
157 			break;
158 		pvt->rule = pvt->rule->next;
159 		if (pvt->rule) {
160 			gr = pvt->rule->inst->gr;
161 			(*gr->rewind)(gr);
162 		}
163 	}
164 	return (NULL);
165 }
166 
167 static struct group *
gr_byname(struct irs_gr * this,const char * name)168 gr_byname(struct irs_gr *this, const char *name) {
169 	struct pvt *pvt = (struct pvt *)this->private;
170 	struct irs_rule *rule;
171 	struct group *tval;
172 	struct irs_gr *gr;
173 	int dirty;
174 
175 	dirty = 0;
176 	for (rule = pvt->rules; rule; rule = rule->next) {
177 		gr = rule->inst->gr;
178 		tval = (*gr->byname)(gr, name);
179 		if (tval) {
180 			if (!grmerge(this, tval, dirty++))
181 				return (NULL);
182 			if (!(rule->flags & IRS_MERGE))
183 				break;
184 		} else {
185 			if (!(rule->flags & IRS_CONTINUE))
186 				break;
187 		}
188 	}
189 	if (dirty)
190 		return (&pvt->group);
191 	return (NULL);
192 }
193 
194 static struct group *
gr_bygid(struct irs_gr * this,gid_t gid)195 gr_bygid(struct irs_gr *this, gid_t gid) {
196 	struct pvt *pvt = (struct pvt *)this->private;
197 	struct irs_rule *rule;
198 	struct group *tval;
199 	struct irs_gr *gr;
200 	int dirty;
201 
202 	dirty = 0;
203 	for (rule = pvt->rules; rule; rule = rule->next) {
204 		gr = rule->inst->gr;
205 		tval = (*gr->bygid)(gr, gid);
206 		if (tval) {
207 			if (!grmerge(this, tval, dirty++))
208 				return (NULL);
209 			if (!(rule->flags & IRS_MERGE))
210 				break;
211 		} else {
212 			if (!(rule->flags & IRS_CONTINUE))
213 				break;
214 		}
215 	}
216 	if (dirty)
217 		return (&pvt->group);
218 	return (NULL);
219 }
220 
221 static void
gr_rewind(struct irs_gr * this)222 gr_rewind(struct irs_gr *this) {
223 	struct pvt *pvt = (struct pvt *)this->private;
224 	struct irs_gr *gr;
225 
226 	pvt->rule = pvt->rules;
227 	if (pvt->rule) {
228 		gr = pvt->rule->inst->gr;
229 		(*gr->rewind)(gr);
230 	}
231 }
232 
233 static int
gr_list(struct irs_gr * this,const char * name,gid_t basegid,gid_t * groups,int * ngroups)234 gr_list(struct irs_gr *this, const char *name,
235 	gid_t basegid, gid_t *groups, int *ngroups)
236 {
237 	struct pvt *pvt = (struct pvt *)this->private;
238 	struct irs_rule *rule;
239 	struct irs_gr *gr;
240 	int t_ngroups, maxgroups;
241 	gid_t *t_groups;
242 	int n, t, rval = 0;
243 
244 	maxgroups = *ngroups;
245 	*ngroups = 0;
246 	t_groups = (gid_t *)malloc(maxgroups * sizeof(gid_t));
247 	if (!t_groups) {
248 		errno = ENOMEM;
249 		return (-1);
250 	}
251 
252 	for (rule = pvt->rules; rule; rule = rule->next) {
253 		t_ngroups = maxgroups;
254 		gr = rule->inst->gr;
255 		t = (*gr->list)(gr, name, basegid, t_groups, &t_ngroups);
256 		for (n = 0; n < t_ngroups; n++) {
257 			if (newgid(*ngroups, groups, t_groups[n])) {
258 				if (*ngroups == maxgroups) {
259 					rval = -1;
260 					goto done;
261 				}
262 				groups[(*ngroups)++] = t_groups[n];
263 			}
264 		}
265 		if (t == 0) {
266 			if (!(rule->flags & IRS_MERGE))
267 				break;
268 		} else {
269 			if (!(rule->flags & IRS_CONTINUE))
270 				break;
271 		}
272 	}
273  done:
274 	free(t_groups);
275 	return (rval);
276 }
277 
278 static void
gr_minimize(struct irs_gr * this)279 gr_minimize(struct irs_gr *this) {
280 	struct pvt *pvt = (struct pvt *)this->private;
281 	struct irs_rule *rule;
282 
283 	for (rule = pvt->rules; rule != NULL; rule = rule->next) {
284 		struct irs_gr *gr = rule->inst->gr;
285 
286 		(*gr->minimize)(gr);
287 	}
288 }
289 
290 static struct __res_state *
gr_res_get(struct irs_gr * this)291 gr_res_get(struct irs_gr *this) {
292 	struct pvt *pvt = (struct pvt *)this->private;
293 
294 	if (!pvt->res) {
295 		struct __res_state *res;
296 		res = (struct __res_state *)malloc(sizeof *res);
297 		if (!res) {
298 			errno = ENOMEM;
299 			return (NULL);
300 		}
301 		memset(res, 0, sizeof *res);
302 		gr_res_set(this, res, free);
303 	}
304 
305 	return (pvt->res);
306 }
307 
308 static void
gr_res_set(struct irs_gr * this,struct __res_state * res,void (* free_res)(void *))309 gr_res_set(struct irs_gr *this, struct __res_state *res,
310 		void (*free_res)(void *)) {
311 	struct pvt *pvt = (struct pvt *)this->private;
312 	struct irs_rule *rule;
313 
314 	if (pvt->res && pvt->free_res) {
315 		res_nclose(pvt->res);
316 		(*pvt->free_res)(pvt->res);
317 	}
318 
319 	pvt->res = res;
320 	pvt->free_res = free_res;
321 
322 	for (rule = pvt->rules; rule != NULL; rule = rule->next) {
323 		struct irs_gr *gr = rule->inst->gr;
324 
325 		if (gr->res_set)
326 			(*gr->res_set)(gr, pvt->res, NULL);
327 	}
328 }
329 
330 /* Private. */
331 
332 static int
grmerge(struct irs_gr * this,const struct group * src,int preserve)333 grmerge(struct irs_gr *this, const struct group *src, int preserve) {
334 	struct pvt *pvt = (struct pvt *)this->private;
335 	char *cp, **m, **p, *oldmembuf, *ep;
336 	int n, ndst, nnew;
337 	size_t used;
338 
339 	if (!preserve) {
340 		pvt->group.gr_gid = src->gr_gid;
341 		if (pvt->nmemb < 1) {
342 			m = malloc(sizeof *m);
343 			if (m == NULL) {
344 				/* No harm done, no work done. */
345 				return (0);
346 			}
347 			pvt->group.gr_mem = m;
348 			pvt->nmemb = 1;
349 		}
350 		pvt->group.gr_mem[0] = NULL;
351 	}
352 	ndst = countvec(pvt->group.gr_mem);
353 	nnew = countnew(pvt->group.gr_mem, src->gr_mem);
354 
355 	/*
356 	 * Make sure destination member array is large enough.
357 	 * p points to new portion.
358 	 */
359 	n = ndst + nnew + 1;
360 	if ((size_t)n > pvt->nmemb) {
361 		m = realloc(pvt->group.gr_mem, n * sizeof *m);
362 		if (m == NULL) {
363 			/* No harm done, no work done. */
364 			return (0);
365 		}
366 		pvt->group.gr_mem = m;
367 		pvt->nmemb = n;
368 	}
369 	p = pvt->group.gr_mem + ndst;
370 
371 	/*
372 	 * Enlarge destination membuf; cp points at new portion.
373 	 */
374 	n = sizenew(pvt->group.gr_mem, src->gr_mem);
375 	INSIST((nnew == 0) == (n == 0));
376 	if (!preserve) {
377 		n += strlen(src->gr_name) + 1;
378 		n += strlen(src->gr_passwd) + 1;
379 	}
380 	if (n == 0) {
381 		/* No work to do. */
382 		return (1);
383 	}
384 	used = preserve ? pvt->membufsize : 0;
385 	cp = malloc(used + n);
386 	if (cp == NULL) {
387 		/* No harm done, no work done. */
388 		return (0);
389 	}
390 	ep = cp + used + n;
391 	if (used != 0)
392 		memcpy(cp, pvt->membuf, used);
393 	oldmembuf = pvt->membuf;
394 	pvt->membuf = cp;
395 	pvt->membufsize = used + n;
396 	cp += used;
397 
398 	/*
399 	 * Adjust group.gr_mem.
400 	 */
401 	if (pvt->membuf != oldmembuf)
402 		for (m = pvt->group.gr_mem; *m; m++)
403 			*m = pvt->membuf + (*m - oldmembuf);
404 
405 	/*
406 	 * Add new elements.
407 	 */
408 	for (m = src->gr_mem; *m; m++)
409 		if (isnew(pvt->group.gr_mem, *m)) {
410 			*p++ = cp;
411 			*p = NULL;
412 			n = strlen(*m) + 1;
413 			if (n > ep - cp) {
414 				FREE_IF(oldmembuf);
415 				return (0);
416 			}
417 			strcpy(cp, *m);		/* (checked) */
418 			cp += n;
419 		}
420 	if (preserve) {
421 		pvt->group.gr_name = pvt->membuf +
422 				     (pvt->group.gr_name - oldmembuf);
423 		pvt->group.gr_passwd = pvt->membuf +
424 				       (pvt->group.gr_passwd - oldmembuf);
425 	} else {
426 		pvt->group.gr_name = cp;
427 		n = strlen(src->gr_name) + 1;
428 		if (n > ep - cp) {
429 			FREE_IF(oldmembuf);
430 			return (0);
431 		}
432 		strcpy(cp, src->gr_name);	/* (checked) */
433 		cp += n;
434 
435 		pvt->group.gr_passwd = cp;
436 		n = strlen(src->gr_passwd) + 1;
437 		if (n > ep - cp) {
438 			FREE_IF(oldmembuf);
439 			return (0);
440 		}
441 		strcpy(cp, src->gr_passwd);	/* (checked) */
442 		cp += n;
443 	}
444 	FREE_IF(oldmembuf);
445 	INSIST(cp >= pvt->membuf && cp <= &pvt->membuf[pvt->membufsize]);
446 	return (1);
447 }
448 
449 static int
countvec(char ** vec)450 countvec(char **vec) {
451 	int n = 0;
452 
453 	while (*vec++)
454 		n++;
455 	return (n);
456 }
457 
458 static int
isnew(char ** old,char * new)459 isnew(char **old, char *new) {
460 	for (; *old; old++)
461 		if (strcmp(*old, new) == 0)
462 			return (0);
463 	return (1);
464 }
465 
466 static int
countnew(char ** old,char ** new)467 countnew(char **old, char **new) {
468 	int n = 0;
469 
470 	for (; *new; new++)
471 		n += isnew(old, *new);
472 	return (n);
473 }
474 
475 static size_t
sizenew(char ** old,char ** new)476 sizenew(char **old, char **new) {
477 	size_t n = 0;
478 
479 	for (; *new; new++)
480 		if (isnew(old, *new))
481 			n += strlen(*new) + 1;
482 	return (n);
483 }
484 
485 static int
newgid(int ngroups,gid_t * groups,gid_t group)486 newgid(int ngroups, gid_t *groups, gid_t group) {
487 	ngroups--, groups++;
488 	for (; ngroups-- > 0; groups++)
489 		if (*groups == group)
490 			return (0);
491 	return (1);
492 }
493 
494 #endif /* WANT_IRS_GR */
495 /*! \file */
496