2 * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2001-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or 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.
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.
18 /* $Id: check.c,v 1.44.18.41 2008/03/29 23:46:10 tbox Exp $ */
26 #include <isc/buffer.h>
29 #include <isc/netaddr.h>
30 #include <isc/parseint.h>
31 #include <isc/region.h>
32 #include <isc/result.h>
33 #include <isc/sockaddr.h>
34 #include <isc/string.h>
35 #include <isc/symtab.h>
39 #include <dns/fixedname.h>
40 #include <dns/rdataclass.h>
41 #include <dns/rdatatype.h>
42 #include <dns/secalg.h>
44 #include <isccfg/aclconf.h>
45 #include <isccfg/cfg.h>
47 #include <bind9/check.h>
49 #ifndef DNS_RDATASET_FIXED
50 #define DNS_RDATASET_FIXED 1
54 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
57 isc_mem_free(userarg, key);
61 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
62 isc_result_t result = ISC_R_SUCCESS;
65 dns_fixedname_t fixed;
67 dns_rdataclass_t rdclass;
68 dns_rdatatype_t rdtype;
72 dns_fixedname_init(&fixed);
73 obj = cfg_tuple_get(ent, "class");
74 if (cfg_obj_isstring(obj)) {
76 DE_CONST(cfg_obj_asstring(obj), r.base);
77 r.length = strlen(r.base);
78 tresult = dns_rdataclass_fromtext(&rdclass, &r);
79 if (tresult != ISC_R_SUCCESS) {
80 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
81 "rrset-order: invalid class '%s'",
83 result = ISC_R_FAILURE;
87 obj = cfg_tuple_get(ent, "type");
88 if (cfg_obj_isstring(obj)) {
90 DE_CONST(cfg_obj_asstring(obj), r.base);
91 r.length = strlen(r.base);
92 tresult = dns_rdatatype_fromtext(&rdtype, &r);
93 if (tresult != ISC_R_SUCCESS) {
94 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
95 "rrset-order: invalid type '%s'",
97 result = ISC_R_FAILURE;
101 obj = cfg_tuple_get(ent, "name");
102 if (cfg_obj_isstring(obj)) {
103 str = cfg_obj_asstring(obj);
104 isc_buffer_init(&b, str, strlen(str));
105 isc_buffer_add(&b, strlen(str));
106 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
107 dns_rootname, ISC_FALSE, NULL);
108 if (tresult != ISC_R_SUCCESS) {
109 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
110 "rrset-order: invalid name '%s'", str);
111 result = ISC_R_FAILURE;
115 obj = cfg_tuple_get(ent, "order");
116 if (!cfg_obj_isstring(obj) ||
117 strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
118 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
119 "rrset-order: keyword 'order' missing");
120 result = ISC_R_FAILURE;
123 obj = cfg_tuple_get(ent, "ordering");
124 if (!cfg_obj_isstring(obj)) {
125 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
126 "rrset-order: missing ordering");
127 result = ISC_R_FAILURE;
128 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
129 #if !DNS_RDATASET_FIXED
130 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
131 "rrset-order: order 'fixed' not fully implemented");
133 } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
134 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
135 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
136 "rrset-order: invalid order '%s'",
137 cfg_obj_asstring(obj));
138 result = ISC_R_FAILURE;
144 check_order(const cfg_obj_t *options, isc_log_t *logctx) {
145 isc_result_t result = ISC_R_SUCCESS;
146 isc_result_t tresult;
147 const cfg_listelt_t *element;
148 const cfg_obj_t *obj = NULL;
150 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
153 for (element = cfg_list_first(obj);
155 element = cfg_list_next(element))
157 tresult = check_orderent(cfg_listelt_value(element), logctx);
158 if (tresult != ISC_R_SUCCESS)
165 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
166 const cfg_listelt_t *element;
167 const cfg_obj_t *alternates = NULL;
168 const cfg_obj_t *value;
169 const cfg_obj_t *obj;
171 dns_fixedname_t fixed;
174 isc_result_t result = ISC_R_SUCCESS;
175 isc_result_t tresult;
177 (void)cfg_map_get(options, "dual-stack-servers", &alternates);
179 if (alternates == NULL)
180 return (ISC_R_SUCCESS);
182 obj = cfg_tuple_get(alternates, "port");
183 if (cfg_obj_isuint32(obj)) {
184 isc_uint32_t val = cfg_obj_asuint32(obj);
185 if (val > ISC_UINT16_MAX) {
186 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
187 "port '%u' out of range", val);
188 result = ISC_R_FAILURE;
191 obj = cfg_tuple_get(alternates, "addresses");
192 for (element = cfg_list_first(obj);
194 element = cfg_list_next(element)) {
195 value = cfg_listelt_value(element);
196 if (cfg_obj_issockaddr(value))
198 obj = cfg_tuple_get(value, "name");
199 str = cfg_obj_asstring(obj);
200 isc_buffer_init(&buffer, str, strlen(str));
201 isc_buffer_add(&buffer, strlen(str));
202 dns_fixedname_init(&fixed);
203 name = dns_fixedname_name(&fixed);
204 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
206 if (tresult != ISC_R_SUCCESS) {
207 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
208 "bad name '%s'", str);
209 result = ISC_R_FAILURE;
211 obj = cfg_tuple_get(value, "port");
212 if (cfg_obj_isuint32(obj)) {
213 isc_uint32_t val = cfg_obj_asuint32(obj);
214 if (val > ISC_UINT16_MAX) {
215 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
216 "port '%u' out of range", val);
217 result = ISC_R_FAILURE;
225 check_forward(const cfg_obj_t *options, const cfg_obj_t *global,
228 const cfg_obj_t *forward = NULL;
229 const cfg_obj_t *forwarders = NULL;
231 (void)cfg_map_get(options, "forward", &forward);
232 (void)cfg_map_get(options, "forwarders", &forwarders);
234 if (forwarders != NULL && global != NULL) {
235 const char *file = cfg_obj_file(global);
236 unsigned int line = cfg_obj_line(global);
237 cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
238 "forwarders declared in root zone and "
239 "in general configuration: %s:%u",
241 return (ISC_R_FAILURE);
243 if (forward != NULL && forwarders == NULL) {
244 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
245 "no matching 'forwarders' statement");
246 return (ISC_R_FAILURE);
248 return (ISC_R_SUCCESS);
252 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
253 isc_result_t result = ISC_R_SUCCESS;
254 isc_result_t tresult;
255 const cfg_listelt_t *element;
258 dns_fixedname_t fixed;
260 const cfg_obj_t *obj;
262 dns_fixedname_init(&fixed);
263 name = dns_fixedname_name(&fixed);
264 obj = cfg_tuple_get(disabled, "name");
265 str = cfg_obj_asstring(obj);
266 isc_buffer_init(&b, str, strlen(str));
267 isc_buffer_add(&b, strlen(str));
268 tresult = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
269 if (tresult != ISC_R_SUCCESS) {
270 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
271 "bad domain name '%s'", str);
275 obj = cfg_tuple_get(disabled, "algorithms");
277 for (element = cfg_list_first(obj);
279 element = cfg_list_next(element))
283 isc_result_t tresult;
285 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
286 r.length = strlen(r.base);
288 tresult = dns_secalg_fromtext(&alg, &r);
289 if (tresult != ISC_R_SUCCESS) {
291 result = isc_parse_uint8(&ui, r.base, 10);
293 if (tresult != ISC_R_SUCCESS) {
294 cfg_obj_log(cfg_listelt_value(element), logctx,
295 ISC_LOG_ERROR, "invalid algorithm '%s'",
304 nameexist(const cfg_obj_t *obj, const char *name, int value,
305 isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
312 isc_symvalue_t symvalue;
314 key = isc_mem_strdup(mctx, name);
316 return (ISC_R_NOMEMORY);
317 symvalue.as_cpointer = obj;
318 result = isc_symtab_define(symtab, key, value, symvalue,
319 isc_symexists_reject);
320 if (result == ISC_R_EXISTS) {
321 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
322 &symvalue) == ISC_R_SUCCESS);
323 file = cfg_obj_file(symvalue.as_cpointer);
324 line = cfg_obj_line(symvalue.as_cpointer);
327 file = "<unknown file>";
328 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
329 isc_mem_free(mctx, key);
330 result = ISC_R_EXISTS;
331 } else if (result != ISC_R_SUCCESS) {
332 isc_mem_free(mctx, key);
338 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
341 const cfg_obj_t *obj;
342 char namebuf[DNS_NAME_FORMATSIZE];
344 dns_fixedname_t fixed;
347 isc_result_t result = ISC_R_SUCCESS;
349 dns_fixedname_init(&fixed);
350 name = dns_fixedname_name(&fixed);
351 obj = cfg_tuple_get(secure, "name");
352 str = cfg_obj_asstring(obj);
353 isc_buffer_init(&b, str, strlen(str));
354 isc_buffer_add(&b, strlen(str));
355 result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
356 if (result != ISC_R_SUCCESS) {
357 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
358 "bad domain name '%s'", str);
360 dns_name_format(name, namebuf, sizeof(namebuf));
361 result = nameexist(secure, namebuf, 1, symtab,
362 "dnssec-must-be-secure '%s': already "
363 "exists previous definition: %s:%u",
370 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
371 const cfg_obj_t *voptions, const cfg_obj_t *config,
372 isc_log_t *logctx, isc_mem_t *mctx)
375 const cfg_obj_t *aclobj = NULL;
376 const cfg_obj_t *options;
377 dns_acl_t *acl = NULL;
379 if (zconfig != NULL) {
380 options = cfg_tuple_get(zconfig, "options");
381 cfg_map_get(options, aclname, &aclobj);
383 if (voptions != NULL && aclobj == NULL)
384 cfg_map_get(voptions, aclname, &aclobj);
385 if (config != NULL && aclobj == NULL) {
387 cfg_map_get(config, "options", &options);
389 cfg_map_get(options, aclname, &aclobj);
392 return (ISC_R_SUCCESS);
393 result = cfg_acl_fromconfig(aclobj, config, logctx, actx, mctx, &acl);
395 dns_acl_detach(&acl);
400 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
401 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
403 isc_result_t result = ISC_R_SUCCESS, tresult;
406 static const char *acls[] = { "allow-query", "allow-query-cache",
407 "allow-recursion", "blackhole", "match-clients",
408 "match-destinations", "sortlist", NULL };
410 while (acls[i] != NULL) {
411 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
413 if (tresult != ISC_R_SUCCESS)
426 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
427 isc_result_t result = ISC_R_SUCCESS;
428 isc_result_t tresult;
430 const cfg_obj_t *obj = NULL;
431 const cfg_listelt_t *element;
432 isc_symtab_t *symtab = NULL;
433 dns_fixedname_t fixed;
438 static intervaltable intervals[] = {
439 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
440 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
441 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
442 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
443 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
444 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
445 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
446 { "sig-validity-interval", 86400, 10 * 366 }, /* 10 years */
447 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
451 * Check that fields specified in units of time other than seconds
452 * have reasonable values.
454 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
457 (void)cfg_map_get(options, intervals[i].name, &obj);
460 val = cfg_obj_asuint32(obj);
461 if (val > intervals[i].max) {
462 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
463 "%s '%u' is out of range (0..%u)",
464 intervals[i].name, val,
466 result = ISC_R_RANGE;
467 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
468 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
469 "%s '%d' is out of range",
470 intervals[i].name, val);
471 result = ISC_R_RANGE;
475 (void)cfg_map_get(options, "preferred-glue", &obj);
478 str = cfg_obj_asstring(obj);
479 if (strcasecmp(str, "a") != 0 &&
480 strcasecmp(str, "aaaa") != 0 &&
481 strcasecmp(str, "none") != 0)
482 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
483 "preferred-glue unexpected value '%s'",
487 (void)cfg_map_get(options, "root-delegation-only", &obj);
489 if (!cfg_obj_isvoid(obj)) {
490 const cfg_listelt_t *element;
491 const cfg_obj_t *exclude;
493 dns_fixedname_t fixed;
497 dns_fixedname_init(&fixed);
498 name = dns_fixedname_name(&fixed);
499 for (element = cfg_list_first(obj);
501 element = cfg_list_next(element)) {
502 exclude = cfg_listelt_value(element);
503 str = cfg_obj_asstring(exclude);
504 isc_buffer_init(&b, str, strlen(str));
505 isc_buffer_add(&b, strlen(str));
506 tresult = dns_name_fromtext(name, &b,
509 if (tresult != ISC_R_SUCCESS) {
510 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
511 "bad domain name '%s'",
520 * Set supported DNSSEC algorithms.
523 (void)cfg_map_get(options, "disable-algorithms", &obj);
525 for (element = cfg_list_first(obj);
527 element = cfg_list_next(element))
529 obj = cfg_listelt_value(element);
530 tresult = disabled_algorithms(obj, logctx);
531 if (tresult != ISC_R_SUCCESS)
536 dns_fixedname_init(&fixed);
537 name = dns_fixedname_name(&fixed);
540 * Check the DLV zone name.
543 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
545 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
547 if (tresult != ISC_R_SUCCESS)
549 for (element = cfg_list_first(obj);
551 element = cfg_list_next(element))
555 obj = cfg_listelt_value(element);
557 dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain"));
558 isc_buffer_init(&b, dlv, strlen(dlv));
559 isc_buffer_add(&b, strlen(dlv));
560 tresult = dns_name_fromtext(name, &b, dns_rootname,
562 if (tresult != ISC_R_SUCCESS) {
563 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
564 "bad domain name '%s'", dlv);
568 if (symtab != NULL) {
569 tresult = nameexist(obj, dlv, 1, symtab,
570 "dnssec-lookaside '%s': "
571 "already exists previous "
574 if (tresult != ISC_R_SUCCESS &&
575 result == ISC_R_SUCCESS)
579 * XXXMPA to be removed when multiple lookaside
580 * namespaces are supported.
582 if (!dns_name_equal(dns_rootname, name)) {
583 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
584 "dnssec-lookaside '%s': "
585 "non-root not yet supported", dlv);
586 if (result == ISC_R_SUCCESS)
587 result = ISC_R_FAILURE;
589 dlv = cfg_obj_asstring(cfg_tuple_get(obj,
591 isc_buffer_init(&b, dlv, strlen(dlv));
592 isc_buffer_add(&b, strlen(dlv));
593 tresult = dns_name_fromtext(name, &b, dns_rootname,
595 if (tresult != ISC_R_SUCCESS) {
596 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
597 "bad domain name '%s'", dlv);
598 if (result == ISC_R_SUCCESS)
603 isc_symtab_destroy(&symtab);
607 * Check dnssec-must-be-secure.
610 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
612 isc_symtab_t *symtab = NULL;
613 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
615 if (tresult != ISC_R_SUCCESS)
617 for (element = cfg_list_first(obj);
619 element = cfg_list_next(element))
621 obj = cfg_listelt_value(element);
622 tresult = mustbesecure(obj, symtab, logctx, mctx);
623 if (tresult != ISC_R_SUCCESS)
627 isc_symtab_destroy(&symtab);
631 * Check empty zone configuration.
634 (void)cfg_map_get(options, "empty-server", &obj);
636 str = cfg_obj_asstring(obj);
637 isc_buffer_init(&b, str, strlen(str));
638 isc_buffer_add(&b, strlen(str));
639 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
640 dns_rootname, ISC_FALSE, NULL);
641 if (tresult != ISC_R_SUCCESS) {
642 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
643 "empty-server: invalid name '%s'", str);
644 result = ISC_R_FAILURE;
649 (void)cfg_map_get(options, "empty-contact", &obj);
651 str = cfg_obj_asstring(obj);
652 isc_buffer_init(&b, str, strlen(str));
653 isc_buffer_add(&b, strlen(str));
654 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
655 dns_rootname, ISC_FALSE, NULL);
656 if (tresult != ISC_R_SUCCESS) {
657 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
658 "empty-contact: invalid name '%s'", str);
659 result = ISC_R_FAILURE;
664 (void)cfg_map_get(options, "disable-empty-zone", &obj);
665 for (element = cfg_list_first(obj);
667 element = cfg_list_next(element))
669 obj = cfg_listelt_value(element);
670 str = cfg_obj_asstring(obj);
671 isc_buffer_init(&b, str, strlen(str));
672 isc_buffer_add(&b, strlen(str));
673 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
674 dns_rootname, ISC_FALSE, NULL);
675 if (tresult != ISC_R_SUCCESS) {
676 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
677 "disable-empty-zone: invalid name '%s'",
679 result = ISC_R_FAILURE;
687 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
689 const cfg_obj_t *masters = NULL;
690 const cfg_listelt_t *elt;
692 result = cfg_map_get(cctx, "masters", &masters);
693 if (result != ISC_R_SUCCESS)
695 for (elt = cfg_list_first(masters);
697 elt = cfg_list_next(elt)) {
698 const cfg_obj_t *list;
699 const char *listname;
701 list = cfg_listelt_value(elt);
702 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
704 if (strcasecmp(listname, name) == 0) {
706 return (ISC_R_SUCCESS);
709 return (ISC_R_NOTFOUND);
713 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
714 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
716 isc_result_t result = ISC_R_SUCCESS;
717 isc_result_t tresult;
718 isc_uint32_t count = 0;
719 isc_symtab_t *symtab = NULL;
720 isc_symvalue_t symvalue;
721 const cfg_listelt_t *element;
722 const cfg_listelt_t **stack = NULL;
723 isc_uint32_t stackcount = 0, pushed = 0;
724 const cfg_obj_t *list;
726 REQUIRE(countp != NULL);
727 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
728 if (result != ISC_R_SUCCESS) {
734 list = cfg_tuple_get(obj, "addresses");
735 element = cfg_list_first(list);
739 element = cfg_list_next(element))
741 const char *listname;
742 const cfg_obj_t *addr;
743 const cfg_obj_t *key;
745 addr = cfg_tuple_get(cfg_listelt_value(element),
747 key = cfg_tuple_get(cfg_listelt_value(element), "key");
749 if (cfg_obj_issockaddr(addr)) {
753 if (!cfg_obj_isvoid(key)) {
754 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
755 "unexpected token '%s'",
756 cfg_obj_asstring(key));
757 if (result == ISC_R_SUCCESS)
758 result = ISC_R_FAILURE;
760 listname = cfg_obj_asstring(addr);
761 symvalue.as_cpointer = addr;
762 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
763 isc_symexists_reject);
764 if (tresult == ISC_R_EXISTS)
766 tresult = get_masters_def(config, listname, &obj);
767 if (tresult != ISC_R_SUCCESS) {
768 if (result == ISC_R_SUCCESS)
770 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
771 "unable to find masters list '%s'",
776 if (stackcount == pushed) {
778 isc_uint32_t newlen = stackcount + 16;
779 size_t newsize, oldsize;
781 newsize = newlen * sizeof(*stack);
782 oldsize = stackcount * sizeof(*stack);
783 new = isc_mem_get(mctx, newsize);
786 if (stackcount != 0) {
787 memcpy(new, stack, oldsize);
788 isc_mem_put(mctx, stack, oldsize);
793 stack[pushed++] = cfg_list_next(element);
797 element = stack[--pushed];
802 isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
803 isc_symtab_destroy(&symtab);
809 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
810 isc_result_t result = ISC_R_SUCCESS;
811 isc_result_t tresult;
812 const cfg_listelt_t *element;
813 const cfg_listelt_t *element2;
814 dns_fixedname_t fixed;
818 for (element = cfg_list_first(policy);
820 element = cfg_list_next(element))
822 const cfg_obj_t *stmt = cfg_listelt_value(element);
823 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
824 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
825 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
826 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
828 dns_fixedname_init(&fixed);
829 str = cfg_obj_asstring(identity);
830 isc_buffer_init(&b, str, strlen(str));
831 isc_buffer_add(&b, strlen(str));
832 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
833 dns_rootname, ISC_FALSE, NULL);
834 if (tresult != ISC_R_SUCCESS) {
835 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
836 "'%s' is not a valid name", str);
840 dns_fixedname_init(&fixed);
841 str = cfg_obj_asstring(dname);
842 isc_buffer_init(&b, str, strlen(str));
843 isc_buffer_add(&b, strlen(str));
844 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
845 dns_rootname, ISC_FALSE, NULL);
846 if (tresult != ISC_R_SUCCESS) {
847 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
848 "'%s' is not a valid name", str);
851 if (tresult == ISC_R_SUCCESS &&
852 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
853 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
854 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
855 "'%s' is not a wildcard", str);
856 result = ISC_R_FAILURE;
859 for (element2 = cfg_list_first(typelist);
861 element2 = cfg_list_next(element2))
863 const cfg_obj_t *typeobj;
865 dns_rdatatype_t type;
867 typeobj = cfg_listelt_value(element2);
868 DE_CONST(cfg_obj_asstring(typeobj), r.base);
869 r.length = strlen(r.base);
871 tresult = dns_rdatatype_fromtext(&type, &r);
872 if (tresult != ISC_R_SUCCESS) {
873 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
874 "'%s' is not a valid type", r.base);
886 #define FORWARDZONE 16
887 #define DELEGATIONZONE 32
896 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
897 const cfg_obj_t *config, isc_symtab_t *symtab,
898 dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
899 isc_log_t *logctx, isc_mem_t *mctx)
904 const cfg_obj_t *zoptions;
905 const cfg_obj_t *obj = NULL;
906 isc_result_t result = ISC_R_SUCCESS;
907 isc_result_t tresult;
909 dns_rdataclass_t zclass;
910 dns_fixedname_t fixedname;
912 isc_boolean_t root = ISC_FALSE;
914 static optionstable options[] = {
915 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL },
916 { "allow-notify", SLAVEZONE | CHECKACL },
917 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
918 { "notify", MASTERZONE | SLAVEZONE },
919 { "also-notify", MASTERZONE | SLAVEZONE },
920 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
921 { "delegation-only", HINTZONE | STUBZONE },
922 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
923 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
924 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
925 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
926 { "notify-source", MASTERZONE | SLAVEZONE },
927 { "notify-source-v6", MASTERZONE | SLAVEZONE },
928 { "transfer-source", SLAVEZONE | STUBZONE },
929 { "transfer-source-v6", SLAVEZONE | STUBZONE },
930 { "max-transfer-time-in", SLAVEZONE | STUBZONE },
931 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
932 { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
933 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
934 { "max-retry-time", SLAVEZONE | STUBZONE },
935 { "min-retry-time", SLAVEZONE | STUBZONE },
936 { "max-refresh-time", SLAVEZONE | STUBZONE },
937 { "min-refresh-time", SLAVEZONE | STUBZONE },
938 { "sig-validity-interval", MASTERZONE },
939 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE },
940 { "allow-update", MASTERZONE | CHECKACL },
941 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
942 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
943 { "journal", MASTERZONE | SLAVEZONE },
944 { "ixfr-base", MASTERZONE | SLAVEZONE },
945 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
946 { "masters", SLAVEZONE | STUBZONE },
947 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
948 { "update-policy", MASTERZONE },
949 { "database", MASTERZONE | SLAVEZONE | STUBZONE },
950 { "key-directory", MASTERZONE },
951 { "check-wildcard", MASTERZONE },
952 { "check-mx", MASTERZONE },
953 { "integrity-check", MASTERZONE },
954 { "check-mx-cname", MASTERZONE },
955 { "check-srv-cname", MASTERZONE },
956 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
957 { "update-check-ksk", MASTERZONE },
960 static optionstable dialups[] = {
961 { "notify", MASTERZONE | SLAVEZONE },
962 { "notify-passive", SLAVEZONE },
963 { "refresh", SLAVEZONE | STUBZONE },
964 { "passive", SLAVEZONE | STUBZONE },
967 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
969 zoptions = cfg_tuple_get(zconfig, "options");
972 (void)cfg_map_get(zoptions, "type", &obj);
974 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
975 "zone '%s': type not present", zname);
976 return (ISC_R_FAILURE);
979 typestr = cfg_obj_asstring(obj);
980 if (strcasecmp(typestr, "master") == 0)
982 else if (strcasecmp(typestr, "slave") == 0)
984 else if (strcasecmp(typestr, "stub") == 0)
986 else if (strcasecmp(typestr, "forward") == 0)
988 else if (strcasecmp(typestr, "hint") == 0)
990 else if (strcasecmp(typestr, "delegation-only") == 0)
991 ztype = DELEGATIONZONE;
993 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
994 "zone '%s': invalid type %s",
996 return (ISC_R_FAILURE);
999 obj = cfg_tuple_get(zconfig, "class");
1000 if (cfg_obj_isstring(obj)) {
1003 DE_CONST(cfg_obj_asstring(obj), r.base);
1004 r.length = strlen(r.base);
1005 result = dns_rdataclass_fromtext(&zclass, &r);
1006 if (result != ISC_R_SUCCESS) {
1007 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1008 "zone '%s': invalid class %s",
1010 return (ISC_R_FAILURE);
1012 if (zclass != defclass) {
1013 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1014 "zone '%s': class '%s' does not "
1015 "match view/default class",
1017 return (ISC_R_FAILURE);
1022 * Look for an already existing zone.
1023 * We need to make this cannonical as isc_symtab_define()
1024 * deals with strings.
1026 dns_fixedname_init(&fixedname);
1027 isc_buffer_init(&b, zname, strlen(zname));
1028 isc_buffer_add(&b, strlen(zname));
1029 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1030 dns_rootname, ISC_TRUE, NULL);
1031 if (tresult != ISC_R_SUCCESS) {
1032 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1033 "zone '%s': is not a valid name", zname);
1034 result = ISC_R_FAILURE;
1036 char namebuf[DNS_NAME_FORMATSIZE];
1038 dns_name_format(dns_fixedname_name(&fixedname),
1039 namebuf, sizeof(namebuf));
1040 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
1041 symtab, "zone '%s': already exists "
1042 "previous definition: %s:%u", logctx, mctx);
1043 if (tresult != ISC_R_SUCCESS)
1045 if (dns_name_equal(dns_fixedname_name(&fixedname),
1051 * Look for inappropriate options for the given zone type.
1052 * Check that ACLs expand correctly.
1054 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1056 if ((options[i].allowed & ztype) == 0 &&
1057 cfg_map_get(zoptions, options[i].name, &obj) ==
1060 if (strcmp(options[i].name, "allow-update") != 0 ||
1061 ztype != SLAVEZONE) {
1062 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1063 "option '%s' is not allowed "
1064 "in '%s' zone '%s'",
1065 options[i].name, typestr, zname);
1066 result = ISC_R_FAILURE;
1068 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1069 "option '%s' is not allowed "
1070 "in '%s' zone '%s'",
1071 options[i].name, typestr, zname);
1074 if ((options[i].allowed & ztype) != 0 &&
1075 (options[i].allowed & CHECKACL) != 0) {
1077 tresult = checkacl(options[i].name, actx, zconfig,
1078 voptions, config, logctx, mctx);
1079 if (tresult != ISC_R_SUCCESS)
1086 * Slave & stub zones must have a "masters" field.
1088 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1090 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1091 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1092 "zone '%s': missing 'masters' entry",
1094 result = ISC_R_FAILURE;
1097 tresult = validate_masters(obj, config, &count,
1099 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1101 if (tresult == ISC_R_SUCCESS && count == 0) {
1102 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1103 "zone '%s': empty 'masters' entry",
1105 result = ISC_R_FAILURE;
1111 * Master zones can't have both "allow-update" and "update-policy".
1113 if (ztype == MASTERZONE) {
1114 isc_result_t res1, res2;
1116 res1 = cfg_map_get(zoptions, "allow-update", &obj);
1118 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1119 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1120 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1121 "zone '%s': 'allow-update' is ignored "
1122 "when 'update-policy' is present",
1124 result = ISC_R_FAILURE;
1125 } else if (res2 == ISC_R_SUCCESS &&
1126 check_update_policy(obj, logctx) != ISC_R_SUCCESS)
1127 result = ISC_R_FAILURE;
1131 * Check the excessively complicated "dialup" option.
1133 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1134 const cfg_obj_t *dialup = NULL;
1135 (void)cfg_map_get(zoptions, "dialup", &dialup);
1136 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1137 const char *str = cfg_obj_asstring(dialup);
1139 i < sizeof(dialups) / sizeof(dialups[0]);
1142 if (strcasecmp(dialups[i].name, str) != 0)
1144 if ((dialups[i].allowed & ztype) == 0) {
1145 cfg_obj_log(obj, logctx,
1147 "dialup type '%s' is not "
1150 str, typestr, zname);
1151 result = ISC_R_FAILURE;
1155 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1156 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1157 "invalid dialup type '%s' in zone "
1158 "'%s'", str, zname);
1159 result = ISC_R_FAILURE;
1165 * Check that forwarding is reasonable.
1169 if (voptions != NULL)
1170 (void)cfg_map_get(voptions, "forwarders", &obj);
1172 const cfg_obj_t *options = NULL;
1173 (void)cfg_map_get(config, "options", &options);
1174 if (options != NULL)
1175 (void)cfg_map_get(options, "forwarders", &obj);
1178 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
1179 result = ISC_R_FAILURE;
1182 * Check various options.
1184 tresult = check_options(zoptions, logctx, mctx);
1185 if (tresult != ISC_R_SUCCESS)
1189 * If the zone type is rbt/rbt64 then master/hint zones
1190 * require file clauses.
1193 tresult = cfg_map_get(zoptions, "database", &obj);
1194 if (tresult == ISC_R_NOTFOUND ||
1195 (tresult == ISC_R_SUCCESS &&
1196 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1197 strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
1199 tresult = cfg_map_get(zoptions, "file", &obj);
1200 if (tresult != ISC_R_SUCCESS &&
1201 (ztype == MASTERZONE || ztype == HINTZONE)) {
1202 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1203 "zone '%s': missing 'file' entry",
1213 typedef struct keyalgorithms {
1219 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1220 const cfg_obj_t *algobj = NULL;
1221 const cfg_obj_t *secretobj = NULL;
1222 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1223 const char *algorithm;
1226 static const algorithmtable algorithms[] = {
1227 { "hmac-md5", 128 },
1228 { "hmac-md5.sig-alg.reg.int", 0 },
1229 { "hmac-md5.sig-alg.reg.int.", 0 },
1230 { "hmac-sha1", 160 },
1231 { "hmac-sha224", 224 },
1232 { "hmac-sha256", 256 },
1233 { "hmac-sha384", 384 },
1234 { "hmac-sha512", 512 },
1238 (void)cfg_map_get(key, "algorithm", &algobj);
1239 (void)cfg_map_get(key, "secret", &secretobj);
1240 if (secretobj == NULL || algobj == NULL) {
1241 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1242 "key '%s' must have both 'secret' and "
1243 "'algorithm' defined",
1245 return (ISC_R_FAILURE);
1248 algorithm = cfg_obj_asstring(algobj);
1249 for (i = 0; algorithms[i].name != NULL; i++) {
1250 len = strlen(algorithms[i].name);
1251 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1252 (algorithm[len] == '\0' ||
1253 (algorithms[i].size != 0 && algorithm[len] == '-')))
1256 if (algorithms[i].name == NULL) {
1257 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1258 "unknown algorithm '%s'", algorithm);
1259 return (ISC_R_NOTFOUND);
1261 if (algorithm[len] == '-') {
1262 isc_uint16_t digestbits;
1263 isc_result_t result;
1264 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1265 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1266 if (result == ISC_R_RANGE ||
1267 digestbits > algorithms[i].size) {
1268 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1269 "key '%s' digest-bits too large "
1270 "[%u..%u]", keyname,
1271 algorithms[i].size / 2,
1272 algorithms[i].size);
1273 return (ISC_R_RANGE);
1275 if ((digestbits % 8) != 0) {
1276 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1277 "key '%s' digest-bits not multiple"
1279 return (ISC_R_RANGE);
1282 * Recommended minima for hmac algorithms.
1284 if ((digestbits < (algorithms[i].size / 2U) ||
1285 (digestbits < 80U)))
1286 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
1287 "key '%s' digest-bits too small "
1289 algorithms[i].size/2);
1291 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1292 "key '%s': unable to parse digest-bits",
1297 return (ISC_R_SUCCESS);
1301 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab, isc_log_t *logctx) {
1302 isc_result_t result = ISC_R_SUCCESS;
1303 isc_result_t tresult;
1304 const cfg_listelt_t *element;
1306 for (element = cfg_list_first(keys);
1308 element = cfg_list_next(element))
1310 const cfg_obj_t *key = cfg_listelt_value(element);
1311 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1312 isc_symvalue_t symvalue;
1314 tresult = bind9_check_key(key, logctx);
1315 if (tresult != ISC_R_SUCCESS)
1318 symvalue.as_cpointer = key;
1319 tresult = isc_symtab_define(symtab, keyname, 1,
1320 symvalue, isc_symexists_reject);
1321 if (tresult == ISC_R_EXISTS) {
1325 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
1326 1, &symvalue) == ISC_R_SUCCESS);
1327 file = cfg_obj_file(symvalue.as_cpointer);
1328 line = cfg_obj_line(symvalue.as_cpointer);
1331 file = "<unknown file>";
1332 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1333 "key '%s': already exists "
1334 "previous definition: %s:%u",
1335 keyname, file, line);
1337 } else if (tresult != ISC_R_SUCCESS)
1347 { "transfer-source", "transfer-source-v6" },
1348 { "notify-source", "notify-source-v6" },
1349 { "query-source", "query-source-v6" },
1354 check_servers(const cfg_obj_t *servers, isc_log_t *logctx) {
1355 isc_result_t result = ISC_R_SUCCESS;
1356 isc_result_t tresult;
1357 const cfg_listelt_t *e1, *e2;
1358 const cfg_obj_t *v1, *v2;
1359 isc_netaddr_t n1, n2;
1360 unsigned int p1, p2;
1361 const cfg_obj_t *obj;
1362 char buf[ISC_NETADDR_FORMATSIZE];
1366 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
1367 v1 = cfg_listelt_value(e1);
1368 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
1370 * Check that unused bits are zero.
1372 tresult = isc_netaddr_prefixok(&n1, p1);
1373 if (tresult != ISC_R_SUCCESS) {
1374 INSIST(tresult == ISC_R_FAILURE);
1375 isc_netaddr_format(&n1, buf, sizeof(buf));
1376 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1377 "server '%s/%u': invalid prefix "
1378 "(extra bits specified)", buf, p1);
1384 if (n1.family == AF_INET)
1385 xfr = sources[source].v6;
1387 xfr = sources[source].v4;
1388 (void)cfg_map_get(v1, xfr, &obj);
1390 isc_netaddr_format(&n1, buf, sizeof(buf));
1391 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1392 "server '%s': %s not legal",
1394 result = ISC_R_FAILURE;
1396 } while (sources[++source].v4 != NULL);
1398 while ((e2 = cfg_list_next(e2)) != NULL) {
1399 v2 = cfg_listelt_value(e2);
1400 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
1401 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
1402 const char *file = cfg_obj_file(v1);
1403 unsigned int line = cfg_obj_line(v1);
1406 file = "<unknown file>";
1408 isc_netaddr_format(&n2, buf, sizeof(buf));
1409 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
1410 "server '%s/%u': already exists "
1411 "previous definition: %s:%u",
1412 buf, p2, file, line);
1413 result = ISC_R_FAILURE;
1421 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
1422 dns_rdataclass_t vclass, isc_log_t *logctx, isc_mem_t *mctx)
1424 const cfg_obj_t *servers = NULL;
1425 const cfg_obj_t *zones = NULL;
1426 const cfg_obj_t *keys = NULL;
1427 const cfg_listelt_t *element;
1428 isc_symtab_t *symtab = NULL;
1429 isc_result_t result = ISC_R_SUCCESS;
1430 isc_result_t tresult = ISC_R_SUCCESS;
1431 cfg_aclconfctx_t actx;
1432 const cfg_obj_t *obj;
1433 isc_boolean_t enablednssec, enablevalidation;
1436 * Check that all zone statements are syntactically correct and
1437 * there are no duplicate zones.
1439 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1440 ISC_FALSE, &symtab);
1441 if (tresult != ISC_R_SUCCESS)
1442 return (ISC_R_NOMEMORY);
1444 cfg_aclconfctx_init(&actx);
1446 if (voptions != NULL)
1447 (void)cfg_map_get(voptions, "zone", &zones);
1449 (void)cfg_map_get(config, "zone", &zones);
1451 for (element = cfg_list_first(zones);
1453 element = cfg_list_next(element))
1455 isc_result_t tresult;
1456 const cfg_obj_t *zone = cfg_listelt_value(element);
1458 tresult = check_zoneconf(zone, voptions, config, symtab,
1459 vclass, &actx, logctx, mctx);
1460 if (tresult != ISC_R_SUCCESS)
1461 result = ISC_R_FAILURE;
1464 isc_symtab_destroy(&symtab);
1467 * Check that all key statements are syntactically correct and
1468 * there are no duplicate keys.
1470 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
1471 if (tresult != ISC_R_SUCCESS)
1472 return (ISC_R_NOMEMORY);
1474 (void)cfg_map_get(config, "key", &keys);
1475 tresult = check_keylist(keys, symtab, logctx);
1476 if (tresult == ISC_R_EXISTS)
1477 result = ISC_R_FAILURE;
1478 else if (tresult != ISC_R_SUCCESS) {
1479 isc_symtab_destroy(&symtab);
1483 if (voptions != NULL) {
1485 (void)cfg_map_get(voptions, "key", &keys);
1486 tresult = check_keylist(keys, symtab, logctx);
1487 if (tresult == ISC_R_EXISTS)
1488 result = ISC_R_FAILURE;
1489 else if (tresult != ISC_R_SUCCESS) {
1490 isc_symtab_destroy(&symtab);
1495 isc_symtab_destroy(&symtab);
1498 * Check that forwarding is reasonable.
1500 if (voptions == NULL) {
1501 const cfg_obj_t *options = NULL;
1502 (void)cfg_map_get(config, "options", &options);
1503 if (options != NULL)
1504 if (check_forward(options, NULL,
1505 logctx) != ISC_R_SUCCESS)
1506 result = ISC_R_FAILURE;
1508 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
1509 result = ISC_R_FAILURE;
1512 * Check that dual-stack-servers is reasonable.
1514 if (voptions == NULL) {
1515 const cfg_obj_t *options = NULL;
1516 (void)cfg_map_get(config, "options", &options);
1517 if (options != NULL)
1518 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1519 result = ISC_R_FAILURE;
1521 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
1522 result = ISC_R_FAILURE;
1526 * Check that rrset-order is reasonable.
1528 if (voptions != NULL) {
1529 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
1530 result = ISC_R_FAILURE;
1533 if (voptions != NULL) {
1534 (void)cfg_map_get(voptions, "server", &servers);
1535 if (servers != NULL &&
1536 check_servers(servers, logctx) != ISC_R_SUCCESS)
1537 result = ISC_R_FAILURE;
1541 * Check that dnssec-enable/dnssec-validation are sensible.
1544 if (voptions != NULL)
1545 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
1547 (void)cfg_map_get(config, "dnssec-enable", &obj);
1549 enablednssec = ISC_TRUE;
1551 enablednssec = cfg_obj_asboolean(obj);
1554 if (voptions != NULL)
1555 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
1557 (void)cfg_map_get(config, "dnssec-validation", &obj);
1559 enablevalidation = ISC_FALSE; /* XXXMPA Change for 9.5. */
1561 enablevalidation = cfg_obj_asboolean(obj);
1563 if (enablevalidation && !enablednssec)
1564 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1565 "'dnssec-validation yes;' and 'dnssec-enable no;'");
1567 if (voptions != NULL)
1568 tresult = check_options(voptions, logctx, mctx);
1570 tresult = check_options(config, logctx, mctx);
1571 if (tresult != ISC_R_SUCCESS)
1574 tresult = check_viewacls(&actx, voptions, config, logctx, mctx);
1575 if (tresult != ISC_R_SUCCESS)
1578 cfg_aclconfctx_destroy(&actx);
1584 default_channels[] = {
1593 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
1596 const cfg_obj_t *categories = NULL;
1597 const cfg_obj_t *category;
1598 const cfg_obj_t *channels = NULL;
1599 const cfg_obj_t *channel;
1600 const cfg_listelt_t *element;
1601 const cfg_listelt_t *delement;
1602 const char *channelname;
1603 const char *catname;
1604 const cfg_obj_t *fileobj = NULL;
1605 const cfg_obj_t *syslogobj = NULL;
1606 const cfg_obj_t *nullobj = NULL;
1607 const cfg_obj_t *stderrobj = NULL;
1608 const cfg_obj_t *logobj = NULL;
1609 isc_result_t result = ISC_R_SUCCESS;
1610 isc_result_t tresult;
1611 isc_symtab_t *symtab = NULL;
1612 isc_symvalue_t symvalue;
1615 (void)cfg_map_get(config, "logging", &logobj);
1617 return (ISC_R_SUCCESS);
1619 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1620 if (result != ISC_R_SUCCESS)
1623 symvalue.as_cpointer = NULL;
1624 for (i = 0; default_channels[i] != NULL; i++) {
1625 tresult = isc_symtab_define(symtab, default_channels[i], 1,
1626 symvalue, isc_symexists_replace);
1627 if (tresult != ISC_R_SUCCESS)
1631 cfg_map_get(logobj, "channel", &channels);
1633 for (element = cfg_list_first(channels);
1635 element = cfg_list_next(element))
1637 channel = cfg_listelt_value(element);
1638 channelname = cfg_obj_asstring(cfg_map_getname(channel));
1639 fileobj = syslogobj = nullobj = stderrobj = NULL;
1640 (void)cfg_map_get(channel, "file", &fileobj);
1641 (void)cfg_map_get(channel, "syslog", &syslogobj);
1642 (void)cfg_map_get(channel, "null", &nullobj);
1643 (void)cfg_map_get(channel, "stderr", &stderrobj);
1645 if (fileobj != NULL)
1647 if (syslogobj != NULL)
1649 if (nullobj != NULL)
1651 if (stderrobj != NULL)
1654 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
1655 "channel '%s': exactly one of file, syslog, "
1656 "null, and stderr must be present",
1658 result = ISC_R_FAILURE;
1660 tresult = isc_symtab_define(symtab, channelname, 1,
1661 symvalue, isc_symexists_replace);
1662 if (tresult != ISC_R_SUCCESS)
1666 cfg_map_get(logobj, "category", &categories);
1668 for (element = cfg_list_first(categories);
1670 element = cfg_list_next(element))
1672 category = cfg_listelt_value(element);
1673 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
1674 if (isc_log_categorybyname(logctx, catname) == NULL) {
1675 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
1676 "undefined category: '%s'", catname);
1677 result = ISC_R_FAILURE;
1679 channels = cfg_tuple_get(category, "destinations");
1680 for (delement = cfg_list_first(channels);
1682 delement = cfg_list_next(delement))
1684 channel = cfg_listelt_value(delement);
1685 channelname = cfg_obj_asstring(channel);
1686 tresult = isc_symtab_lookup(symtab, channelname, 1,
1688 if (tresult != ISC_R_SUCCESS) {
1689 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
1690 "undefined channel: '%s'",
1696 isc_symtab_destroy(&symtab);
1701 key_exists(const cfg_obj_t *keylist, const char *keyname) {
1702 const cfg_listelt_t *element;
1704 const cfg_obj_t *obj;
1706 if (keylist == NULL)
1707 return (ISC_R_NOTFOUND);
1708 for (element = cfg_list_first(keylist);
1710 element = cfg_list_next(element))
1712 obj = cfg_listelt_value(element);
1713 str = cfg_obj_asstring(cfg_map_getname(obj));
1714 if (strcasecmp(str, keyname) == 0)
1715 return (ISC_R_SUCCESS);
1717 return (ISC_R_NOTFOUND);
1721 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
1724 isc_result_t result = ISC_R_SUCCESS, tresult;
1725 const cfg_obj_t *control_keylist;
1726 const cfg_listelt_t *element;
1727 const cfg_obj_t *key;
1729 control_keylist = cfg_tuple_get(control, "keys");
1730 if (cfg_obj_isvoid(control_keylist))
1731 return (ISC_R_SUCCESS);
1733 for (element = cfg_list_first(control_keylist);
1735 element = cfg_list_next(element))
1737 key = cfg_listelt_value(element);
1738 tresult = key_exists(keylist, cfg_obj_asstring(key));
1739 if (tresult != ISC_R_SUCCESS) {
1740 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1741 "unknown key '%s'", cfg_obj_asstring(key));
1749 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
1752 isc_result_t result = ISC_R_SUCCESS, tresult;
1753 cfg_aclconfctx_t actx;
1754 const cfg_listelt_t *element, *element2;
1755 const cfg_obj_t *allow;
1756 const cfg_obj_t *control;
1757 const cfg_obj_t *controls;
1758 const cfg_obj_t *controlslist = NULL;
1759 const cfg_obj_t *inetcontrols;
1760 const cfg_obj_t *unixcontrols;
1761 const cfg_obj_t *keylist = NULL;
1763 isc_uint32_t perm, mask;
1764 dns_acl_t *acl = NULL;
1765 isc_sockaddr_t addr;
1768 (void)cfg_map_get(config, "controls", &controlslist);
1769 if (controlslist == NULL)
1770 return (ISC_R_SUCCESS);
1772 (void)cfg_map_get(config, "key", &keylist);
1774 cfg_aclconfctx_init(&actx);
1777 * INET: Check allow clause.
1778 * UNIX: Check "perm" for sanity, check path length.
1780 for (element = cfg_list_first(controlslist);
1782 element = cfg_list_next(element)) {
1783 controls = cfg_listelt_value(element);
1784 unixcontrols = NULL;
1785 inetcontrols = NULL;
1786 (void)cfg_map_get(controls, "unix", &unixcontrols);
1787 (void)cfg_map_get(controls, "inet", &inetcontrols);
1788 for (element2 = cfg_list_first(inetcontrols);
1790 element2 = cfg_list_next(element2)) {
1791 control = cfg_listelt_value(element2);
1792 allow = cfg_tuple_get(control, "allow");
1793 tresult = cfg_acl_fromconfig(allow, config, logctx,
1796 dns_acl_detach(&acl);
1797 if (tresult != ISC_R_SUCCESS)
1799 tresult = bind9_check_controlskeys(control, keylist,
1801 if (tresult != ISC_R_SUCCESS)
1804 for (element2 = cfg_list_first(unixcontrols);
1806 element2 = cfg_list_next(element2)) {
1807 control = cfg_listelt_value(element2);
1808 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
1809 tresult = isc_sockaddr_frompath(&addr, path);
1810 if (tresult == ISC_R_NOSPACE) {
1811 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
1812 "unix control '%s': path too long",
1814 result = ISC_R_NOSPACE;
1816 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
1817 for (i = 0; i < 3; i++) {
1818 #ifdef NEED_SECURE_DIRECTORY
1819 mask = (0x1 << (i*3)); /* SEARCH */
1821 mask = (0x6 << (i*3)); /* READ + WRITE */
1823 if ((perm & mask) == mask)
1827 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
1828 "unix control '%s' allows access "
1829 "to everyone", path);
1830 } else if (i == 3) {
1831 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
1832 "unix control '%s' allows access "
1835 tresult = bind9_check_controlskeys(control, keylist,
1837 if (tresult != ISC_R_SUCCESS)
1841 cfg_aclconfctx_destroy(&actx);
1846 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
1849 const cfg_obj_t *options = NULL;
1850 const cfg_obj_t *servers = NULL;
1851 const cfg_obj_t *views = NULL;
1852 const cfg_obj_t *acls = NULL;
1853 const cfg_obj_t *kals = NULL;
1854 const cfg_obj_t *obj;
1855 const cfg_listelt_t *velement;
1856 isc_result_t result = ISC_R_SUCCESS;
1857 isc_result_t tresult;
1858 isc_symtab_t *symtab = NULL;
1860 static const char *builtin[] = { "localhost", "localnets",
1863 (void)cfg_map_get(config, "options", &options);
1865 if (options != NULL &&
1866 check_options(options, logctx, mctx) != ISC_R_SUCCESS)
1867 result = ISC_R_FAILURE;
1869 (void)cfg_map_get(config, "server", &servers);
1870 if (servers != NULL &&
1871 check_servers(servers, logctx) != ISC_R_SUCCESS)
1872 result = ISC_R_FAILURE;
1874 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
1875 result = ISC_R_FAILURE;
1877 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
1878 result = ISC_R_FAILURE;
1880 if (options != NULL &&
1881 check_order(options, logctx) != ISC_R_SUCCESS)
1882 result = ISC_R_FAILURE;
1884 (void)cfg_map_get(config, "view", &views);
1886 if (views != NULL && options != NULL)
1887 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1888 result = ISC_R_FAILURE;
1890 if (views == NULL) {
1891 if (check_viewconf(config, NULL, dns_rdataclass_in,
1892 logctx, mctx) != ISC_R_SUCCESS)
1893 result = ISC_R_FAILURE;
1895 const cfg_obj_t *zones = NULL;
1897 (void)cfg_map_get(config, "zone", &zones);
1898 if (zones != NULL) {
1899 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
1900 "when using 'view' statements, "
1901 "all zones must be in views");
1902 result = ISC_R_FAILURE;
1906 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
1907 if (tresult != ISC_R_SUCCESS)
1909 for (velement = cfg_list_first(views);
1911 velement = cfg_list_next(velement))
1913 const cfg_obj_t *view = cfg_listelt_value(velement);
1914 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
1915 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
1916 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
1917 dns_rdataclass_t vclass = dns_rdataclass_in;
1918 isc_result_t tresult = ISC_R_SUCCESS;
1919 const char *key = cfg_obj_asstring(vname);
1920 isc_symvalue_t symvalue;
1922 if (cfg_obj_isstring(vclassobj)) {
1925 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
1926 r.length = strlen(r.base);
1927 tresult = dns_rdataclass_fromtext(&vclass, &r);
1928 if (tresult != ISC_R_SUCCESS)
1929 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
1930 "view '%s': invalid class %s",
1931 cfg_obj_asstring(vname), r.base);
1933 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
1934 symvalue.as_cpointer = view;
1935 tresult = isc_symtab_define(symtab, key, vclass,
1937 isc_symexists_reject);
1938 if (tresult == ISC_R_EXISTS) {
1941 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
1942 vclass, &symvalue) == ISC_R_SUCCESS);
1943 file = cfg_obj_file(symvalue.as_cpointer);
1944 line = cfg_obj_line(symvalue.as_cpointer);
1945 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
1946 "view '%s': already exists "
1947 "previous definition: %s:%u",
1950 } else if (tresult != ISC_R_SUCCESS) {
1952 } else if ((strcasecmp(key, "_bind") == 0 &&
1953 vclass == dns_rdataclass_ch) ||
1954 (strcasecmp(key, "_default") == 0 &&
1955 vclass == dns_rdataclass_in)) {
1956 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
1957 "attempt to redefine builtin view "
1959 result = ISC_R_EXISTS;
1962 if (tresult == ISC_R_SUCCESS)
1963 tresult = check_viewconf(config, voptions,
1964 vclass, logctx, mctx);
1965 if (tresult != ISC_R_SUCCESS)
1966 result = ISC_R_FAILURE;
1969 isc_symtab_destroy(&symtab);
1971 if (views != NULL && options != NULL) {
1973 tresult = cfg_map_get(options, "cache-file", &obj);
1974 if (tresult == ISC_R_SUCCESS) {
1975 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1976 "'cache-file' cannot be a global "
1977 "option if views are present");
1978 result = ISC_R_FAILURE;
1982 tresult = cfg_map_get(config, "acl", &acls);
1983 if (tresult == ISC_R_SUCCESS) {
1984 const cfg_listelt_t *elt;
1985 const cfg_listelt_t *elt2;
1986 const char *aclname;
1988 for (elt = cfg_list_first(acls);
1990 elt = cfg_list_next(elt)) {
1991 const cfg_obj_t *acl = cfg_listelt_value(elt);
1994 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
1996 i < sizeof(builtin) / sizeof(builtin[0]);
1998 if (strcasecmp(aclname, builtin[i]) == 0) {
1999 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
2000 "attempt to redefine "
2003 result = ISC_R_FAILURE;
2007 for (elt2 = cfg_list_next(elt);
2009 elt2 = cfg_list_next(elt2)) {
2010 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2012 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2014 if (strcasecmp(aclname, name) == 0) {
2015 const char *file = cfg_obj_file(acl);
2016 unsigned int line = cfg_obj_line(acl);
2019 file = "<unknown file>";
2021 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2022 "attempt to redefine "
2023 "acl '%s' previous "
2024 "definition: %s:%u",
2026 result = ISC_R_FAILURE;
2032 tresult = cfg_map_get(config, "kal", &kals);
2033 if (tresult == ISC_R_SUCCESS) {
2034 const cfg_listelt_t *elt;
2035 const cfg_listelt_t *elt2;
2036 const char *aclname;
2038 for (elt = cfg_list_first(kals);
2040 elt = cfg_list_next(elt)) {
2041 const cfg_obj_t *acl = cfg_listelt_value(elt);
2043 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2045 for (elt2 = cfg_list_next(elt);
2047 elt2 = cfg_list_next(elt2)) {
2048 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2050 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2052 if (strcasecmp(aclname, name) == 0) {
2053 const char *file = cfg_obj_file(acl);
2054 unsigned int line = cfg_obj_line(acl);
2057 file = "<unknown file>";
2059 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2060 "attempt to redefine "
2061 "kal '%s' previous "
2062 "definition: %s:%u",
2064 result = ISC_R_FAILURE;