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