]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind9/lib/bind9/check.c
This commit was generated by cvs2svn to compensate for changes in r142403,
[FreeBSD/FreeBSD.git] / contrib / bind9 / lib / bind9 / 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.37.6.28 2004/07/29 00:08:08 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/parseint.h>
30 #include <isc/region.h>
31 #include <isc/result.h>
32 #include <isc/sockaddr.h>
33 #include <isc/symtab.h>
34 #include <isc/util.h>
35
36 #include <dns/fixedname.h>
37 #include <dns/rdataclass.h>
38 #include <dns/rdatatype.h>
39 #include <dns/secalg.h>
40
41 #include <isccfg/cfg.h>
42
43 #include <bind9/check.h>
44
45 static void
46 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
47         UNUSED(type);
48         UNUSED(value);
49         isc_mem_free(userarg, key);
50 }
51
52 static isc_result_t
53 check_orderent(cfg_obj_t *ent, isc_log_t *logctx) {
54         isc_result_t result = ISC_R_SUCCESS;
55         isc_result_t tresult;
56         isc_textregion_t r;
57         dns_fixedname_t fixed;
58         cfg_obj_t *obj;
59         dns_rdataclass_t rdclass;
60         dns_rdatatype_t rdtype;
61         isc_buffer_t b;
62         const char *str;
63
64         dns_fixedname_init(&fixed);
65         obj = cfg_tuple_get(ent, "class");
66         if (cfg_obj_isstring(obj)) {
67
68                 DE_CONST(cfg_obj_asstring(obj), r.base);
69                 r.length = strlen(r.base);
70                 tresult = dns_rdataclass_fromtext(&rdclass, &r);
71                 if (tresult != ISC_R_SUCCESS) {
72                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
73                                     "rrset-order: invalid class '%s'",
74                                     r.base);
75                         result = ISC_R_FAILURE;
76                 }
77         }
78
79         obj = cfg_tuple_get(ent, "type");
80         if (cfg_obj_isstring(obj)) {
81
82                 DE_CONST(cfg_obj_asstring(obj), r.base);
83                 r.length = strlen(r.base);
84                 tresult = dns_rdatatype_fromtext(&rdtype, &r);
85                 if (tresult != ISC_R_SUCCESS) {
86                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
87                                     "rrset-order: invalid type '%s'",
88                                     r.base);
89                         result = ISC_R_FAILURE;
90                 }
91         }
92
93         obj = cfg_tuple_get(ent, "name");
94         if (cfg_obj_isstring(obj)) {
95                 str = cfg_obj_asstring(obj);
96                 isc_buffer_init(&b, str, strlen(str));
97                 isc_buffer_add(&b, strlen(str));
98                 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
99                                             dns_rootname, ISC_FALSE, NULL);
100                 if (tresult != ISC_R_SUCCESS) {
101                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
102                                     "rrset-order: invalid name '%s'", str);
103                         result = ISC_R_FAILURE;
104                 }
105         }
106
107         obj = cfg_tuple_get(ent, "order");
108         if (!cfg_obj_isstring(obj) ||
109             strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
110                 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
111                             "rrset-order: keyword 'order' missing");
112                 result = ISC_R_FAILURE;
113         }
114
115         obj = cfg_tuple_get(ent, "ordering");
116         if (!cfg_obj_isstring(obj)) {
117             cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
118                         "rrset-order: missing ordering");
119                 result = ISC_R_FAILURE;
120         } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
121                 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
122                             "rrset-order: order 'fixed' not implemented");
123         } else if (/* strcasecmp(cfg_obj_asstring(obj), "fixed") != 0 && */
124                    strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
125                    strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
126                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
127                             "rrset-order: invalid order '%s'",
128                             cfg_obj_asstring(obj));
129                 result = ISC_R_FAILURE;
130         }
131         return (result);
132 }
133
134 static isc_result_t
135 check_order(cfg_obj_t *options, isc_log_t *logctx) {
136         isc_result_t result = ISC_R_SUCCESS;
137         isc_result_t tresult;
138         cfg_listelt_t *element;
139         cfg_obj_t *obj = NULL;
140
141         if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
142                 return (result);
143
144         for (element = cfg_list_first(obj);
145              element != NULL;
146              element = cfg_list_next(element))
147         {
148                 tresult = check_orderent(cfg_listelt_value(element), logctx);
149                 if (tresult != ISC_R_SUCCESS)
150                         result = tresult;
151         }
152         return (result);
153 }
154
155 static isc_result_t
156 check_dual_stack(cfg_obj_t *options, isc_log_t *logctx) {
157         cfg_listelt_t *element;
158         cfg_obj_t *alternates = NULL;
159         cfg_obj_t *value;
160         cfg_obj_t *obj;
161         char *str;
162         dns_fixedname_t fixed;
163         dns_name_t *name;
164         isc_buffer_t buffer;
165         isc_result_t result = ISC_R_SUCCESS;
166         isc_result_t tresult;
167
168         (void)cfg_map_get(options, "dual-stack-servers", &alternates);
169
170         if (alternates == NULL)
171                 return (ISC_R_SUCCESS);
172
173         obj = cfg_tuple_get(alternates, "port");
174         if (cfg_obj_isuint32(obj)) {
175                 isc_uint32_t val = cfg_obj_asuint32(obj);
176                 if (val > ISC_UINT16_MAX) {
177                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
178                                     "port '%u' out of range", val);
179                         result = ISC_R_FAILURE;
180                 }
181         }
182         obj = cfg_tuple_get(alternates, "addresses");
183         for (element = cfg_list_first(obj);
184              element != NULL;
185              element = cfg_list_next(element)) {
186                 value = cfg_listelt_value(element);
187                 if (cfg_obj_issockaddr(value))
188                         continue;
189                 obj = cfg_tuple_get(value, "name");
190                 str = cfg_obj_asstring(obj);
191                 isc_buffer_init(&buffer, str, strlen(str));
192                 isc_buffer_add(&buffer, strlen(str));
193                 dns_fixedname_init(&fixed);
194                 name = dns_fixedname_name(&fixed);
195                 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
196                                            ISC_FALSE, NULL);
197                 if (tresult != ISC_R_SUCCESS) {
198                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
199                                     "bad name '%s'", str);
200                         result = ISC_R_FAILURE;
201                 }
202                 obj = cfg_tuple_get(value, "port");
203                 if (cfg_obj_isuint32(obj)) {
204                         isc_uint32_t val = cfg_obj_asuint32(obj);
205                         if (val > ISC_UINT16_MAX) {
206                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
207                                             "port '%u' out of range", val);
208                                 result = ISC_R_FAILURE;
209                         }
210                 }
211         }
212         return (result);
213 }
214
215 static isc_result_t
216 check_forward(cfg_obj_t *options, isc_log_t *logctx) {
217         cfg_obj_t *forward = NULL;
218         cfg_obj_t *forwarders = NULL;
219
220         (void)cfg_map_get(options, "forward", &forward);
221         (void)cfg_map_get(options, "forwarders", &forwarders);
222
223         if (forward != NULL && forwarders == NULL) {
224                 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
225                             "no matching 'forwarders' statement");
226                 return (ISC_R_FAILURE);
227         }
228         return (ISC_R_SUCCESS);
229 }
230
231 static isc_result_t
232 disabled_algorithms(cfg_obj_t *disabled, isc_log_t *logctx) {
233         isc_result_t result = ISC_R_SUCCESS;
234         isc_result_t tresult;
235         cfg_listelt_t *element;
236         const char *str;
237         isc_buffer_t b;
238         dns_fixedname_t fixed;
239         dns_name_t *name;
240         cfg_obj_t *obj;
241
242         dns_fixedname_init(&fixed);
243         name = dns_fixedname_name(&fixed);
244         obj = cfg_tuple_get(disabled, "name");
245         str = cfg_obj_asstring(obj);
246         isc_buffer_init(&b, str, strlen(str));
247         isc_buffer_add(&b, strlen(str));
248         tresult = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
249         if (tresult != ISC_R_SUCCESS) {
250                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
251                             "bad domain name '%s'", str);
252                 result = tresult;
253         }
254
255         obj = cfg_tuple_get(disabled, "algorithms");
256
257         for (element = cfg_list_first(obj);
258              element != NULL;
259              element = cfg_list_next(element))
260         {
261                 isc_textregion_t r;
262                 dns_secalg_t alg;
263                 isc_result_t tresult;
264
265                 r.base = cfg_obj_asstring(cfg_listelt_value(element));
266                 r.length = strlen(r.base);
267
268                 tresult = dns_secalg_fromtext(&alg, &r);
269                 if (tresult != ISC_R_SUCCESS) {
270                         isc_uint8_t ui;
271                         result = isc_parse_uint8(&ui, r.base, 10);
272                 }
273                 if (tresult != ISC_R_SUCCESS) {
274                         cfg_obj_log(cfg_listelt_value(element), logctx,
275                                     ISC_LOG_ERROR, "invalid algorithm");
276                         result = tresult;
277                 }
278         }
279         return (result);
280 }
281
282 static isc_result_t
283 nameexist(cfg_obj_t *obj, const char *name, int value, isc_symtab_t *symtab,
284           const char *fmt, isc_log_t *logctx, isc_mem_t *mctx)
285 {
286         char *key;
287         const char *file;
288         unsigned int line;
289         isc_result_t result;
290         isc_symvalue_t symvalue;
291
292         key = isc_mem_strdup(mctx, name);
293         if (key == NULL)
294                 return (ISC_R_NOMEMORY);
295         symvalue.as_pointer = obj;
296         result = isc_symtab_define(symtab, key, value, symvalue,
297                                    isc_symexists_reject);
298         if (result == ISC_R_EXISTS) {
299                 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
300                                                 &symvalue) == ISC_R_SUCCESS);
301                 file = cfg_obj_file(symvalue.as_pointer);
302                 line = cfg_obj_line(symvalue.as_pointer);
303
304                 if (file == NULL)
305                         file = "<unknown file>";
306                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
307                 isc_mem_free(mctx, key);
308                 result = ISC_R_EXISTS;
309         } else if (result != ISC_R_SUCCESS) {
310                 isc_mem_free(mctx, key);
311         }
312         return (result);
313 }
314
315 static isc_result_t
316 mustbesecure(cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
317              isc_mem_t *mctx)
318 {
319         cfg_obj_t *obj;
320         char namebuf[DNS_NAME_FORMATSIZE];
321         const char *str;
322         dns_fixedname_t fixed;
323         dns_name_t *name;
324         isc_buffer_t b;
325         isc_result_t result = ISC_R_SUCCESS;
326
327         dns_fixedname_init(&fixed);
328         name = dns_fixedname_name(&fixed);
329         obj = cfg_tuple_get(secure, "name");
330         str = cfg_obj_asstring(obj);
331         isc_buffer_init(&b, str, strlen(str));
332         isc_buffer_add(&b, strlen(str));
333         result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
334         if (result != ISC_R_SUCCESS) {
335                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
336                             "bad domain name '%s'", str);
337         } else {
338                 dns_name_format(name, namebuf, sizeof(namebuf));
339                 result = nameexist(secure, namebuf, 1, symtab,
340                                    "dnssec-must-be-secure '%s': already "
341                                    "exists previous definition: %s:%u",
342                                    logctx, mctx);
343         }
344         return (result);
345 }
346
347 typedef struct {
348         const char *name;
349         unsigned int scale;
350         unsigned int max;
351 } intervaltable;
352
353 static isc_result_t
354 check_options(cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
355         isc_result_t result = ISC_R_SUCCESS;
356         isc_result_t tresult;
357         unsigned int i;
358         cfg_obj_t *obj = NULL;
359         cfg_listelt_t *element;
360         isc_symtab_t *symtab = NULL;
361
362         static intervaltable intervals[] = {
363         { "cleaning-interval", 60, 28 * 24 * 60 },      /* 28 days */
364         { "heartbeat-interval", 60, 28 * 24 * 60 },     /* 28 days */
365         { "interface-interval", 60, 28 * 24 * 60 },     /* 28 days */
366         { "max-transfer-idle-in", 60, 28 * 24 * 60 },   /* 28 days */
367         { "max-transfer-idle-out", 60, 28 * 24 * 60 },  /* 28 days */
368         { "max-transfer-time-in", 60, 28 * 24 * 60 },   /* 28 days */
369         { "max-transfer-time-out", 60, 28 * 24 * 60 },  /* 28 days */
370         { "sig-validity-interval", 86400, 10 * 366 },   /* 10 years */
371         { "statistics-interval", 60, 28 * 24 * 60 },    /* 28 days */
372         };
373
374         /*
375          * Check that fields specified in units of time other than seconds
376          * have reasonable values.
377          */
378         for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
379                 isc_uint32_t val;
380                 obj = NULL;
381                 (void)cfg_map_get(options, intervals[i].name, &obj);
382                 if (obj == NULL)
383                         continue;
384                 val = cfg_obj_asuint32(obj);
385                 if (val > intervals[i].max) {
386                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
387                                     "%s '%u' is out of range (0..%u)",
388                                     intervals[i].name, val,
389                                     intervals[i].max);
390                         result = ISC_R_RANGE;
391                 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
392                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
393                                     "%s '%d' is out of range",
394                                     intervals[i].name, val);
395                         result = ISC_R_RANGE;
396                 }
397         }
398         obj = NULL;
399         (void)cfg_map_get(options, "preferred-glue", &obj);
400         if (obj != NULL) {
401                 const char *str;
402                 str = cfg_obj_asstring(obj);
403                 if (strcasecmp(str, "a") != 0 &&
404                     strcasecmp(str, "aaaa") != 0 &&
405                     strcasecmp(str, "none") != 0)
406                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
407                                     "preferred-glue unexpected value '%s'",
408                                     str);
409         }
410         obj = NULL;
411         (void)cfg_map_get(options, "root-delegation-only", &obj);
412         if (obj != NULL) {
413                 if (!cfg_obj_isvoid(obj)) {
414                         cfg_listelt_t *element;
415                         cfg_obj_t *exclude;
416                         char *str;
417                         dns_fixedname_t fixed;
418                         dns_name_t *name;
419                         isc_buffer_t b;
420
421                         dns_fixedname_init(&fixed);
422                         name = dns_fixedname_name(&fixed);
423                         for (element = cfg_list_first(obj);
424                              element != NULL;
425                              element = cfg_list_next(element)) {
426                                 exclude = cfg_listelt_value(element);
427                                 str = cfg_obj_asstring(exclude);
428                                 isc_buffer_init(&b, str, strlen(str));
429                                 isc_buffer_add(&b, strlen(str));
430                                 tresult = dns_name_fromtext(name, &b,
431                                                            dns_rootname,
432                                                            ISC_FALSE, NULL);
433                                 if (tresult != ISC_R_SUCCESS) {
434                                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
435                                                     "bad domain name '%s'",
436                                                     str);
437                                         result = tresult;
438                                 }
439                         }
440                 }
441         }
442        
443         /*
444          * Set supported DNSSEC algorithms.
445          */
446         obj = NULL;
447         (void)cfg_map_get(options, "disable-algorithms", &obj);
448         if (obj != NULL) {
449                 for (element = cfg_list_first(obj);
450                      element != NULL;
451                      element = cfg_list_next(element))
452                 {
453                         obj = cfg_listelt_value(element);
454                         tresult = disabled_algorithms(obj, logctx);
455                         if (tresult != ISC_R_SUCCESS)
456                                 result = tresult;
457                 }
458         }
459
460         /*
461          * Check the DLV zone name.
462          */
463         obj = NULL;
464         (void)cfg_map_get(options, "dnssec-lookaside", &obj);
465         if (obj != NULL) {
466                 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
467                                             ISC_TRUE, &symtab);
468                 if (tresult != ISC_R_SUCCESS)
469                         result = tresult;
470                 for (element = cfg_list_first(obj);
471                      element != NULL;
472                      element = cfg_list_next(element))
473                 {
474                         dns_fixedname_t fixedname;
475                         dns_name_t *name;
476                         const char *dlv;
477                         isc_buffer_t b;
478
479                         obj = cfg_listelt_value(element);
480
481                         dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain"));
482                         dns_fixedname_init(&fixedname);
483                         name = dns_fixedname_name(&fixedname);
484                         isc_buffer_init(&b, dlv, strlen(dlv));
485                         isc_buffer_add(&b, strlen(dlv));
486                         tresult = dns_name_fromtext(name, &b, dns_rootname,
487                                                     ISC_TRUE, NULL);
488                         if (tresult != ISC_R_SUCCESS) {
489                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
490                                             "bad domain name '%s'", dlv);
491                                 result = tresult;
492                         }
493                         if (symtab != NULL) {
494                                 tresult = nameexist(obj, dlv, 1, symtab,
495                                                     "dnssec-lookaside '%s': "
496                                                     "already exists previous "
497                                                     "definition: %s:%u",
498                                                     logctx, mctx);
499                                 if (tresult != ISC_R_SUCCESS &&
500                                     result == ISC_R_SUCCESS)
501                                         result = tresult;
502                         }
503                         /*
504                          * XXXMPA to be removed when multiple lookaside
505                          * namespaces are supported.
506                          */
507                         if (!dns_name_equal(dns_rootname, name)) {
508                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
509                                             "dnssec-lookaside '%s': "
510                                             "non-root not yet supported", dlv);
511                                 if (result == ISC_R_SUCCESS)
512                                         result = ISC_R_FAILURE;
513                         }
514                         dlv = cfg_obj_asstring(cfg_tuple_get(obj,
515                                                "trust-anchor"));
516                         dns_fixedname_init(&fixedname);
517                         isc_buffer_init(&b, dlv, strlen(dlv));
518                         isc_buffer_add(&b, strlen(dlv));
519                         tresult = dns_name_fromtext(name, &b, dns_rootname,
520                                                     ISC_TRUE, NULL);
521                         if (tresult != ISC_R_SUCCESS) {
522                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
523                                             "bad domain name '%s'", dlv);
524                                 if (result == ISC_R_SUCCESS)
525                                         result = tresult;
526                         }
527                 }
528                 if (symtab != NULL)
529                         isc_symtab_destroy(&symtab);
530         }
531
532         /*
533          * Check dnssec-must-be-secure.
534          */
535         obj = NULL;
536         (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
537         if (obj != NULL) {
538                 isc_symtab_t *symtab = NULL;
539                 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
540                                             ISC_FALSE, &symtab);
541                 if (tresult != ISC_R_SUCCESS)
542                         result = tresult;
543                 for (element = cfg_list_first(obj);
544                      element != NULL;
545                      element = cfg_list_next(element))
546                 {
547                         obj = cfg_listelt_value(element);
548                         tresult = mustbesecure(obj, symtab, logctx, mctx);
549                         if (tresult != ISC_R_SUCCESS)
550                                 result = tresult;
551                 }
552                 if (symtab != NULL)
553                         isc_symtab_destroy(&symtab);
554         }
555
556         return (result);
557 }
558
559 static isc_result_t
560 get_masters_def(cfg_obj_t *cctx, char *name, cfg_obj_t **ret) {
561         isc_result_t result;
562         cfg_obj_t *masters = NULL;
563         cfg_listelt_t *elt;
564
565         result = cfg_map_get(cctx, "masters", &masters);
566         if (result != ISC_R_SUCCESS)
567                 return (result);
568         for (elt = cfg_list_first(masters);
569              elt != NULL;
570              elt = cfg_list_next(elt)) {
571                 cfg_obj_t *list;
572                 const char *listname;
573
574                 list = cfg_listelt_value(elt);
575                 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
576
577                 if (strcasecmp(listname, name) == 0) {
578                         *ret = list;
579                         return (ISC_R_SUCCESS);
580                 }
581         }
582         return (ISC_R_NOTFOUND);
583 }
584
585 static isc_result_t
586 validate_masters(cfg_obj_t *obj, cfg_obj_t *config, isc_uint32_t *countp,
587                  isc_log_t *logctx, isc_mem_t *mctx)
588 {
589         isc_result_t result = ISC_R_SUCCESS;
590         isc_result_t tresult;
591         isc_uint32_t count = 0;
592         isc_symtab_t *symtab = NULL;
593         isc_symvalue_t symvalue;
594         cfg_listelt_t *element;
595         cfg_listelt_t **stack = NULL;
596         isc_uint32_t stackcount = 0, pushed = 0;
597         cfg_obj_t *list;
598
599         REQUIRE(countp != NULL);
600         result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
601         if (result != ISC_R_SUCCESS)
602                 return (result);
603
604  newlist:
605         list = cfg_tuple_get(obj, "addresses");
606         element = cfg_list_first(list);
607  resume:        
608         for ( ;
609              element != NULL;
610              element = cfg_list_next(element))
611         {
612                 char *listname;
613                 cfg_obj_t *addr;
614                 cfg_obj_t *key;
615
616                 addr = cfg_tuple_get(cfg_listelt_value(element),
617                                      "masterselement");
618                 key = cfg_tuple_get(cfg_listelt_value(element), "key");
619
620                 if (cfg_obj_issockaddr(addr)) {
621                         count++;
622                         continue;
623                 }
624                 if (!cfg_obj_isvoid(key)) {
625                         cfg_obj_log(key, logctx, ISC_LOG_ERROR,
626                                     "unexpected token '%s'",
627                                     cfg_obj_asstring(key));
628                         if (result == ISC_R_SUCCESS)
629                                 result = ISC_R_FAILURE;
630                 }
631                 listname = cfg_obj_asstring(addr);
632                 symvalue.as_pointer = addr;
633                 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
634                                             isc_symexists_reject);
635                 if (tresult == ISC_R_EXISTS)
636                         continue;
637                 tresult = get_masters_def(config, listname, &obj);
638                 if (tresult != ISC_R_SUCCESS) {
639                         if (result == ISC_R_SUCCESS)
640                                 result = tresult;
641                         cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
642                                     "unable to find masters list '%s'",
643                                     listname);
644                         continue;
645                 }
646                 /* Grow stack? */
647                 if (stackcount == pushed) {
648                         void * new;
649                         isc_uint32_t newlen = stackcount + 16;
650                         size_t newsize, oldsize;
651
652                         newsize = newlen * sizeof(*stack);
653                         oldsize = stackcount * sizeof(*stack);
654                         new = isc_mem_get(mctx, newsize);
655                         if (new == NULL)
656                                 goto cleanup;
657                         if (stackcount != 0) {
658                                 memcpy(new, stack, oldsize);
659                                 isc_mem_put(mctx, stack, oldsize);
660                         }
661                         stack = new;
662                         stackcount = newlen;
663                 }
664                 stack[pushed++] = cfg_list_next(element);
665                 goto newlist;
666         }
667         if (pushed != 0) {
668                 element = stack[--pushed];
669                 goto resume;
670         }
671  cleanup:
672         if (stack != NULL)
673                 isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
674         isc_symtab_destroy(&symtab);
675         *countp = count;
676         return (result);
677 }
678
679 #define MASTERZONE      1
680 #define SLAVEZONE       2
681 #define STUBZONE        4
682 #define HINTZONE        8
683 #define FORWARDZONE     16
684 #define DELEGATIONZONE  32
685
686 typedef struct {
687         const char *name;
688         int allowed;
689 } optionstable;
690
691 static isc_result_t
692 check_zoneconf(cfg_obj_t *zconfig, cfg_obj_t *config, isc_symtab_t *symtab,
693                dns_rdataclass_t defclass, isc_log_t *logctx, isc_mem_t *mctx)
694 {
695         const char *zname;
696         const char *typestr;
697         unsigned int ztype;
698         cfg_obj_t *zoptions;
699         cfg_obj_t *obj = NULL;
700         isc_result_t result = ISC_R_SUCCESS;
701         isc_result_t tresult;
702         unsigned int i;
703         dns_rdataclass_t zclass;
704         dns_fixedname_t fixedname;
705         isc_buffer_t b;
706
707         static optionstable options[] = {
708         { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE },
709         { "allow-notify", SLAVEZONE },
710         { "allow-transfer", MASTERZONE | SLAVEZONE },
711         { "notify", MASTERZONE | SLAVEZONE },
712         { "also-notify", MASTERZONE | SLAVEZONE },
713         { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
714         { "delegation-only", HINTZONE | STUBZONE },
715         { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
716         { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
717         { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
718         { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
719         { "notify-source", MASTERZONE | SLAVEZONE },
720         { "notify-source-v6", MASTERZONE | SLAVEZONE },
721         { "transfer-source", SLAVEZONE | STUBZONE },
722         { "transfer-source-v6", SLAVEZONE | STUBZONE },
723         { "max-transfer-time-in", SLAVEZONE | STUBZONE },
724         { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
725         { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
726         { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
727         { "max-retry-time", SLAVEZONE | STUBZONE },
728         { "min-retry-time", SLAVEZONE | STUBZONE },
729         { "max-refresh-time", SLAVEZONE | STUBZONE },
730         { "min-refresh-time", SLAVEZONE | STUBZONE },
731         { "sig-validity-interval", MASTERZONE },
732         { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE },
733         { "allow-update", MASTERZONE },
734         { "allow-update-forwarding", SLAVEZONE },
735         { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE},
736         { "ixfr-base", MASTERZONE | SLAVEZONE },
737         { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
738         { "masters", SLAVEZONE | STUBZONE },
739         { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
740         { "update-policy", MASTERZONE },
741         { "database", MASTERZONE | SLAVEZONE | STUBZONE },
742         { "key-directory", MASTERZONE },
743         };
744
745         static optionstable dialups[] = {
746         { "notify", MASTERZONE | SLAVEZONE },
747         { "notify-passive", SLAVEZONE },
748         { "refresh", SLAVEZONE | STUBZONE },
749         { "passive", SLAVEZONE | STUBZONE },
750         };
751
752         zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
753
754         zoptions = cfg_tuple_get(zconfig, "options");
755
756         obj = NULL;
757         (void)cfg_map_get(zoptions, "type", &obj);
758         if (obj == NULL) {
759                 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
760                             "zone '%s': type not present", zname);
761                 return (ISC_R_FAILURE);
762         }
763
764         typestr = cfg_obj_asstring(obj);
765         if (strcasecmp(typestr, "master") == 0)
766                 ztype = MASTERZONE;
767         else if (strcasecmp(typestr, "slave") == 0)
768                 ztype = SLAVEZONE;
769         else if (strcasecmp(typestr, "stub") == 0)
770                 ztype = STUBZONE;
771         else if (strcasecmp(typestr, "forward") == 0)
772                 ztype = FORWARDZONE;
773         else if (strcasecmp(typestr, "hint") == 0)
774                 ztype = HINTZONE;
775         else if (strcasecmp(typestr, "delegation-only") == 0)
776                 ztype = DELEGATIONZONE;
777         else {
778                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
779                             "zone '%s': invalid type %s",
780                             zname, typestr);
781                 return (ISC_R_FAILURE);
782         }
783
784         obj = cfg_tuple_get(zconfig, "class");
785         if (cfg_obj_isstring(obj)) {
786                 isc_textregion_t r;
787
788                 DE_CONST(cfg_obj_asstring(obj), r.base);
789                 r.length = strlen(r.base);
790                 result = dns_rdataclass_fromtext(&zclass, &r);
791                 if (result != ISC_R_SUCCESS) {
792                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
793                                     "zone '%s': invalid class %s",
794                                     zname, r.base);
795                         return (ISC_R_FAILURE);
796                 }
797                 if (zclass != defclass) {
798                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
799                                     "zone '%s': class '%s' does not "
800                                     "match view/default class",
801                                     zname, r.base);
802                         return (ISC_R_FAILURE);
803                 }
804         }
805
806         /*
807          * Look for an already existing zone.
808          * We need to make this cannonical as isc_symtab_define()
809          * deals with strings.
810          */
811         dns_fixedname_init(&fixedname);
812         isc_buffer_init(&b, zname, strlen(zname));
813         isc_buffer_add(&b, strlen(zname));
814         tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
815                                    dns_rootname, ISC_TRUE, NULL);
816         if (result != ISC_R_SUCCESS) {
817                 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
818                             "zone '%s': is not a valid name", zname);
819                 tresult = ISC_R_FAILURE;
820         } else {
821                 char namebuf[DNS_NAME_FORMATSIZE];
822
823                 dns_name_format(dns_fixedname_name(&fixedname),
824                                 namebuf, sizeof(namebuf));
825                 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
826                                    symtab, "zone '%s': already exists "
827                                    "previous definition: %s:%u", logctx, mctx);
828                 if (tresult != ISC_R_SUCCESS)
829                         result = tresult;
830         }
831
832         /*
833          * Look for inappropriate options for the given zone type.
834          */
835         for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
836                 obj = NULL;
837                 if ((options[i].allowed & ztype) == 0 &&
838                     cfg_map_get(zoptions, options[i].name, &obj) ==
839                     ISC_R_SUCCESS)
840                 {
841                         if (strcmp(options[i].name, "allow-update") != 0 ||
842                             ztype != SLAVEZONE) {
843                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
844                                             "option '%s' is not allowed "
845                                             "in '%s' zone '%s'",
846                                             options[i].name, typestr, zname);
847                                         result = ISC_R_FAILURE;
848                         } else
849                                 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
850                                             "option '%s' is not allowed "
851                                             "in '%s' zone '%s'",
852                                             options[i].name, typestr, zname);
853                 }
854         }
855
856         /*
857          * Slave & stub zones must have a "masters" field.
858          */
859         if (ztype == SLAVEZONE || ztype == STUBZONE) {
860                 obj = NULL;
861                 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
862                         cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
863                                     "zone '%s': missing 'masters' entry",
864                                     zname);
865                         result = ISC_R_FAILURE;
866                 } else {
867                         isc_uint32_t count;
868                         tresult = validate_masters(obj, config, &count,
869                                                    logctx, mctx);
870                         if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
871                                 result = tresult;
872                         if (tresult == ISC_R_SUCCESS && count == 0) {
873                                 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
874                                             "zone '%s': empty 'masters' entry",
875                                             zname);
876                                 result = ISC_R_FAILURE;
877                         }
878                 }
879         }
880
881         /*
882          * Master zones can't have both "allow-update" and "update-policy".
883          */
884         if (ztype == MASTERZONE) {
885                 isc_result_t res1, res2;
886                 obj = NULL;
887                 res1 = cfg_map_get(zoptions, "allow-update", &obj);
888                 obj = NULL;
889                 res2 = cfg_map_get(zoptions, "update-policy", &obj);
890                 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
891                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
892                                     "zone '%s': 'allow-update' is ignored "
893                                     "when 'update-policy' is present",
894                                     zname);
895                         result = ISC_R_FAILURE;
896                 }
897         }
898
899         /*
900          * Check the excessively complicated "dialup" option.
901          */
902         if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
903                 cfg_obj_t *dialup = NULL;
904                 (void)cfg_map_get(zoptions, "dialup", &dialup);
905                 if (dialup != NULL && cfg_obj_isstring(dialup)) {
906                         char *str = cfg_obj_asstring(dialup);
907                         for (i = 0;
908                              i < sizeof(dialups) / sizeof(dialups[0]);
909                              i++)
910                         {
911                                 if (strcasecmp(dialups[i].name, str) != 0)
912                                         continue;
913                                 if ((dialups[i].allowed & ztype) == 0) {
914                                         cfg_obj_log(obj, logctx,
915                                                     ISC_LOG_ERROR,
916                                                     "dialup type '%s' is not "
917                                                     "allowed in '%s' "
918                                                     "zone '%s'",
919                                                     str, typestr, zname);
920                                         result = ISC_R_FAILURE;
921                                 }
922                                 break;
923                         }
924                         if (i == sizeof(dialups) / sizeof(dialups[0])) {
925                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
926                                             "invalid dialup type '%s' in zone "
927                                             "'%s'", str, zname);
928                                 result = ISC_R_FAILURE;
929                         }
930                 }
931         }
932
933         /*
934          * Check that forwarding is reasonable.
935          */
936         if (check_forward(zoptions, logctx) != ISC_R_SUCCESS)
937                 result = ISC_R_FAILURE;
938
939         /*
940          * Check various options.
941          */
942         tresult = check_options(zoptions, logctx, mctx);
943         if (tresult != ISC_R_SUCCESS)
944                 result = tresult;
945
946         return (result);
947 }
948
949 isc_result_t
950 bind9_check_key(cfg_obj_t *key, isc_log_t *logctx) {
951         cfg_obj_t *algobj = NULL;
952         cfg_obj_t *secretobj = NULL;
953         const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
954         
955         (void)cfg_map_get(key, "algorithm", &algobj);
956         (void)cfg_map_get(key, "secret", &secretobj);
957         if (secretobj == NULL || algobj == NULL) {
958                 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
959                             "key '%s' must have both 'secret' and "
960                             "'algorithm' defined",
961                             keyname);
962                 return (ISC_R_FAILURE);
963         }
964         return (ISC_R_SUCCESS);
965 }
966
967 static isc_result_t
968 check_keylist(cfg_obj_t *keys, isc_symtab_t *symtab, isc_log_t *logctx) {
969         isc_result_t result = ISC_R_SUCCESS;
970         isc_result_t tresult;
971         cfg_listelt_t *element;
972
973         for (element = cfg_list_first(keys);
974              element != NULL;
975              element = cfg_list_next(element))
976         {
977                 cfg_obj_t *key = cfg_listelt_value(element);
978                 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
979                 isc_symvalue_t symvalue;
980
981                 symvalue.as_pointer = key;
982                 tresult = isc_symtab_define(symtab, keyname, 1,
983                                             symvalue, isc_symexists_reject);
984                 if (tresult == ISC_R_EXISTS) {
985                         const char *file;
986                         unsigned int line;
987
988                         RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
989                                             1, &symvalue) == ISC_R_SUCCESS);
990                         file = cfg_obj_file(symvalue.as_pointer);
991                         line = cfg_obj_line(symvalue.as_pointer);
992
993                         if (file == NULL)
994                                 file = "<unknown file>";
995                         cfg_obj_log(key, logctx, ISC_LOG_ERROR,
996                                     "key '%s': already exists "
997                                     "previous definition: %s:%u",
998                                     keyname, file, line);
999                         result = tresult;
1000                 } else if (tresult != ISC_R_SUCCESS)
1001                         return (tresult);
1002
1003                 tresult = bind9_check_key(key, logctx);
1004                 if (tresult != ISC_R_SUCCESS)
1005                         return (tresult);
1006         }
1007         return (result);
1008 }
1009
1010 static isc_result_t
1011 check_servers(cfg_obj_t *servers, isc_log_t *logctx) {
1012         isc_result_t result = ISC_R_SUCCESS;
1013         cfg_listelt_t *e1, *e2;
1014         cfg_obj_t *v1, *v2;
1015         isc_sockaddr_t *s1, *s2;
1016         isc_netaddr_t na;
1017         cfg_obj_t *ts;
1018         char buf[128];
1019         const char *xfr;
1020         isc_buffer_t target;
1021
1022         for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
1023                 v1 = cfg_listelt_value(e1);
1024                 s1 = cfg_obj_assockaddr(cfg_map_getname(v1));
1025                 ts = NULL;
1026                 if (isc_sockaddr_pf(s1) == AF_INET)
1027                         xfr = "transfer-source-v6";
1028                 else
1029                         xfr = "transfer-source";
1030                 (void)cfg_map_get(v1, xfr, &ts);
1031                 if (ts != NULL) {
1032                         isc_netaddr_fromsockaddr(&na, s1);
1033                         isc_buffer_init(&target, buf, sizeof(buf) - 1);
1034                         RUNTIME_CHECK(isc_netaddr_totext(&na, &target)
1035                                       == ISC_R_SUCCESS);
1036                         buf[isc_buffer_usedlength(&target)] = '\0';
1037                         cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1038                                     "server '%s': %s not valid", buf, xfr);
1039                         result = ISC_R_FAILURE;
1040                 }
1041                 e2 = e1;
1042                 while ((e2 = cfg_list_next(e2)) != NULL) {
1043                         v2 = cfg_listelt_value(e2);
1044                         s2 = cfg_obj_assockaddr(cfg_map_getname(v2));
1045                         if (isc_sockaddr_eqaddr(s1, s2)) {
1046                                 const char *file = cfg_obj_file(v1);
1047                                 unsigned int line = cfg_obj_line(v1);
1048
1049                                 if (file == NULL)
1050                                         file = "<unknown file>";
1051
1052                                 isc_netaddr_fromsockaddr(&na, s2);
1053                                 isc_buffer_init(&target, buf, sizeof(buf) - 1);
1054                                 RUNTIME_CHECK(isc_netaddr_totext(&na, &target)
1055                                               == ISC_R_SUCCESS);
1056                                 buf[isc_buffer_usedlength(&target)] = '\0';
1057
1058                                 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
1059                                             "server '%s': already exists "
1060                                             "previous definition: %s:%u",
1061                                             buf, file, line);
1062                                 result = ISC_R_FAILURE;
1063                         }
1064                 }
1065         }
1066         return (result);
1067 }
1068                 
1069 static isc_result_t
1070 check_viewconf(cfg_obj_t *config, cfg_obj_t *vconfig, dns_rdataclass_t vclass,
1071                isc_log_t *logctx, isc_mem_t *mctx)
1072 {
1073         cfg_obj_t *servers = NULL;
1074         cfg_obj_t *zones = NULL;
1075         cfg_obj_t *keys = NULL;
1076         cfg_listelt_t *element;
1077         isc_symtab_t *symtab = NULL;
1078         isc_result_t result = ISC_R_SUCCESS;
1079         isc_result_t tresult = ISC_R_SUCCESS;
1080
1081         /*
1082          * Check that all zone statements are syntactically correct and
1083          * there are no duplicate zones.
1084          */
1085         tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1086                                     ISC_FALSE, &symtab);
1087         if (tresult != ISC_R_SUCCESS)
1088                 return (ISC_R_NOMEMORY);
1089
1090         if (vconfig != NULL)
1091                 (void)cfg_map_get(vconfig, "zone", &zones);
1092         else
1093                 (void)cfg_map_get(config, "zone", &zones);
1094
1095         for (element = cfg_list_first(zones);
1096              element != NULL;
1097              element = cfg_list_next(element))
1098         {
1099                 isc_result_t tresult;
1100                 cfg_obj_t *zone = cfg_listelt_value(element);
1101
1102                 tresult = check_zoneconf(zone, config, symtab, vclass,
1103                                          logctx, mctx);
1104                 if (tresult != ISC_R_SUCCESS)
1105                         result = ISC_R_FAILURE;
1106         }
1107
1108         isc_symtab_destroy(&symtab);
1109
1110         /*
1111          * Check that all key statements are syntactically correct and
1112          * there are no duplicate keys.
1113          */
1114         tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
1115         if (tresult != ISC_R_SUCCESS)
1116                 return (ISC_R_NOMEMORY);
1117
1118         (void)cfg_map_get(config, "key", &keys);
1119         tresult = check_keylist(keys, symtab, logctx);
1120         if (tresult == ISC_R_EXISTS)
1121                 result = ISC_R_FAILURE;
1122         else if (tresult != ISC_R_SUCCESS) {
1123                 isc_symtab_destroy(&symtab);
1124                 return (tresult);
1125         }
1126         
1127         if (vconfig != NULL) {
1128                 keys = NULL;
1129                 (void)cfg_map_get(vconfig, "key", &keys);
1130                 tresult = check_keylist(keys, symtab, logctx);
1131                 if (tresult == ISC_R_EXISTS)
1132                         result = ISC_R_FAILURE;
1133                 else if (tresult != ISC_R_SUCCESS) {
1134                         isc_symtab_destroy(&symtab);
1135                         return (tresult);
1136                 }
1137         }
1138
1139         isc_symtab_destroy(&symtab);
1140
1141         /*
1142          * Check that forwarding is reasonable.
1143          */
1144         if (vconfig == NULL) {
1145                 cfg_obj_t *options = NULL;
1146                 (void)cfg_map_get(config, "options", &options);
1147                 if (options != NULL)
1148                         if (check_forward(options, logctx) != ISC_R_SUCCESS)
1149                                 result = ISC_R_FAILURE;
1150         } else {
1151                 if (check_forward(vconfig, logctx) != ISC_R_SUCCESS)
1152                         result = ISC_R_FAILURE;
1153         }
1154         /*
1155          * Check that dual-stack-servers is reasonable.
1156          */
1157         if (vconfig == NULL) {
1158                 cfg_obj_t *options = NULL;
1159                 (void)cfg_map_get(config, "options", &options);
1160                 if (options != NULL)
1161                         if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1162                                 result = ISC_R_FAILURE;
1163         } else {
1164                 if (check_dual_stack(vconfig, logctx) != ISC_R_SUCCESS)
1165                         result = ISC_R_FAILURE;
1166         }
1167
1168         /*
1169          * Check that rrset-order is reasonable.
1170          */
1171         if (vconfig != NULL) {
1172                 if (check_order(vconfig, logctx) != ISC_R_SUCCESS)
1173                         result = ISC_R_FAILURE;
1174         }
1175
1176         if (vconfig != NULL) {
1177                 (void)cfg_map_get(vconfig, "server", &servers);
1178                 if (servers != NULL &&
1179                     check_servers(servers, logctx) != ISC_R_SUCCESS)
1180                         result = ISC_R_FAILURE;
1181         }
1182
1183         if (vconfig != NULL)
1184                 tresult = check_options(vconfig, logctx, mctx);
1185         else
1186                 tresult = check_options(config, logctx, mctx);
1187         if (tresult != ISC_R_SUCCESS)
1188                 result = tresult;
1189
1190         return (result);
1191 }
1192
1193
1194 isc_result_t
1195 bind9_check_namedconf(cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) {
1196         cfg_obj_t *options = NULL;
1197         cfg_obj_t *servers = NULL;
1198         cfg_obj_t *views = NULL;
1199         cfg_obj_t *acls = NULL;
1200         cfg_obj_t *kals = NULL;
1201         cfg_obj_t *obj;
1202         cfg_listelt_t *velement;
1203         isc_result_t result = ISC_R_SUCCESS;
1204         isc_result_t tresult;
1205         isc_symtab_t *symtab = NULL;
1206
1207         static const char *builtin[] = { "localhost", "localnets",
1208                                          "any", "none"};
1209
1210         (void)cfg_map_get(config, "options", &options);
1211
1212         if (options != NULL &&
1213             check_options(options, logctx, mctx) != ISC_R_SUCCESS)
1214                 result = ISC_R_FAILURE;
1215
1216         (void)cfg_map_get(config, "server", &servers);
1217         if (servers != NULL &&
1218             check_servers(servers, logctx) != ISC_R_SUCCESS)
1219                 result = ISC_R_FAILURE;
1220
1221         if (options != NULL && 
1222             check_order(options, logctx) != ISC_R_SUCCESS)
1223                 result = ISC_R_FAILURE;
1224
1225         (void)cfg_map_get(config, "view", &views);
1226
1227         if (views != NULL && options != NULL)
1228                 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1229                         result = ISC_R_FAILURE;
1230
1231         if (views == NULL) {
1232                 if (check_viewconf(config, NULL, dns_rdataclass_in,
1233                                    logctx, mctx) != ISC_R_SUCCESS)
1234                         result = ISC_R_FAILURE;
1235         } else {
1236                 cfg_obj_t *zones = NULL;
1237
1238                 (void)cfg_map_get(config, "zone", &zones);
1239                 if (zones != NULL) {
1240                         cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
1241                                     "when using 'view' statements, "
1242                                     "all zones must be in views");
1243                         result = ISC_R_FAILURE;
1244                 }
1245         }
1246
1247         tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
1248         if (tresult != ISC_R_SUCCESS)
1249                 result = tresult;
1250         for (velement = cfg_list_first(views);
1251              velement != NULL;
1252              velement = cfg_list_next(velement))
1253         {
1254                 cfg_obj_t *view = cfg_listelt_value(velement);
1255                 cfg_obj_t *vname = cfg_tuple_get(view, "name");
1256                 cfg_obj_t *voptions = cfg_tuple_get(view, "options");
1257                 cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
1258                 dns_rdataclass_t vclass = dns_rdataclass_in;
1259                 isc_result_t tresult = ISC_R_SUCCESS;
1260                 const char *key = cfg_obj_asstring(vname);
1261                 isc_symvalue_t symvalue;
1262
1263                 if (cfg_obj_isstring(vclassobj)) {
1264                         isc_textregion_t r;
1265
1266                         DE_CONST(cfg_obj_asstring(vclassobj), r.base);
1267                         r.length = strlen(r.base);
1268                         tresult = dns_rdataclass_fromtext(&vclass, &r);
1269                         if (tresult != ISC_R_SUCCESS)
1270                                 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
1271                                             "view '%s': invalid class %s",
1272                                             cfg_obj_asstring(vname), r.base);
1273                 }
1274                 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
1275                         symvalue.as_pointer = view;
1276                         tresult = isc_symtab_define(symtab, key, vclass,
1277                                                     symvalue,
1278                                                     isc_symexists_reject);
1279                         if (tresult == ISC_R_EXISTS) {
1280                                 const char *file;
1281                                 unsigned int line;
1282                                 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
1283                                            vclass, &symvalue) == ISC_R_SUCCESS);
1284                                 file = cfg_obj_file(symvalue.as_pointer);
1285                                 line = cfg_obj_line(symvalue.as_pointer);
1286                                 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
1287                                             "view '%s': already exists "
1288                                             "previous definition: %s:%u",
1289                                             key, file, line);
1290                                 result = tresult;
1291                         } else if (result != ISC_R_SUCCESS) {
1292                                 result = tresult;
1293                         } else if ((strcasecmp(key, "_bind") == 0 &&
1294                                     vclass == dns_rdataclass_ch) ||
1295                                    (strcasecmp(key, "_default") == 0 &&
1296                                     vclass == dns_rdataclass_in)) {
1297                                 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
1298                                             "attempt to redefine builtin view "
1299                                             "'%s'", key);
1300                                 result = ISC_R_EXISTS;
1301                         }
1302                 }
1303                 if (tresult == ISC_R_SUCCESS)
1304                         tresult = check_viewconf(config, voptions,
1305                                                  vclass, logctx, mctx);
1306                 if (tresult != ISC_R_SUCCESS)
1307                         result = ISC_R_FAILURE;
1308         }
1309         if (symtab != NULL)
1310                 isc_symtab_destroy(&symtab);
1311
1312         if (views != NULL && options != NULL) {
1313                 obj = NULL;
1314                 tresult = cfg_map_get(options, "cache-file", &obj);
1315                 if (tresult == ISC_R_SUCCESS) {
1316                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1317                                     "'cache-file' cannot be a global "
1318                                     "option if views are present");
1319                         result = ISC_R_FAILURE;
1320                 }
1321         }
1322
1323         tresult = cfg_map_get(config, "acl", &acls);
1324         if (tresult == ISC_R_SUCCESS) {
1325                 cfg_listelt_t *elt;
1326                 cfg_listelt_t *elt2;
1327                 const char *aclname;
1328
1329                 for (elt = cfg_list_first(acls);
1330                      elt != NULL;
1331                      elt = cfg_list_next(elt)) {
1332                         cfg_obj_t *acl = cfg_listelt_value(elt);
1333                         unsigned int i;
1334
1335                         aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
1336                         for (i = 0;
1337                              i < sizeof(builtin) / sizeof(builtin[0]);
1338                              i++)
1339                                 if (strcasecmp(aclname, builtin[i]) == 0) {
1340                                         cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
1341                                                     "attempt to redefine "
1342                                                     "builtin acl '%s'",
1343                                                     aclname);
1344                                         result = ISC_R_FAILURE;
1345                                         break;
1346                                 }
1347
1348                         for (elt2 = cfg_list_next(elt);
1349                              elt2 != NULL;
1350                              elt2 = cfg_list_next(elt2)) {
1351                                 cfg_obj_t *acl2 = cfg_listelt_value(elt2);
1352                                 const char *name;
1353                                 name = cfg_obj_asstring(cfg_tuple_get(acl2,
1354                                                                       "name"));
1355                                 if (strcasecmp(aclname, name) == 0) {
1356                                         const char *file = cfg_obj_file(acl);
1357                                         unsigned int line = cfg_obj_line(acl);
1358
1359                                         if (file == NULL)
1360                                                 file = "<unknown file>";
1361
1362                                         cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
1363                                                     "attempt to redefine "
1364                                                     "acl '%s' previous "
1365                                                     "definition: %s:%u",
1366                                                      name, file, line);
1367                                         result = ISC_R_FAILURE;
1368                                 }
1369                         }
1370                 }
1371         }
1372
1373         tresult = cfg_map_get(config, "kal", &kals);
1374         if (tresult == ISC_R_SUCCESS) {
1375                 cfg_listelt_t *elt;
1376                 cfg_listelt_t *elt2;
1377                 const char *aclname;
1378
1379                 for (elt = cfg_list_first(kals);
1380                      elt != NULL;
1381                      elt = cfg_list_next(elt)) {
1382                         cfg_obj_t *acl = cfg_listelt_value(elt);
1383
1384                         aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
1385
1386                         for (elt2 = cfg_list_next(elt);
1387                              elt2 != NULL;
1388                              elt2 = cfg_list_next(elt2)) {
1389                                 cfg_obj_t *acl2 = cfg_listelt_value(elt2);
1390                                 const char *name;
1391                                 name = cfg_obj_asstring(cfg_tuple_get(acl2,
1392                                                                       "name"));
1393                                 if (strcasecmp(aclname, name) == 0) {
1394                                         const char *file = cfg_obj_file(acl);
1395                                         unsigned int line = cfg_obj_line(acl);
1396
1397                                         if (file == NULL)
1398                                                 file = "<unknown file>";
1399
1400                                         cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
1401                                                     "attempt to redefine "
1402                                                     "kal '%s' previous "
1403                                                     "definition: %s:%u",
1404                                                      name, file, line);
1405                                         result = ISC_R_FAILURE;
1406                                 }
1407                         }
1408                 }
1409         }
1410
1411         return (result);
1412 }