Merge from vendor branch CVS:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / bind / irs / gen_gr.c
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.4.2.3 2004/05/17 07:46:43 marka 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 *
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
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 *
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 *
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 *
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
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
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
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 *
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
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
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
448 countvec(char **vec) {
449         int n = 0;
450
451         while (*vec++)
452                 n++;
453         return (n);
454 }
455
456 static int
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
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
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
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 */