Merge from vendor branch NCURSES:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / isccfg / check.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2001-2003  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 WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: check.c,v 1.14.2.25 2004/07/29 00:08:17 marka Exp $ */
19
20 #include <config.h>
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <isc/buffer.h>
26 #include <isc/log.h>
27 #include <isc/mem.h>
28 #include <isc/netaddr.h>
29 #include <isc/result.h>
30 #include <isc/sockaddr.h>
31 #include <isc/symtab.h>
32 #include <isc/util.h>
33
34 #include <dns/fixedname.h>
35 #include <dns/rdataclass.h>
36
37 #include <isccfg/cfg.h>
38 #include <isccfg/check.h>
39
40 static void
41 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
42         UNUSED(type);
43         UNUSED(value);
44         isc_mem_free(userarg, key);
45 }
46
47 static isc_result_t
48 check_forward(cfg_obj_t *options, isc_log_t *logctx) {
49         cfg_obj_t *forward = NULL;
50         cfg_obj_t *forwarders = NULL;
51
52         (void)cfg_map_get(options, "forward", &forward);
53         (void)cfg_map_get(options, "forwarders", &forwarders);
54
55         if (forward != NULL && forwarders == NULL) {
56                 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
57                             "no matching 'forwarders' statement");
58                 return (ISC_R_FAILURE);
59         }
60         return (ISC_R_SUCCESS);
61 }
62
63 typedef struct {
64         const char *name;
65         unsigned int scale;
66 } intervaltable;
67
68 static isc_result_t
69 check_options(cfg_obj_t *options, isc_log_t *logctx) {
70         isc_result_t result = ISC_R_SUCCESS;
71         unsigned int i;
72         cfg_obj_t *obj;
73
74         static intervaltable intervals[] = {
75         { "cleaning-interval", 60 },
76         { "heartbeat-interval", 60 },
77         { "interface-interval", 60 },
78         { "max-transfer-idle-in", 60 },
79         { "max-transfer-idle-out", 60 },
80         { "max-transfer-time-in", 60 },
81         { "max-transfer-time-out", 60 },
82         { "sig-validity-interval", 86400},
83         { "statistics-interval", 60 },
84         };
85
86         /*
87          * Check that fields specified in units of time other than seconds
88          * have reasonable values.
89          */
90         for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
91                 isc_uint32_t val;
92                 cfg_obj_t *obj = NULL;
93                 (void)cfg_map_get(options, intervals[i].name, &obj);
94                 if (obj == NULL)
95                         continue;
96                 val = cfg_obj_asuint32(obj);
97                 if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
98                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
99                                     "%s '%d' is out of range",
100                                     intervals[i].name, val);
101                         result = ISC_R_RANGE;
102                 }
103         }
104
105         obj = NULL;
106         (void)cfg_map_get(options, "root-delegation-only", &obj);
107         if (obj != NULL) {
108                 if (!cfg_obj_isvoid(obj)) {
109                         cfg_listelt_t *element;
110                         cfg_obj_t *exclude;
111                         char *str;
112                         dns_fixedname_t fixed;
113                         dns_name_t *name;
114                         isc_buffer_t b;
115                         isc_result_t tresult;
116
117                         dns_fixedname_init(&fixed);
118                         name = dns_fixedname_name(&fixed);
119                         for (element = cfg_list_first(obj);
120                              element != NULL;
121                              element = cfg_list_next(element)) {
122                                 exclude = cfg_listelt_value(element);
123                                 str = cfg_obj_asstring(exclude);
124                                 isc_buffer_init(&b, str, strlen(str));
125                                 isc_buffer_add(&b, strlen(str));
126                                 tresult = dns_name_fromtext(name, &b,
127                                                            dns_rootname,
128                                                            ISC_FALSE, NULL);
129                                 if (tresult != ISC_R_SUCCESS) {
130                                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
131                                                     "bad domain name '%s'",
132                                                     str);
133                                         result = tresult;
134                                 }
135                         }
136                 }
137         }
138         return (result);
139 }
140
141 #define MASTERZONE      1
142 #define SLAVEZONE       2
143 #define STUBZONE        4
144 #define HINTZONE        8
145 #define FORWARDZONE     16
146 #define DELEGATIONZONE  32
147
148 typedef struct {
149         const char *name;
150         int allowed;
151 } optionstable;
152
153 static isc_result_t
154 check_zoneconf(cfg_obj_t *zconfig, isc_symtab_t *symtab, isc_log_t *logctx,
155                isc_mem_t *mctx)
156 {
157         const char *zname;
158         const char *typestr;
159         unsigned int ztype;
160         cfg_obj_t *zoptions;
161         cfg_obj_t *obj = NULL;
162         cfg_obj_t *addrlist = NULL;
163         isc_symvalue_t symvalue;
164         isc_result_t result = ISC_R_SUCCESS;
165         isc_result_t tresult;
166         unsigned int i;
167         dns_fixedname_t fixedname;
168         isc_buffer_t b;
169
170         static optionstable options[] = {
171         { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE },
172         { "allow-notify", SLAVEZONE },
173         { "allow-transfer", MASTERZONE | SLAVEZONE },
174         { "notify", MASTERZONE | SLAVEZONE },
175         { "also-notify", MASTERZONE | SLAVEZONE },
176         { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
177         { "delegation-only", HINTZONE | STUBZONE },
178         { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
179         { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
180         { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
181         { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
182         { "notify-source", MASTERZONE | SLAVEZONE },
183         { "notify-source-v6", MASTERZONE | SLAVEZONE },
184         { "transfer-source", SLAVEZONE | STUBZONE },
185         { "transfer-source-v6", SLAVEZONE | STUBZONE },
186         { "max-transfer-time-in", SLAVEZONE | STUBZONE },
187         { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
188         { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
189         { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
190         { "max-retry-time", SLAVEZONE | STUBZONE },
191         { "min-retry-time", SLAVEZONE | STUBZONE },
192         { "max-refresh-time", SLAVEZONE | STUBZONE },
193         { "min-refresh-time", SLAVEZONE | STUBZONE },
194         { "sig-validity-interval", MASTERZONE },
195         { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE },
196         { "allow-update", MASTERZONE },
197         { "allow-update-forwarding", SLAVEZONE },
198         { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE},
199         { "ixfr-base", MASTERZONE | SLAVEZONE },
200         { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
201         { "masters", SLAVEZONE | STUBZONE },
202         { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
203         { "update-policy", MASTERZONE },
204         { "database", MASTERZONE | SLAVEZONE | STUBZONE },
205         };
206
207         static optionstable dialups[] = {
208         { "notify", MASTERZONE | SLAVEZONE },
209         { "notify-passive", SLAVEZONE },
210         { "refresh", SLAVEZONE | STUBZONE },
211         { "passive", SLAVEZONE | STUBZONE },
212         };
213
214         zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
215
216         zoptions = cfg_tuple_get(zconfig, "options");
217
218         obj = NULL;
219         (void)cfg_map_get(zoptions, "type", &obj);
220         if (obj == NULL) {
221                 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
222                             "zone '%s': type not present", zname);
223                 return (ISC_R_FAILURE);
224         }
225
226         typestr = cfg_obj_asstring(obj);
227         if (strcasecmp(typestr, "master") == 0)
228                 ztype = MASTERZONE;
229         else if (strcasecmp(typestr, "slave") == 0)
230                 ztype = SLAVEZONE;
231         else if (strcasecmp(typestr, "stub") == 0)
232                 ztype = STUBZONE;
233         else if (strcasecmp(typestr, "forward") == 0)
234                 ztype = FORWARDZONE;
235         else if (strcasecmp(typestr, "hint") == 0)
236                 ztype = HINTZONE;
237         else if (strcasecmp(typestr, "delegation-only") == 0)
238                 ztype = DELEGATIONZONE;
239         else {
240                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
241                             "zone '%s': invalid type %s",
242                             zname, typestr);
243                 return (ISC_R_FAILURE);
244         }
245
246         /*
247          * Look for an already existing zone.
248          * We need to make this cannonical as isc_symtab_define()
249          * deals with strings.
250          */
251         dns_fixedname_init(&fixedname);
252         isc_buffer_init(&b, zname, strlen(zname));
253         isc_buffer_add(&b, strlen(zname));
254         result = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
255                                    dns_rootname, ISC_TRUE, NULL);
256         if (result != ISC_R_SUCCESS) {
257                 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
258                             "zone '%s': is not a valid name", zname);
259                 result = ISC_R_FAILURE;
260         } else {
261                 char namebuf[DNS_NAME_FORMATSIZE];
262                 char *key;
263
264                 dns_name_format(dns_fixedname_name(&fixedname),
265                                 namebuf, sizeof(namebuf));
266                 key = isc_mem_strdup(mctx, namebuf);
267                 if (key == NULL)
268                         return (ISC_R_NOMEMORY);
269                 symvalue.as_pointer = NULL;
270                 tresult = isc_symtab_define(symtab, key,
271                                             ztype == HINTZONE ? 1 : 2,
272                                             symvalue, isc_symexists_reject);
273                 if (tresult == ISC_R_EXISTS) {
274                         isc_mem_free(mctx, key);
275                         cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
276                                     "zone '%s': already exists ", zname);
277                         result = ISC_R_FAILURE;
278                 } else if (tresult != ISC_R_SUCCESS) {
279                         isc_mem_free(mctx, key);
280
281                         return (tresult);
282                 }
283         }
284
285         /*
286          * Look for inappropriate options for the given zone type.
287          */
288         for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
289                 obj = NULL;
290                 if ((options[i].allowed & ztype) == 0 &&
291                     cfg_map_get(zoptions, options[i].name, &obj) ==
292                     ISC_R_SUCCESS)
293                 {
294                         if (strcmp(options[i].name, "allow-update") != 0 ||
295                             ztype != SLAVEZONE) {
296                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
297                                             "option '%s' is not allowed "
298                                             "in '%s' zone '%s'",
299                                             options[i].name, typestr, zname);
300                                         result = ISC_R_FAILURE;
301                         } else
302                                 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
303                                             "option '%s' is not allowed "
304                                             "in '%s' zone '%s'",
305                                             options[i].name, typestr, zname);
306                 }
307         }
308
309         /*
310          * Slave & stub zones must have a "masters" field.
311          */
312         if (ztype == SLAVEZONE || ztype == STUBZONE) {
313                 obj = NULL;
314                 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
315                         cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
316                                     "zone '%s': missing 'masters' entry",
317                                     zname);
318                         result = ISC_R_FAILURE;
319                 } else {
320                         addrlist = cfg_tuple_get(obj, "addresses");
321                         if (cfg_list_first(addrlist) == NULL) {
322                                 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
323                                             "zone '%s': empty 'masters' entry",
324                                             zname);
325                                 result = ISC_R_FAILURE;
326                         }
327                 }
328         }
329
330         /*
331          * Master zones can't have both "allow-update" and "update-policy".
332          */
333         if (ztype == MASTERZONE) {
334                 isc_result_t res1, res2;
335                 obj = NULL;
336                 res1 = cfg_map_get(zoptions, "allow-update", &obj);
337                 obj = NULL;
338                 res2 = cfg_map_get(zoptions, "update-policy", &obj);
339                 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
340                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
341                                     "zone '%s': 'allow-update' is ignored "
342                                     "when 'update-policy' is present",
343                                     zname);
344                         result = ISC_R_FAILURE;
345                 }
346         }
347
348         /*
349          * Check the excessively complicated "dialup" option.
350          */
351         if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
352                 cfg_obj_t *dialup = NULL;
353                 cfg_map_get(zoptions, "dialup", &dialup);
354                 if (dialup != NULL && cfg_obj_isstring(dialup)) {
355                         char *str = cfg_obj_asstring(dialup);
356                         for (i = 0;
357                              i < sizeof(dialups) / sizeof(dialups[0]);
358                              i++)
359                         {
360                                 if (strcasecmp(dialups[i].name, str) != 0)
361                                         continue;
362                                 if ((dialups[i].allowed & ztype) == 0) {
363                                         cfg_obj_log(obj, logctx,
364                                                     ISC_LOG_ERROR,
365                                                     "dialup type '%s' is not "
366                                                     "allowed in '%s' "
367                                                     "zone '%s'",
368                                                     str, typestr, zname);
369                                         result = ISC_R_FAILURE;
370                                 }
371                                 break;
372                         }
373                         if (i == sizeof(dialups) / sizeof(dialups[0])) {
374                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
375                                             "invalid dialup type '%s' in zone "
376                                             "'%s'", str, zname);
377                                 result = ISC_R_FAILURE;
378                         }
379                 }
380         }
381
382         /*
383          * Check that forwarding is reasonable.
384          */
385         if (check_forward(zoptions, logctx) != ISC_R_SUCCESS)
386                 result = ISC_R_FAILURE;
387
388         /*
389          * Check various options.
390          */
391         tresult = check_options(zoptions, logctx);
392         if (tresult != ISC_R_SUCCESS)
393                 result = tresult;
394
395         return (result);
396 }
397
398 isc_result_t
399 cfg_check_key(cfg_obj_t *key, isc_log_t *logctx) {
400         cfg_obj_t *algobj = NULL;
401         cfg_obj_t *secretobj = NULL;
402         const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
403         
404         cfg_map_get(key, "algorithm", &algobj);
405         cfg_map_get(key, "secret", &secretobj);
406         if (secretobj == NULL || algobj == NULL) {
407                 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
408                             "key '%s' must have both 'secret' and "
409                             "'algorithm' defined",
410                             keyname);
411                 return ISC_R_FAILURE;
412         }
413         return ISC_R_SUCCESS;
414 }
415                 
416 static isc_result_t
417 check_keylist(cfg_obj_t *keys, isc_symtab_t *symtab, isc_log_t *logctx) {
418         isc_result_t result = ISC_R_SUCCESS;
419         isc_result_t tresult;
420         cfg_listelt_t *element;
421
422         for (element = cfg_list_first(keys);
423              element != NULL;
424              element = cfg_list_next(element))
425         {
426                 cfg_obj_t *key = cfg_listelt_value(element);
427                 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
428                 isc_symvalue_t symvalue;
429
430                 symvalue.as_pointer = NULL;
431                 tresult = isc_symtab_define(symtab, keyname, 1,
432                                             symvalue, isc_symexists_reject);
433                 if (tresult == ISC_R_EXISTS) {
434                         cfg_obj_log(key, logctx, ISC_LOG_ERROR,
435                                     "key '%s': already exists ", keyname);
436                         result = tresult;
437                 } else if (tresult != ISC_R_SUCCESS)
438                         return (tresult);
439
440                 tresult = cfg_check_key(key, logctx);
441                 if (tresult != ISC_R_SUCCESS)
442                         return (tresult);
443         }
444         return (result);
445 }
446
447 static isc_result_t
448 check_servers(cfg_obj_t *servers, isc_log_t *logctx) {
449         isc_result_t result = ISC_R_SUCCESS;
450         cfg_listelt_t *e1, *e2;
451         cfg_obj_t *v1, *v2;
452         isc_sockaddr_t *s1, *s2;
453         isc_netaddr_t na;
454
455         for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
456                 v1 = cfg_listelt_value(e1);
457                 s1 = cfg_obj_assockaddr(cfg_map_getname(v1));
458                 e2 = e1;
459                 while ((e2 = cfg_list_next(e2)) != NULL) {
460                         v2 = cfg_listelt_value(e2);
461                         s2 = cfg_obj_assockaddr(cfg_map_getname(v2));
462                         if (isc_sockaddr_eqaddr(s1, s2)) {
463                                 isc_buffer_t target;
464                                 char buf[128];
465
466                                 isc_netaddr_fromsockaddr(&na, s2);
467                                 isc_buffer_init(&target, buf, sizeof(buf) - 1);
468                                 INSIST(isc_netaddr_totext(&na, &target)
469                                        == ISC_R_SUCCESS);
470                                 buf[isc_buffer_usedlength(&target)] = '\0';
471
472                                 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
473                                             "server '%s': already exists",
474                                             buf);
475                                 result = ISC_R_FAILURE;
476                         }
477                 }
478         }
479         return (result);
480 }
481                 
482 static isc_result_t
483 check_viewconf(cfg_obj_t *config, cfg_obj_t *vconfig, isc_log_t *logctx, isc_mem_t *mctx)
484 {
485         cfg_obj_t *servers = NULL;
486         cfg_obj_t *zones = NULL;
487         cfg_obj_t *keys = NULL;
488         cfg_listelt_t *element;
489         isc_symtab_t *symtab = NULL;
490         isc_result_t result = ISC_R_SUCCESS;
491         isc_result_t tresult = ISC_R_SUCCESS;
492
493         /*
494          * Check that all zone statements are syntactically correct and
495          * there are no duplicate zones.
496          */
497         tresult = isc_symtab_create(mctx, 100, freekey, mctx,
498                                     ISC_FALSE, &symtab);
499         if (tresult != ISC_R_SUCCESS)
500                 return (ISC_R_NOMEMORY);
501
502         if (vconfig != NULL)
503                 (void)cfg_map_get(vconfig, "zone", &zones);
504         else
505                 (void)cfg_map_get(config, "zone", &zones);
506
507         for (element = cfg_list_first(zones);
508              element != NULL;
509              element = cfg_list_next(element))
510         {
511                 cfg_obj_t *zone = cfg_listelt_value(element);
512
513                 if (check_zoneconf(zone, symtab, logctx, mctx) != ISC_R_SUCCESS)
514                         result = ISC_R_FAILURE;
515         }
516
517         isc_symtab_destroy(&symtab);
518
519         /*
520          * Check that all key statements are syntactically correct and
521          * there are no duplicate keys.
522          */
523         tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
524         if (tresult != ISC_R_SUCCESS)
525                 return (ISC_R_NOMEMORY);
526
527         cfg_map_get(config, "key", &keys);
528         tresult = check_keylist(keys, symtab, logctx);
529         if (tresult == ISC_R_EXISTS)
530                 result = ISC_R_FAILURE;
531         else if (tresult != ISC_R_SUCCESS) {
532                 isc_symtab_destroy(&symtab);
533                 return (tresult);
534         }
535         
536         if (vconfig != NULL) {
537                 keys = NULL;
538                 (void)cfg_map_get(vconfig, "key", &keys);
539                 tresult = check_keylist(keys, symtab, logctx);
540                 if (tresult == ISC_R_EXISTS)
541                         result = ISC_R_FAILURE;
542                 else if (tresult != ISC_R_SUCCESS) {
543                         isc_symtab_destroy(&symtab);
544                         return (tresult);
545                 }
546         }
547
548         isc_symtab_destroy(&symtab);
549
550         /*
551          * Check that forwarding is reasonable.
552          */
553         if (vconfig == NULL) {
554                 cfg_obj_t *options = NULL;
555                 cfg_map_get(config, "options", &options);
556                 if (options != NULL)
557                         if (check_forward(options, logctx) != ISC_R_SUCCESS)
558                                 result = ISC_R_FAILURE;
559         } else {
560                 if (check_forward(vconfig, logctx) != ISC_R_SUCCESS)
561                         result = ISC_R_FAILURE;
562         }
563
564
565         if (vconfig != NULL) {
566                 (void)cfg_map_get(vconfig, "server", &servers);
567                 if (servers != NULL &&
568                     check_servers(servers, logctx) != ISC_R_SUCCESS)
569                         result = ISC_R_FAILURE;
570         }
571
572         if (vconfig != NULL)
573                 tresult = check_options(vconfig, logctx);
574         else
575                 tresult = check_options(config, logctx);
576         if (tresult != ISC_R_SUCCESS)
577                 result = tresult;
578
579         return (result);
580 }
581
582
583 isc_result_t
584 cfg_check_namedconf(cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) {
585         cfg_obj_t *options = NULL;
586         cfg_obj_t *servers = NULL;
587         cfg_obj_t *views = NULL;
588         cfg_obj_t *acls = NULL;
589         cfg_obj_t *obj;
590         cfg_listelt_t *velement;
591         isc_result_t result = ISC_R_SUCCESS;
592         isc_result_t tresult;
593         isc_symtab_t *symtab = NULL;
594
595         static const char *builtin[] = { "localhost", "localnets",
596                                          "any", "none" };
597
598         (void)cfg_map_get(config, "options", &options);
599
600         if (options != NULL &&
601             check_options(options, logctx) != ISC_R_SUCCESS)
602                 result = ISC_R_FAILURE;
603
604         (void)cfg_map_get(config, "server", &servers);
605         if (servers != NULL &&
606             check_servers(servers, logctx) != ISC_R_SUCCESS)
607                 result = ISC_R_FAILURE;
608
609         (void)cfg_map_get(config, "view", &views);
610
611         if (views == NULL) {
612                 if (check_viewconf(config, NULL, logctx, mctx)
613                                    != ISC_R_SUCCESS)
614                         result = ISC_R_FAILURE;
615         } else {
616                 cfg_obj_t *zones = NULL;
617
618                 (void)cfg_map_get(config, "zone", &zones);
619                 if (zones != NULL) {
620                         cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
621                                     "when using 'view' statements, "
622                                     "all zones must be in views");
623                         result = ISC_R_FAILURE;
624                 }
625         }
626
627         tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
628         if (tresult != ISC_R_SUCCESS)
629                 result = tresult;
630         for (velement = cfg_list_first(views);
631              velement != NULL;
632              velement = cfg_list_next(velement))
633         {
634                 cfg_obj_t *view = cfg_listelt_value(velement);
635                 cfg_obj_t *vname = cfg_tuple_get(view, "name");
636                 cfg_obj_t *voptions = cfg_tuple_get(view, "options");
637                 cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
638                 dns_rdataclass_t vclass = dns_rdataclass_in;
639                 isc_result_t tresult = ISC_R_SUCCESS;
640                 const char *key = cfg_obj_asstring(vname);
641                 isc_symvalue_t symvalue;
642
643                 if (cfg_obj_isstring(vclassobj)) {
644                         isc_textregion_t r;
645                 
646                         DE_CONST(cfg_obj_asstring(vclassobj), r.base);
647                         r.length = strlen(r.base);
648                         tresult = dns_rdataclass_fromtext(&vclass, &r);
649                         if (tresult != ISC_R_SUCCESS)
650                                 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
651                                             "view '%s': invalid class %s",
652                                             cfg_obj_asstring(vname), r.base);
653                 }
654                 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
655                         symvalue.as_pointer = view;
656                         tresult = isc_symtab_define(symtab, key, vclass,
657                                                     symvalue,
658                                                     isc_symexists_reject);
659                         if (tresult == ISC_R_EXISTS) {
660                                 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
661                                             "view '%s': already exists", key);
662                                 result = tresult;
663                         } else if (result != ISC_R_SUCCESS) {
664                                 result = tresult;
665                         } else if ((strcasecmp(key, "_bind") == 0 &&
666                                     vclass == dns_rdataclass_ch) ||
667                                    (strcasecmp(key, "_default") == 0 &&
668                                     vclass == dns_rdataclass_in)) {
669                                 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
670                                             "attempt to redefine builtin view "
671                                             "'%s'", key);
672                                 result = ISC_R_EXISTS;
673                         }
674                 }
675                 if (check_viewconf(config, voptions, logctx, mctx)
676                     != ISC_R_SUCCESS)
677                         result = ISC_R_FAILURE;
678         }
679         if (symtab != NULL)
680                 isc_symtab_destroy(&symtab);
681
682         if (views != NULL && options != NULL) {
683                 obj = NULL;
684                 tresult = cfg_map_get(options, "cache-file", &obj);
685                 if (tresult == ISC_R_SUCCESS) {
686                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
687                                     "'cache-file' cannot be a global "
688                                     "option if views are present");
689                         result = ISC_R_FAILURE;
690                 }
691         }
692
693         tresult = cfg_map_get(config, "acl", &acls);
694         if (tresult == ISC_R_SUCCESS) {
695                 cfg_listelt_t *elt;
696                 cfg_listelt_t *elt2;
697                 const char *aclname;
698
699                 for (elt = cfg_list_first(acls);
700                      elt != NULL;
701                      elt = cfg_list_next(elt)) {
702                         cfg_obj_t *acl = cfg_listelt_value(elt);
703                         unsigned int i;
704
705                         aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
706                         for (i = 0;
707                              i < sizeof(builtin) / sizeof(builtin[0]);
708                              i++)
709                                 if (strcasecmp(aclname, builtin[i]) == 0) {
710                                         cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
711                                                     "attempt to redefine "
712                                                     "builtin acl '%s'",
713                                                     aclname);
714                                         result = ISC_R_FAILURE;
715                                         break;
716                                 }
717
718                         for (elt2 = cfg_list_next(elt);
719                              elt2 != NULL;
720                              elt2 = cfg_list_next(elt2)) {
721                                 cfg_obj_t *acl2 = cfg_listelt_value(elt2);
722                                 const char *name;
723                                 name = cfg_obj_asstring(cfg_tuple_get(acl2,
724                                                                       "name"));
725                                 if (strcasecmp(aclname, name) == 0) {
726                                         cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
727                                                     "attempt to redefine "
728                                                     "acl '%s'", name);
729                                         result = ISC_R_FAILURE;
730                                         break;
731                                 }
732                         }
733                 }
734         }
735
736         return (result);
737 }