2 * Copyright (C) 2004-2010 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.114.4.6 2010/08/11 18:19:57 each Exp $ */
26 #include <isc/base64.h>
27 #include <isc/buffer.h>
30 #include <isc/netaddr.h>
31 #include <isc/parseint.h>
32 #include <isc/region.h>
33 #include <isc/result.h>
34 #include <isc/sockaddr.h>
35 #include <isc/string.h>
36 #include <isc/symtab.h>
40 #include <dns/fixedname.h>
41 #include <dns/rdataclass.h>
42 #include <dns/rdatatype.h>
43 #include <dns/secalg.h>
47 #include <isccfg/aclconf.h>
48 #include <isccfg/cfg.h>
50 #include <bind9/check.h>
53 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
56 isc_mem_free(userarg, key);
60 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
61 isc_result_t result = ISC_R_SUCCESS;
64 dns_fixedname_t fixed;
66 dns_rdataclass_t rdclass;
67 dns_rdatatype_t rdtype;
71 dns_fixedname_init(&fixed);
72 obj = cfg_tuple_get(ent, "class");
73 if (cfg_obj_isstring(obj)) {
75 DE_CONST(cfg_obj_asstring(obj), r.base);
76 r.length = strlen(r.base);
77 tresult = dns_rdataclass_fromtext(&rdclass, &r);
78 if (tresult != ISC_R_SUCCESS) {
79 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
80 "rrset-order: invalid class '%s'",
82 result = ISC_R_FAILURE;
86 obj = cfg_tuple_get(ent, "type");
87 if (cfg_obj_isstring(obj)) {
89 DE_CONST(cfg_obj_asstring(obj), r.base);
90 r.length = strlen(r.base);
91 tresult = dns_rdatatype_fromtext(&rdtype, &r);
92 if (tresult != ISC_R_SUCCESS) {
93 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
94 "rrset-order: invalid type '%s'",
96 result = ISC_R_FAILURE;
100 obj = cfg_tuple_get(ent, "name");
101 if (cfg_obj_isstring(obj)) {
102 str = cfg_obj_asstring(obj);
103 isc_buffer_init(&b, str, strlen(str));
104 isc_buffer_add(&b, strlen(str));
105 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
106 dns_rootname, 0, NULL);
107 if (tresult != ISC_R_SUCCESS) {
108 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
109 "rrset-order: invalid name '%s'", str);
110 result = ISC_R_FAILURE;
114 obj = cfg_tuple_get(ent, "order");
115 if (!cfg_obj_isstring(obj) ||
116 strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
117 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
118 "rrset-order: keyword 'order' missing");
119 result = ISC_R_FAILURE;
122 obj = cfg_tuple_get(ent, "ordering");
123 if (!cfg_obj_isstring(obj)) {
124 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
125 "rrset-order: missing ordering");
126 result = ISC_R_FAILURE;
127 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
128 #if !DNS_RDATASET_FIXED
129 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
130 "rrset-order: order 'fixed' was disabled at "
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, 0, 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, 0, 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,
394 actx, mctx, 0, &acl);
396 dns_acl_detach(&acl);
401 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
402 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
404 isc_result_t result = ISC_R_SUCCESS, tresult;
407 static const char *acls[] = { "allow-query", "allow-query-on",
408 "allow-query-cache", "allow-query-cache-on",
409 "blackhole", "match-clients", "match-destinations",
410 "sortlist", "filter-aaaa", NULL };
412 while (acls[i] != NULL) {
413 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
415 if (tresult != ISC_R_SUCCESS)
422 * Check allow-recursion and allow-recursion-on acls, and also log a
423 * warning if they're inconsistent with the "recursion" option.
426 check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
427 const char *viewname, const cfg_obj_t *config,
428 isc_log_t *logctx, isc_mem_t *mctx)
430 const cfg_obj_t *options, *aclobj, *obj = NULL;
431 dns_acl_t *acl = NULL;
432 isc_result_t result = ISC_R_SUCCESS, tresult;
433 isc_boolean_t recursion;
434 const char *forview = " for view ";
437 static const char *acls[] = { "allow-recursion", "allow-recursion-on",
440 if (voptions != NULL)
441 cfg_map_get(voptions, "recursion", &obj);
442 if (obj == NULL && config != NULL) {
444 cfg_map_get(config, "options", &options);
446 cfg_map_get(options, "recursion", &obj);
449 recursion = ISC_TRUE;
451 recursion = cfg_obj_asboolean(obj);
453 if (viewname == NULL) {
458 for (i = 0; acls[i] != NULL; i++) {
459 aclobj = options = NULL;
462 if (voptions != NULL)
463 cfg_map_get(voptions, acls[i], &aclobj);
464 if (config != NULL && aclobj == NULL) {
466 cfg_map_get(config, "options", &options);
468 cfg_map_get(options, acls[i], &aclobj);
473 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
474 actx, mctx, 0, &acl);
476 if (tresult != ISC_R_SUCCESS)
482 if (recursion == ISC_FALSE && !dns_acl_isnone(acl)) {
483 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
484 "both \"recursion no;\" and "
486 acls[i], forview, viewname);
490 dns_acl_detach(&acl);
497 check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
498 const char *viewname, const cfg_obj_t *config,
499 isc_log_t *logctx, isc_mem_t *mctx)
501 const cfg_obj_t *options, *aclobj, *obj = NULL;
502 dns_acl_t *acl = NULL;
503 isc_result_t result = ISC_R_SUCCESS, tresult;
504 dns_v4_aaaa_t filter;
505 const char *forview = " for view ";
507 if (voptions != NULL)
508 cfg_map_get(voptions, "filter-aaaa-on-v4", &obj);
509 if (obj == NULL && config != NULL) {
511 cfg_map_get(config, "options", &options);
513 cfg_map_get(options, "filter-aaaa-on-v4", &obj);
517 filter = dns_v4_aaaa_ok; /* default */
518 else if (cfg_obj_isboolean(obj))
519 filter = cfg_obj_asboolean(obj) ? dns_v4_aaaa_filter :
522 filter = dns_v4_aaaa_break_dnssec; /* break-dnssec */
524 if (viewname == NULL) {
529 aclobj = options = NULL;
532 if (voptions != NULL)
533 cfg_map_get(voptions, "filter-aaaa", &aclobj);
534 if (config != NULL && aclobj == NULL) {
536 cfg_map_get(config, "options", &options);
538 cfg_map_get(options, "filter-aaaa", &aclobj);
543 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
544 actx, mctx, 0, &acl);
546 if (tresult != ISC_R_SUCCESS) {
548 } else if (filter != dns_v4_aaaa_ok && dns_acl_isnone(acl)) {
549 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
550 "both \"filter-aaaa-on-v4 %s;\" and "
551 "\"filter-aaaa\" is 'none;'%s%s",
552 filter == dns_v4_aaaa_break_dnssec ?
553 "break-dnssec" : "yes", forview, viewname);
554 result = ISC_R_FAILURE;
555 } else if (filter == dns_v4_aaaa_ok && !dns_acl_isnone(acl)) {
556 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
557 "both \"filter-aaaa-on-v4 no;\" and "
558 "\"filter-aaaa\" is set%s%s", forview, viewname);
559 result = ISC_R_FAILURE;
563 dns_acl_detach(&acl);
575 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
576 isc_result_t result = ISC_R_SUCCESS;
577 isc_result_t tresult;
579 const cfg_obj_t *obj = NULL;
580 const cfg_obj_t *resignobj = NULL;
581 const cfg_listelt_t *element;
582 isc_symtab_t *symtab = NULL;
583 dns_fixedname_t fixed;
588 static intervaltable intervals[] = {
589 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
590 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
591 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
592 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
593 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
594 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
595 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
596 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
600 * Check that fields specified in units of time other than seconds
601 * have reasonable values.
603 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
606 (void)cfg_map_get(options, intervals[i].name, &obj);
609 val = cfg_obj_asuint32(obj);
610 if (val > intervals[i].max) {
611 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
612 "%s '%u' is out of range (0..%u)",
613 intervals[i].name, val,
615 result = ISC_R_RANGE;
616 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
617 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
618 "%s '%d' is out of range",
619 intervals[i].name, val);
620 result = ISC_R_RANGE;
625 cfg_map_get(options, "sig-validity-interval", &obj);
627 isc_uint32_t validity, resign = 0;
629 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
630 resignobj = cfg_tuple_get(obj, "re-sign");
631 if (!cfg_obj_isvoid(resignobj))
632 resign = cfg_obj_asuint32(resignobj);
634 if (validity > 3660 || validity == 0) { /* 10 years */
635 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
636 "%s '%u' is out of range (1..3660)",
637 "sig-validity-interval", validity);
638 result = ISC_R_RANGE;
641 if (!cfg_obj_isvoid(resignobj)) {
642 if (resign > 3660 || resign == 0) { /* 10 years */
643 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
644 "%s '%u' is out of range (1..3660)",
645 "sig-validity-interval (re-sign)",
647 result = ISC_R_RANGE;
648 } else if ((validity > 7 && validity < resign) ||
649 (validity <= 7 && validity * 24 < resign)) {
650 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
651 "validity interval (%u days) "
652 "less than re-signing interval "
653 "(%u %s)", validity, resign,
654 (validity > 7) ? "days" : "hours");
655 result = ISC_R_RANGE;
661 (void)cfg_map_get(options, "preferred-glue", &obj);
664 str = cfg_obj_asstring(obj);
665 if (strcasecmp(str, "a") != 0 &&
666 strcasecmp(str, "aaaa") != 0 &&
667 strcasecmp(str, "none") != 0)
668 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
669 "preferred-glue unexpected value '%s'",
674 (void)cfg_map_get(options, "root-delegation-only", &obj);
676 if (!cfg_obj_isvoid(obj)) {
677 const cfg_listelt_t *element;
678 const cfg_obj_t *exclude;
680 dns_fixedname_t fixed;
684 dns_fixedname_init(&fixed);
685 name = dns_fixedname_name(&fixed);
686 for (element = cfg_list_first(obj);
688 element = cfg_list_next(element)) {
689 exclude = cfg_listelt_value(element);
690 str = cfg_obj_asstring(exclude);
691 isc_buffer_init(&b, str, strlen(str));
692 isc_buffer_add(&b, strlen(str));
693 tresult = dns_name_fromtext(name, &b,
696 if (tresult != ISC_R_SUCCESS) {
697 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
698 "bad domain name '%s'",
707 * Set supported DNSSEC algorithms.
710 (void)cfg_map_get(options, "disable-algorithms", &obj);
712 for (element = cfg_list_first(obj);
714 element = cfg_list_next(element))
716 obj = cfg_listelt_value(element);
717 tresult = disabled_algorithms(obj, logctx);
718 if (tresult != ISC_R_SUCCESS)
723 dns_fixedname_init(&fixed);
724 name = dns_fixedname_name(&fixed);
727 * Check the DLV zone name.
730 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
732 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
734 if (tresult != ISC_R_SUCCESS)
736 for (element = cfg_list_first(obj);
738 element = cfg_list_next(element))
741 const cfg_obj_t *anchor;
743 obj = cfg_listelt_value(element);
745 dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain"));
746 anchor = cfg_tuple_get(obj, "trust-anchor");
749 * If domain is "auto" and trust anchor is missing,
750 * skip remaining tests
752 if (!strcmp(dlv, "auto") && cfg_obj_isvoid(anchor))
755 isc_buffer_init(&b, dlv, strlen(dlv));
756 isc_buffer_add(&b, strlen(dlv));
757 tresult = dns_name_fromtext(name, &b, dns_rootname,
759 if (tresult != ISC_R_SUCCESS) {
760 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
761 "bad domain name '%s'", dlv);
765 if (symtab != NULL) {
766 tresult = nameexist(obj, dlv, 1, symtab,
767 "dnssec-lookaside '%s': "
768 "already exists previous "
771 if (tresult != ISC_R_SUCCESS &&
772 result == ISC_R_SUCCESS)
776 * XXXMPA to be removed when multiple lookaside
777 * namespaces are supported.
779 if (!dns_name_equal(dns_rootname, name)) {
780 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
781 "dnssec-lookaside '%s': "
782 "non-root not yet supported", dlv);
783 if (result == ISC_R_SUCCESS)
784 result = ISC_R_FAILURE;
787 if (!cfg_obj_isvoid(anchor)) {
788 dlv = cfg_obj_asstring(anchor);
789 isc_buffer_init(&b, dlv, strlen(dlv));
790 isc_buffer_add(&b, strlen(dlv));
791 tresult = dns_name_fromtext(name, &b,
795 if (tresult != ISC_R_SUCCESS) {
796 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
797 "bad domain name '%s'",
799 if (result == ISC_R_SUCCESS)
803 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
804 "dnssec-lookaside requires "
805 "either 'auto' or a domain and "
807 if (result == ISC_R_SUCCESS)
808 result = ISC_R_FAILURE;
813 isc_symtab_destroy(&symtab);
817 * Check dnssec-must-be-secure.
820 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
822 isc_symtab_t *symtab = NULL;
823 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
825 if (tresult != ISC_R_SUCCESS)
827 for (element = cfg_list_first(obj);
829 element = cfg_list_next(element))
831 obj = cfg_listelt_value(element);
832 tresult = mustbesecure(obj, symtab, logctx, mctx);
833 if (tresult != ISC_R_SUCCESS)
837 isc_symtab_destroy(&symtab);
841 * Check empty zone configuration.
844 (void)cfg_map_get(options, "empty-server", &obj);
846 str = cfg_obj_asstring(obj);
847 isc_buffer_init(&b, str, strlen(str));
848 isc_buffer_add(&b, strlen(str));
849 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
850 dns_rootname, 0, NULL);
851 if (tresult != ISC_R_SUCCESS) {
852 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
853 "empty-server: invalid name '%s'", str);
854 result = ISC_R_FAILURE;
859 (void)cfg_map_get(options, "empty-contact", &obj);
861 str = cfg_obj_asstring(obj);
862 isc_buffer_init(&b, str, strlen(str));
863 isc_buffer_add(&b, strlen(str));
864 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
865 dns_rootname, 0, NULL);
866 if (tresult != ISC_R_SUCCESS) {
867 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
868 "empty-contact: invalid name '%s'", str);
869 result = ISC_R_FAILURE;
874 (void)cfg_map_get(options, "disable-empty-zone", &obj);
875 for (element = cfg_list_first(obj);
877 element = cfg_list_next(element))
879 obj = cfg_listelt_value(element);
880 str = cfg_obj_asstring(obj);
881 isc_buffer_init(&b, str, strlen(str));
882 isc_buffer_add(&b, strlen(str));
883 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
884 dns_rootname, 0, NULL);
885 if (tresult != ISC_R_SUCCESS) {
886 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
887 "disable-empty-zone: invalid name '%s'",
889 result = ISC_R_FAILURE;
894 * Check that server-id is not too long.
895 * 1024 bytes should be big enough.
898 (void)cfg_map_get(options, "server-id", &obj);
899 if (obj != NULL && cfg_obj_isstring(obj) &&
900 strlen(cfg_obj_asstring(obj)) > 1024U) {
901 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
902 "'server-id' too big (>1024 bytes)");
903 result = ISC_R_FAILURE;
910 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
912 const cfg_obj_t *masters = NULL;
913 const cfg_listelt_t *elt;
915 result = cfg_map_get(cctx, "masters", &masters);
916 if (result != ISC_R_SUCCESS)
918 for (elt = cfg_list_first(masters);
920 elt = cfg_list_next(elt)) {
921 const cfg_obj_t *list;
922 const char *listname;
924 list = cfg_listelt_value(elt);
925 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
927 if (strcasecmp(listname, name) == 0) {
929 return (ISC_R_SUCCESS);
932 return (ISC_R_NOTFOUND);
936 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
937 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
939 isc_result_t result = ISC_R_SUCCESS;
940 isc_result_t tresult;
941 isc_uint32_t count = 0;
942 isc_symtab_t *symtab = NULL;
943 isc_symvalue_t symvalue;
944 const cfg_listelt_t *element;
945 const cfg_listelt_t **stack = NULL;
946 isc_uint32_t stackcount = 0, pushed = 0;
947 const cfg_obj_t *list;
949 REQUIRE(countp != NULL);
950 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
951 if (result != ISC_R_SUCCESS) {
957 list = cfg_tuple_get(obj, "addresses");
958 element = cfg_list_first(list);
962 element = cfg_list_next(element))
964 const char *listname;
965 const cfg_obj_t *addr;
966 const cfg_obj_t *key;
968 addr = cfg_tuple_get(cfg_listelt_value(element),
970 key = cfg_tuple_get(cfg_listelt_value(element), "key");
972 if (cfg_obj_issockaddr(addr)) {
976 if (!cfg_obj_isvoid(key)) {
977 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
978 "unexpected token '%s'",
979 cfg_obj_asstring(key));
980 if (result == ISC_R_SUCCESS)
981 result = ISC_R_FAILURE;
983 listname = cfg_obj_asstring(addr);
984 symvalue.as_cpointer = addr;
985 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
986 isc_symexists_reject);
987 if (tresult == ISC_R_EXISTS)
989 tresult = get_masters_def(config, listname, &obj);
990 if (tresult != ISC_R_SUCCESS) {
991 if (result == ISC_R_SUCCESS)
993 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
994 "unable to find masters list '%s'",
999 if (stackcount == pushed) {
1001 isc_uint32_t newlen = stackcount + 16;
1002 size_t newsize, oldsize;
1004 newsize = newlen * sizeof(*stack);
1005 oldsize = stackcount * sizeof(*stack);
1006 new = isc_mem_get(mctx, newsize);
1009 if (stackcount != 0) {
1012 DE_CONST(stack, ptr);
1013 memcpy(new, stack, oldsize);
1014 isc_mem_put(mctx, ptr, oldsize);
1017 stackcount = newlen;
1019 stack[pushed++] = cfg_list_next(element);
1023 element = stack[--pushed];
1027 if (stack != NULL) {
1030 DE_CONST(stack, ptr);
1031 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
1033 isc_symtab_destroy(&symtab);
1039 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
1040 isc_result_t result = ISC_R_SUCCESS;
1041 isc_result_t tresult;
1042 const cfg_listelt_t *element;
1043 const cfg_listelt_t *element2;
1044 dns_fixedname_t fixed;
1048 /* Check for "update-policy local;" */
1049 if (cfg_obj_isstring(policy) &&
1050 strcmp("local", cfg_obj_asstring(policy)) == 0)
1051 return (ISC_R_SUCCESS);
1053 /* Now check the grant policy */
1054 for (element = cfg_list_first(policy);
1056 element = cfg_list_next(element))
1058 const cfg_obj_t *stmt = cfg_listelt_value(element);
1059 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
1060 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
1061 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
1062 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
1064 dns_fixedname_init(&fixed);
1065 str = cfg_obj_asstring(identity);
1066 isc_buffer_init(&b, str, strlen(str));
1067 isc_buffer_add(&b, strlen(str));
1068 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1069 dns_rootname, 0, NULL);
1070 if (tresult != ISC_R_SUCCESS) {
1071 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1072 "'%s' is not a valid name", str);
1076 if (tresult == ISC_R_SUCCESS &&
1077 strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) {
1078 dns_fixedname_init(&fixed);
1079 str = cfg_obj_asstring(dname);
1080 isc_buffer_init(&b, str, strlen(str));
1081 isc_buffer_add(&b, strlen(str));
1082 tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
1083 &b, dns_rootname, 0, NULL);
1084 if (tresult != ISC_R_SUCCESS) {
1085 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
1086 "'%s' is not a valid name", str);
1091 if (tresult == ISC_R_SUCCESS &&
1092 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
1093 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
1094 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1095 "'%s' is not a wildcard", str);
1096 result = ISC_R_FAILURE;
1099 for (element2 = cfg_list_first(typelist);
1101 element2 = cfg_list_next(element2))
1103 const cfg_obj_t *typeobj;
1105 dns_rdatatype_t type;
1107 typeobj = cfg_listelt_value(element2);
1108 DE_CONST(cfg_obj_asstring(typeobj), r.base);
1109 r.length = strlen(r.base);
1111 tresult = dns_rdatatype_fromtext(&type, &r);
1112 if (tresult != ISC_R_SUCCESS) {
1113 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
1114 "'%s' is not a valid type", r.base);
1122 #define MASTERZONE 1
1126 #define FORWARDZONE 16
1127 #define DELEGATIONZONE 32
1136 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
1137 const cfg_obj_t *config, isc_symtab_t *symtab,
1138 dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
1139 isc_log_t *logctx, isc_mem_t *mctx)
1142 const char *typestr;
1144 const cfg_obj_t *zoptions;
1145 const cfg_obj_t *obj = NULL;
1146 isc_result_t result = ISC_R_SUCCESS;
1147 isc_result_t tresult;
1149 dns_rdataclass_t zclass;
1150 dns_fixedname_t fixedname;
1152 isc_boolean_t root = ISC_FALSE;
1154 static optionstable options[] = {
1155 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL },
1156 { "allow-notify", SLAVEZONE | CHECKACL },
1157 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
1158 { "notify", MASTERZONE | SLAVEZONE },
1159 { "also-notify", MASTERZONE | SLAVEZONE },
1160 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
1161 { "delegation-only", HINTZONE | STUBZONE | DELEGATIONZONE },
1162 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
1163 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
1164 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
1165 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
1166 { "notify-source", MASTERZONE | SLAVEZONE },
1167 { "notify-source-v6", MASTERZONE | SLAVEZONE },
1168 { "transfer-source", SLAVEZONE | STUBZONE },
1169 { "transfer-source-v6", SLAVEZONE | STUBZONE },
1170 { "max-transfer-time-in", SLAVEZONE | STUBZONE },
1171 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
1172 { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
1173 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
1174 { "max-retry-time", SLAVEZONE | STUBZONE },
1175 { "min-retry-time", SLAVEZONE | STUBZONE },
1176 { "max-refresh-time", SLAVEZONE | STUBZONE },
1177 { "min-refresh-time", SLAVEZONE | STUBZONE },
1178 { "dnssec-secure-to-insecure", MASTERZONE },
1179 { "sig-validity-interval", MASTERZONE },
1180 { "sig-re-signing-interval", MASTERZONE },
1181 { "sig-signing-nodes", MASTERZONE },
1182 { "sig-signing-type", MASTERZONE },
1183 { "sig-signing-signatures", MASTERZONE },
1184 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE },
1185 { "allow-update", MASTERZONE | CHECKACL },
1186 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
1187 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1188 { "journal", MASTERZONE | SLAVEZONE },
1189 { "ixfr-base", MASTERZONE | SLAVEZONE },
1190 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
1191 { "masters", SLAVEZONE | STUBZONE },
1192 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
1193 { "update-policy", MASTERZONE },
1194 { "database", MASTERZONE | SLAVEZONE | STUBZONE },
1195 { "key-directory", MASTERZONE },
1196 { "check-wildcard", MASTERZONE },
1197 { "check-mx", MASTERZONE },
1198 { "check-dup-records", MASTERZONE },
1199 { "integrity-check", MASTERZONE },
1200 { "check-mx-cname", MASTERZONE },
1201 { "check-srv-cname", MASTERZONE },
1202 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1203 { "update-check-ksk", MASTERZONE },
1204 { "dnssec-dnskey-kskonly", MASTERZONE },
1205 { "auto-dnssec", MASTERZONE },
1206 { "try-tcp-refresh", SLAVEZONE },
1209 static optionstable dialups[] = {
1210 { "notify", MASTERZONE | SLAVEZONE },
1211 { "notify-passive", SLAVEZONE },
1212 { "refresh", SLAVEZONE | STUBZONE },
1213 { "passive", SLAVEZONE | STUBZONE },
1216 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1218 zoptions = cfg_tuple_get(zconfig, "options");
1221 (void)cfg_map_get(zoptions, "type", &obj);
1223 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1224 "zone '%s': type not present", zname);
1225 return (ISC_R_FAILURE);
1228 typestr = cfg_obj_asstring(obj);
1229 if (strcasecmp(typestr, "master") == 0)
1231 else if (strcasecmp(typestr, "slave") == 0)
1233 else if (strcasecmp(typestr, "stub") == 0)
1235 else if (strcasecmp(typestr, "forward") == 0)
1236 ztype = FORWARDZONE;
1237 else if (strcasecmp(typestr, "hint") == 0)
1239 else if (strcasecmp(typestr, "delegation-only") == 0)
1240 ztype = DELEGATIONZONE;
1242 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1243 "zone '%s': invalid type %s",
1245 return (ISC_R_FAILURE);
1248 obj = cfg_tuple_get(zconfig, "class");
1249 if (cfg_obj_isstring(obj)) {
1252 DE_CONST(cfg_obj_asstring(obj), r.base);
1253 r.length = strlen(r.base);
1254 result = dns_rdataclass_fromtext(&zclass, &r);
1255 if (result != ISC_R_SUCCESS) {
1256 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1257 "zone '%s': invalid class %s",
1259 return (ISC_R_FAILURE);
1261 if (zclass != defclass) {
1262 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1263 "zone '%s': class '%s' does not "
1264 "match view/default class",
1266 return (ISC_R_FAILURE);
1271 * Look for an already existing zone.
1272 * We need to make this canonical as isc_symtab_define()
1273 * deals with strings.
1275 dns_fixedname_init(&fixedname);
1276 isc_buffer_init(&b, zname, strlen(zname));
1277 isc_buffer_add(&b, strlen(zname));
1278 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1279 dns_rootname, DNS_NAME_DOWNCASE, NULL);
1280 if (tresult != ISC_R_SUCCESS) {
1281 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1282 "zone '%s': is not a valid name", zname);
1283 result = ISC_R_FAILURE;
1285 char namebuf[DNS_NAME_FORMATSIZE];
1287 dns_name_format(dns_fixedname_name(&fixedname),
1288 namebuf, sizeof(namebuf));
1289 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
1290 symtab, "zone '%s': already exists "
1291 "previous definition: %s:%u", logctx, mctx);
1292 if (tresult != ISC_R_SUCCESS)
1294 if (dns_name_equal(dns_fixedname_name(&fixedname),
1300 * Look for inappropriate options for the given zone type.
1301 * Check that ACLs expand correctly.
1303 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1305 if ((options[i].allowed & ztype) == 0 &&
1306 cfg_map_get(zoptions, options[i].name, &obj) ==
1309 if (strcmp(options[i].name, "allow-update") != 0 ||
1310 ztype != SLAVEZONE) {
1311 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1312 "option '%s' is not allowed "
1313 "in '%s' zone '%s'",
1314 options[i].name, typestr, zname);
1315 result = ISC_R_FAILURE;
1317 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1318 "option '%s' is not allowed "
1319 "in '%s' zone '%s'",
1320 options[i].name, typestr, zname);
1323 if ((options[i].allowed & ztype) != 0 &&
1324 (options[i].allowed & CHECKACL) != 0) {
1326 tresult = checkacl(options[i].name, actx, zconfig,
1327 voptions, config, logctx, mctx);
1328 if (tresult != ISC_R_SUCCESS)
1335 * Slave & stub zones must have a "masters" field.
1337 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1339 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1340 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1341 "zone '%s': missing 'masters' entry",
1343 result = ISC_R_FAILURE;
1346 tresult = validate_masters(obj, config, &count,
1348 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1350 if (tresult == ISC_R_SUCCESS && count == 0) {
1351 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1352 "zone '%s': empty 'masters' entry",
1354 result = ISC_R_FAILURE;
1360 * Master zones can't have both "allow-update" and "update-policy".
1362 if (ztype == MASTERZONE) {
1363 isc_result_t res1, res2, res3;
1368 res1 = cfg_map_get(zoptions, "allow-update", &obj);
1370 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1371 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1372 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1373 "zone '%s': 'allow-update' is ignored "
1374 "when 'update-policy' is present",
1376 result = ISC_R_FAILURE;
1377 } else if (res2 == ISC_R_SUCCESS &&
1378 check_update_policy(obj, logctx) != ISC_R_SUCCESS)
1379 result = ISC_R_FAILURE;
1380 ddns = ISC_TF(res1 == ISC_R_SUCCESS || res2 == ISC_R_SUCCESS);
1384 res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
1385 if (res3 == ISC_R_SUCCESS)
1386 arg = cfg_obj_asstring(obj);
1387 if (strcasecmp(arg, "off") != 0 && !ddns) {
1388 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1389 "'auto-dnssec %s;' requires "
1390 "dynamic DNS to be configured in the zone",
1392 result = ISC_R_FAILURE;
1394 if (strcasecmp(arg, "create") == 0) {
1395 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1396 "'auto-dnssec create;' is not "
1398 result = ISC_R_FAILURE;
1402 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
1403 if (res1 == ISC_R_SUCCESS) {
1404 isc_uint32_t type = cfg_obj_asuint32(obj);
1405 if (type < 0xff00U || type > 0xffffU)
1406 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1407 "sig-signing-type: %u out of "
1408 "range [%u..%u]", type,
1410 result = ISC_R_FAILURE;
1415 * Check the excessively complicated "dialup" option.
1417 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1418 const cfg_obj_t *dialup = NULL;
1419 (void)cfg_map_get(zoptions, "dialup", &dialup);
1420 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1421 const char *str = cfg_obj_asstring(dialup);
1423 i < sizeof(dialups) / sizeof(dialups[0]);
1426 if (strcasecmp(dialups[i].name, str) != 0)
1428 if ((dialups[i].allowed & ztype) == 0) {
1429 cfg_obj_log(obj, logctx,
1431 "dialup type '%s' is not "
1434 str, typestr, zname);
1435 result = ISC_R_FAILURE;
1439 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1440 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1441 "invalid dialup type '%s' in zone "
1442 "'%s'", str, zname);
1443 result = ISC_R_FAILURE;
1449 * Check that forwarding is reasonable.
1453 if (voptions != NULL)
1454 (void)cfg_map_get(voptions, "forwarders", &obj);
1456 const cfg_obj_t *options = NULL;
1457 (void)cfg_map_get(config, "options", &options);
1458 if (options != NULL)
1459 (void)cfg_map_get(options, "forwarders", &obj);
1462 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
1463 result = ISC_R_FAILURE;
1466 * Check various options.
1468 tresult = check_options(zoptions, logctx, mctx);
1469 if (tresult != ISC_R_SUCCESS)
1473 * If the zone type is rbt/rbt64 then master/hint zones
1474 * require file clauses.
1477 tresult = cfg_map_get(zoptions, "database", &obj);
1478 if (tresult == ISC_R_NOTFOUND ||
1479 (tresult == ISC_R_SUCCESS &&
1480 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1481 strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
1483 tresult = cfg_map_get(zoptions, "file", &obj);
1484 if (tresult != ISC_R_SUCCESS &&
1485 (ztype == MASTERZONE || ztype == HINTZONE)) {
1486 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1487 "zone '%s': missing 'file' entry",
1497 typedef struct keyalgorithms {
1503 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1504 const cfg_obj_t *algobj = NULL;
1505 const cfg_obj_t *secretobj = NULL;
1506 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1507 const char *algorithm;
1510 isc_result_t result;
1512 unsigned char secretbuf[1024];
1513 static const algorithmtable algorithms[] = {
1514 { "hmac-md5", 128 },
1515 { "hmac-md5.sig-alg.reg.int", 0 },
1516 { "hmac-md5.sig-alg.reg.int.", 0 },
1517 { "hmac-sha1", 160 },
1518 { "hmac-sha224", 224 },
1519 { "hmac-sha256", 256 },
1520 { "hmac-sha384", 384 },
1521 { "hmac-sha512", 512 },
1525 (void)cfg_map_get(key, "algorithm", &algobj);
1526 (void)cfg_map_get(key, "secret", &secretobj);
1527 if (secretobj == NULL || algobj == NULL) {
1528 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1529 "key '%s' must have both 'secret' and "
1530 "'algorithm' defined",
1532 return (ISC_R_FAILURE);
1535 isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
1536 result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
1537 if (result != ISC_R_SUCCESS) {
1538 cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
1539 "bad secret '%s'", isc_result_totext(result));
1543 algorithm = cfg_obj_asstring(algobj);
1544 for (i = 0; algorithms[i].name != NULL; i++) {
1545 len = strlen(algorithms[i].name);
1546 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1547 (algorithm[len] == '\0' ||
1548 (algorithms[i].size != 0 && algorithm[len] == '-')))
1551 if (algorithms[i].name == NULL) {
1552 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1553 "unknown algorithm '%s'", algorithm);
1554 return (ISC_R_NOTFOUND);
1556 if (algorithm[len] == '-') {
1557 isc_uint16_t digestbits;
1558 isc_result_t result;
1559 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1560 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1561 if (result == ISC_R_RANGE ||
1562 digestbits > algorithms[i].size) {
1563 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1564 "key '%s' digest-bits too large "
1565 "[%u..%u]", keyname,
1566 algorithms[i].size / 2,
1567 algorithms[i].size);
1568 return (ISC_R_RANGE);
1570 if ((digestbits % 8) != 0) {
1571 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1572 "key '%s' digest-bits not multiple"
1574 return (ISC_R_RANGE);
1577 * Recommended minima for hmac algorithms.
1579 if ((digestbits < (algorithms[i].size / 2U) ||
1580 (digestbits < 80U)))
1581 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
1582 "key '%s' digest-bits too small "
1584 algorithms[i].size/2);
1586 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1587 "key '%s': unable to parse digest-bits",
1592 return (ISC_R_SUCCESS);
1596 * Check key list for duplicates key names and that the key names
1597 * are valid domain names as these keys are used for TSIG.
1599 * Check the key contents for validity.
1602 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
1603 isc_mem_t *mctx, isc_log_t *logctx)
1605 char namebuf[DNS_NAME_FORMATSIZE];
1606 dns_fixedname_t fname;
1608 isc_result_t result = ISC_R_SUCCESS;
1609 isc_result_t tresult;
1610 const cfg_listelt_t *element;
1612 dns_fixedname_init(&fname);
1613 name = dns_fixedname_name(&fname);
1614 for (element = cfg_list_first(keys);
1616 element = cfg_list_next(element))
1618 const cfg_obj_t *key = cfg_listelt_value(element);
1619 const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
1620 isc_symvalue_t symvalue;
1624 isc_buffer_init(&b, keyid, strlen(keyid));
1625 isc_buffer_add(&b, strlen(keyid));
1626 tresult = dns_name_fromtext(name, &b, dns_rootname,
1628 if (tresult != ISC_R_SUCCESS) {
1629 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1630 "key '%s': bad key name", keyid);
1634 tresult = bind9_check_key(key, logctx);
1635 if (tresult != ISC_R_SUCCESS)
1638 dns_name_format(name, namebuf, sizeof(namebuf));
1639 keyname = isc_mem_strdup(mctx, namebuf);
1640 if (keyname == NULL)
1641 return (ISC_R_NOMEMORY);
1642 symvalue.as_cpointer = key;
1643 tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
1644 isc_symexists_reject);
1645 if (tresult == ISC_R_EXISTS) {
1649 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
1650 1, &symvalue) == ISC_R_SUCCESS);
1651 file = cfg_obj_file(symvalue.as_cpointer);
1652 line = cfg_obj_line(symvalue.as_cpointer);
1655 file = "<unknown file>";
1656 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1657 "key '%s': already exists "
1658 "previous definition: %s:%u",
1660 isc_mem_free(mctx, keyname);
1662 } else if (tresult != ISC_R_SUCCESS) {
1663 isc_mem_free(mctx, keyname);
1674 { "transfer-source", "transfer-source-v6" },
1675 { "notify-source", "notify-source-v6" },
1676 { "query-source", "query-source-v6" },
1681 * RNDC keys are not normalised unlike TSIG keys.
1683 * "foo." is different to "foo".
1685 static isc_boolean_t
1686 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
1687 const cfg_listelt_t *element;
1688 const cfg_obj_t *obj;
1691 if (keylist == NULL)
1694 for (element = cfg_list_first(keylist);
1696 element = cfg_list_next(element))
1698 obj = cfg_listelt_value(element);
1699 str = cfg_obj_asstring(cfg_map_getname(obj));
1700 if (!strcasecmp(str, keyname))
1707 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
1708 isc_symtab_t *symtab, isc_log_t *logctx)
1710 dns_fixedname_t fname;
1711 isc_result_t result = ISC_R_SUCCESS;
1712 isc_result_t tresult;
1713 const cfg_listelt_t *e1, *e2;
1714 const cfg_obj_t *v1, *v2, *keys;
1715 const cfg_obj_t *servers;
1716 isc_netaddr_t n1, n2;
1717 unsigned int p1, p2;
1718 const cfg_obj_t *obj;
1719 char buf[ISC_NETADDR_FORMATSIZE];
1720 char namebuf[DNS_NAME_FORMATSIZE];
1725 dns_name_t *keyname;
1728 if (voptions != NULL)
1729 (void)cfg_map_get(voptions, "server", &servers);
1730 if (servers == NULL)
1731 (void)cfg_map_get(config, "server", &servers);
1732 if (servers == NULL)
1733 return (ISC_R_SUCCESS);
1735 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
1736 v1 = cfg_listelt_value(e1);
1737 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
1739 * Check that unused bits are zero.
1741 tresult = isc_netaddr_prefixok(&n1, p1);
1742 if (tresult != ISC_R_SUCCESS) {
1743 INSIST(tresult == ISC_R_FAILURE);
1744 isc_netaddr_format(&n1, buf, sizeof(buf));
1745 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1746 "server '%s/%u': invalid prefix "
1747 "(extra bits specified)", buf, p1);
1753 if (n1.family == AF_INET)
1754 xfr = sources[source].v6;
1756 xfr = sources[source].v4;
1757 (void)cfg_map_get(v1, xfr, &obj);
1759 isc_netaddr_format(&n1, buf, sizeof(buf));
1760 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1761 "server '%s/%u': %s not legal",
1763 result = ISC_R_FAILURE;
1765 } while (sources[++source].v4 != NULL);
1767 while ((e2 = cfg_list_next(e2)) != NULL) {
1768 v2 = cfg_listelt_value(e2);
1769 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
1770 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
1771 const char *file = cfg_obj_file(v1);
1772 unsigned int line = cfg_obj_line(v1);
1775 file = "<unknown file>";
1777 isc_netaddr_format(&n2, buf, sizeof(buf));
1778 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
1779 "server '%s/%u': already exists "
1780 "previous definition: %s:%u",
1781 buf, p2, file, line);
1782 result = ISC_R_FAILURE;
1786 cfg_map_get(v1, "keys", &keys);
1789 * Normalize key name.
1791 keyval = cfg_obj_asstring(keys);
1792 dns_fixedname_init(&fname);
1793 isc_buffer_init(&b, keyval, strlen(keyval));
1794 isc_buffer_add(&b, strlen(keyval));
1795 keyname = dns_fixedname_name(&fname);
1796 tresult = dns_name_fromtext(keyname, &b, dns_rootname,
1798 if (tresult != ISC_R_SUCCESS) {
1799 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
1800 "bad key name '%s'", keyval);
1801 result = ISC_R_FAILURE;
1804 dns_name_format(keyname, namebuf, sizeof(namebuf));
1805 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
1806 if (tresult != ISC_R_SUCCESS) {
1807 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
1808 "unknown key '%s'", keyval);
1809 result = ISC_R_FAILURE;
1817 check_trusted_key(const cfg_obj_t *key, isc_boolean_t managed,
1820 const char *keystr, *keynamestr;
1821 dns_fixedname_t fkeyname;
1822 dns_name_t *keyname;
1823 isc_buffer_t keydatabuf;
1825 isc_result_t result = ISC_R_SUCCESS;
1826 isc_result_t tresult;
1827 isc_uint32_t flags, proto, alg;
1828 unsigned char keydata[4096];
1830 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
1831 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
1832 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
1833 keyname = dns_fixedname_name(&fkeyname);
1834 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
1836 if (flags > 0xffff) {
1837 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
1838 "flags too big: %u\n", flags);
1839 result = ISC_R_FAILURE;
1842 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
1843 "protocol too big: %u\n", proto);
1844 result = ISC_R_FAILURE;
1847 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
1848 "algorithm too big: %u\n", alg);
1849 result = ISC_R_FAILURE;
1853 const char *initmethod;
1854 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
1856 if (strcasecmp(initmethod, "initial-key") != 0) {
1857 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1858 "managed key '%s': "
1859 "invalid initialization method '%s'",
1860 keynamestr, initmethod);
1861 result = ISC_R_FAILURE;
1865 isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
1867 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
1868 tresult = isc_base64_decodestring(keystr, &keydatabuf);
1870 if (tresult != ISC_R_SUCCESS) {
1871 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1872 "%s", isc_result_totext(tresult));
1873 result = ISC_R_FAILURE;
1875 isc_buffer_usedregion(&keydatabuf, &r);
1877 if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
1878 r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
1879 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
1880 "%s key '%s' has a weak exponent",
1881 managed ? "managed" : "trusted",
1889 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
1890 const char *viewname, dns_rdataclass_t vclass,
1891 isc_log_t *logctx, isc_mem_t *mctx)
1893 const cfg_obj_t *zones = NULL;
1894 const cfg_obj_t *keys = NULL;
1895 const cfg_listelt_t *element, *element2;
1896 isc_symtab_t *symtab = NULL;
1897 isc_result_t result = ISC_R_SUCCESS;
1898 isc_result_t tresult = ISC_R_SUCCESS;
1899 cfg_aclconfctx_t actx;
1900 const cfg_obj_t *obj;
1901 isc_boolean_t enablednssec, enablevalidation;
1904 * Check that all zone statements are syntactically correct and
1905 * there are no duplicate zones.
1907 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1908 ISC_FALSE, &symtab);
1909 if (tresult != ISC_R_SUCCESS)
1910 return (ISC_R_NOMEMORY);
1912 cfg_aclconfctx_init(&actx);
1914 if (voptions != NULL)
1915 (void)cfg_map_get(voptions, "zone", &zones);
1917 (void)cfg_map_get(config, "zone", &zones);
1919 for (element = cfg_list_first(zones);
1921 element = cfg_list_next(element))
1923 isc_result_t tresult;
1924 const cfg_obj_t *zone = cfg_listelt_value(element);
1926 tresult = check_zoneconf(zone, voptions, config, symtab,
1927 vclass, &actx, logctx, mctx);
1928 if (tresult != ISC_R_SUCCESS)
1929 result = ISC_R_FAILURE;
1932 isc_symtab_destroy(&symtab);
1935 * Check that forwarding is reasonable.
1937 if (voptions == NULL) {
1938 const cfg_obj_t *options = NULL;
1939 (void)cfg_map_get(config, "options", &options);
1940 if (options != NULL)
1941 if (check_forward(options, NULL,
1942 logctx) != ISC_R_SUCCESS)
1943 result = ISC_R_FAILURE;
1945 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
1946 result = ISC_R_FAILURE;
1950 * Check that dual-stack-servers is reasonable.
1952 if (voptions == NULL) {
1953 const cfg_obj_t *options = NULL;
1954 (void)cfg_map_get(config, "options", &options);
1955 if (options != NULL)
1956 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1957 result = ISC_R_FAILURE;
1959 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
1960 result = ISC_R_FAILURE;
1964 * Check that rrset-order is reasonable.
1966 if (voptions != NULL) {
1967 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
1968 result = ISC_R_FAILURE;
1972 * Check that all key statements are syntactically correct and
1973 * there are no duplicate keys.
1975 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1976 ISC_FALSE, &symtab);
1977 if (tresult != ISC_R_SUCCESS)
1978 return (ISC_R_NOMEMORY);
1980 (void)cfg_map_get(config, "key", &keys);
1981 tresult = check_keylist(keys, symtab, mctx, logctx);
1982 if (tresult == ISC_R_EXISTS)
1983 result = ISC_R_FAILURE;
1984 else if (tresult != ISC_R_SUCCESS) {
1985 isc_symtab_destroy(&symtab);
1989 if (voptions != NULL) {
1991 (void)cfg_map_get(voptions, "key", &keys);
1992 tresult = check_keylist(keys, symtab, mctx, logctx);
1993 if (tresult == ISC_R_EXISTS)
1994 result = ISC_R_FAILURE;
1995 else if (tresult != ISC_R_SUCCESS) {
1996 isc_symtab_destroy(&symtab);
2002 * Global servers can refer to keys in views.
2004 if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
2005 result = ISC_R_FAILURE;
2007 isc_symtab_destroy(&symtab);
2010 * Check that dnssec-enable/dnssec-validation are sensible.
2013 if (voptions != NULL)
2014 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
2016 (void)cfg_map_get(config, "dnssec-enable", &obj);
2018 enablednssec = ISC_TRUE;
2020 enablednssec = cfg_obj_asboolean(obj);
2023 if (voptions != NULL)
2024 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
2026 (void)cfg_map_get(config, "dnssec-validation", &obj);
2028 enablevalidation = ISC_FALSE; /* XXXMPA Change for 9.5. */
2030 enablevalidation = cfg_obj_asboolean(obj);
2032 if (enablevalidation && !enablednssec)
2033 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2034 "'dnssec-validation yes;' and 'dnssec-enable no;'");
2037 * Check trusted-keys and managed-keys.
2040 if (voptions != NULL)
2041 (void)cfg_map_get(voptions, "trusted-keys", &keys);
2043 (void)cfg_map_get(config, "trusted-keys", &keys);
2045 for (element = cfg_list_first(keys);
2047 element = cfg_list_next(element))
2049 const cfg_obj_t *keylist = cfg_listelt_value(element);
2050 for (element2 = cfg_list_first(keylist);
2052 element2 = cfg_list_next(element2)) {
2053 obj = cfg_listelt_value(element2);
2054 tresult = check_trusted_key(obj, ISC_FALSE, logctx);
2055 if (tresult != ISC_R_SUCCESS)
2061 if (voptions != NULL)
2062 (void)cfg_map_get(voptions, "managed-keys", &keys);
2064 (void)cfg_map_get(config, "managed-keys", &keys);
2066 for (element = cfg_list_first(keys);
2068 element = cfg_list_next(element))
2070 const cfg_obj_t *keylist = cfg_listelt_value(element);
2071 for (element2 = cfg_list_first(keylist);
2073 element2 = cfg_list_next(element2)) {
2074 obj = cfg_listelt_value(element2);
2075 tresult = check_trusted_key(obj, ISC_TRUE, logctx);
2076 if (tresult != ISC_R_SUCCESS)
2083 if (voptions != NULL)
2084 tresult = check_options(voptions, logctx, mctx);
2086 tresult = check_options(config, logctx, mctx);
2087 if (tresult != ISC_R_SUCCESS)
2090 tresult = check_viewacls(&actx, voptions, config, logctx, mctx);
2091 if (tresult != ISC_R_SUCCESS)
2094 tresult = check_recursionacls(&actx, voptions, viewname,
2095 config, logctx, mctx);
2096 if (tresult != ISC_R_SUCCESS)
2099 tresult = check_filteraaaa(&actx, voptions, viewname, config,
2101 if (tresult != ISC_R_SUCCESS)
2104 cfg_aclconfctx_clear(&actx);
2110 default_channels[] = {
2119 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
2122 const cfg_obj_t *categories = NULL;
2123 const cfg_obj_t *category;
2124 const cfg_obj_t *channels = NULL;
2125 const cfg_obj_t *channel;
2126 const cfg_listelt_t *element;
2127 const cfg_listelt_t *delement;
2128 const char *channelname;
2129 const char *catname;
2130 const cfg_obj_t *fileobj = NULL;
2131 const cfg_obj_t *syslogobj = NULL;
2132 const cfg_obj_t *nullobj = NULL;
2133 const cfg_obj_t *stderrobj = NULL;
2134 const cfg_obj_t *logobj = NULL;
2135 isc_result_t result = ISC_R_SUCCESS;
2136 isc_result_t tresult;
2137 isc_symtab_t *symtab = NULL;
2138 isc_symvalue_t symvalue;
2141 (void)cfg_map_get(config, "logging", &logobj);
2143 return (ISC_R_SUCCESS);
2145 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
2146 if (result != ISC_R_SUCCESS)
2149 symvalue.as_cpointer = NULL;
2150 for (i = 0; default_channels[i] != NULL; i++) {
2151 tresult = isc_symtab_define(symtab, default_channels[i], 1,
2152 symvalue, isc_symexists_replace);
2153 if (tresult != ISC_R_SUCCESS)
2157 cfg_map_get(logobj, "channel", &channels);
2159 for (element = cfg_list_first(channels);
2161 element = cfg_list_next(element))
2163 channel = cfg_listelt_value(element);
2164 channelname = cfg_obj_asstring(cfg_map_getname(channel));
2165 fileobj = syslogobj = nullobj = stderrobj = NULL;
2166 (void)cfg_map_get(channel, "file", &fileobj);
2167 (void)cfg_map_get(channel, "syslog", &syslogobj);
2168 (void)cfg_map_get(channel, "null", &nullobj);
2169 (void)cfg_map_get(channel, "stderr", &stderrobj);
2171 if (fileobj != NULL)
2173 if (syslogobj != NULL)
2175 if (nullobj != NULL)
2177 if (stderrobj != NULL)
2180 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2181 "channel '%s': exactly one of file, syslog, "
2182 "null, and stderr must be present",
2184 result = ISC_R_FAILURE;
2186 tresult = isc_symtab_define(symtab, channelname, 1,
2187 symvalue, isc_symexists_replace);
2188 if (tresult != ISC_R_SUCCESS)
2192 cfg_map_get(logobj, "category", &categories);
2194 for (element = cfg_list_first(categories);
2196 element = cfg_list_next(element))
2198 category = cfg_listelt_value(element);
2199 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
2200 if (isc_log_categorybyname(logctx, catname) == NULL) {
2201 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
2202 "undefined category: '%s'", catname);
2203 result = ISC_R_FAILURE;
2205 channels = cfg_tuple_get(category, "destinations");
2206 for (delement = cfg_list_first(channels);
2208 delement = cfg_list_next(delement))
2210 channel = cfg_listelt_value(delement);
2211 channelname = cfg_obj_asstring(channel);
2212 tresult = isc_symtab_lookup(symtab, channelname, 1,
2214 if (tresult != ISC_R_SUCCESS) {
2215 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2216 "undefined channel: '%s'",
2222 isc_symtab_destroy(&symtab);
2227 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
2230 isc_result_t result = ISC_R_SUCCESS;
2231 const cfg_obj_t *control_keylist;
2232 const cfg_listelt_t *element;
2233 const cfg_obj_t *key;
2236 control_keylist = cfg_tuple_get(control, "keys");
2237 if (cfg_obj_isvoid(control_keylist))
2238 return (ISC_R_SUCCESS);
2240 for (element = cfg_list_first(control_keylist);
2242 element = cfg_list_next(element))
2244 key = cfg_listelt_value(element);
2245 keyval = cfg_obj_asstring(key);
2247 if (!rndckey_exists(keylist, keyval)) {
2248 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2249 "unknown key '%s'", keyval);
2250 result = ISC_R_NOTFOUND;
2257 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
2260 isc_result_t result = ISC_R_SUCCESS, tresult;
2261 cfg_aclconfctx_t actx;
2262 const cfg_listelt_t *element, *element2;
2263 const cfg_obj_t *allow;
2264 const cfg_obj_t *control;
2265 const cfg_obj_t *controls;
2266 const cfg_obj_t *controlslist = NULL;
2267 const cfg_obj_t *inetcontrols;
2268 const cfg_obj_t *unixcontrols;
2269 const cfg_obj_t *keylist = NULL;
2271 isc_uint32_t perm, mask;
2272 dns_acl_t *acl = NULL;
2273 isc_sockaddr_t addr;
2276 (void)cfg_map_get(config, "controls", &controlslist);
2277 if (controlslist == NULL)
2278 return (ISC_R_SUCCESS);
2280 (void)cfg_map_get(config, "key", &keylist);
2282 cfg_aclconfctx_init(&actx);
2285 * INET: Check allow clause.
2286 * UNIX: Check "perm" for sanity, check path length.
2288 for (element = cfg_list_first(controlslist);
2290 element = cfg_list_next(element)) {
2291 controls = cfg_listelt_value(element);
2292 unixcontrols = NULL;
2293 inetcontrols = NULL;
2294 (void)cfg_map_get(controls, "unix", &unixcontrols);
2295 (void)cfg_map_get(controls, "inet", &inetcontrols);
2296 for (element2 = cfg_list_first(inetcontrols);
2298 element2 = cfg_list_next(element2)) {
2299 control = cfg_listelt_value(element2);
2300 allow = cfg_tuple_get(control, "allow");
2301 tresult = cfg_acl_fromconfig(allow, config, logctx,
2302 &actx, mctx, 0, &acl);
2304 dns_acl_detach(&acl);
2305 if (tresult != ISC_R_SUCCESS)
2307 tresult = bind9_check_controlskeys(control, keylist,
2309 if (tresult != ISC_R_SUCCESS)
2312 for (element2 = cfg_list_first(unixcontrols);
2314 element2 = cfg_list_next(element2)) {
2315 control = cfg_listelt_value(element2);
2316 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
2317 tresult = isc_sockaddr_frompath(&addr, path);
2318 if (tresult == ISC_R_NOSPACE) {
2319 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
2320 "unix control '%s': path too long",
2322 result = ISC_R_NOSPACE;
2324 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
2325 for (i = 0; i < 3; i++) {
2326 #ifdef NEED_SECURE_DIRECTORY
2327 mask = (0x1 << (i*3)); /* SEARCH */
2329 mask = (0x6 << (i*3)); /* READ + WRITE */
2331 if ((perm & mask) == mask)
2335 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2336 "unix control '%s' allows access "
2337 "to everyone", path);
2338 } else if (i == 3) {
2339 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2340 "unix control '%s' allows access "
2343 tresult = bind9_check_controlskeys(control, keylist,
2345 if (tresult != ISC_R_SUCCESS)
2349 cfg_aclconfctx_clear(&actx);
2354 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
2357 const cfg_obj_t *options = NULL;
2358 const cfg_obj_t *views = NULL;
2359 const cfg_obj_t *acls = NULL;
2360 const cfg_obj_t *kals = NULL;
2361 const cfg_obj_t *obj;
2362 const cfg_listelt_t *velement;
2363 isc_result_t result = ISC_R_SUCCESS;
2364 isc_result_t tresult;
2365 isc_symtab_t *symtab = NULL;
2367 static const char *builtin[] = { "localhost", "localnets",
2370 (void)cfg_map_get(config, "options", &options);
2372 if (options != NULL &&
2373 check_options(options, logctx, mctx) != ISC_R_SUCCESS)
2374 result = ISC_R_FAILURE;
2376 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
2377 result = ISC_R_FAILURE;
2379 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
2380 result = ISC_R_FAILURE;
2382 if (options != NULL &&
2383 check_order(options, logctx) != ISC_R_SUCCESS)
2384 result = ISC_R_FAILURE;
2386 (void)cfg_map_get(config, "view", &views);
2388 if (views != NULL && options != NULL)
2389 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2390 result = ISC_R_FAILURE;
2392 if (views == NULL) {
2393 if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
2394 logctx, mctx) != ISC_R_SUCCESS)
2395 result = ISC_R_FAILURE;
2397 const cfg_obj_t *zones = NULL;
2399 (void)cfg_map_get(config, "zone", &zones);
2400 if (zones != NULL) {
2401 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
2402 "when using 'view' statements, "
2403 "all zones must be in views");
2404 result = ISC_R_FAILURE;
2408 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
2409 if (tresult != ISC_R_SUCCESS)
2411 for (velement = cfg_list_first(views);
2413 velement = cfg_list_next(velement))
2415 const cfg_obj_t *view = cfg_listelt_value(velement);
2416 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
2417 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
2418 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
2419 dns_rdataclass_t vclass = dns_rdataclass_in;
2420 isc_result_t tresult = ISC_R_SUCCESS;
2421 const char *key = cfg_obj_asstring(vname);
2422 isc_symvalue_t symvalue;
2424 if (cfg_obj_isstring(vclassobj)) {
2427 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
2428 r.length = strlen(r.base);
2429 tresult = dns_rdataclass_fromtext(&vclass, &r);
2430 if (tresult != ISC_R_SUCCESS)
2431 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
2432 "view '%s': invalid class %s",
2433 cfg_obj_asstring(vname), r.base);
2435 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
2436 symvalue.as_cpointer = view;
2437 tresult = isc_symtab_define(symtab, key, vclass,
2439 isc_symexists_reject);
2440 if (tresult == ISC_R_EXISTS) {
2443 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
2444 vclass, &symvalue) == ISC_R_SUCCESS);
2445 file = cfg_obj_file(symvalue.as_cpointer);
2446 line = cfg_obj_line(symvalue.as_cpointer);
2447 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2448 "view '%s': already exists "
2449 "previous definition: %s:%u",
2452 } else if (tresult != ISC_R_SUCCESS) {
2454 } else if ((strcasecmp(key, "_bind") == 0 &&
2455 vclass == dns_rdataclass_ch) ||
2456 (strcasecmp(key, "_default") == 0 &&
2457 vclass == dns_rdataclass_in)) {
2458 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2459 "attempt to redefine builtin view "
2461 result = ISC_R_EXISTS;
2464 if (tresult == ISC_R_SUCCESS)
2465 tresult = check_viewconf(config, voptions, key,
2466 vclass, logctx, mctx);
2467 if (tresult != ISC_R_SUCCESS)
2468 result = ISC_R_FAILURE;
2471 isc_symtab_destroy(&symtab);
2473 if (views != NULL && options != NULL) {
2475 tresult = cfg_map_get(options, "cache-file", &obj);
2476 if (tresult == ISC_R_SUCCESS) {
2477 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2478 "'cache-file' cannot be a global "
2479 "option if views are present");
2480 result = ISC_R_FAILURE;
2484 cfg_map_get(config, "acl", &acls);
2487 const cfg_listelt_t *elt;
2488 const cfg_listelt_t *elt2;
2489 const char *aclname;
2491 for (elt = cfg_list_first(acls);
2493 elt = cfg_list_next(elt)) {
2494 const cfg_obj_t *acl = cfg_listelt_value(elt);
2495 unsigned int line = cfg_obj_line(acl);
2498 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2500 i < sizeof(builtin) / sizeof(builtin[0]);
2502 if (strcasecmp(aclname, builtin[i]) == 0) {
2503 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
2504 "attempt to redefine "
2507 result = ISC_R_FAILURE;
2511 for (elt2 = cfg_list_next(elt);
2513 elt2 = cfg_list_next(elt2)) {
2514 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2516 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2518 if (strcasecmp(aclname, name) == 0) {
2519 const char *file = cfg_obj_file(acl);
2522 file = "<unknown file>";
2524 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2525 "attempt to redefine "
2526 "acl '%s' previous "
2527 "definition: %s:%u",
2529 result = ISC_R_FAILURE;
2535 tresult = cfg_map_get(config, "kal", &kals);
2536 if (tresult == ISC_R_SUCCESS) {
2537 const cfg_listelt_t *elt;
2538 const cfg_listelt_t *elt2;
2539 const char *aclname;
2541 for (elt = cfg_list_first(kals);
2543 elt = cfg_list_next(elt)) {
2544 const cfg_obj_t *acl = cfg_listelt_value(elt);
2546 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2548 for (elt2 = cfg_list_next(elt);
2550 elt2 = cfg_list_next(elt2)) {
2551 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2553 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2555 if (strcasecmp(aclname, name) == 0) {
2556 const char *file = cfg_obj_file(acl);
2557 unsigned int line = cfg_obj_line(acl);
2560 file = "<unknown file>";
2562 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2563 "attempt to redefine "
2564 "kal '%s' previous "
2565 "definition: %s:%u",
2567 result = ISC_R_FAILURE;