2 * Copyright (C) 2004-2009 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.95.12.4 2009/06/03 00:06:01 marka 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>
50 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
53 isc_mem_free(userarg, key);
57 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
58 isc_result_t result = ISC_R_SUCCESS;
61 dns_fixedname_t fixed;
63 dns_rdataclass_t rdclass;
64 dns_rdatatype_t rdtype;
68 dns_fixedname_init(&fixed);
69 obj = cfg_tuple_get(ent, "class");
70 if (cfg_obj_isstring(obj)) {
72 DE_CONST(cfg_obj_asstring(obj), r.base);
73 r.length = strlen(r.base);
74 tresult = dns_rdataclass_fromtext(&rdclass, &r);
75 if (tresult != ISC_R_SUCCESS) {
76 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
77 "rrset-order: invalid class '%s'",
79 result = ISC_R_FAILURE;
83 obj = cfg_tuple_get(ent, "type");
84 if (cfg_obj_isstring(obj)) {
86 DE_CONST(cfg_obj_asstring(obj), r.base);
87 r.length = strlen(r.base);
88 tresult = dns_rdatatype_fromtext(&rdtype, &r);
89 if (tresult != ISC_R_SUCCESS) {
90 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
91 "rrset-order: invalid type '%s'",
93 result = ISC_R_FAILURE;
97 obj = cfg_tuple_get(ent, "name");
98 if (cfg_obj_isstring(obj)) {
99 str = cfg_obj_asstring(obj);
100 isc_buffer_init(&b, str, strlen(str));
101 isc_buffer_add(&b, strlen(str));
102 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
103 dns_rootname, ISC_FALSE, NULL);
104 if (tresult != ISC_R_SUCCESS) {
105 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
106 "rrset-order: invalid name '%s'", str);
107 result = ISC_R_FAILURE;
111 obj = cfg_tuple_get(ent, "order");
112 if (!cfg_obj_isstring(obj) ||
113 strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
114 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
115 "rrset-order: keyword 'order' missing");
116 result = ISC_R_FAILURE;
119 obj = cfg_tuple_get(ent, "ordering");
120 if (!cfg_obj_isstring(obj)) {
121 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
122 "rrset-order: missing ordering");
123 result = ISC_R_FAILURE;
124 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
125 #if !DNS_RDATASET_FIXED
126 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
127 "rrset-order: order 'fixed' was disabled at "
130 } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
131 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
132 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
133 "rrset-order: invalid order '%s'",
134 cfg_obj_asstring(obj));
135 result = ISC_R_FAILURE;
141 check_order(const cfg_obj_t *options, isc_log_t *logctx) {
142 isc_result_t result = ISC_R_SUCCESS;
143 isc_result_t tresult;
144 const cfg_listelt_t *element;
145 const cfg_obj_t *obj = NULL;
147 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
150 for (element = cfg_list_first(obj);
152 element = cfg_list_next(element))
154 tresult = check_orderent(cfg_listelt_value(element), logctx);
155 if (tresult != ISC_R_SUCCESS)
162 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
163 const cfg_listelt_t *element;
164 const cfg_obj_t *alternates = NULL;
165 const cfg_obj_t *value;
166 const cfg_obj_t *obj;
168 dns_fixedname_t fixed;
171 isc_result_t result = ISC_R_SUCCESS;
172 isc_result_t tresult;
174 (void)cfg_map_get(options, "dual-stack-servers", &alternates);
176 if (alternates == NULL)
177 return (ISC_R_SUCCESS);
179 obj = cfg_tuple_get(alternates, "port");
180 if (cfg_obj_isuint32(obj)) {
181 isc_uint32_t val = cfg_obj_asuint32(obj);
182 if (val > ISC_UINT16_MAX) {
183 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
184 "port '%u' out of range", val);
185 result = ISC_R_FAILURE;
188 obj = cfg_tuple_get(alternates, "addresses");
189 for (element = cfg_list_first(obj);
191 element = cfg_list_next(element)) {
192 value = cfg_listelt_value(element);
193 if (cfg_obj_issockaddr(value))
195 obj = cfg_tuple_get(value, "name");
196 str = cfg_obj_asstring(obj);
197 isc_buffer_init(&buffer, str, strlen(str));
198 isc_buffer_add(&buffer, strlen(str));
199 dns_fixedname_init(&fixed);
200 name = dns_fixedname_name(&fixed);
201 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
203 if (tresult != ISC_R_SUCCESS) {
204 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
205 "bad name '%s'", str);
206 result = ISC_R_FAILURE;
208 obj = cfg_tuple_get(value, "port");
209 if (cfg_obj_isuint32(obj)) {
210 isc_uint32_t val = cfg_obj_asuint32(obj);
211 if (val > ISC_UINT16_MAX) {
212 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
213 "port '%u' out of range", val);
214 result = ISC_R_FAILURE;
222 check_forward(const cfg_obj_t *options, const cfg_obj_t *global,
225 const cfg_obj_t *forward = NULL;
226 const cfg_obj_t *forwarders = NULL;
228 (void)cfg_map_get(options, "forward", &forward);
229 (void)cfg_map_get(options, "forwarders", &forwarders);
231 if (forwarders != NULL && global != NULL) {
232 const char *file = cfg_obj_file(global);
233 unsigned int line = cfg_obj_line(global);
234 cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
235 "forwarders declared in root zone and "
236 "in general configuration: %s:%u",
238 return (ISC_R_FAILURE);
240 if (forward != NULL && forwarders == NULL) {
241 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
242 "no matching 'forwarders' statement");
243 return (ISC_R_FAILURE);
245 return (ISC_R_SUCCESS);
249 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
250 isc_result_t result = ISC_R_SUCCESS;
251 isc_result_t tresult;
252 const cfg_listelt_t *element;
255 dns_fixedname_t fixed;
257 const cfg_obj_t *obj;
259 dns_fixedname_init(&fixed);
260 name = dns_fixedname_name(&fixed);
261 obj = cfg_tuple_get(disabled, "name");
262 str = cfg_obj_asstring(obj);
263 isc_buffer_init(&b, str, strlen(str));
264 isc_buffer_add(&b, strlen(str));
265 tresult = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
266 if (tresult != ISC_R_SUCCESS) {
267 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
268 "bad domain name '%s'", str);
272 obj = cfg_tuple_get(disabled, "algorithms");
274 for (element = cfg_list_first(obj);
276 element = cfg_list_next(element))
280 isc_result_t tresult;
282 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
283 r.length = strlen(r.base);
285 tresult = dns_secalg_fromtext(&alg, &r);
286 if (tresult != ISC_R_SUCCESS) {
288 result = isc_parse_uint8(&ui, r.base, 10);
290 if (tresult != ISC_R_SUCCESS) {
291 cfg_obj_log(cfg_listelt_value(element), logctx,
292 ISC_LOG_ERROR, "invalid algorithm '%s'",
301 nameexist(const cfg_obj_t *obj, const char *name, int value,
302 isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
309 isc_symvalue_t symvalue;
311 key = isc_mem_strdup(mctx, name);
313 return (ISC_R_NOMEMORY);
314 symvalue.as_cpointer = obj;
315 result = isc_symtab_define(symtab, key, value, symvalue,
316 isc_symexists_reject);
317 if (result == ISC_R_EXISTS) {
318 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
319 &symvalue) == ISC_R_SUCCESS);
320 file = cfg_obj_file(symvalue.as_cpointer);
321 line = cfg_obj_line(symvalue.as_cpointer);
324 file = "<unknown file>";
325 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
326 isc_mem_free(mctx, key);
327 result = ISC_R_EXISTS;
328 } else if (result != ISC_R_SUCCESS) {
329 isc_mem_free(mctx, key);
335 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
338 const cfg_obj_t *obj;
339 char namebuf[DNS_NAME_FORMATSIZE];
341 dns_fixedname_t fixed;
344 isc_result_t result = ISC_R_SUCCESS;
346 dns_fixedname_init(&fixed);
347 name = dns_fixedname_name(&fixed);
348 obj = cfg_tuple_get(secure, "name");
349 str = cfg_obj_asstring(obj);
350 isc_buffer_init(&b, str, strlen(str));
351 isc_buffer_add(&b, strlen(str));
352 result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
353 if (result != ISC_R_SUCCESS) {
354 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
355 "bad domain name '%s'", str);
357 dns_name_format(name, namebuf, sizeof(namebuf));
358 result = nameexist(secure, namebuf, 1, symtab,
359 "dnssec-must-be-secure '%s': already "
360 "exists previous definition: %s:%u",
367 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
368 const cfg_obj_t *voptions, const cfg_obj_t *config,
369 isc_log_t *logctx, isc_mem_t *mctx)
372 const cfg_obj_t *aclobj = NULL;
373 const cfg_obj_t *options;
374 dns_acl_t *acl = NULL;
376 if (zconfig != NULL) {
377 options = cfg_tuple_get(zconfig, "options");
378 cfg_map_get(options, aclname, &aclobj);
380 if (voptions != NULL && aclobj == NULL)
381 cfg_map_get(voptions, aclname, &aclobj);
382 if (config != NULL && aclobj == NULL) {
384 cfg_map_get(config, "options", &options);
386 cfg_map_get(options, aclname, &aclobj);
389 return (ISC_R_SUCCESS);
390 result = cfg_acl_fromconfig(aclobj, config, logctx,
391 actx, mctx, 0, &acl);
393 dns_acl_detach(&acl);
398 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
399 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
401 isc_result_t result = ISC_R_SUCCESS, tresult;
404 static const char *acls[] = { "allow-query", "allow-query-on",
405 "allow-query-cache", "allow-query-cache-on",
406 "blackhole", "match-clients", "match-destinations",
409 while (acls[i] != NULL) {
410 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
412 if (tresult != ISC_R_SUCCESS)
419 * Check allow-recursion and allow-recursion-on acls, and also log a
420 * warning if they're inconsistent with the "recursion" option.
423 check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
424 const char *viewname, const cfg_obj_t *config,
425 isc_log_t *logctx, isc_mem_t *mctx)
427 const cfg_obj_t *options, *aclobj, *obj = NULL;
428 dns_acl_t *acl = NULL;
429 isc_result_t result = ISC_R_SUCCESS, tresult;
430 isc_boolean_t recursion;
431 const char *forview = " for view ";
434 static const char *acls[] = { "allow-recursion", "allow-recursion-on",
437 if (voptions != NULL)
438 cfg_map_get(voptions, "recursion", &obj);
439 if (obj == NULL && config != NULL) {
441 cfg_map_get(config, "options", &options);
443 cfg_map_get(options, "recursion", &obj);
446 recursion = ISC_TRUE;
448 recursion = cfg_obj_asboolean(obj);
450 if (viewname == NULL) {
455 for (i = 0; acls[i] != NULL; i++) {
456 aclobj = options = NULL;
459 if (voptions != NULL)
460 cfg_map_get(voptions, acls[i], &aclobj);
461 if (config != NULL && aclobj == NULL) {
463 cfg_map_get(config, "options", &options);
465 cfg_map_get(options, acls[i], &aclobj);
470 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
471 actx, mctx, 0, &acl);
473 if (tresult != ISC_R_SUCCESS)
479 if (recursion == ISC_FALSE && !dns_acl_isnone(acl)) {
480 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
481 "both \"recursion no;\" and "
483 acls[i], forview, viewname);
487 dns_acl_detach(&acl);
500 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
501 isc_result_t result = ISC_R_SUCCESS;
502 isc_result_t tresult;
504 const cfg_obj_t *obj = NULL;
505 const cfg_obj_t *resignobj = NULL;
506 const cfg_listelt_t *element;
507 isc_symtab_t *symtab = NULL;
508 dns_fixedname_t fixed;
513 static intervaltable intervals[] = {
514 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
515 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
516 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
517 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
518 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
519 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
520 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
521 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
525 * Check that fields specified in units of time other than seconds
526 * have reasonable values.
528 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
531 (void)cfg_map_get(options, intervals[i].name, &obj);
534 val = cfg_obj_asuint32(obj);
535 if (val > intervals[i].max) {
536 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
537 "%s '%u' is out of range (0..%u)",
538 intervals[i].name, val,
540 result = ISC_R_RANGE;
541 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
542 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
543 "%s '%d' is out of range",
544 intervals[i].name, val);
545 result = ISC_R_RANGE;
550 cfg_map_get(options, "sig-validity-interval", &obj);
552 isc_uint32_t validity, resign = 0;
554 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
555 resignobj = cfg_tuple_get(obj, "re-sign");
556 if (!cfg_obj_isvoid(resignobj))
557 resign = cfg_obj_asuint32(resignobj);
559 if (validity > 3660 || validity == 0) { /* 10 years */
560 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
561 "%s '%u' is out of range (1..3660)",
562 "sig-validity-interval", validity);
563 result = ISC_R_RANGE;
566 if (!cfg_obj_isvoid(resignobj)) {
567 if (resign > 3660 || resign == 0) { /* 10 years */
568 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
569 "%s '%u' is out of range (1..3660)",
570 "sig-validity-interval (re-sign)",
572 result = ISC_R_RANGE;
573 } else if ((validity > 7 && validity < resign) ||
574 (validity <= 7 && validity * 24 < resign)) {
575 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
576 "validity interval (%u days) "
577 "less than re-signing interval "
578 "(%u %s)", validity, resign,
579 (validity > 7) ? "days" : "hours");
580 result = ISC_R_RANGE;
586 (void)cfg_map_get(options, "preferred-glue", &obj);
589 str = cfg_obj_asstring(obj);
590 if (strcasecmp(str, "a") != 0 &&
591 strcasecmp(str, "aaaa") != 0 &&
592 strcasecmp(str, "none") != 0)
593 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
594 "preferred-glue unexpected value '%s'",
599 (void)cfg_map_get(options, "root-delegation-only", &obj);
601 if (!cfg_obj_isvoid(obj)) {
602 const cfg_listelt_t *element;
603 const cfg_obj_t *exclude;
605 dns_fixedname_t fixed;
609 dns_fixedname_init(&fixed);
610 name = dns_fixedname_name(&fixed);
611 for (element = cfg_list_first(obj);
613 element = cfg_list_next(element)) {
614 exclude = cfg_listelt_value(element);
615 str = cfg_obj_asstring(exclude);
616 isc_buffer_init(&b, str, strlen(str));
617 isc_buffer_add(&b, strlen(str));
618 tresult = dns_name_fromtext(name, &b,
621 if (tresult != ISC_R_SUCCESS) {
622 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
623 "bad domain name '%s'",
632 * Set supported DNSSEC algorithms.
635 (void)cfg_map_get(options, "disable-algorithms", &obj);
637 for (element = cfg_list_first(obj);
639 element = cfg_list_next(element))
641 obj = cfg_listelt_value(element);
642 tresult = disabled_algorithms(obj, logctx);
643 if (tresult != ISC_R_SUCCESS)
648 dns_fixedname_init(&fixed);
649 name = dns_fixedname_name(&fixed);
652 * Check the DLV zone name.
655 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
657 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
659 if (tresult != ISC_R_SUCCESS)
661 for (element = cfg_list_first(obj);
663 element = cfg_list_next(element))
667 obj = cfg_listelt_value(element);
669 dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain"));
670 isc_buffer_init(&b, dlv, strlen(dlv));
671 isc_buffer_add(&b, strlen(dlv));
672 tresult = dns_name_fromtext(name, &b, dns_rootname,
674 if (tresult != ISC_R_SUCCESS) {
675 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
676 "bad domain name '%s'", dlv);
680 if (symtab != NULL) {
681 tresult = nameexist(obj, dlv, 1, symtab,
682 "dnssec-lookaside '%s': "
683 "already exists previous "
686 if (tresult != ISC_R_SUCCESS &&
687 result == ISC_R_SUCCESS)
691 * XXXMPA to be removed when multiple lookaside
692 * namespaces are supported.
694 if (!dns_name_equal(dns_rootname, name)) {
695 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
696 "dnssec-lookaside '%s': "
697 "non-root not yet supported", dlv);
698 if (result == ISC_R_SUCCESS)
699 result = ISC_R_FAILURE;
701 dlv = cfg_obj_asstring(cfg_tuple_get(obj,
703 isc_buffer_init(&b, dlv, strlen(dlv));
704 isc_buffer_add(&b, strlen(dlv));
705 tresult = dns_name_fromtext(name, &b, dns_rootname,
707 if (tresult != ISC_R_SUCCESS) {
708 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
709 "bad domain name '%s'", dlv);
710 if (result == ISC_R_SUCCESS)
715 isc_symtab_destroy(&symtab);
719 * Check dnssec-must-be-secure.
722 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
724 isc_symtab_t *symtab = NULL;
725 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
727 if (tresult != ISC_R_SUCCESS)
729 for (element = cfg_list_first(obj);
731 element = cfg_list_next(element))
733 obj = cfg_listelt_value(element);
734 tresult = mustbesecure(obj, symtab, logctx, mctx);
735 if (tresult != ISC_R_SUCCESS)
739 isc_symtab_destroy(&symtab);
743 * Check empty zone configuration.
746 (void)cfg_map_get(options, "empty-server", &obj);
748 str = cfg_obj_asstring(obj);
749 isc_buffer_init(&b, str, strlen(str));
750 isc_buffer_add(&b, strlen(str));
751 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
752 dns_rootname, ISC_FALSE, NULL);
753 if (tresult != ISC_R_SUCCESS) {
754 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
755 "empty-server: invalid name '%s'", str);
756 result = ISC_R_FAILURE;
761 (void)cfg_map_get(options, "empty-contact", &obj);
763 str = cfg_obj_asstring(obj);
764 isc_buffer_init(&b, str, strlen(str));
765 isc_buffer_add(&b, strlen(str));
766 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
767 dns_rootname, ISC_FALSE, NULL);
768 if (tresult != ISC_R_SUCCESS) {
769 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
770 "empty-contact: invalid name '%s'", str);
771 result = ISC_R_FAILURE;
776 (void)cfg_map_get(options, "disable-empty-zone", &obj);
777 for (element = cfg_list_first(obj);
779 element = cfg_list_next(element))
781 obj = cfg_listelt_value(element);
782 str = cfg_obj_asstring(obj);
783 isc_buffer_init(&b, str, strlen(str));
784 isc_buffer_add(&b, strlen(str));
785 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
786 dns_rootname, ISC_FALSE, NULL);
787 if (tresult != ISC_R_SUCCESS) {
788 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
789 "disable-empty-zone: invalid name '%s'",
791 result = ISC_R_FAILURE;
796 * Check that server-id is not too long.
797 * 1024 bytes should be big enough.
800 (void)cfg_map_get(options, "server-id", &obj);
801 if (obj != NULL && cfg_obj_isstring(obj) &&
802 strlen(cfg_obj_asstring(obj)) > 1024U) {
803 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
804 "'server-id' too big (>1024 bytes)");
805 result = ISC_R_FAILURE;
812 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
814 const cfg_obj_t *masters = NULL;
815 const cfg_listelt_t *elt;
817 result = cfg_map_get(cctx, "masters", &masters);
818 if (result != ISC_R_SUCCESS)
820 for (elt = cfg_list_first(masters);
822 elt = cfg_list_next(elt)) {
823 const cfg_obj_t *list;
824 const char *listname;
826 list = cfg_listelt_value(elt);
827 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
829 if (strcasecmp(listname, name) == 0) {
831 return (ISC_R_SUCCESS);
834 return (ISC_R_NOTFOUND);
838 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
839 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
841 isc_result_t result = ISC_R_SUCCESS;
842 isc_result_t tresult;
843 isc_uint32_t count = 0;
844 isc_symtab_t *symtab = NULL;
845 isc_symvalue_t symvalue;
846 const cfg_listelt_t *element;
847 const cfg_listelt_t **stack = NULL;
848 isc_uint32_t stackcount = 0, pushed = 0;
849 const cfg_obj_t *list;
851 REQUIRE(countp != NULL);
852 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
853 if (result != ISC_R_SUCCESS) {
859 list = cfg_tuple_get(obj, "addresses");
860 element = cfg_list_first(list);
864 element = cfg_list_next(element))
866 const char *listname;
867 const cfg_obj_t *addr;
868 const cfg_obj_t *key;
870 addr = cfg_tuple_get(cfg_listelt_value(element),
872 key = cfg_tuple_get(cfg_listelt_value(element), "key");
874 if (cfg_obj_issockaddr(addr)) {
878 if (!cfg_obj_isvoid(key)) {
879 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
880 "unexpected token '%s'",
881 cfg_obj_asstring(key));
882 if (result == ISC_R_SUCCESS)
883 result = ISC_R_FAILURE;
885 listname = cfg_obj_asstring(addr);
886 symvalue.as_cpointer = addr;
887 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
888 isc_symexists_reject);
889 if (tresult == ISC_R_EXISTS)
891 tresult = get_masters_def(config, listname, &obj);
892 if (tresult != ISC_R_SUCCESS) {
893 if (result == ISC_R_SUCCESS)
895 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
896 "unable to find masters list '%s'",
901 if (stackcount == pushed) {
903 isc_uint32_t newlen = stackcount + 16;
904 size_t newsize, oldsize;
906 newsize = newlen * sizeof(*stack);
907 oldsize = stackcount * sizeof(*stack);
908 new = isc_mem_get(mctx, newsize);
911 if (stackcount != 0) {
914 DE_CONST(stack, ptr);
915 memcpy(new, stack, oldsize);
916 isc_mem_put(mctx, ptr, oldsize);
921 stack[pushed++] = cfg_list_next(element);
925 element = stack[--pushed];
932 DE_CONST(stack, ptr);
933 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
935 isc_symtab_destroy(&symtab);
941 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
942 isc_result_t result = ISC_R_SUCCESS;
943 isc_result_t tresult;
944 const cfg_listelt_t *element;
945 const cfg_listelt_t *element2;
946 dns_fixedname_t fixed;
950 for (element = cfg_list_first(policy);
952 element = cfg_list_next(element))
954 const cfg_obj_t *stmt = cfg_listelt_value(element);
955 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
956 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
957 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
958 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
960 dns_fixedname_init(&fixed);
961 str = cfg_obj_asstring(identity);
962 isc_buffer_init(&b, str, strlen(str));
963 isc_buffer_add(&b, strlen(str));
964 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
965 dns_rootname, ISC_FALSE, NULL);
966 if (tresult != ISC_R_SUCCESS) {
967 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
968 "'%s' is not a valid name", str);
972 dns_fixedname_init(&fixed);
973 str = cfg_obj_asstring(dname);
974 isc_buffer_init(&b, str, strlen(str));
975 isc_buffer_add(&b, strlen(str));
976 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
977 dns_rootname, ISC_FALSE, NULL);
978 if (tresult != ISC_R_SUCCESS) {
979 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
980 "'%s' is not a valid name", str);
983 if (tresult == ISC_R_SUCCESS &&
984 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
985 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
986 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
987 "'%s' is not a wildcard", str);
988 result = ISC_R_FAILURE;
991 for (element2 = cfg_list_first(typelist);
993 element2 = cfg_list_next(element2))
995 const cfg_obj_t *typeobj;
997 dns_rdatatype_t type;
999 typeobj = cfg_listelt_value(element2);
1000 DE_CONST(cfg_obj_asstring(typeobj), r.base);
1001 r.length = strlen(r.base);
1003 tresult = dns_rdatatype_fromtext(&type, &r);
1004 if (tresult != ISC_R_SUCCESS) {
1005 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
1006 "'%s' is not a valid type", r.base);
1014 #define MASTERZONE 1
1018 #define FORWARDZONE 16
1019 #define DELEGATIONZONE 32
1028 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
1029 const cfg_obj_t *config, isc_symtab_t *symtab,
1030 dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
1031 isc_log_t *logctx, isc_mem_t *mctx)
1034 const char *typestr;
1036 const cfg_obj_t *zoptions;
1037 const cfg_obj_t *obj = NULL;
1038 isc_result_t result = ISC_R_SUCCESS;
1039 isc_result_t tresult;
1041 dns_rdataclass_t zclass;
1042 dns_fixedname_t fixedname;
1044 isc_boolean_t root = ISC_FALSE;
1046 static optionstable options[] = {
1047 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL },
1048 { "allow-notify", SLAVEZONE | CHECKACL },
1049 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
1050 { "notify", MASTERZONE | SLAVEZONE },
1051 { "also-notify", MASTERZONE | SLAVEZONE },
1052 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
1053 { "delegation-only", HINTZONE | STUBZONE | DELEGATIONZONE },
1054 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
1055 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
1056 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
1057 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
1058 { "notify-source", MASTERZONE | SLAVEZONE },
1059 { "notify-source-v6", MASTERZONE | SLAVEZONE },
1060 { "transfer-source", SLAVEZONE | STUBZONE },
1061 { "transfer-source-v6", SLAVEZONE | STUBZONE },
1062 { "max-transfer-time-in", SLAVEZONE | STUBZONE },
1063 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
1064 { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
1065 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
1066 { "max-retry-time", SLAVEZONE | STUBZONE },
1067 { "min-retry-time", SLAVEZONE | STUBZONE },
1068 { "max-refresh-time", SLAVEZONE | STUBZONE },
1069 { "min-refresh-time", SLAVEZONE | STUBZONE },
1070 { "sig-validity-interval", MASTERZONE },
1071 { "sig-re-signing-interval", MASTERZONE },
1072 { "sig-signing-nodes", MASTERZONE },
1073 { "sig-signing-type", MASTERZONE },
1074 { "sig-signing-signatures", MASTERZONE },
1075 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE },
1076 { "allow-update", MASTERZONE | CHECKACL },
1077 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
1078 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1079 { "journal", MASTERZONE | SLAVEZONE },
1080 { "ixfr-base", MASTERZONE | SLAVEZONE },
1081 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
1082 { "masters", SLAVEZONE | STUBZONE },
1083 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
1084 { "update-policy", MASTERZONE },
1085 { "database", MASTERZONE | SLAVEZONE | STUBZONE },
1086 { "key-directory", MASTERZONE },
1087 { "check-wildcard", MASTERZONE },
1088 { "check-mx", MASTERZONE },
1089 { "integrity-check", MASTERZONE },
1090 { "check-mx-cname", MASTERZONE },
1091 { "check-srv-cname", MASTERZONE },
1092 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1093 { "update-check-ksk", MASTERZONE },
1094 { "try-tcp-refresh", SLAVEZONE },
1097 static optionstable dialups[] = {
1098 { "notify", MASTERZONE | SLAVEZONE },
1099 { "notify-passive", SLAVEZONE },
1100 { "refresh", SLAVEZONE | STUBZONE },
1101 { "passive", SLAVEZONE | STUBZONE },
1104 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1106 zoptions = cfg_tuple_get(zconfig, "options");
1109 (void)cfg_map_get(zoptions, "type", &obj);
1111 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1112 "zone '%s': type not present", zname);
1113 return (ISC_R_FAILURE);
1116 typestr = cfg_obj_asstring(obj);
1117 if (strcasecmp(typestr, "master") == 0)
1119 else if (strcasecmp(typestr, "slave") == 0)
1121 else if (strcasecmp(typestr, "stub") == 0)
1123 else if (strcasecmp(typestr, "forward") == 0)
1124 ztype = FORWARDZONE;
1125 else if (strcasecmp(typestr, "hint") == 0)
1127 else if (strcasecmp(typestr, "delegation-only") == 0)
1128 ztype = DELEGATIONZONE;
1130 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1131 "zone '%s': invalid type %s",
1133 return (ISC_R_FAILURE);
1136 obj = cfg_tuple_get(zconfig, "class");
1137 if (cfg_obj_isstring(obj)) {
1140 DE_CONST(cfg_obj_asstring(obj), r.base);
1141 r.length = strlen(r.base);
1142 result = dns_rdataclass_fromtext(&zclass, &r);
1143 if (result != ISC_R_SUCCESS) {
1144 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1145 "zone '%s': invalid class %s",
1147 return (ISC_R_FAILURE);
1149 if (zclass != defclass) {
1150 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1151 "zone '%s': class '%s' does not "
1152 "match view/default class",
1154 return (ISC_R_FAILURE);
1159 * Look for an already existing zone.
1160 * We need to make this canonical as isc_symtab_define()
1161 * deals with strings.
1163 dns_fixedname_init(&fixedname);
1164 isc_buffer_init(&b, zname, strlen(zname));
1165 isc_buffer_add(&b, strlen(zname));
1166 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1167 dns_rootname, ISC_TRUE, NULL);
1168 if (tresult != ISC_R_SUCCESS) {
1169 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1170 "zone '%s': is not a valid name", zname);
1171 result = ISC_R_FAILURE;
1173 char namebuf[DNS_NAME_FORMATSIZE];
1175 dns_name_format(dns_fixedname_name(&fixedname),
1176 namebuf, sizeof(namebuf));
1177 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
1178 symtab, "zone '%s': already exists "
1179 "previous definition: %s:%u", logctx, mctx);
1180 if (tresult != ISC_R_SUCCESS)
1182 if (dns_name_equal(dns_fixedname_name(&fixedname),
1188 * Look for inappropriate options for the given zone type.
1189 * Check that ACLs expand correctly.
1191 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1193 if ((options[i].allowed & ztype) == 0 &&
1194 cfg_map_get(zoptions, options[i].name, &obj) ==
1197 if (strcmp(options[i].name, "allow-update") != 0 ||
1198 ztype != SLAVEZONE) {
1199 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1200 "option '%s' is not allowed "
1201 "in '%s' zone '%s'",
1202 options[i].name, typestr, zname);
1203 result = ISC_R_FAILURE;
1205 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1206 "option '%s' is not allowed "
1207 "in '%s' zone '%s'",
1208 options[i].name, typestr, zname);
1211 if ((options[i].allowed & ztype) != 0 &&
1212 (options[i].allowed & CHECKACL) != 0) {
1214 tresult = checkacl(options[i].name, actx, zconfig,
1215 voptions, config, logctx, mctx);
1216 if (tresult != ISC_R_SUCCESS)
1223 * Slave & stub zones must have a "masters" field.
1225 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1227 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1228 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1229 "zone '%s': missing 'masters' entry",
1231 result = ISC_R_FAILURE;
1234 tresult = validate_masters(obj, config, &count,
1236 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1238 if (tresult == ISC_R_SUCCESS && count == 0) {
1239 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1240 "zone '%s': empty 'masters' entry",
1242 result = ISC_R_FAILURE;
1248 * Master zones can't have both "allow-update" and "update-policy".
1250 if (ztype == MASTERZONE) {
1251 isc_result_t res1, res2;
1253 res1 = cfg_map_get(zoptions, "allow-update", &obj);
1255 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1256 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1257 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1258 "zone '%s': 'allow-update' is ignored "
1259 "when 'update-policy' is present",
1261 result = ISC_R_FAILURE;
1262 } else if (res2 == ISC_R_SUCCESS &&
1263 check_update_policy(obj, logctx) != ISC_R_SUCCESS)
1264 result = ISC_R_FAILURE;
1266 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
1267 if (res1 == ISC_R_SUCCESS) {
1268 isc_uint32_t type = cfg_obj_asuint32(obj);
1269 if (type < 0xff00U || type > 0xffffU)
1270 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1271 "sig-signing-type: %u out of "
1272 "range [%u..%u]", type,
1274 result = ISC_R_FAILURE;
1279 * Check the excessively complicated "dialup" option.
1281 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1282 const cfg_obj_t *dialup = NULL;
1283 (void)cfg_map_get(zoptions, "dialup", &dialup);
1284 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1285 const char *str = cfg_obj_asstring(dialup);
1287 i < sizeof(dialups) / sizeof(dialups[0]);
1290 if (strcasecmp(dialups[i].name, str) != 0)
1292 if ((dialups[i].allowed & ztype) == 0) {
1293 cfg_obj_log(obj, logctx,
1295 "dialup type '%s' is not "
1298 str, typestr, zname);
1299 result = ISC_R_FAILURE;
1303 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1304 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1305 "invalid dialup type '%s' in zone "
1306 "'%s'", str, zname);
1307 result = ISC_R_FAILURE;
1313 * Check that forwarding is reasonable.
1317 if (voptions != NULL)
1318 (void)cfg_map_get(voptions, "forwarders", &obj);
1320 const cfg_obj_t *options = NULL;
1321 (void)cfg_map_get(config, "options", &options);
1322 if (options != NULL)
1323 (void)cfg_map_get(options, "forwarders", &obj);
1326 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
1327 result = ISC_R_FAILURE;
1330 * Check various options.
1332 tresult = check_options(zoptions, logctx, mctx);
1333 if (tresult != ISC_R_SUCCESS)
1337 * If the zone type is rbt/rbt64 then master/hint zones
1338 * require file clauses.
1341 tresult = cfg_map_get(zoptions, "database", &obj);
1342 if (tresult == ISC_R_NOTFOUND ||
1343 (tresult == ISC_R_SUCCESS &&
1344 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1345 strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
1347 tresult = cfg_map_get(zoptions, "file", &obj);
1348 if (tresult != ISC_R_SUCCESS &&
1349 (ztype == MASTERZONE || ztype == HINTZONE)) {
1350 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1351 "zone '%s': missing 'file' entry",
1361 typedef struct keyalgorithms {
1367 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1368 const cfg_obj_t *algobj = NULL;
1369 const cfg_obj_t *secretobj = NULL;
1370 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1371 const char *algorithm;
1374 static const algorithmtable algorithms[] = {
1375 { "hmac-md5", 128 },
1376 { "hmac-md5.sig-alg.reg.int", 0 },
1377 { "hmac-md5.sig-alg.reg.int.", 0 },
1378 { "hmac-sha1", 160 },
1379 { "hmac-sha224", 224 },
1380 { "hmac-sha256", 256 },
1381 { "hmac-sha384", 384 },
1382 { "hmac-sha512", 512 },
1386 (void)cfg_map_get(key, "algorithm", &algobj);
1387 (void)cfg_map_get(key, "secret", &secretobj);
1388 if (secretobj == NULL || algobj == NULL) {
1389 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1390 "key '%s' must have both 'secret' and "
1391 "'algorithm' defined",
1393 return (ISC_R_FAILURE);
1396 algorithm = cfg_obj_asstring(algobj);
1397 for (i = 0; algorithms[i].name != NULL; i++) {
1398 len = strlen(algorithms[i].name);
1399 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1400 (algorithm[len] == '\0' ||
1401 (algorithms[i].size != 0 && algorithm[len] == '-')))
1404 if (algorithms[i].name == NULL) {
1405 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1406 "unknown algorithm '%s'", algorithm);
1407 return (ISC_R_NOTFOUND);
1409 if (algorithm[len] == '-') {
1410 isc_uint16_t digestbits;
1411 isc_result_t result;
1412 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1413 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1414 if (result == ISC_R_RANGE ||
1415 digestbits > algorithms[i].size) {
1416 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1417 "key '%s' digest-bits too large "
1418 "[%u..%u]", keyname,
1419 algorithms[i].size / 2,
1420 algorithms[i].size);
1421 return (ISC_R_RANGE);
1423 if ((digestbits % 8) != 0) {
1424 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1425 "key '%s' digest-bits not multiple"
1427 return (ISC_R_RANGE);
1430 * Recommended minima for hmac algorithms.
1432 if ((digestbits < (algorithms[i].size / 2U) ||
1433 (digestbits < 80U)))
1434 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
1435 "key '%s' digest-bits too small "
1437 algorithms[i].size/2);
1439 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1440 "key '%s': unable to parse digest-bits",
1445 return (ISC_R_SUCCESS);
1449 * Check key list for duplicates key names and that the key names
1450 * are valid domain names as these keys are used for TSIG.
1452 * Check the key contents for validity.
1455 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
1456 isc_mem_t *mctx, isc_log_t *logctx)
1458 char namebuf[DNS_NAME_FORMATSIZE];
1459 dns_fixedname_t fname;
1461 isc_result_t result = ISC_R_SUCCESS;
1462 isc_result_t tresult;
1463 const cfg_listelt_t *element;
1465 dns_fixedname_init(&fname);
1466 name = dns_fixedname_name(&fname);
1467 for (element = cfg_list_first(keys);
1469 element = cfg_list_next(element))
1471 const cfg_obj_t *key = cfg_listelt_value(element);
1472 const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
1473 isc_symvalue_t symvalue;
1477 isc_buffer_init(&b, keyid, strlen(keyid));
1478 isc_buffer_add(&b, strlen(keyid));
1479 tresult = dns_name_fromtext(name, &b, dns_rootname,
1481 if (tresult != ISC_R_SUCCESS) {
1482 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1483 "key '%s': bad key name", keyid);
1487 tresult = bind9_check_key(key, logctx);
1488 if (tresult != ISC_R_SUCCESS)
1491 dns_name_format(name, namebuf, sizeof(namebuf));
1492 keyname = isc_mem_strdup(mctx, namebuf);
1493 if (keyname == NULL)
1494 return (ISC_R_NOMEMORY);
1495 symvalue.as_cpointer = key;
1496 tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
1497 isc_symexists_reject);
1498 if (tresult == ISC_R_EXISTS) {
1502 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
1503 1, &symvalue) == ISC_R_SUCCESS);
1504 file = cfg_obj_file(symvalue.as_cpointer);
1505 line = cfg_obj_line(symvalue.as_cpointer);
1508 file = "<unknown file>";
1509 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1510 "key '%s': already exists "
1511 "previous definition: %s:%u",
1513 isc_mem_free(mctx, keyname);
1515 } else if (tresult != ISC_R_SUCCESS) {
1516 isc_mem_free(mctx, keyname);
1527 { "transfer-source", "transfer-source-v6" },
1528 { "notify-source", "notify-source-v6" },
1529 { "query-source", "query-source-v6" },
1534 * RNDC keys are not normalised unlike TSIG keys.
1536 * "foo." is different to "foo".
1538 static isc_boolean_t
1539 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
1540 const cfg_listelt_t *element;
1541 const cfg_obj_t *obj;
1544 if (keylist == NULL)
1547 for (element = cfg_list_first(keylist);
1549 element = cfg_list_next(element))
1551 obj = cfg_listelt_value(element);
1552 str = cfg_obj_asstring(cfg_map_getname(obj));
1553 if (!strcasecmp(str, keyname))
1560 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
1561 isc_symtab_t *symtab, isc_log_t *logctx)
1563 dns_fixedname_t fname;
1564 isc_result_t result = ISC_R_SUCCESS;
1565 isc_result_t tresult;
1566 const cfg_listelt_t *e1, *e2;
1567 const cfg_obj_t *v1, *v2, *keys;
1568 const cfg_obj_t *servers;
1569 isc_netaddr_t n1, n2;
1570 unsigned int p1, p2;
1571 const cfg_obj_t *obj;
1572 char buf[ISC_NETADDR_FORMATSIZE];
1573 char namebuf[DNS_NAME_FORMATSIZE];
1578 dns_name_t *keyname;
1581 if (voptions != NULL)
1582 (void)cfg_map_get(voptions, "server", &servers);
1583 if (servers == NULL)
1584 (void)cfg_map_get(config, "server", &servers);
1585 if (servers == NULL)
1586 return (ISC_R_SUCCESS);
1588 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
1589 v1 = cfg_listelt_value(e1);
1590 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
1592 * Check that unused bits are zero.
1594 tresult = isc_netaddr_prefixok(&n1, p1);
1595 if (tresult != ISC_R_SUCCESS) {
1596 INSIST(tresult == ISC_R_FAILURE);
1597 isc_netaddr_format(&n1, buf, sizeof(buf));
1598 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1599 "server '%s/%u': invalid prefix "
1600 "(extra bits specified)", buf, p1);
1606 if (n1.family == AF_INET)
1607 xfr = sources[source].v6;
1609 xfr = sources[source].v4;
1610 (void)cfg_map_get(v1, xfr, &obj);
1612 isc_netaddr_format(&n1, buf, sizeof(buf));
1613 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1614 "server '%s/%u': %s not legal",
1616 result = ISC_R_FAILURE;
1618 } while (sources[++source].v4 != NULL);
1620 while ((e2 = cfg_list_next(e2)) != NULL) {
1621 v2 = cfg_listelt_value(e2);
1622 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
1623 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
1624 const char *file = cfg_obj_file(v1);
1625 unsigned int line = cfg_obj_line(v1);
1628 file = "<unknown file>";
1630 isc_netaddr_format(&n2, buf, sizeof(buf));
1631 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
1632 "server '%s/%u': already exists "
1633 "previous definition: %s:%u",
1634 buf, p2, file, line);
1635 result = ISC_R_FAILURE;
1639 cfg_map_get(v1, "keys", &keys);
1642 * Normalize key name.
1644 keyval = cfg_obj_asstring(keys);
1645 dns_fixedname_init(&fname);
1646 isc_buffer_init(&b, keyval, strlen(keyval));
1647 isc_buffer_add(&b, strlen(keyval));
1648 keyname = dns_fixedname_name(&fname);
1649 tresult = dns_name_fromtext(keyname, &b, dns_rootname,
1651 if (tresult != ISC_R_SUCCESS) {
1652 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
1653 "bad key name '%s'", keyval);
1654 result = ISC_R_FAILURE;
1657 dns_name_format(keyname, namebuf, sizeof(namebuf));
1658 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
1659 if (tresult != ISC_R_SUCCESS) {
1660 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
1661 "unknown key '%s'", keyval);
1662 result = ISC_R_FAILURE;
1670 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
1671 const char *viewname, dns_rdataclass_t vclass,
1672 isc_log_t *logctx, isc_mem_t *mctx)
1674 const cfg_obj_t *zones = NULL;
1675 const cfg_obj_t *keys = NULL;
1676 const cfg_listelt_t *element;
1677 isc_symtab_t *symtab = NULL;
1678 isc_result_t result = ISC_R_SUCCESS;
1679 isc_result_t tresult = ISC_R_SUCCESS;
1680 cfg_aclconfctx_t actx;
1681 const cfg_obj_t *obj;
1682 isc_boolean_t enablednssec, enablevalidation;
1685 * Check that all zone statements are syntactically correct and
1686 * there are no duplicate zones.
1688 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1689 ISC_FALSE, &symtab);
1690 if (tresult != ISC_R_SUCCESS)
1691 return (ISC_R_NOMEMORY);
1693 cfg_aclconfctx_init(&actx);
1695 if (voptions != NULL)
1696 (void)cfg_map_get(voptions, "zone", &zones);
1698 (void)cfg_map_get(config, "zone", &zones);
1700 for (element = cfg_list_first(zones);
1702 element = cfg_list_next(element))
1704 isc_result_t tresult;
1705 const cfg_obj_t *zone = cfg_listelt_value(element);
1707 tresult = check_zoneconf(zone, voptions, config, symtab,
1708 vclass, &actx, logctx, mctx);
1709 if (tresult != ISC_R_SUCCESS)
1710 result = ISC_R_FAILURE;
1713 isc_symtab_destroy(&symtab);
1716 * Check that forwarding is reasonable.
1718 if (voptions == NULL) {
1719 const cfg_obj_t *options = NULL;
1720 (void)cfg_map_get(config, "options", &options);
1721 if (options != NULL)
1722 if (check_forward(options, NULL,
1723 logctx) != ISC_R_SUCCESS)
1724 result = ISC_R_FAILURE;
1726 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
1727 result = ISC_R_FAILURE;
1731 * Check that dual-stack-servers is reasonable.
1733 if (voptions == NULL) {
1734 const cfg_obj_t *options = NULL;
1735 (void)cfg_map_get(config, "options", &options);
1736 if (options != NULL)
1737 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1738 result = ISC_R_FAILURE;
1740 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
1741 result = ISC_R_FAILURE;
1745 * Check that rrset-order is reasonable.
1747 if (voptions != NULL) {
1748 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
1749 result = ISC_R_FAILURE;
1753 * Check that all key statements are syntactically correct and
1754 * there are no duplicate keys.
1756 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1757 ISC_FALSE, &symtab);
1758 if (tresult != ISC_R_SUCCESS)
1759 return (ISC_R_NOMEMORY);
1761 (void)cfg_map_get(config, "key", &keys);
1762 tresult = check_keylist(keys, symtab, mctx, logctx);
1763 if (tresult == ISC_R_EXISTS)
1764 result = ISC_R_FAILURE;
1765 else if (tresult != ISC_R_SUCCESS) {
1766 isc_symtab_destroy(&symtab);
1770 if (voptions != NULL) {
1772 (void)cfg_map_get(voptions, "key", &keys);
1773 tresult = check_keylist(keys, symtab, mctx, logctx);
1774 if (tresult == ISC_R_EXISTS)
1775 result = ISC_R_FAILURE;
1776 else if (tresult != ISC_R_SUCCESS) {
1777 isc_symtab_destroy(&symtab);
1783 * Global servers can refer to keys in views.
1785 if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
1786 result = ISC_R_FAILURE;
1788 isc_symtab_destroy(&symtab);
1791 * Check that dnssec-enable/dnssec-validation are sensible.
1794 if (voptions != NULL)
1795 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
1797 (void)cfg_map_get(config, "dnssec-enable", &obj);
1799 enablednssec = ISC_TRUE;
1801 enablednssec = cfg_obj_asboolean(obj);
1804 if (voptions != NULL)
1805 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
1807 (void)cfg_map_get(config, "dnssec-validation", &obj);
1809 enablevalidation = ISC_FALSE; /* XXXMPA Change for 9.5. */
1811 enablevalidation = cfg_obj_asboolean(obj);
1813 if (enablevalidation && !enablednssec)
1814 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1815 "'dnssec-validation yes;' and 'dnssec-enable no;'");
1817 if (voptions != NULL)
1818 tresult = check_options(voptions, logctx, mctx);
1820 tresult = check_options(config, logctx, mctx);
1821 if (tresult != ISC_R_SUCCESS)
1824 tresult = check_viewacls(&actx, voptions, config, logctx, mctx);
1825 if (tresult != ISC_R_SUCCESS)
1828 tresult = check_recursionacls(&actx, voptions, viewname,
1829 config, logctx, mctx);
1830 if (tresult != ISC_R_SUCCESS)
1833 cfg_aclconfctx_destroy(&actx);
1839 default_channels[] = {
1848 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
1851 const cfg_obj_t *categories = NULL;
1852 const cfg_obj_t *category;
1853 const cfg_obj_t *channels = NULL;
1854 const cfg_obj_t *channel;
1855 const cfg_listelt_t *element;
1856 const cfg_listelt_t *delement;
1857 const char *channelname;
1858 const char *catname;
1859 const cfg_obj_t *fileobj = NULL;
1860 const cfg_obj_t *syslogobj = NULL;
1861 const cfg_obj_t *nullobj = NULL;
1862 const cfg_obj_t *stderrobj = NULL;
1863 const cfg_obj_t *logobj = NULL;
1864 isc_result_t result = ISC_R_SUCCESS;
1865 isc_result_t tresult;
1866 isc_symtab_t *symtab = NULL;
1867 isc_symvalue_t symvalue;
1870 (void)cfg_map_get(config, "logging", &logobj);
1872 return (ISC_R_SUCCESS);
1874 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1875 if (result != ISC_R_SUCCESS)
1878 symvalue.as_cpointer = NULL;
1879 for (i = 0; default_channels[i] != NULL; i++) {
1880 tresult = isc_symtab_define(symtab, default_channels[i], 1,
1881 symvalue, isc_symexists_replace);
1882 if (tresult != ISC_R_SUCCESS)
1886 cfg_map_get(logobj, "channel", &channels);
1888 for (element = cfg_list_first(channels);
1890 element = cfg_list_next(element))
1892 channel = cfg_listelt_value(element);
1893 channelname = cfg_obj_asstring(cfg_map_getname(channel));
1894 fileobj = syslogobj = nullobj = stderrobj = NULL;
1895 (void)cfg_map_get(channel, "file", &fileobj);
1896 (void)cfg_map_get(channel, "syslog", &syslogobj);
1897 (void)cfg_map_get(channel, "null", &nullobj);
1898 (void)cfg_map_get(channel, "stderr", &stderrobj);
1900 if (fileobj != NULL)
1902 if (syslogobj != NULL)
1904 if (nullobj != NULL)
1906 if (stderrobj != NULL)
1909 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
1910 "channel '%s': exactly one of file, syslog, "
1911 "null, and stderr must be present",
1913 result = ISC_R_FAILURE;
1915 tresult = isc_symtab_define(symtab, channelname, 1,
1916 symvalue, isc_symexists_replace);
1917 if (tresult != ISC_R_SUCCESS)
1921 cfg_map_get(logobj, "category", &categories);
1923 for (element = cfg_list_first(categories);
1925 element = cfg_list_next(element))
1927 category = cfg_listelt_value(element);
1928 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
1929 if (isc_log_categorybyname(logctx, catname) == NULL) {
1930 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
1931 "undefined category: '%s'", catname);
1932 result = ISC_R_FAILURE;
1934 channels = cfg_tuple_get(category, "destinations");
1935 for (delement = cfg_list_first(channels);
1937 delement = cfg_list_next(delement))
1939 channel = cfg_listelt_value(delement);
1940 channelname = cfg_obj_asstring(channel);
1941 tresult = isc_symtab_lookup(symtab, channelname, 1,
1943 if (tresult != ISC_R_SUCCESS) {
1944 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
1945 "undefined channel: '%s'",
1951 isc_symtab_destroy(&symtab);
1956 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
1959 isc_result_t result = ISC_R_SUCCESS;
1960 const cfg_obj_t *control_keylist;
1961 const cfg_listelt_t *element;
1962 const cfg_obj_t *key;
1965 control_keylist = cfg_tuple_get(control, "keys");
1966 if (cfg_obj_isvoid(control_keylist))
1967 return (ISC_R_SUCCESS);
1969 for (element = cfg_list_first(control_keylist);
1971 element = cfg_list_next(element))
1973 key = cfg_listelt_value(element);
1974 keyval = cfg_obj_asstring(key);
1976 if (!rndckey_exists(keylist, keyval)) {
1977 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1978 "unknown key '%s'", keyval);
1979 result = ISC_R_NOTFOUND;
1986 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
1989 isc_result_t result = ISC_R_SUCCESS, tresult;
1990 cfg_aclconfctx_t actx;
1991 const cfg_listelt_t *element, *element2;
1992 const cfg_obj_t *allow;
1993 const cfg_obj_t *control;
1994 const cfg_obj_t *controls;
1995 const cfg_obj_t *controlslist = NULL;
1996 const cfg_obj_t *inetcontrols;
1997 const cfg_obj_t *unixcontrols;
1998 const cfg_obj_t *keylist = NULL;
2000 isc_uint32_t perm, mask;
2001 dns_acl_t *acl = NULL;
2002 isc_sockaddr_t addr;
2005 (void)cfg_map_get(config, "controls", &controlslist);
2006 if (controlslist == NULL)
2007 return (ISC_R_SUCCESS);
2009 (void)cfg_map_get(config, "key", &keylist);
2011 cfg_aclconfctx_init(&actx);
2014 * INET: Check allow clause.
2015 * UNIX: Check "perm" for sanity, check path length.
2017 for (element = cfg_list_first(controlslist);
2019 element = cfg_list_next(element)) {
2020 controls = cfg_listelt_value(element);
2021 unixcontrols = NULL;
2022 inetcontrols = NULL;
2023 (void)cfg_map_get(controls, "unix", &unixcontrols);
2024 (void)cfg_map_get(controls, "inet", &inetcontrols);
2025 for (element2 = cfg_list_first(inetcontrols);
2027 element2 = cfg_list_next(element2)) {
2028 control = cfg_listelt_value(element2);
2029 allow = cfg_tuple_get(control, "allow");
2030 tresult = cfg_acl_fromconfig(allow, config, logctx,
2031 &actx, mctx, 0, &acl);
2033 dns_acl_detach(&acl);
2034 if (tresult != ISC_R_SUCCESS)
2036 tresult = bind9_check_controlskeys(control, keylist,
2038 if (tresult != ISC_R_SUCCESS)
2041 for (element2 = cfg_list_first(unixcontrols);
2043 element2 = cfg_list_next(element2)) {
2044 control = cfg_listelt_value(element2);
2045 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
2046 tresult = isc_sockaddr_frompath(&addr, path);
2047 if (tresult == ISC_R_NOSPACE) {
2048 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
2049 "unix control '%s': path too long",
2051 result = ISC_R_NOSPACE;
2053 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
2054 for (i = 0; i < 3; i++) {
2055 #ifdef NEED_SECURE_DIRECTORY
2056 mask = (0x1 << (i*3)); /* SEARCH */
2058 mask = (0x6 << (i*3)); /* READ + WRITE */
2060 if ((perm & mask) == mask)
2064 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2065 "unix control '%s' allows access "
2066 "to everyone", path);
2067 } else if (i == 3) {
2068 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2069 "unix control '%s' allows access "
2072 tresult = bind9_check_controlskeys(control, keylist,
2074 if (tresult != ISC_R_SUCCESS)
2078 cfg_aclconfctx_destroy(&actx);
2083 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
2086 const cfg_obj_t *options = NULL;
2087 const cfg_obj_t *views = NULL;
2088 const cfg_obj_t *acls = NULL;
2089 const cfg_obj_t *kals = NULL;
2090 const cfg_obj_t *obj;
2091 const cfg_listelt_t *velement;
2092 isc_result_t result = ISC_R_SUCCESS;
2093 isc_result_t tresult;
2094 isc_symtab_t *symtab = NULL;
2096 static const char *builtin[] = { "localhost", "localnets",
2099 (void)cfg_map_get(config, "options", &options);
2101 if (options != NULL &&
2102 check_options(options, logctx, mctx) != ISC_R_SUCCESS)
2103 result = ISC_R_FAILURE;
2105 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
2106 result = ISC_R_FAILURE;
2108 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
2109 result = ISC_R_FAILURE;
2111 if (options != NULL &&
2112 check_order(options, logctx) != ISC_R_SUCCESS)
2113 result = ISC_R_FAILURE;
2115 (void)cfg_map_get(config, "view", &views);
2117 if (views != NULL && options != NULL)
2118 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2119 result = ISC_R_FAILURE;
2121 if (views == NULL) {
2122 if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
2123 logctx, mctx) != ISC_R_SUCCESS)
2124 result = ISC_R_FAILURE;
2126 const cfg_obj_t *zones = NULL;
2128 (void)cfg_map_get(config, "zone", &zones);
2129 if (zones != NULL) {
2130 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
2131 "when using 'view' statements, "
2132 "all zones must be in views");
2133 result = ISC_R_FAILURE;
2137 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
2138 if (tresult != ISC_R_SUCCESS)
2140 for (velement = cfg_list_first(views);
2142 velement = cfg_list_next(velement))
2144 const cfg_obj_t *view = cfg_listelt_value(velement);
2145 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
2146 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
2147 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
2148 dns_rdataclass_t vclass = dns_rdataclass_in;
2149 isc_result_t tresult = ISC_R_SUCCESS;
2150 const char *key = cfg_obj_asstring(vname);
2151 isc_symvalue_t symvalue;
2153 if (cfg_obj_isstring(vclassobj)) {
2156 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
2157 r.length = strlen(r.base);
2158 tresult = dns_rdataclass_fromtext(&vclass, &r);
2159 if (tresult != ISC_R_SUCCESS)
2160 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
2161 "view '%s': invalid class %s",
2162 cfg_obj_asstring(vname), r.base);
2164 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
2165 symvalue.as_cpointer = view;
2166 tresult = isc_symtab_define(symtab, key, vclass,
2168 isc_symexists_reject);
2169 if (tresult == ISC_R_EXISTS) {
2172 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
2173 vclass, &symvalue) == ISC_R_SUCCESS);
2174 file = cfg_obj_file(symvalue.as_cpointer);
2175 line = cfg_obj_line(symvalue.as_cpointer);
2176 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2177 "view '%s': already exists "
2178 "previous definition: %s:%u",
2181 } else if (tresult != ISC_R_SUCCESS) {
2183 } else if ((strcasecmp(key, "_bind") == 0 &&
2184 vclass == dns_rdataclass_ch) ||
2185 (strcasecmp(key, "_default") == 0 &&
2186 vclass == dns_rdataclass_in)) {
2187 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2188 "attempt to redefine builtin view "
2190 result = ISC_R_EXISTS;
2193 if (tresult == ISC_R_SUCCESS)
2194 tresult = check_viewconf(config, voptions, key,
2195 vclass, logctx, mctx);
2196 if (tresult != ISC_R_SUCCESS)
2197 result = ISC_R_FAILURE;
2200 isc_symtab_destroy(&symtab);
2202 if (views != NULL && options != NULL) {
2204 tresult = cfg_map_get(options, "cache-file", &obj);
2205 if (tresult == ISC_R_SUCCESS) {
2206 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2207 "'cache-file' cannot be a global "
2208 "option if views are present");
2209 result = ISC_R_FAILURE;
2213 cfg_map_get(config, "acl", &acls);
2216 const cfg_listelt_t *elt;
2217 const cfg_listelt_t *elt2;
2218 const char *aclname;
2220 for (elt = cfg_list_first(acls);
2222 elt = cfg_list_next(elt)) {
2223 const cfg_obj_t *acl = cfg_listelt_value(elt);
2224 unsigned int line = cfg_obj_line(acl);
2227 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2229 i < sizeof(builtin) / sizeof(builtin[0]);
2231 if (strcasecmp(aclname, builtin[i]) == 0) {
2232 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
2233 "attempt to redefine "
2236 result = ISC_R_FAILURE;
2240 for (elt2 = cfg_list_next(elt);
2242 elt2 = cfg_list_next(elt2)) {
2243 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2245 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2247 if (strcasecmp(aclname, name) == 0) {
2248 const char *file = cfg_obj_file(acl);
2251 file = "<unknown file>";
2253 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2254 "attempt to redefine "
2255 "acl '%s' previous "
2256 "definition: %s:%u",
2258 result = ISC_R_FAILURE;
2264 tresult = cfg_map_get(config, "kal", &kals);
2265 if (tresult == ISC_R_SUCCESS) {
2266 const cfg_listelt_t *elt;
2267 const cfg_listelt_t *elt2;
2268 const char *aclname;
2270 for (elt = cfg_list_first(kals);
2272 elt = cfg_list_next(elt)) {
2273 const cfg_obj_t *acl = cfg_listelt_value(elt);
2275 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2277 for (elt2 = cfg_list_next(elt);
2279 elt2 = cfg_list_next(elt2)) {
2280 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2282 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2284 if (strcasecmp(aclname, name) == 0) {
2285 const char *file = cfg_obj_file(acl);
2286 unsigned int line = cfg_obj_line(acl);
2289 file = "<unknown file>";
2291 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2292 "attempt to redefine "
2293 "kal '%s' previous "
2294 "definition: %s:%u",
2296 result = ISC_R_FAILURE;