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