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