2 * Copyright (C) 2004-2007 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.35 2007/09/13 05:04:01 each 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, isc_log_t *logctx) {
226 const cfg_obj_t *forward = NULL;
227 const cfg_obj_t *forwarders = NULL;
229 (void)cfg_map_get(options, "forward", &forward);
230 (void)cfg_map_get(options, "forwarders", &forwarders);
232 if (forward != NULL && forwarders == NULL) {
233 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
234 "no matching 'forwarders' statement");
235 return (ISC_R_FAILURE);
237 return (ISC_R_SUCCESS);
241 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
242 isc_result_t result = ISC_R_SUCCESS;
243 isc_result_t tresult;
244 const cfg_listelt_t *element;
247 dns_fixedname_t fixed;
249 const cfg_obj_t *obj;
251 dns_fixedname_init(&fixed);
252 name = dns_fixedname_name(&fixed);
253 obj = cfg_tuple_get(disabled, "name");
254 str = cfg_obj_asstring(obj);
255 isc_buffer_init(&b, str, strlen(str));
256 isc_buffer_add(&b, strlen(str));
257 tresult = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
258 if (tresult != ISC_R_SUCCESS) {
259 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
260 "bad domain name '%s'", str);
264 obj = cfg_tuple_get(disabled, "algorithms");
266 for (element = cfg_list_first(obj);
268 element = cfg_list_next(element))
272 isc_result_t tresult;
274 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
275 r.length = strlen(r.base);
277 tresult = dns_secalg_fromtext(&alg, &r);
278 if (tresult != ISC_R_SUCCESS) {
280 result = isc_parse_uint8(&ui, r.base, 10);
282 if (tresult != ISC_R_SUCCESS) {
283 cfg_obj_log(cfg_listelt_value(element), logctx,
284 ISC_LOG_ERROR, "invalid algorithm '%s'",
293 nameexist(const cfg_obj_t *obj, const char *name, int value,
294 isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
301 isc_symvalue_t symvalue;
303 key = isc_mem_strdup(mctx, name);
305 return (ISC_R_NOMEMORY);
306 symvalue.as_cpointer = obj;
307 result = isc_symtab_define(symtab, key, value, symvalue,
308 isc_symexists_reject);
309 if (result == ISC_R_EXISTS) {
310 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
311 &symvalue) == ISC_R_SUCCESS);
312 file = cfg_obj_file(symvalue.as_cpointer);
313 line = cfg_obj_line(symvalue.as_cpointer);
316 file = "<unknown file>";
317 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
318 isc_mem_free(mctx, key);
319 result = ISC_R_EXISTS;
320 } else if (result != ISC_R_SUCCESS) {
321 isc_mem_free(mctx, key);
327 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
330 const cfg_obj_t *obj;
331 char namebuf[DNS_NAME_FORMATSIZE];
333 dns_fixedname_t fixed;
336 isc_result_t result = ISC_R_SUCCESS;
338 dns_fixedname_init(&fixed);
339 name = dns_fixedname_name(&fixed);
340 obj = cfg_tuple_get(secure, "name");
341 str = cfg_obj_asstring(obj);
342 isc_buffer_init(&b, str, strlen(str));
343 isc_buffer_add(&b, strlen(str));
344 result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
345 if (result != ISC_R_SUCCESS) {
346 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
347 "bad domain name '%s'", str);
349 dns_name_format(name, namebuf, sizeof(namebuf));
350 result = nameexist(secure, namebuf, 1, symtab,
351 "dnssec-must-be-secure '%s': already "
352 "exists previous definition: %s:%u",
359 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
360 const cfg_obj_t *voptions, const cfg_obj_t *config,
361 isc_log_t *logctx, isc_mem_t *mctx)
364 const cfg_obj_t *aclobj = NULL;
365 const cfg_obj_t *options;
366 dns_acl_t *acl = NULL;
368 if (zconfig != NULL) {
369 options = cfg_tuple_get(zconfig, "options");
370 cfg_map_get(options, aclname, &aclobj);
372 if (voptions != NULL && aclobj == NULL)
373 cfg_map_get(voptions, aclname, &aclobj);
374 if (config != NULL && aclobj == NULL) {
376 cfg_map_get(config, "options", &options);
378 cfg_map_get(options, aclname, &aclobj);
381 return (ISC_R_SUCCESS);
382 result = cfg_acl_fromconfig(aclobj, config, logctx, actx, mctx, &acl);
384 dns_acl_detach(&acl);
389 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
390 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
392 isc_result_t result = ISC_R_SUCCESS, tresult;
395 static const char *acls[] = { "allow-query", "allow-query-cache",
396 "allow-recursion", "blackhole", "match-clients",
397 "match-destinations", "sortlist", NULL };
399 while (acls[i] != NULL) {
400 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
402 if (tresult != ISC_R_SUCCESS)
415 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
416 isc_result_t result = ISC_R_SUCCESS;
417 isc_result_t tresult;
419 const cfg_obj_t *obj = NULL;
420 const cfg_listelt_t *element;
421 isc_symtab_t *symtab = NULL;
422 dns_fixedname_t fixed;
427 static intervaltable intervals[] = {
428 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
429 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
430 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
431 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
432 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
433 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
434 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
435 { "sig-validity-interval", 86400, 10 * 366 }, /* 10 years */
436 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
440 * Check that fields specified in units of time other than seconds
441 * have reasonable values.
443 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
446 (void)cfg_map_get(options, intervals[i].name, &obj);
449 val = cfg_obj_asuint32(obj);
450 if (val > intervals[i].max) {
451 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
452 "%s '%u' is out of range (0..%u)",
453 intervals[i].name, val,
455 result = ISC_R_RANGE;
456 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
457 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
458 "%s '%d' is out of range",
459 intervals[i].name, val);
460 result = ISC_R_RANGE;
464 (void)cfg_map_get(options, "preferred-glue", &obj);
467 str = cfg_obj_asstring(obj);
468 if (strcasecmp(str, "a") != 0 &&
469 strcasecmp(str, "aaaa") != 0 &&
470 strcasecmp(str, "none") != 0)
471 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
472 "preferred-glue unexpected value '%s'",
476 (void)cfg_map_get(options, "root-delegation-only", &obj);
478 if (!cfg_obj_isvoid(obj)) {
479 const cfg_listelt_t *element;
480 const cfg_obj_t *exclude;
482 dns_fixedname_t fixed;
486 dns_fixedname_init(&fixed);
487 name = dns_fixedname_name(&fixed);
488 for (element = cfg_list_first(obj);
490 element = cfg_list_next(element)) {
491 exclude = cfg_listelt_value(element);
492 str = cfg_obj_asstring(exclude);
493 isc_buffer_init(&b, str, strlen(str));
494 isc_buffer_add(&b, strlen(str));
495 tresult = dns_name_fromtext(name, &b,
498 if (tresult != ISC_R_SUCCESS) {
499 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
500 "bad domain name '%s'",
509 * Set supported DNSSEC algorithms.
512 (void)cfg_map_get(options, "disable-algorithms", &obj);
514 for (element = cfg_list_first(obj);
516 element = cfg_list_next(element))
518 obj = cfg_listelt_value(element);
519 tresult = disabled_algorithms(obj, logctx);
520 if (tresult != ISC_R_SUCCESS)
525 dns_fixedname_init(&fixed);
526 name = dns_fixedname_name(&fixed);
529 * Check the DLV zone name.
532 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
534 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
536 if (tresult != ISC_R_SUCCESS)
538 for (element = cfg_list_first(obj);
540 element = cfg_list_next(element))
544 obj = cfg_listelt_value(element);
546 dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain"));
547 isc_buffer_init(&b, dlv, strlen(dlv));
548 isc_buffer_add(&b, strlen(dlv));
549 tresult = dns_name_fromtext(name, &b, dns_rootname,
551 if (tresult != ISC_R_SUCCESS) {
552 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
553 "bad domain name '%s'", dlv);
556 if (symtab != NULL) {
557 tresult = nameexist(obj, dlv, 1, symtab,
558 "dnssec-lookaside '%s': "
559 "already exists previous "
562 if (tresult != ISC_R_SUCCESS &&
563 result == ISC_R_SUCCESS)
567 * XXXMPA to be removed when multiple lookaside
568 * namespaces are supported.
570 if (!dns_name_equal(dns_rootname, name)) {
571 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
572 "dnssec-lookaside '%s': "
573 "non-root not yet supported", dlv);
574 if (result == ISC_R_SUCCESS)
575 result = ISC_R_FAILURE;
577 dlv = cfg_obj_asstring(cfg_tuple_get(obj,
579 isc_buffer_init(&b, dlv, strlen(dlv));
580 isc_buffer_add(&b, strlen(dlv));
581 tresult = dns_name_fromtext(name, &b, dns_rootname,
583 if (tresult != ISC_R_SUCCESS) {
584 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
585 "bad domain name '%s'", dlv);
586 if (result == ISC_R_SUCCESS)
591 isc_symtab_destroy(&symtab);
595 * Check dnssec-must-be-secure.
598 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
600 isc_symtab_t *symtab = NULL;
601 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
603 if (tresult != ISC_R_SUCCESS)
605 for (element = cfg_list_first(obj);
607 element = cfg_list_next(element))
609 obj = cfg_listelt_value(element);
610 tresult = mustbesecure(obj, symtab, logctx, mctx);
611 if (tresult != ISC_R_SUCCESS)
615 isc_symtab_destroy(&symtab);
619 * Check empty zone configuration.
622 (void)cfg_map_get(options, "empty-server", &obj);
624 str = cfg_obj_asstring(obj);
625 isc_buffer_init(&b, str, strlen(str));
626 isc_buffer_add(&b, strlen(str));
627 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
628 dns_rootname, ISC_FALSE, NULL);
629 if (tresult != ISC_R_SUCCESS) {
630 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
631 "empty-server: invalid name '%s'", str);
632 result = ISC_R_FAILURE;
637 (void)cfg_map_get(options, "empty-contact", &obj);
639 str = cfg_obj_asstring(obj);
640 isc_buffer_init(&b, str, strlen(str));
641 isc_buffer_add(&b, strlen(str));
642 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
643 dns_rootname, ISC_FALSE, NULL);
644 if (tresult != ISC_R_SUCCESS) {
645 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
646 "empty-contact: invalid name '%s'", str);
647 result = ISC_R_FAILURE;
652 (void)cfg_map_get(options, "disable-empty-zone", &obj);
653 for (element = cfg_list_first(obj);
655 element = cfg_list_next(element))
657 obj = cfg_listelt_value(element);
658 str = cfg_obj_asstring(obj);
659 isc_buffer_init(&b, str, strlen(str));
660 isc_buffer_add(&b, strlen(str));
661 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
662 dns_rootname, ISC_FALSE, NULL);
663 if (tresult != ISC_R_SUCCESS) {
664 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
665 "disable-empty-zone: invalid name '%s'",
667 result = ISC_R_FAILURE;
675 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
677 const cfg_obj_t *masters = NULL;
678 const cfg_listelt_t *elt;
680 result = cfg_map_get(cctx, "masters", &masters);
681 if (result != ISC_R_SUCCESS)
683 for (elt = cfg_list_first(masters);
685 elt = cfg_list_next(elt)) {
686 const cfg_obj_t *list;
687 const char *listname;
689 list = cfg_listelt_value(elt);
690 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
692 if (strcasecmp(listname, name) == 0) {
694 return (ISC_R_SUCCESS);
697 return (ISC_R_NOTFOUND);
701 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
702 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
704 isc_result_t result = ISC_R_SUCCESS;
705 isc_result_t tresult;
706 isc_uint32_t count = 0;
707 isc_symtab_t *symtab = NULL;
708 isc_symvalue_t symvalue;
709 const cfg_listelt_t *element;
710 const cfg_listelt_t **stack = NULL;
711 isc_uint32_t stackcount = 0, pushed = 0;
712 const cfg_obj_t *list;
714 REQUIRE(countp != NULL);
715 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
716 if (result != ISC_R_SUCCESS) {
722 list = cfg_tuple_get(obj, "addresses");
723 element = cfg_list_first(list);
727 element = cfg_list_next(element))
729 const char *listname;
730 const cfg_obj_t *addr;
731 const cfg_obj_t *key;
733 addr = cfg_tuple_get(cfg_listelt_value(element),
735 key = cfg_tuple_get(cfg_listelt_value(element), "key");
737 if (cfg_obj_issockaddr(addr)) {
741 if (!cfg_obj_isvoid(key)) {
742 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
743 "unexpected token '%s'",
744 cfg_obj_asstring(key));
745 if (result == ISC_R_SUCCESS)
746 result = ISC_R_FAILURE;
748 listname = cfg_obj_asstring(addr);
749 symvalue.as_cpointer = addr;
750 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
751 isc_symexists_reject);
752 if (tresult == ISC_R_EXISTS)
754 tresult = get_masters_def(config, listname, &obj);
755 if (tresult != ISC_R_SUCCESS) {
756 if (result == ISC_R_SUCCESS)
758 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
759 "unable to find masters list '%s'",
764 if (stackcount == pushed) {
766 isc_uint32_t newlen = stackcount + 16;
767 size_t newsize, oldsize;
769 newsize = newlen * sizeof(*stack);
770 oldsize = stackcount * sizeof(*stack);
771 new = isc_mem_get(mctx, newsize);
774 if (stackcount != 0) {
775 memcpy(new, stack, oldsize);
776 isc_mem_put(mctx, stack, oldsize);
781 stack[pushed++] = cfg_list_next(element);
785 element = stack[--pushed];
790 isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
791 isc_symtab_destroy(&symtab);
797 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
798 isc_result_t result = ISC_R_SUCCESS;
799 isc_result_t tresult;
800 const cfg_listelt_t *element;
801 const cfg_listelt_t *element2;
802 dns_fixedname_t fixed;
806 for (element = cfg_list_first(policy);
808 element = cfg_list_next(element))
810 const cfg_obj_t *stmt = cfg_listelt_value(element);
811 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
812 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
813 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
814 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
816 dns_fixedname_init(&fixed);
817 str = cfg_obj_asstring(identity);
818 isc_buffer_init(&b, str, strlen(str));
819 isc_buffer_add(&b, strlen(str));
820 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
821 dns_rootname, ISC_FALSE, NULL);
822 if (tresult != ISC_R_SUCCESS) {
823 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
824 "'%s' is not a valid name", str);
828 dns_fixedname_init(&fixed);
829 str = cfg_obj_asstring(dname);
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(dname, logctx, ISC_LOG_ERROR,
836 "'%s' is not a valid name", str);
839 if (tresult == ISC_R_SUCCESS &&
840 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
841 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
842 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
843 "'%s' is not a wildcard", str);
844 result = ISC_R_FAILURE;
847 for (element2 = cfg_list_first(typelist);
849 element2 = cfg_list_next(element2))
851 const cfg_obj_t *typeobj;
853 dns_rdatatype_t type;
855 typeobj = cfg_listelt_value(element2);
856 DE_CONST(cfg_obj_asstring(typeobj), r.base);
857 r.length = strlen(r.base);
859 tresult = dns_rdatatype_fromtext(&type, &r);
860 if (tresult != ISC_R_SUCCESS) {
861 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
862 "'%s' is not a valid type", r.base);
874 #define FORWARDZONE 16
875 #define DELEGATIONZONE 32
884 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
885 const cfg_obj_t *config, isc_symtab_t *symtab,
886 dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
887 isc_log_t *logctx, isc_mem_t *mctx)
892 const cfg_obj_t *zoptions;
893 const cfg_obj_t *obj = NULL;
894 isc_result_t result = ISC_R_SUCCESS;
895 isc_result_t tresult;
897 dns_rdataclass_t zclass;
898 dns_fixedname_t fixedname;
901 static optionstable options[] = {
902 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL },
903 { "allow-notify", SLAVEZONE | CHECKACL },
904 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
905 { "notify", MASTERZONE | SLAVEZONE },
906 { "also-notify", MASTERZONE | SLAVEZONE },
907 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
908 { "delegation-only", HINTZONE | STUBZONE },
909 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
910 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
911 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
912 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
913 { "notify-source", MASTERZONE | SLAVEZONE },
914 { "notify-source-v6", MASTERZONE | SLAVEZONE },
915 { "transfer-source", SLAVEZONE | STUBZONE },
916 { "transfer-source-v6", SLAVEZONE | STUBZONE },
917 { "max-transfer-time-in", SLAVEZONE | STUBZONE },
918 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
919 { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
920 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
921 { "max-retry-time", SLAVEZONE | STUBZONE },
922 { "min-retry-time", SLAVEZONE | STUBZONE },
923 { "max-refresh-time", SLAVEZONE | STUBZONE },
924 { "min-refresh-time", SLAVEZONE | STUBZONE },
925 { "sig-validity-interval", MASTERZONE },
926 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE },
927 { "allow-update", MASTERZONE | CHECKACL },
928 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
929 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
930 { "journal", MASTERZONE | SLAVEZONE },
931 { "ixfr-base", MASTERZONE | SLAVEZONE },
932 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
933 { "masters", SLAVEZONE | STUBZONE },
934 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
935 { "update-policy", MASTERZONE },
936 { "database", MASTERZONE | SLAVEZONE | STUBZONE },
937 { "key-directory", MASTERZONE },
938 { "check-wildcard", MASTERZONE },
939 { "check-mx", MASTERZONE },
940 { "integrity-check", MASTERZONE },
941 { "check-mx-cname", MASTERZONE },
942 { "check-srv-cname", MASTERZONE },
943 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
944 { "update-check-ksk", MASTERZONE },
947 static optionstable dialups[] = {
948 { "notify", MASTERZONE | SLAVEZONE },
949 { "notify-passive", SLAVEZONE },
950 { "refresh", SLAVEZONE | STUBZONE },
951 { "passive", SLAVEZONE | STUBZONE },
954 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
956 zoptions = cfg_tuple_get(zconfig, "options");
959 (void)cfg_map_get(zoptions, "type", &obj);
961 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
962 "zone '%s': type not present", zname);
963 return (ISC_R_FAILURE);
966 typestr = cfg_obj_asstring(obj);
967 if (strcasecmp(typestr, "master") == 0)
969 else if (strcasecmp(typestr, "slave") == 0)
971 else if (strcasecmp(typestr, "stub") == 0)
973 else if (strcasecmp(typestr, "forward") == 0)
975 else if (strcasecmp(typestr, "hint") == 0)
977 else if (strcasecmp(typestr, "delegation-only") == 0)
978 ztype = DELEGATIONZONE;
980 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
981 "zone '%s': invalid type %s",
983 return (ISC_R_FAILURE);
986 obj = cfg_tuple_get(zconfig, "class");
987 if (cfg_obj_isstring(obj)) {
990 DE_CONST(cfg_obj_asstring(obj), r.base);
991 r.length = strlen(r.base);
992 result = dns_rdataclass_fromtext(&zclass, &r);
993 if (result != ISC_R_SUCCESS) {
994 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
995 "zone '%s': invalid class %s",
997 return (ISC_R_FAILURE);
999 if (zclass != defclass) {
1000 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1001 "zone '%s': class '%s' does not "
1002 "match view/default class",
1004 return (ISC_R_FAILURE);
1009 * Look for an already existing zone.
1010 * We need to make this cannonical as isc_symtab_define()
1011 * deals with strings.
1013 dns_fixedname_init(&fixedname);
1014 isc_buffer_init(&b, zname, strlen(zname));
1015 isc_buffer_add(&b, strlen(zname));
1016 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1017 dns_rootname, ISC_TRUE, NULL);
1018 if (result != ISC_R_SUCCESS) {
1019 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1020 "zone '%s': is not a valid name", zname);
1021 tresult = ISC_R_FAILURE;
1023 char namebuf[DNS_NAME_FORMATSIZE];
1025 dns_name_format(dns_fixedname_name(&fixedname),
1026 namebuf, sizeof(namebuf));
1027 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
1028 symtab, "zone '%s': already exists "
1029 "previous definition: %s:%u", logctx, mctx);
1030 if (tresult != ISC_R_SUCCESS)
1035 * Look for inappropriate options for the given zone type.
1036 * Check that ACLs expand correctly.
1038 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1040 if ((options[i].allowed & ztype) == 0 &&
1041 cfg_map_get(zoptions, options[i].name, &obj) ==
1044 if (strcmp(options[i].name, "allow-update") != 0 ||
1045 ztype != SLAVEZONE) {
1046 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1047 "option '%s' is not allowed "
1048 "in '%s' zone '%s'",
1049 options[i].name, typestr, zname);
1050 result = ISC_R_FAILURE;
1052 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1053 "option '%s' is not allowed "
1054 "in '%s' zone '%s'",
1055 options[i].name, typestr, zname);
1058 if ((options[i].allowed & ztype) != 0 &&
1059 (options[i].allowed & CHECKACL) != 0) {
1061 tresult = checkacl(options[i].name, actx, zconfig,
1062 voptions, config, logctx, mctx);
1063 if (tresult != ISC_R_SUCCESS)
1070 * Slave & stub zones must have a "masters" field.
1072 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1074 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1075 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1076 "zone '%s': missing 'masters' entry",
1078 result = ISC_R_FAILURE;
1081 tresult = validate_masters(obj, config, &count,
1083 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1085 if (tresult == ISC_R_SUCCESS && count == 0) {
1086 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1087 "zone '%s': empty 'masters' entry",
1089 result = ISC_R_FAILURE;
1095 * Master zones can't have both "allow-update" and "update-policy".
1097 if (ztype == MASTERZONE) {
1098 isc_result_t res1, res2;
1100 res1 = cfg_map_get(zoptions, "allow-update", &obj);
1102 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1103 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1104 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1105 "zone '%s': 'allow-update' is ignored "
1106 "when 'update-policy' is present",
1108 result = ISC_R_FAILURE;
1109 } else if (res2 == ISC_R_SUCCESS &&
1110 check_update_policy(obj, logctx) != ISC_R_SUCCESS)
1111 result = ISC_R_FAILURE;
1115 * Check the excessively complicated "dialup" option.
1117 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1118 const cfg_obj_t *dialup = NULL;
1119 (void)cfg_map_get(zoptions, "dialup", &dialup);
1120 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1121 const char *str = cfg_obj_asstring(dialup);
1123 i < sizeof(dialups) / sizeof(dialups[0]);
1126 if (strcasecmp(dialups[i].name, str) != 0)
1128 if ((dialups[i].allowed & ztype) == 0) {
1129 cfg_obj_log(obj, logctx,
1131 "dialup type '%s' is not "
1134 str, typestr, zname);
1135 result = ISC_R_FAILURE;
1139 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1140 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1141 "invalid dialup type '%s' in zone "
1142 "'%s'", str, zname);
1143 result = ISC_R_FAILURE;
1149 * Check that forwarding is reasonable.
1151 if (check_forward(zoptions, logctx) != ISC_R_SUCCESS)
1152 result = ISC_R_FAILURE;
1155 * Check various options.
1157 tresult = check_options(zoptions, logctx, mctx);
1158 if (tresult != ISC_R_SUCCESS)
1162 * If the zone type is rbt/rbt64 then master/hint zones
1163 * require file clauses.
1166 tresult = cfg_map_get(zoptions, "database", &obj);
1167 if (tresult == ISC_R_NOTFOUND ||
1168 (tresult == ISC_R_SUCCESS &&
1169 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1170 strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
1172 tresult = cfg_map_get(zoptions, "file", &obj);
1173 if (tresult != ISC_R_SUCCESS &&
1174 (ztype == MASTERZONE || ztype == HINTZONE)) {
1175 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1176 "zone '%s': missing 'file' entry",
1186 typedef struct keyalgorithms {
1192 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1193 const cfg_obj_t *algobj = NULL;
1194 const cfg_obj_t *secretobj = NULL;
1195 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1196 const char *algorithm;
1199 static const algorithmtable algorithms[] = {
1200 { "hmac-md5", 128 },
1201 { "hmac-md5.sig-alg.reg.int", 0 },
1202 { "hmac-md5.sig-alg.reg.int.", 0 },
1203 { "hmac-sha1", 160 },
1204 { "hmac-sha224", 224 },
1205 { "hmac-sha256", 256 },
1206 { "hmac-sha384", 384 },
1207 { "hmac-sha512", 512 },
1211 (void)cfg_map_get(key, "algorithm", &algobj);
1212 (void)cfg_map_get(key, "secret", &secretobj);
1213 if (secretobj == NULL || algobj == NULL) {
1214 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1215 "key '%s' must have both 'secret' and "
1216 "'algorithm' defined",
1218 return (ISC_R_FAILURE);
1221 algorithm = cfg_obj_asstring(algobj);
1222 for (i = 0; algorithms[i].name != NULL; i++) {
1223 len = strlen(algorithms[i].name);
1224 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1225 (algorithm[len] == '\0' ||
1226 (algorithms[i].size != 0 && algorithm[len] == '-')))
1229 if (algorithms[i].name == NULL) {
1230 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1231 "unknown algorithm '%s'", algorithm);
1232 return (ISC_R_NOTFOUND);
1234 if (algorithm[len] == '-') {
1235 isc_uint16_t digestbits;
1236 isc_result_t result;
1237 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1238 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1239 if (result == ISC_R_RANGE ||
1240 digestbits > algorithms[i].size) {
1241 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1242 "key '%s' digest-bits too large "
1243 "[%u..%u]", keyname,
1244 algorithms[i].size / 2,
1245 algorithms[i].size);
1246 return (ISC_R_RANGE);
1248 if ((digestbits % 8) != 0) {
1249 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1250 "key '%s' digest-bits not multiple"
1252 return (ISC_R_RANGE);
1255 * Recommended minima for hmac algorithms.
1257 if ((digestbits < (algorithms[i].size / 2U) ||
1258 (digestbits < 80U)))
1259 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
1260 "key '%s' digest-bits too small "
1262 algorithms[i].size/2);
1264 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1265 "key '%s': unable to parse digest-bits",
1270 return (ISC_R_SUCCESS);
1274 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab, isc_log_t *logctx) {
1275 isc_result_t result = ISC_R_SUCCESS;
1276 isc_result_t tresult;
1277 const cfg_listelt_t *element;
1279 for (element = cfg_list_first(keys);
1281 element = cfg_list_next(element))
1283 const cfg_obj_t *key = cfg_listelt_value(element);
1284 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1285 isc_symvalue_t symvalue;
1287 tresult = bind9_check_key(key, logctx);
1288 if (tresult != ISC_R_SUCCESS)
1291 symvalue.as_cpointer = key;
1292 tresult = isc_symtab_define(symtab, keyname, 1,
1293 symvalue, isc_symexists_reject);
1294 if (tresult == ISC_R_EXISTS) {
1298 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
1299 1, &symvalue) == ISC_R_SUCCESS);
1300 file = cfg_obj_file(symvalue.as_cpointer);
1301 line = cfg_obj_line(symvalue.as_cpointer);
1304 file = "<unknown file>";
1305 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1306 "key '%s': already exists "
1307 "previous definition: %s:%u",
1308 keyname, file, line);
1310 } else if (tresult != ISC_R_SUCCESS)
1320 { "transfer-source", "transfer-source-v6" },
1321 { "notify-source", "notify-source-v6" },
1322 { "query-source", "query-source-v6" },
1327 check_servers(const cfg_obj_t *servers, isc_log_t *logctx) {
1328 isc_result_t result = ISC_R_SUCCESS;
1329 isc_result_t tresult;
1330 const cfg_listelt_t *e1, *e2;
1331 const cfg_obj_t *v1, *v2;
1332 isc_netaddr_t n1, n2;
1333 unsigned int p1, p2;
1334 const cfg_obj_t *obj;
1335 char buf[ISC_NETADDR_FORMATSIZE];
1339 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
1340 v1 = cfg_listelt_value(e1);
1341 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
1343 * Check that unused bits are zero.
1345 tresult = isc_netaddr_prefixok(&n1, p1);
1346 if (tresult != ISC_R_SUCCESS) {
1347 INSIST(tresult == ISC_R_FAILURE);
1348 isc_netaddr_format(&n1, buf, sizeof(buf));
1349 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1350 "server '%s/%u': invalid prefix "
1351 "(extra bits specified)", buf, p1);
1357 if (n1.family == AF_INET)
1358 xfr = sources[source].v6;
1360 xfr = sources[source].v4;
1361 (void)cfg_map_get(v1, xfr, &obj);
1363 isc_netaddr_format(&n1, buf, sizeof(buf));
1364 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1365 "server '%s': %s not legal",
1367 result = ISC_R_FAILURE;
1369 } while (sources[++source].v4 != NULL);
1371 while ((e2 = cfg_list_next(e2)) != NULL) {
1372 v2 = cfg_listelt_value(e2);
1373 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
1374 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
1375 const char *file = cfg_obj_file(v1);
1376 unsigned int line = cfg_obj_line(v1);
1379 file = "<unknown file>";
1381 isc_netaddr_format(&n2, buf, sizeof(buf));
1382 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
1383 "server '%s/%u': already exists "
1384 "previous definition: %s:%u",
1385 buf, p2, file, line);
1386 result = ISC_R_FAILURE;
1394 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
1395 dns_rdataclass_t vclass, isc_log_t *logctx, isc_mem_t *mctx)
1397 const cfg_obj_t *servers = NULL;
1398 const cfg_obj_t *zones = NULL;
1399 const cfg_obj_t *keys = NULL;
1400 const cfg_listelt_t *element;
1401 isc_symtab_t *symtab = NULL;
1402 isc_result_t result = ISC_R_SUCCESS;
1403 isc_result_t tresult = ISC_R_SUCCESS;
1404 cfg_aclconfctx_t actx;
1405 const cfg_obj_t *obj;
1406 isc_boolean_t enablednssec, enablevalidation;
1409 * Check that all zone statements are syntactically correct and
1410 * there are no duplicate zones.
1412 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1413 ISC_FALSE, &symtab);
1414 if (tresult != ISC_R_SUCCESS)
1415 return (ISC_R_NOMEMORY);
1417 cfg_aclconfctx_init(&actx);
1419 if (voptions != NULL)
1420 (void)cfg_map_get(voptions, "zone", &zones);
1422 (void)cfg_map_get(config, "zone", &zones);
1424 for (element = cfg_list_first(zones);
1426 element = cfg_list_next(element))
1428 isc_result_t tresult;
1429 const cfg_obj_t *zone = cfg_listelt_value(element);
1431 tresult = check_zoneconf(zone, voptions, config, symtab,
1432 vclass, &actx, logctx, mctx);
1433 if (tresult != ISC_R_SUCCESS)
1434 result = ISC_R_FAILURE;
1437 isc_symtab_destroy(&symtab);
1440 * Check that all key statements are syntactically correct and
1441 * there are no duplicate keys.
1443 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
1444 if (tresult != ISC_R_SUCCESS)
1445 return (ISC_R_NOMEMORY);
1447 (void)cfg_map_get(config, "key", &keys);
1448 tresult = check_keylist(keys, symtab, logctx);
1449 if (tresult == ISC_R_EXISTS)
1450 result = ISC_R_FAILURE;
1451 else if (tresult != ISC_R_SUCCESS) {
1452 isc_symtab_destroy(&symtab);
1456 if (voptions != NULL) {
1458 (void)cfg_map_get(voptions, "key", &keys);
1459 tresult = check_keylist(keys, symtab, logctx);
1460 if (tresult == ISC_R_EXISTS)
1461 result = ISC_R_FAILURE;
1462 else if (tresult != ISC_R_SUCCESS) {
1463 isc_symtab_destroy(&symtab);
1468 isc_symtab_destroy(&symtab);
1471 * Check that forwarding is reasonable.
1473 if (voptions == NULL) {
1474 const cfg_obj_t *options = NULL;
1475 (void)cfg_map_get(config, "options", &options);
1476 if (options != NULL)
1477 if (check_forward(options, logctx) != ISC_R_SUCCESS)
1478 result = ISC_R_FAILURE;
1480 if (check_forward(voptions, logctx) != ISC_R_SUCCESS)
1481 result = ISC_R_FAILURE;
1484 * Check that dual-stack-servers is reasonable.
1486 if (voptions == NULL) {
1487 const cfg_obj_t *options = NULL;
1488 (void)cfg_map_get(config, "options", &options);
1489 if (options != NULL)
1490 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1491 result = ISC_R_FAILURE;
1493 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
1494 result = ISC_R_FAILURE;
1498 * Check that rrset-order is reasonable.
1500 if (voptions != NULL) {
1501 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
1502 result = ISC_R_FAILURE;
1505 if (voptions != NULL) {
1506 (void)cfg_map_get(voptions, "server", &servers);
1507 if (servers != NULL &&
1508 check_servers(servers, logctx) != ISC_R_SUCCESS)
1509 result = ISC_R_FAILURE;
1513 * Check that dnssec-enable/dnssec-validation are sensible.
1516 if (voptions != NULL)
1517 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
1519 (void)cfg_map_get(config, "dnssec-enable", &obj);
1521 enablednssec = ISC_TRUE;
1523 enablednssec = cfg_obj_asboolean(obj);
1526 if (voptions != NULL)
1527 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
1529 (void)cfg_map_get(config, "dnssec-validation", &obj);
1531 enablevalidation = ISC_FALSE; /* XXXMPA Change for 9.5. */
1533 enablevalidation = cfg_obj_asboolean(obj);
1535 if (enablevalidation && !enablednssec)
1536 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1537 "'dnssec-validation yes;' and 'dnssec-enable no;'");
1539 if (voptions != NULL)
1540 tresult = check_options(voptions, logctx, mctx);
1542 tresult = check_options(config, logctx, mctx);
1543 if (tresult != ISC_R_SUCCESS)
1546 tresult = check_viewacls(&actx, voptions, config, logctx, mctx);
1547 if (tresult != ISC_R_SUCCESS)
1550 cfg_aclconfctx_destroy(&actx);
1556 default_channels[] = {
1565 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
1568 const cfg_obj_t *categories = NULL;
1569 const cfg_obj_t *category;
1570 const cfg_obj_t *channels = NULL;
1571 const cfg_obj_t *channel;
1572 const cfg_listelt_t *element;
1573 const cfg_listelt_t *delement;
1574 const char *channelname;
1575 const char *catname;
1576 const cfg_obj_t *fileobj = NULL;
1577 const cfg_obj_t *syslogobj = NULL;
1578 const cfg_obj_t *nullobj = NULL;
1579 const cfg_obj_t *stderrobj = NULL;
1580 const cfg_obj_t *logobj = NULL;
1581 isc_result_t result = ISC_R_SUCCESS;
1582 isc_result_t tresult;
1583 isc_symtab_t *symtab = NULL;
1584 isc_symvalue_t symvalue;
1587 (void)cfg_map_get(config, "logging", &logobj);
1589 return (ISC_R_SUCCESS);
1591 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1592 if (result != ISC_R_SUCCESS)
1595 symvalue.as_cpointer = NULL;
1596 for (i = 0; default_channels[i] != NULL; i++) {
1597 tresult = isc_symtab_define(symtab, default_channels[i], 1,
1598 symvalue, isc_symexists_replace);
1599 if (tresult != ISC_R_SUCCESS)
1603 cfg_map_get(logobj, "channel", &channels);
1605 for (element = cfg_list_first(channels);
1607 element = cfg_list_next(element))
1609 channel = cfg_listelt_value(element);
1610 channelname = cfg_obj_asstring(cfg_map_getname(channel));
1611 fileobj = syslogobj = nullobj = stderrobj = NULL;
1612 (void)cfg_map_get(channel, "file", &fileobj);
1613 (void)cfg_map_get(channel, "syslog", &syslogobj);
1614 (void)cfg_map_get(channel, "null", &nullobj);
1615 (void)cfg_map_get(channel, "stderr", &stderrobj);
1617 if (fileobj != NULL)
1619 if (syslogobj != NULL)
1621 if (nullobj != NULL)
1623 if (stderrobj != NULL)
1626 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
1627 "channel '%s': exactly one of file, syslog, "
1628 "null, and stderr must be present",
1630 result = ISC_R_FAILURE;
1632 tresult = isc_symtab_define(symtab, channelname, 1,
1633 symvalue, isc_symexists_replace);
1634 if (tresult != ISC_R_SUCCESS)
1638 cfg_map_get(logobj, "category", &categories);
1640 for (element = cfg_list_first(categories);
1642 element = cfg_list_next(element))
1644 category = cfg_listelt_value(element);
1645 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
1646 if (isc_log_categorybyname(logctx, catname) == NULL) {
1647 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
1648 "undefined category: '%s'", catname);
1649 result = ISC_R_FAILURE;
1651 channels = cfg_tuple_get(category, "destinations");
1652 for (delement = cfg_list_first(channels);
1654 delement = cfg_list_next(delement))
1656 channel = cfg_listelt_value(delement);
1657 channelname = cfg_obj_asstring(channel);
1658 tresult = isc_symtab_lookup(symtab, channelname, 1,
1660 if (tresult != ISC_R_SUCCESS) {
1661 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
1662 "undefined channel: '%s'",
1668 isc_symtab_destroy(&symtab);
1673 key_exists(const cfg_obj_t *keylist, const char *keyname) {
1674 const cfg_listelt_t *element;
1676 const cfg_obj_t *obj;
1678 if (keylist == NULL)
1679 return (ISC_R_NOTFOUND);
1680 for (element = cfg_list_first(keylist);
1682 element = cfg_list_next(element))
1684 obj = cfg_listelt_value(element);
1685 str = cfg_obj_asstring(cfg_map_getname(obj));
1686 if (strcasecmp(str, keyname) == 0)
1687 return (ISC_R_SUCCESS);
1689 return (ISC_R_NOTFOUND);
1693 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
1696 isc_result_t result = ISC_R_SUCCESS, tresult;
1697 const cfg_obj_t *control_keylist;
1698 const cfg_listelt_t *element;
1699 const cfg_obj_t *key;
1701 control_keylist = cfg_tuple_get(control, "keys");
1702 if (cfg_obj_isvoid(control_keylist))
1703 return (ISC_R_SUCCESS);
1705 for (element = cfg_list_first(control_keylist);
1707 element = cfg_list_next(element))
1709 key = cfg_listelt_value(element);
1710 tresult = key_exists(keylist, cfg_obj_asstring(key));
1711 if (tresult != ISC_R_SUCCESS) {
1712 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1713 "unknown key '%s'", cfg_obj_asstring(key));
1721 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
1724 isc_result_t result = ISC_R_SUCCESS, tresult;
1725 cfg_aclconfctx_t actx;
1726 const cfg_listelt_t *element, *element2;
1727 const cfg_obj_t *allow;
1728 const cfg_obj_t *control;
1729 const cfg_obj_t *controls;
1730 const cfg_obj_t *controlslist = NULL;
1731 const cfg_obj_t *inetcontrols;
1732 const cfg_obj_t *unixcontrols;
1733 const cfg_obj_t *keylist = NULL;
1735 isc_uint32_t perm, mask;
1736 dns_acl_t *acl = NULL;
1737 isc_sockaddr_t addr;
1740 (void)cfg_map_get(config, "controls", &controlslist);
1741 if (controlslist == NULL)
1742 return (ISC_R_SUCCESS);
1744 (void)cfg_map_get(config, "key", &keylist);
1746 cfg_aclconfctx_init(&actx);
1749 * INET: Check allow clause.
1750 * UNIX: Check "perm" for sanity, check path length.
1752 for (element = cfg_list_first(controlslist);
1754 element = cfg_list_next(element)) {
1755 controls = cfg_listelt_value(element);
1756 unixcontrols = NULL;
1757 inetcontrols = NULL;
1758 (void)cfg_map_get(controls, "unix", &unixcontrols);
1759 (void)cfg_map_get(controls, "inet", &inetcontrols);
1760 for (element2 = cfg_list_first(inetcontrols);
1762 element2 = cfg_list_next(element2)) {
1763 control = cfg_listelt_value(element2);
1764 allow = cfg_tuple_get(control, "allow");
1765 tresult = cfg_acl_fromconfig(allow, config, logctx,
1768 dns_acl_detach(&acl);
1769 if (tresult != ISC_R_SUCCESS)
1771 tresult = bind9_check_controlskeys(control, keylist,
1773 if (tresult != ISC_R_SUCCESS)
1776 for (element2 = cfg_list_first(unixcontrols);
1778 element2 = cfg_list_next(element2)) {
1779 control = cfg_listelt_value(element2);
1780 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
1781 tresult = isc_sockaddr_frompath(&addr, path);
1782 if (tresult == ISC_R_NOSPACE) {
1783 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
1784 "unix control '%s': path too long",
1786 result = ISC_R_NOSPACE;
1788 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
1789 for (i = 0; i < 3; i++) {
1790 #ifdef NEED_SECURE_DIRECTORY
1791 mask = (0x1 << (i*3)); /* SEARCH */
1793 mask = (0x6 << (i*3)); /* READ + WRITE */
1795 if ((perm & mask) == mask)
1799 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
1800 "unix control '%s' allows access "
1801 "to everyone", path);
1802 } else if (i == 3) {
1803 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
1804 "unix control '%s' allows access "
1807 tresult = bind9_check_controlskeys(control, keylist,
1809 if (tresult != ISC_R_SUCCESS)
1813 cfg_aclconfctx_destroy(&actx);
1818 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
1821 const cfg_obj_t *options = NULL;
1822 const cfg_obj_t *servers = NULL;
1823 const cfg_obj_t *views = NULL;
1824 const cfg_obj_t *acls = NULL;
1825 const cfg_obj_t *kals = NULL;
1826 const cfg_obj_t *obj;
1827 const cfg_listelt_t *velement;
1828 isc_result_t result = ISC_R_SUCCESS;
1829 isc_result_t tresult;
1830 isc_symtab_t *symtab = NULL;
1832 static const char *builtin[] = { "localhost", "localnets",
1835 (void)cfg_map_get(config, "options", &options);
1837 if (options != NULL &&
1838 check_options(options, logctx, mctx) != ISC_R_SUCCESS)
1839 result = ISC_R_FAILURE;
1841 (void)cfg_map_get(config, "server", &servers);
1842 if (servers != NULL &&
1843 check_servers(servers, logctx) != ISC_R_SUCCESS)
1844 result = ISC_R_FAILURE;
1846 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
1847 result = ISC_R_FAILURE;
1849 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
1850 result = ISC_R_FAILURE;
1852 if (options != NULL &&
1853 check_order(options, logctx) != ISC_R_SUCCESS)
1854 result = ISC_R_FAILURE;
1856 (void)cfg_map_get(config, "view", &views);
1858 if (views != NULL && options != NULL)
1859 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1860 result = ISC_R_FAILURE;
1862 if (views == NULL) {
1863 if (check_viewconf(config, NULL, dns_rdataclass_in,
1864 logctx, mctx) != ISC_R_SUCCESS)
1865 result = ISC_R_FAILURE;
1867 const cfg_obj_t *zones = NULL;
1869 (void)cfg_map_get(config, "zone", &zones);
1870 if (zones != NULL) {
1871 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
1872 "when using 'view' statements, "
1873 "all zones must be in views");
1874 result = ISC_R_FAILURE;
1878 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
1879 if (tresult != ISC_R_SUCCESS)
1881 for (velement = cfg_list_first(views);
1883 velement = cfg_list_next(velement))
1885 const cfg_obj_t *view = cfg_listelt_value(velement);
1886 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
1887 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
1888 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
1889 dns_rdataclass_t vclass = dns_rdataclass_in;
1890 isc_result_t tresult = ISC_R_SUCCESS;
1891 const char *key = cfg_obj_asstring(vname);
1892 isc_symvalue_t symvalue;
1894 if (cfg_obj_isstring(vclassobj)) {
1897 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
1898 r.length = strlen(r.base);
1899 tresult = dns_rdataclass_fromtext(&vclass, &r);
1900 if (tresult != ISC_R_SUCCESS)
1901 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
1902 "view '%s': invalid class %s",
1903 cfg_obj_asstring(vname), r.base);
1905 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
1906 symvalue.as_cpointer = view;
1907 tresult = isc_symtab_define(symtab, key, vclass,
1909 isc_symexists_reject);
1910 if (tresult == ISC_R_EXISTS) {
1913 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
1914 vclass, &symvalue) == ISC_R_SUCCESS);
1915 file = cfg_obj_file(symvalue.as_cpointer);
1916 line = cfg_obj_line(symvalue.as_cpointer);
1917 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
1918 "view '%s': already exists "
1919 "previous definition: %s:%u",
1922 } else if (result != ISC_R_SUCCESS) {
1924 } else if ((strcasecmp(key, "_bind") == 0 &&
1925 vclass == dns_rdataclass_ch) ||
1926 (strcasecmp(key, "_default") == 0 &&
1927 vclass == dns_rdataclass_in)) {
1928 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
1929 "attempt to redefine builtin view "
1931 result = ISC_R_EXISTS;
1934 if (tresult == ISC_R_SUCCESS)
1935 tresult = check_viewconf(config, voptions,
1936 vclass, logctx, mctx);
1937 if (tresult != ISC_R_SUCCESS)
1938 result = ISC_R_FAILURE;
1941 isc_symtab_destroy(&symtab);
1943 if (views != NULL && options != NULL) {
1945 tresult = cfg_map_get(options, "cache-file", &obj);
1946 if (tresult == ISC_R_SUCCESS) {
1947 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1948 "'cache-file' cannot be a global "
1949 "option if views are present");
1950 result = ISC_R_FAILURE;
1954 tresult = cfg_map_get(config, "acl", &acls);
1955 if (tresult == ISC_R_SUCCESS) {
1956 const cfg_listelt_t *elt;
1957 const cfg_listelt_t *elt2;
1958 const char *aclname;
1960 for (elt = cfg_list_first(acls);
1962 elt = cfg_list_next(elt)) {
1963 const cfg_obj_t *acl = cfg_listelt_value(elt);
1966 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
1968 i < sizeof(builtin) / sizeof(builtin[0]);
1970 if (strcasecmp(aclname, builtin[i]) == 0) {
1971 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
1972 "attempt to redefine "
1975 result = ISC_R_FAILURE;
1979 for (elt2 = cfg_list_next(elt);
1981 elt2 = cfg_list_next(elt2)) {
1982 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
1984 name = cfg_obj_asstring(cfg_tuple_get(acl2,
1986 if (strcasecmp(aclname, name) == 0) {
1987 const char *file = cfg_obj_file(acl);
1988 unsigned int line = cfg_obj_line(acl);
1991 file = "<unknown file>";
1993 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
1994 "attempt to redefine "
1995 "acl '%s' previous "
1996 "definition: %s:%u",
1998 result = ISC_R_FAILURE;
2004 tresult = cfg_map_get(config, "kal", &kals);
2005 if (tresult == ISC_R_SUCCESS) {
2006 const cfg_listelt_t *elt;
2007 const cfg_listelt_t *elt2;
2008 const char *aclname;
2010 for (elt = cfg_list_first(kals);
2012 elt = cfg_list_next(elt)) {
2013 const cfg_obj_t *acl = cfg_listelt_value(elt);
2015 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2017 for (elt2 = cfg_list_next(elt);
2019 elt2 = cfg_list_next(elt2)) {
2020 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2022 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2024 if (strcasecmp(aclname, name) == 0) {
2025 const char *file = cfg_obj_file(acl);
2026 unsigned int line = cfg_obj_line(acl);
2029 file = "<unknown file>";
2031 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2032 "attempt to redefine "
2033 "kal '%s' previous "
2034 "definition: %s:%u",
2036 result = ISC_R_FAILURE;