etc/services - sync with NetBSD-8
[minix.git] / external / bsd / bind / dist / lib / bind9 / check.c
blobd705a201e2abb47ec394ca16f31161220b546b61
1 /* $NetBSD: check.c,v 1.12 2015/07/08 17:28:58 christos Exp $ */
3 /*
4 * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2001-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /*! \file */
22 #include <config.h>
24 #include <stdlib.h>
26 #include <isc/base64.h>
27 #include <isc/buffer.h>
28 #include <isc/file.h>
29 #include <isc/hex.h>
30 #include <isc/log.h>
31 #include <isc/mem.h>
32 #include <isc/netaddr.h>
33 #include <isc/parseint.h>
34 #include <isc/platform.h>
35 #include <isc/region.h>
36 #include <isc/result.h>
37 #include <isc/sockaddr.h>
38 #include <isc/string.h>
39 #include <isc/symtab.h>
40 #include <isc/util.h>
42 #ifdef ISC_PLATFORM_USESIT
43 #ifdef AES_SIT
44 #include <isc/aes.h>
45 #endif
46 #ifdef HMAC_SHA1_SIT
47 #include <isc/sha1.h>
48 #endif
49 #ifdef HMAC_SHA256_SIT
50 #include <isc/sha2.h>
51 #endif
52 #endif
54 #include <dns/acl.h>
55 #include <dns/fixedname.h>
56 #include <dns/rdataclass.h>
57 #include <dns/rdatatype.h>
58 #include <dns/secalg.h>
60 #include <dst/dst.h>
62 #include <isccfg/aclconf.h>
63 #include <isccfg/cfg.h>
65 #include <bind9/check.h>
67 static isc_result_t
68 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, isc_boolean_t writeable,
69 isc_log_t *logctxlogc);
71 static void
72 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
73 UNUSED(type);
74 UNUSED(value);
75 isc_mem_free(userarg, key);
78 static isc_result_t
79 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
80 isc_result_t result = ISC_R_SUCCESS;
81 isc_result_t tresult;
82 isc_textregion_t r;
83 dns_fixedname_t fixed;
84 const cfg_obj_t *obj;
85 dns_rdataclass_t rdclass;
86 dns_rdatatype_t rdtype;
87 isc_buffer_t b;
88 const char *str;
90 dns_fixedname_init(&fixed);
91 obj = cfg_tuple_get(ent, "class");
92 if (cfg_obj_isstring(obj)) {
94 DE_CONST(cfg_obj_asstring(obj), r.base);
95 r.length = strlen(r.base);
96 tresult = dns_rdataclass_fromtext(&rdclass, &r);
97 if (tresult != ISC_R_SUCCESS) {
98 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
99 "rrset-order: invalid class '%s'",
100 r.base);
101 result = ISC_R_FAILURE;
105 obj = cfg_tuple_get(ent, "type");
106 if (cfg_obj_isstring(obj)) {
107 DE_CONST(cfg_obj_asstring(obj), r.base);
108 r.length = strlen(r.base);
109 tresult = dns_rdatatype_fromtext(&rdtype, &r);
110 if (tresult != ISC_R_SUCCESS) {
111 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
112 "rrset-order: invalid type '%s'",
113 r.base);
114 result = ISC_R_FAILURE;
118 obj = cfg_tuple_get(ent, "name");
119 if (cfg_obj_isstring(obj)) {
120 str = cfg_obj_asstring(obj);
121 isc_buffer_constinit(&b, str, strlen(str));
122 isc_buffer_add(&b, strlen(str));
123 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
124 dns_rootname, 0, NULL);
125 if (tresult != ISC_R_SUCCESS) {
126 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
127 "rrset-order: invalid name '%s'", str);
128 result = ISC_R_FAILURE;
132 obj = cfg_tuple_get(ent, "order");
133 if (!cfg_obj_isstring(obj) ||
134 strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
135 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
136 "rrset-order: keyword 'order' missing");
137 result = ISC_R_FAILURE;
140 obj = cfg_tuple_get(ent, "ordering");
141 if (!cfg_obj_isstring(obj)) {
142 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
143 "rrset-order: missing ordering");
144 result = ISC_R_FAILURE;
145 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
146 #if !DNS_RDATASET_FIXED
147 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
148 "rrset-order: order 'fixed' was disabled at "
149 "compilation time");
150 #endif
151 } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
152 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
153 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
154 "rrset-order: invalid order '%s'",
155 cfg_obj_asstring(obj));
156 result = ISC_R_FAILURE;
158 return (result);
161 static isc_result_t
162 check_order(const cfg_obj_t *options, isc_log_t *logctx) {
163 isc_result_t result = ISC_R_SUCCESS;
164 isc_result_t tresult;
165 const cfg_listelt_t *element;
166 const cfg_obj_t *obj = NULL;
168 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
169 return (result);
171 for (element = cfg_list_first(obj);
172 element != NULL;
173 element = cfg_list_next(element))
175 tresult = check_orderent(cfg_listelt_value(element), logctx);
176 if (tresult != ISC_R_SUCCESS)
177 result = tresult;
179 return (result);
182 static isc_result_t
183 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
184 const cfg_listelt_t *element;
185 const cfg_obj_t *alternates = NULL;
186 const cfg_obj_t *value;
187 const cfg_obj_t *obj;
188 const char *str;
189 dns_fixedname_t fixed;
190 dns_name_t *name;
191 isc_buffer_t buffer;
192 isc_result_t result = ISC_R_SUCCESS;
193 isc_result_t tresult;
195 (void)cfg_map_get(options, "dual-stack-servers", &alternates);
197 if (alternates == NULL)
198 return (ISC_R_SUCCESS);
200 obj = cfg_tuple_get(alternates, "port");
201 if (cfg_obj_isuint32(obj)) {
202 isc_uint32_t val = cfg_obj_asuint32(obj);
203 if (val > ISC_UINT16_MAX) {
204 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
205 "port '%u' out of range", val);
206 result = ISC_R_FAILURE;
209 obj = cfg_tuple_get(alternates, "addresses");
210 for (element = cfg_list_first(obj);
211 element != NULL;
212 element = cfg_list_next(element)) {
213 value = cfg_listelt_value(element);
214 if (cfg_obj_issockaddr(value))
215 continue;
216 obj = cfg_tuple_get(value, "name");
217 str = cfg_obj_asstring(obj);
218 isc_buffer_constinit(&buffer, str, strlen(str));
219 isc_buffer_add(&buffer, strlen(str));
220 dns_fixedname_init(&fixed);
221 name = dns_fixedname_name(&fixed);
222 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
223 0, NULL);
224 if (tresult != ISC_R_SUCCESS) {
225 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
226 "bad name '%s'", str);
227 result = ISC_R_FAILURE;
229 obj = cfg_tuple_get(value, "port");
230 if (cfg_obj_isuint32(obj)) {
231 isc_uint32_t val = cfg_obj_asuint32(obj);
232 if (val > ISC_UINT16_MAX) {
233 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
234 "port '%u' out of range", val);
235 result = ISC_R_FAILURE;
239 return (result);
242 static isc_result_t
243 check_forward(const cfg_obj_t *options, const cfg_obj_t *global,
244 isc_log_t *logctx)
246 const cfg_obj_t *forward = NULL;
247 const cfg_obj_t *forwarders = NULL;
249 (void)cfg_map_get(options, "forward", &forward);
250 (void)cfg_map_get(options, "forwarders", &forwarders);
252 if (forwarders != NULL && global != NULL) {
253 const char *file = cfg_obj_file(global);
254 unsigned int line = cfg_obj_line(global);
255 cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
256 "forwarders declared in root zone and "
257 "in general configuration: %s:%u",
258 file, line);
259 return (ISC_R_FAILURE);
261 if (forward != NULL && forwarders == NULL) {
262 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
263 "no matching 'forwarders' statement");
264 return (ISC_R_FAILURE);
266 return (ISC_R_SUCCESS);
269 static isc_result_t
270 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
271 isc_result_t result = ISC_R_SUCCESS;
272 isc_result_t tresult;
273 const cfg_listelt_t *element;
274 const char *str;
275 isc_buffer_t b;
276 dns_fixedname_t fixed;
277 dns_name_t *name;
278 const cfg_obj_t *obj;
280 dns_fixedname_init(&fixed);
281 name = dns_fixedname_name(&fixed);
282 obj = cfg_tuple_get(disabled, "name");
283 str = cfg_obj_asstring(obj);
284 isc_buffer_constinit(&b, str, strlen(str));
285 isc_buffer_add(&b, strlen(str));
286 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
287 if (tresult != ISC_R_SUCCESS) {
288 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
289 "bad domain name '%s'", str);
290 result = tresult;
293 obj = cfg_tuple_get(disabled, "algorithms");
295 for (element = cfg_list_first(obj);
296 element != NULL;
297 element = cfg_list_next(element))
299 isc_textregion_t r;
300 dns_secalg_t alg;
302 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
303 r.length = strlen(r.base);
305 tresult = dns_secalg_fromtext(&alg, &r);
306 if (tresult != ISC_R_SUCCESS) {
307 cfg_obj_log(cfg_listelt_value(element), logctx,
308 ISC_LOG_ERROR, "invalid algorithm '%s'",
309 r.base);
310 result = tresult;
313 return (result);
316 static isc_result_t
317 disabled_ds_digests(const cfg_obj_t *disabled, isc_log_t *logctx) {
318 isc_result_t result = ISC_R_SUCCESS;
319 isc_result_t tresult;
320 const cfg_listelt_t *element;
321 const char *str;
322 isc_buffer_t b;
323 dns_fixedname_t fixed;
324 dns_name_t *name;
325 const cfg_obj_t *obj;
327 dns_fixedname_init(&fixed);
328 name = dns_fixedname_name(&fixed);
329 obj = cfg_tuple_get(disabled, "name");
330 str = cfg_obj_asstring(obj);
331 isc_buffer_constinit(&b, str, strlen(str));
332 isc_buffer_add(&b, strlen(str));
333 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
334 if (tresult != ISC_R_SUCCESS) {
335 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
336 "bad domain name '%s'", str);
337 result = tresult;
340 obj = cfg_tuple_get(disabled, "digests");
342 for (element = cfg_list_first(obj);
343 element != NULL;
344 element = cfg_list_next(element))
346 isc_textregion_t r;
347 dns_dsdigest_t digest;
349 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
350 r.length = strlen(r.base);
352 /* works with a numeric argument too */
353 tresult = dns_dsdigest_fromtext(&digest, &r);
354 if (tresult != ISC_R_SUCCESS) {
355 cfg_obj_log(cfg_listelt_value(element), logctx,
356 ISC_LOG_ERROR, "invalid digest type '%s'",
357 r.base);
358 result = tresult;
361 return (result);
364 static isc_result_t
365 nameexist(const cfg_obj_t *obj, const char *name, int value,
366 isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
367 isc_mem_t *mctx)
369 char *key;
370 const char *file;
371 unsigned int line;
372 isc_result_t result;
373 isc_symvalue_t symvalue;
375 key = isc_mem_strdup(mctx, name);
376 if (key == NULL)
377 return (ISC_R_NOMEMORY);
378 symvalue.as_cpointer = obj;
379 result = isc_symtab_define(symtab, key, value, symvalue,
380 isc_symexists_reject);
381 if (result == ISC_R_EXISTS) {
382 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
383 &symvalue) == ISC_R_SUCCESS);
384 file = cfg_obj_file(symvalue.as_cpointer);
385 line = cfg_obj_line(symvalue.as_cpointer);
387 if (file == NULL)
388 file = "<unknown file>";
389 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
390 isc_mem_free(mctx, key);
391 result = ISC_R_EXISTS;
392 } else if (result != ISC_R_SUCCESS) {
393 isc_mem_free(mctx, key);
395 return (result);
398 static isc_result_t
399 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
400 isc_mem_t *mctx)
402 const cfg_obj_t *obj;
403 char namebuf[DNS_NAME_FORMATSIZE];
404 const char *str;
405 dns_fixedname_t fixed;
406 dns_name_t *name;
407 isc_buffer_t b;
408 isc_result_t result = ISC_R_SUCCESS;
410 dns_fixedname_init(&fixed);
411 name = dns_fixedname_name(&fixed);
412 obj = cfg_tuple_get(secure, "name");
413 str = cfg_obj_asstring(obj);
414 isc_buffer_constinit(&b, str, strlen(str));
415 isc_buffer_add(&b, strlen(str));
416 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
417 if (result != ISC_R_SUCCESS) {
418 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
419 "bad domain name '%s'", str);
420 } else {
421 dns_name_format(name, namebuf, sizeof(namebuf));
422 result = nameexist(secure, namebuf, 1, symtab,
423 "dnssec-must-be-secure '%s': already "
424 "exists previous definition: %s:%u",
425 logctx, mctx);
427 return (result);
430 static isc_result_t
431 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
432 const cfg_obj_t *voptions, const cfg_obj_t *config,
433 isc_log_t *logctx, isc_mem_t *mctx)
435 isc_result_t result;
436 const cfg_obj_t *aclobj = NULL;
437 const cfg_obj_t *options;
438 dns_acl_t *acl = NULL;
440 if (zconfig != NULL) {
441 options = cfg_tuple_get(zconfig, "options");
442 cfg_map_get(options, aclname, &aclobj);
444 if (voptions != NULL && aclobj == NULL)
445 cfg_map_get(voptions, aclname, &aclobj);
446 if (config != NULL && aclobj == NULL) {
447 options = NULL;
448 cfg_map_get(config, "options", &options);
449 if (options != NULL)
450 cfg_map_get(options, aclname, &aclobj);
452 if (aclobj == NULL)
453 return (ISC_R_SUCCESS);
454 result = cfg_acl_fromconfig(aclobj, config, logctx,
455 actx, mctx, 0, &acl);
456 if (acl != NULL)
457 dns_acl_detach(&acl);
458 return (result);
461 static isc_result_t
462 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
463 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
465 isc_result_t result = ISC_R_SUCCESS, tresult;
466 int i = 0;
468 static const char *acls[] = { "allow-query", "allow-query-on",
469 "allow-query-cache", "allow-query-cache-on",
470 "blackhole", "match-clients", "match-destinations",
471 "sortlist", "filter-aaaa", NULL };
473 while (acls[i] != NULL) {
474 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
475 logctx, mctx);
476 if (tresult != ISC_R_SUCCESS)
477 result = tresult;
479 return (result);
482 static const unsigned char zeros[16];
484 static isc_result_t
485 check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
486 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
488 isc_result_t result = ISC_R_SUCCESS;
489 const cfg_obj_t *dns64 = NULL;
490 const cfg_obj_t *options;
491 const cfg_listelt_t *element;
492 const cfg_obj_t *map, *obj;
493 isc_netaddr_t na, sa;
494 unsigned int prefixlen;
495 int nbytes;
496 int i;
498 static const char *acls[] = { "clients", "exclude", "mapped", NULL};
500 if (voptions != NULL)
501 cfg_map_get(voptions, "dns64", &dns64);
502 if (config != NULL && dns64 == NULL) {
503 options = NULL;
504 cfg_map_get(config, "options", &options);
505 if (options != NULL)
506 cfg_map_get(options, "dns64", &dns64);
508 if (dns64 == NULL)
509 return (ISC_R_SUCCESS);
511 for (element = cfg_list_first(dns64);
512 element != NULL;
513 element = cfg_list_next(element))
515 map = cfg_listelt_value(element);
516 obj = cfg_map_getname(map);
518 cfg_obj_asnetprefix(obj, &na, &prefixlen);
519 if (na.family != AF_INET6) {
520 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
521 "dns64 requires a IPv6 prefix");
522 result = ISC_R_FAILURE;
523 continue;
526 if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 &&
527 prefixlen != 56 && prefixlen != 64 && prefixlen != 96) {
528 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
529 "bad prefix length %u [32/40/48/56/64/96]",
530 prefixlen);
531 result = ISC_R_FAILURE;
532 continue;
535 for (i = 0; acls[i] != NULL; i++) {
536 obj = NULL;
537 (void)cfg_map_get(map, acls[i], &obj);
538 if (obj != NULL) {
539 dns_acl_t *acl = NULL;
540 isc_result_t tresult;
542 tresult = cfg_acl_fromconfig(obj, config,
543 logctx, actx,
544 mctx, 0, &acl);
545 if (acl != NULL)
546 dns_acl_detach(&acl);
547 if (tresult != ISC_R_SUCCESS)
548 result = tresult;
552 obj = NULL;
553 (void)cfg_map_get(map, "suffix", &obj);
554 if (obj != NULL) {
555 isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj));
556 if (sa.family != AF_INET6) {
557 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
558 "dns64 requires a IPv6 suffix");
559 result = ISC_R_FAILURE;
560 continue;
562 nbytes = prefixlen / 8 + 4;
563 if (prefixlen >= 32 && prefixlen <= 64)
564 nbytes++;
565 if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) {
566 char netaddrbuf[ISC_NETADDR_FORMATSIZE];
567 isc_netaddr_format(&sa, netaddrbuf,
568 sizeof(netaddrbuf));
569 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
570 "bad suffix '%s' leading "
571 "%u octets not zeros",
572 netaddrbuf, nbytes);
573 result = ISC_R_FAILURE;
578 return (result);
583 * Check allow-recursion and allow-recursion-on acls, and also log a
584 * warning if they're inconsistent with the "recursion" option.
586 static isc_result_t
587 check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
588 const char *viewname, const cfg_obj_t *config,
589 isc_log_t *logctx, isc_mem_t *mctx)
591 const cfg_obj_t *options, *aclobj, *obj = NULL;
592 dns_acl_t *acl = NULL;
593 isc_result_t result = ISC_R_SUCCESS, tresult;
594 isc_boolean_t recursion;
595 const char *forview = " for view ";
596 int i = 0;
598 static const char *acls[] = { "allow-recursion", "allow-recursion-on",
599 NULL };
601 if (voptions != NULL)
602 cfg_map_get(voptions, "recursion", &obj);
603 if (obj == NULL && config != NULL) {
604 options = NULL;
605 cfg_map_get(config, "options", &options);
606 if (options != NULL)
607 cfg_map_get(options, "recursion", &obj);
609 if (obj == NULL)
610 recursion = ISC_TRUE;
611 else
612 recursion = cfg_obj_asboolean(obj);
614 if (viewname == NULL) {
615 viewname = "";
616 forview = "";
619 for (i = 0; acls[i] != NULL; i++) {
620 aclobj = options = NULL;
621 acl = NULL;
623 if (voptions != NULL)
624 cfg_map_get(voptions, acls[i], &aclobj);
625 if (config != NULL && aclobj == NULL) {
626 options = NULL;
627 cfg_map_get(config, "options", &options);
628 if (options != NULL)
629 cfg_map_get(options, acls[i], &aclobj);
631 if (aclobj == NULL)
632 continue;
634 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
635 actx, mctx, 0, &acl);
637 if (tresult != ISC_R_SUCCESS)
638 result = tresult;
640 if (acl == NULL)
641 continue;
643 if (recursion == ISC_FALSE && !dns_acl_isnone(acl)) {
644 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
645 "both \"recursion no;\" and "
646 "\"%s\" active%s%s",
647 acls[i], forview, viewname);
650 if (acl != NULL)
651 dns_acl_detach(&acl);
654 return (result);
657 static isc_result_t
658 check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
659 const char *viewname, const cfg_obj_t *config,
660 isc_log_t *logctx, isc_mem_t *mctx)
662 const cfg_obj_t *options, *aclobj, *obj;
663 dns_acl_t *acl = NULL;
664 isc_result_t result = ISC_R_SUCCESS;
665 dns_aaaa_t filter4, filter6;
666 const char *forview = " for view ";
668 if (viewname == NULL) {
669 viewname = "";
670 forview = "";
673 aclobj = options = NULL;
674 acl = NULL;
676 if (voptions != NULL)
677 cfg_map_get(voptions, "filter-aaaa", &aclobj);
678 if (config != NULL && aclobj == NULL) {
679 options = NULL;
680 cfg_map_get(config, "options", &options);
681 if (options != NULL)
682 cfg_map_get(options, "filter-aaaa", &aclobj);
684 if (aclobj == NULL)
685 return (result);
687 result = cfg_acl_fromconfig(aclobj, config, logctx,
688 actx, mctx, 0, &acl);
689 if (result != ISC_R_SUCCESS)
690 goto failure;
692 obj = NULL;
693 if (voptions != NULL)
694 cfg_map_get(voptions, "filter-aaaa-on-v4", &obj);
695 if (obj == NULL && config != NULL) {
696 options = NULL;
697 cfg_map_get(config, "options", &options);
698 if (options != NULL)
699 cfg_map_get(options, "filter-aaaa-on-v4", &obj);
702 if (obj == NULL)
703 filter4 = dns_aaaa_ok; /* default */
704 else if (cfg_obj_isboolean(obj))
705 filter4 = cfg_obj_asboolean(obj) ? dns_aaaa_filter :
706 dns_aaaa_ok;
707 else
708 filter4 = dns_aaaa_break_dnssec; /* break-dnssec */
710 obj = NULL;
711 if (voptions != NULL)
712 cfg_map_get(voptions, "filter-aaaa-on-v6", &obj);
713 if (obj == NULL && config != NULL) {
714 options = NULL;
715 cfg_map_get(config, "options", &options);
716 if (options != NULL)
717 cfg_map_get(options, "filter-aaaa-on-v6", &obj);
720 if (obj == NULL)
721 filter6 = dns_aaaa_ok; /* default */
722 else if (cfg_obj_isboolean(obj))
723 filter6 = cfg_obj_asboolean(obj) ? dns_aaaa_filter :
724 dns_aaaa_ok;
725 else
726 filter6 = dns_aaaa_break_dnssec; /* break-dnssec */
728 if ((filter4 != dns_aaaa_ok || filter6 != dns_aaaa_ok) &&
729 dns_acl_isnone(acl))
731 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
732 "\"filter-aaaa\" is 'none;' but "
733 "either filter-aaaa-on-v4 or filter-aaaa-on-v6 "
734 "is enabled%s%s", forview, viewname);
735 result = ISC_R_FAILURE;
736 } else if (filter4 == dns_aaaa_ok && filter6 == dns_aaaa_ok &&
737 !dns_acl_isnone(acl))
739 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
740 "\"filter-aaaa\" is set but "
741 "neither filter-aaaa-on-v4 or filter-aaaa-on-v6 "
742 "is enabled%s%s", forview, viewname);
743 result = ISC_R_FAILURE;
746 failure:
747 if (acl != NULL)
748 dns_acl_detach(&acl);
750 return (result);
753 typedef struct {
754 const char *name;
755 unsigned int scale;
756 unsigned int max;
757 } intervaltable;
759 typedef enum {
760 optlevel_config,
761 optlevel_options,
762 optlevel_view,
763 optlevel_zone
764 } optlevel_t;
766 static isc_result_t
767 check_dscp(const cfg_obj_t *options, isc_log_t *logctx) {
768 isc_result_t result = ISC_R_SUCCESS;
769 const cfg_obj_t *obj = NULL;
772 * Check that DSCP setting is within range
774 obj = NULL;
775 (void)cfg_map_get(options, "dscp", &obj);
776 if (obj != NULL) {
777 isc_uint32_t dscp = cfg_obj_asuint32(obj);
778 if (dscp >= 64) {
779 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
780 "'dscp' out of range (0-63)");
781 result = ISC_R_FAILURE;
785 return (result);
788 static isc_result_t
789 check_name(const char *str) {
790 dns_fixedname_t fixed;
792 dns_fixedname_init(&fixed);
793 return (dns_name_fromstring(dns_fixedname_name(&fixed), str, 0, NULL));
796 static isc_result_t
797 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
798 optlevel_t optlevel)
800 isc_result_t result = ISC_R_SUCCESS;
801 isc_result_t tresult;
802 unsigned int i;
803 const cfg_obj_t *obj = NULL;
804 const cfg_obj_t *resignobj = NULL;
805 const cfg_listelt_t *element;
806 isc_symtab_t *symtab = NULL;
807 dns_fixedname_t fixed;
808 const char *str;
809 dns_name_t *name;
810 #ifdef ISC_PLATFORM_USESIT
811 isc_buffer_t b;
812 #endif
814 static intervaltable intervals[] = {
815 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
816 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
817 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
818 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
819 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
820 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
821 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
822 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
825 static const char *server_contact[] = {
826 "empty-server", "empty-contact",
827 "dns64-server", "dns64-contact",
828 NULL
832 * Check that fields specified in units of time other than seconds
833 * have reasonable values.
835 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
836 isc_uint32_t val;
837 obj = NULL;
838 (void)cfg_map_get(options, intervals[i].name, &obj);
839 if (obj == NULL)
840 continue;
841 val = cfg_obj_asuint32(obj);
842 if (val > intervals[i].max) {
843 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
844 "%s '%u' is out of range (0..%u)",
845 intervals[i].name, val,
846 intervals[i].max);
847 result = ISC_R_RANGE;
848 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
849 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
850 "%s '%d' is out of range",
851 intervals[i].name, val);
852 result = ISC_R_RANGE;
856 obj = NULL;
857 cfg_map_get(options, "max-rsa-exponent-size", &obj);
858 if (obj != NULL) {
859 isc_uint32_t val;
861 val = cfg_obj_asuint32(obj);
862 if (val != 0 && (val < 35 || val > 4096)) {
863 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
864 "max-rsa-exponent-size '%u' is out of "
865 "range (35..4096)", val);
866 result = ISC_R_RANGE;
870 obj = NULL;
871 cfg_map_get(options, "sig-validity-interval", &obj);
872 if (obj != NULL) {
873 isc_uint32_t validity, resign = 0;
875 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
876 resignobj = cfg_tuple_get(obj, "re-sign");
877 if (!cfg_obj_isvoid(resignobj))
878 resign = cfg_obj_asuint32(resignobj);
880 if (validity > 3660 || validity == 0) { /* 10 years */
881 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
882 "%s '%u' is out of range (1..3660)",
883 "sig-validity-interval", validity);
884 result = ISC_R_RANGE;
887 if (!cfg_obj_isvoid(resignobj)) {
888 if (resign > 3660 || resign == 0) { /* 10 years */
889 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
890 "%s '%u' is out of range (1..3660)",
891 "sig-validity-interval (re-sign)",
892 validity);
893 result = ISC_R_RANGE;
894 } else if ((validity > 7 && validity < resign) ||
895 (validity <= 7 && validity * 24 < resign)) {
896 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
897 "validity interval (%u days) "
898 "less than re-signing interval "
899 "(%u %s)", validity, resign,
900 (validity > 7) ? "days" : "hours");
901 result = ISC_R_RANGE;
906 obj = NULL;
907 (void)cfg_map_get(options, "preferred-glue", &obj);
908 if (obj != NULL) {
909 str = cfg_obj_asstring(obj);
910 if (strcasecmp(str, "a") != 0 &&
911 strcasecmp(str, "aaaa") != 0 &&
912 strcasecmp(str, "none") != 0)
913 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
914 "preferred-glue unexpected value '%s'",
915 str);
918 obj = NULL;
919 (void)cfg_map_get(options, "root-delegation-only", &obj);
920 if (obj != NULL) {
921 if (!cfg_obj_isvoid(obj)) {
922 for (element = cfg_list_first(obj);
923 element != NULL;
924 element = cfg_list_next(element)) {
925 const cfg_obj_t *exclude;
927 exclude = cfg_listelt_value(element);
928 str = cfg_obj_asstring(exclude);
929 tresult = check_name(str);
930 if (tresult != ISC_R_SUCCESS) {
931 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
932 "bad domain name '%s'",
933 str);
934 result = tresult;
941 * Set supported DNSSEC algorithms.
943 obj = NULL;
944 (void)cfg_map_get(options, "disable-algorithms", &obj);
945 if (obj != NULL) {
946 for (element = cfg_list_first(obj);
947 element != NULL;
948 element = cfg_list_next(element))
950 obj = cfg_listelt_value(element);
951 tresult = disabled_algorithms(obj, logctx);
952 if (tresult != ISC_R_SUCCESS)
953 result = tresult;
958 * Set supported DS/DLV digest types.
960 obj = NULL;
961 (void)cfg_map_get(options, "disable-ds-digests", &obj);
962 if (obj != NULL) {
963 for (element = cfg_list_first(obj);
964 element != NULL;
965 element = cfg_list_next(element))
967 obj = cfg_listelt_value(element);
968 tresult = disabled_ds_digests(obj, logctx);
969 if (tresult != ISC_R_SUCCESS)
970 result = tresult;
974 dns_fixedname_init(&fixed);
975 name = dns_fixedname_name(&fixed);
978 * Check the DLV zone name.
980 obj = NULL;
981 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
982 if (obj != NULL) {
983 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
984 ISC_FALSE, &symtab);
985 if (tresult != ISC_R_SUCCESS)
986 result = tresult;
987 for (element = cfg_list_first(obj);
988 element != NULL;
989 element = cfg_list_next(element))
991 const char *dlv;
992 const cfg_obj_t *dlvobj, *anchor;
994 obj = cfg_listelt_value(element);
996 anchor = cfg_tuple_get(obj, "trust-anchor");
997 dlvobj = cfg_tuple_get(obj, "domain");
998 dlv = cfg_obj_asstring(dlvobj);
1001 * If domain is "auto" or "no" and trust anchor
1002 * is missing, skip remaining tests
1004 if (cfg_obj_isvoid(anchor)) {
1005 if (!strcasecmp(dlv, "no") ||
1006 !strcasecmp(dlv, "auto"))
1007 continue;
1010 tresult = dns_name_fromstring(name, dlv, 0, NULL);
1011 if (tresult != ISC_R_SUCCESS) {
1012 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1013 "bad domain name '%s'", dlv);
1014 result = tresult;
1015 continue;
1017 if (symtab != NULL) {
1018 tresult = nameexist(obj, dlv, 1, symtab,
1019 "dnssec-lookaside '%s': "
1020 "already exists previous "
1021 "definition: %s:%u",
1022 logctx, mctx);
1023 if (tresult != ISC_R_SUCCESS &&
1024 result == ISC_R_SUCCESS)
1025 result = tresult;
1029 * XXXMPA to be removed when multiple lookaside
1030 * namespaces are supported.
1032 if (!dns_name_equal(dns_rootname, name)) {
1033 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1034 "dnssec-lookaside '%s': "
1035 "non-root not yet supported", dlv);
1036 if (result == ISC_R_SUCCESS)
1037 result = ISC_R_FAILURE;
1040 if (!cfg_obj_isvoid(anchor)) {
1041 dlv = cfg_obj_asstring(anchor);
1042 tresult = check_name(dlv);
1043 if (tresult != ISC_R_SUCCESS) {
1044 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1045 "bad domain name '%s'",
1046 dlv);
1047 if (result == ISC_R_SUCCESS)
1048 result = tresult;
1050 } else {
1051 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1052 "dnssec-lookaside requires "
1053 "either 'auto' or 'no', or a "
1054 "domain and trust anchor");
1055 if (result == ISC_R_SUCCESS)
1056 result = ISC_R_FAILURE;
1060 if (symtab != NULL)
1061 isc_symtab_destroy(&symtab);
1065 * Check auto-dnssec at the view/options level
1067 obj = NULL;
1068 (void)cfg_map_get(options, "auto-dnssec", &obj);
1069 if (obj != NULL) {
1070 const char *arg = cfg_obj_asstring(obj);
1071 if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) {
1072 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1073 "auto-dnssec may only be activated at the "
1074 "zone level");
1075 result = ISC_R_FAILURE;
1080 * Check dnssec-must-be-secure.
1082 obj = NULL;
1083 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
1084 if (obj != NULL) {
1085 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1086 ISC_FALSE, &symtab);
1087 if (tresult != ISC_R_SUCCESS)
1088 result = tresult;
1089 for (element = cfg_list_first(obj);
1090 element != NULL;
1091 element = cfg_list_next(element))
1093 obj = cfg_listelt_value(element);
1094 tresult = mustbesecure(obj, symtab, logctx, mctx);
1095 if (tresult != ISC_R_SUCCESS)
1096 result = tresult;
1098 if (symtab != NULL)
1099 isc_symtab_destroy(&symtab);
1103 * Check server/contacts for syntactic validity.
1105 for (i= 0; server_contact[i] != NULL; i++) {
1106 obj = NULL;
1107 (void)cfg_map_get(options, server_contact[i], &obj);
1108 if (obj != NULL) {
1109 str = cfg_obj_asstring(obj);
1110 if (check_name(str) != ISC_R_SUCCESS) {
1111 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1112 "%s: invalid name '%s'",
1113 server_contact[i], str);
1114 result = ISC_R_FAILURE;
1120 * Check empty zone configuration.
1122 obj = NULL;
1123 (void)cfg_map_get(options, "disable-empty-zone", &obj);
1124 for (element = cfg_list_first(obj);
1125 element != NULL;
1126 element = cfg_list_next(element))
1128 obj = cfg_listelt_value(element);
1129 str = cfg_obj_asstring(obj);
1130 if (check_name(str) != ISC_R_SUCCESS) {
1131 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1132 "disable-empty-zone: invalid name '%s'",
1133 str);
1134 result = ISC_R_FAILURE;
1139 * Check that server-id is not too long.
1140 * 1024 bytes should be big enough.
1142 obj = NULL;
1143 (void)cfg_map_get(options, "server-id", &obj);
1144 if (obj != NULL && cfg_obj_isstring(obj) &&
1145 strlen(cfg_obj_asstring(obj)) > 1024U) {
1146 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1147 "'server-id' too big (>1024 bytes)");
1148 result = ISC_R_FAILURE;
1151 tresult = check_dscp(options, logctx);
1152 if (tresult != ISC_R_SUCCESS)
1153 result = tresult;
1155 #ifdef ISC_PLATFORM_USESIT
1156 obj = NULL;
1157 (void) cfg_map_get(options, "sit-secret", &obj);
1158 if (obj != NULL) {
1159 unsigned char secret[32];
1161 memset(secret, 0, sizeof(secret));
1162 isc_buffer_init(&b, secret, sizeof(secret));
1163 tresult = isc_hex_decodestring(cfg_obj_asstring(obj), &b);
1164 if (tresult == ISC_R_NOSPACE) {
1165 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1166 "sit-secret: too long");
1167 } else if (tresult != ISC_R_SUCCESS) {
1168 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1169 "sit-secret: invalid hex string");
1171 if (tresult != ISC_R_SUCCESS)
1172 result = tresult;
1173 #ifdef AES_SIT
1174 if (tresult == ISC_R_SUCCESS &&
1175 isc_buffer_usedlength(&b) != ISC_AES128_KEYLENGTH) {
1176 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1177 "AES sit-secret must be on 128 bits");
1178 result = ISC_R_RANGE;
1180 #endif
1181 #ifdef HMAC_SHA1_SIT
1182 if (tresult == ISC_R_SUCCESS &&
1183 isc_buffer_usedlength(&b) != ISC_SHA1_DIGESTLENGTH) {
1184 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1185 "SHA1 sit-secret must be on 160 bits");
1186 result = ISC_R_RANGE;
1188 #endif
1189 #ifdef HMAC_SHA256_SIT
1190 if (tresult == ISC_R_SUCCESS &&
1191 isc_buffer_usedlength(&b) != ISC_SHA256_DIGESTLENGTH) {
1192 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1193 "SHA256 sit-secret must be on 256 bits");
1194 result = ISC_R_RANGE;
1196 #endif
1198 #endif
1200 return (result);
1203 static isc_result_t
1204 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
1205 isc_result_t result;
1206 const cfg_obj_t *masters = NULL;
1207 const cfg_listelt_t *elt;
1209 result = cfg_map_get(cctx, "masters", &masters);
1210 if (result != ISC_R_SUCCESS)
1211 return (result);
1212 for (elt = cfg_list_first(masters);
1213 elt != NULL;
1214 elt = cfg_list_next(elt)) {
1215 const cfg_obj_t *list;
1216 const char *listname;
1218 list = cfg_listelt_value(elt);
1219 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
1221 if (strcasecmp(listname, name) == 0) {
1222 *ret = list;
1223 return (ISC_R_SUCCESS);
1226 return (ISC_R_NOTFOUND);
1229 static isc_result_t
1230 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
1231 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
1233 isc_result_t result = ISC_R_SUCCESS;
1234 isc_result_t tresult;
1235 isc_uint32_t count = 0;
1236 isc_symtab_t *symtab = NULL;
1237 isc_symvalue_t symvalue;
1238 const cfg_listelt_t *element;
1239 const cfg_listelt_t **stack = NULL;
1240 isc_uint32_t stackcount = 0, pushed = 0;
1241 const cfg_obj_t *list;
1243 REQUIRE(countp != NULL);
1244 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1245 if (result != ISC_R_SUCCESS) {
1246 *countp = count;
1247 return (result);
1250 newlist:
1251 list = cfg_tuple_get(obj, "addresses");
1252 element = cfg_list_first(list);
1253 resume:
1254 for ( ;
1255 element != NULL;
1256 element = cfg_list_next(element))
1258 const char *listname;
1259 const cfg_obj_t *addr;
1260 const cfg_obj_t *key;
1262 addr = cfg_tuple_get(cfg_listelt_value(element),
1263 "masterselement");
1264 key = cfg_tuple_get(cfg_listelt_value(element), "key");
1266 if (cfg_obj_issockaddr(addr)) {
1267 count++;
1268 continue;
1270 if (!cfg_obj_isvoid(key)) {
1271 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1272 "unexpected token '%s'",
1273 cfg_obj_asstring(key));
1274 if (result == ISC_R_SUCCESS)
1275 result = ISC_R_FAILURE;
1277 listname = cfg_obj_asstring(addr);
1278 symvalue.as_cpointer = addr;
1279 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
1280 isc_symexists_reject);
1281 if (tresult == ISC_R_EXISTS)
1282 continue;
1283 tresult = get_masters_def(config, listname, &obj);
1284 if (tresult != ISC_R_SUCCESS) {
1285 if (result == ISC_R_SUCCESS)
1286 result = tresult;
1287 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
1288 "unable to find masters list '%s'",
1289 listname);
1290 continue;
1292 /* Grow stack? */
1293 if (stackcount == pushed) {
1294 void * new;
1295 isc_uint32_t newlen = stackcount + 16;
1296 size_t newsize, oldsize;
1298 newsize = newlen * sizeof(*stack);
1299 oldsize = stackcount * sizeof(*stack);
1300 new = isc_mem_get(mctx, newsize);
1301 if (new == NULL)
1302 goto cleanup;
1303 if (stackcount != 0) {
1304 void *ptr;
1306 DE_CONST(stack, ptr);
1307 memmove(new, stack, oldsize);
1308 isc_mem_put(mctx, ptr, oldsize);
1310 stack = new;
1311 stackcount = newlen;
1313 stack[pushed++] = cfg_list_next(element);
1314 goto newlist;
1316 if (pushed != 0) {
1317 element = stack[--pushed];
1318 goto resume;
1320 cleanup:
1321 if (stack != NULL) {
1322 void *ptr;
1324 DE_CONST(stack, ptr);
1325 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
1327 isc_symtab_destroy(&symtab);
1328 *countp = count;
1329 return (result);
1332 static isc_result_t
1333 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
1334 isc_result_t result = ISC_R_SUCCESS;
1335 isc_result_t tresult;
1336 const cfg_listelt_t *element;
1337 const cfg_listelt_t *element2;
1338 dns_fixedname_t fixed;
1339 const char *str;
1340 isc_buffer_t b;
1342 /* Check for "update-policy local;" */
1343 if (cfg_obj_isstring(policy) &&
1344 strcmp("local", cfg_obj_asstring(policy)) == 0)
1345 return (ISC_R_SUCCESS);
1347 /* Now check the grant policy */
1348 for (element = cfg_list_first(policy);
1349 element != NULL;
1350 element = cfg_list_next(element))
1352 const cfg_obj_t *stmt = cfg_listelt_value(element);
1353 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
1354 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
1355 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
1356 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
1358 dns_fixedname_init(&fixed);
1359 str = cfg_obj_asstring(identity);
1360 isc_buffer_constinit(&b, str, strlen(str));
1361 isc_buffer_add(&b, strlen(str));
1362 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1363 dns_rootname, 0, NULL);
1364 if (tresult != ISC_R_SUCCESS) {
1365 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1366 "'%s' is not a valid name", str);
1367 result = tresult;
1370 if (tresult == ISC_R_SUCCESS &&
1371 strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) {
1372 dns_fixedname_init(&fixed);
1373 str = cfg_obj_asstring(dname);
1374 isc_buffer_constinit(&b, str, strlen(str));
1375 isc_buffer_add(&b, strlen(str));
1376 tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
1377 &b, dns_rootname, 0, NULL);
1378 if (tresult != ISC_R_SUCCESS) {
1379 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
1380 "'%s' is not a valid name", str);
1381 result = tresult;
1385 if (tresult == ISC_R_SUCCESS &&
1386 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
1387 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
1388 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1389 "'%s' is not a wildcard", str);
1390 result = ISC_R_FAILURE;
1393 for (element2 = cfg_list_first(typelist);
1394 element2 != NULL;
1395 element2 = cfg_list_next(element2))
1397 const cfg_obj_t *typeobj;
1398 isc_textregion_t r;
1399 dns_rdatatype_t type;
1401 typeobj = cfg_listelt_value(element2);
1402 DE_CONST(cfg_obj_asstring(typeobj), r.base);
1403 r.length = strlen(r.base);
1405 tresult = dns_rdatatype_fromtext(&type, &r);
1406 if (tresult != ISC_R_SUCCESS) {
1407 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
1408 "'%s' is not a valid type", r.base);
1409 result = tresult;
1413 return (result);
1416 #define MASTERZONE 1
1417 #define SLAVEZONE 2
1418 #define STUBZONE 4
1419 #define HINTZONE 8
1420 #define FORWARDZONE 16
1421 #define DELEGATIONZONE 32
1422 #define STATICSTUBZONE 64
1423 #define REDIRECTZONE 128
1424 #define STREDIRECTZONE 0 /* Set to REDIRECTZONE to allow xfr-in. */
1425 #define CHECKACL 512
1427 typedef struct {
1428 const char *name;
1429 int allowed;
1430 } optionstable;
1432 static isc_result_t
1433 check_nonzero(const cfg_obj_t *options, isc_log_t *logctx) {
1434 isc_result_t result = ISC_R_SUCCESS;
1435 const cfg_obj_t *obj = NULL;
1436 unsigned int i;
1438 static const char *nonzero[] = { "max-retry-time", "min-retry-time",
1439 "max-refresh-time", "min-refresh-time" };
1441 * Check if value is zero.
1443 for (i = 0; i < sizeof(nonzero) / sizeof(nonzero[0]); i++) {
1444 obj = NULL;
1445 if (cfg_map_get(options, nonzero[i], &obj) == ISC_R_SUCCESS &&
1446 cfg_obj_asuint32(obj) == 0) {
1447 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1448 "'%s' must not be zero", nonzero[i]);
1449 result = ISC_R_FAILURE;
1452 return (result);
1455 static isc_result_t
1456 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
1457 const cfg_obj_t *config, isc_symtab_t *symtab,
1458 isc_symtab_t *files, dns_rdataclass_t defclass,
1459 cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx)
1461 const char *znamestr;
1462 const char *typestr;
1463 unsigned int ztype;
1464 const cfg_obj_t *zoptions, *goptions = NULL;
1465 const cfg_obj_t *obj = NULL;
1466 isc_result_t result = ISC_R_SUCCESS;
1467 isc_result_t tresult;
1468 unsigned int i;
1469 dns_rdataclass_t zclass;
1470 dns_fixedname_t fixedname;
1471 dns_name_t *zname = NULL;
1472 isc_buffer_t b;
1473 isc_boolean_t root = ISC_FALSE;
1474 const cfg_listelt_t *element;
1475 isc_boolean_t dlz;
1476 dns_masterformat_t masterformat;
1477 isc_boolean_t ddns = ISC_FALSE;
1479 static optionstable options[] = {
1480 { "allow-notify", SLAVEZONE | CHECKACL },
1481 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE |
1482 CHECKACL | STATICSTUBZONE },
1483 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
1484 { "allow-update", MASTERZONE | CHECKACL },
1485 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
1486 { "also-notify", MASTERZONE | SLAVEZONE },
1487 { "auto-dnssec", MASTERZONE | SLAVEZONE },
1488 { "check-dup-records", MASTERZONE },
1489 { "check-mx", MASTERZONE },
1490 { "check-mx-cname", MASTERZONE },
1491 { "check-srv-cname", MASTERZONE },
1492 { "check-wildcard", MASTERZONE },
1493 { "database", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE },
1494 { "delegation-only", HINTZONE | STUBZONE | FORWARDZONE |
1495 DELEGATIONZONE },
1496 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE | STREDIRECTZONE },
1497 { "dnssec-dnskey-kskonly", MASTERZONE | SLAVEZONE },
1498 { "dnssec-loadkeys-interval", MASTERZONE | SLAVEZONE },
1499 { "dnssec-secure-to-insecure", MASTERZONE },
1500 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE | REDIRECTZONE },
1501 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | STATICSTUBZONE |
1502 FORWARDZONE },
1503 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | STATICSTUBZONE |
1504 FORWARDZONE },
1505 { "integrity-check", MASTERZONE },
1506 { "ixfr-base", MASTERZONE | SLAVEZONE },
1507 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
1508 { "journal", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1509 { "key-directory", MASTERZONE | SLAVEZONE },
1510 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1511 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE |
1512 REDIRECTZONE },
1513 { "masters", SLAVEZONE | STUBZONE | REDIRECTZONE },
1514 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1515 { "max-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1516 { "max-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1517 { "max-transfer-idle-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1518 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
1519 { "max-transfer-time-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1520 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
1521 { "max-zone-ttl", MASTERZONE | REDIRECTZONE },
1522 { "min-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1523 { "min-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1524 { "notify", MASTERZONE | SLAVEZONE },
1525 { "notify-source", MASTERZONE | SLAVEZONE },
1526 { "notify-source-v6", MASTERZONE | SLAVEZONE },
1527 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
1528 { "request-ixfr", SLAVEZONE | REDIRECTZONE },
1529 { "server-addresses", STATICSTUBZONE },
1530 { "server-names", STATICSTUBZONE },
1531 { "sig-re-signing-interval", MASTERZONE | SLAVEZONE },
1532 { "sig-signing-nodes", MASTERZONE | SLAVEZONE },
1533 { "sig-signing-signatures", MASTERZONE | SLAVEZONE },
1534 { "sig-signing-type", MASTERZONE | SLAVEZONE },
1535 { "sig-validity-interval", MASTERZONE | SLAVEZONE },
1536 { "signing", MASTERZONE | SLAVEZONE },
1537 { "transfer-source", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1538 { "transfer-source-v6", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1539 { "try-tcp-refresh", SLAVEZONE | STREDIRECTZONE },
1540 { "update-check-ksk", MASTERZONE | SLAVEZONE },
1541 { "update-policy", MASTERZONE },
1542 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE |
1543 STATICSTUBZONE | REDIRECTZONE },
1546 static optionstable dialups[] = {
1547 { "notify", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1548 { "notify-passive", SLAVEZONE | STREDIRECTZONE },
1549 { "refresh", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1550 { "passive", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1553 znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1555 zoptions = cfg_tuple_get(zconfig, "options");
1557 if (config != NULL)
1558 cfg_map_get(config, "options", &goptions);
1560 obj = NULL;
1561 (void)cfg_map_get(zoptions, "in-view", &obj);
1562 if (obj != NULL) {
1563 const cfg_obj_t *fwd = NULL;
1564 unsigned int maxopts = 1;
1565 (void)cfg_map_get(zoptions, "forward", &fwd);
1566 if (fwd != NULL)
1567 maxopts++;
1568 fwd = NULL;
1569 (void)cfg_map_get(zoptions, "forwarders", &fwd);
1570 if (fwd != NULL)
1571 maxopts++;
1572 if (cfg_map_count(zoptions) > maxopts) {
1573 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1574 "zone '%s': 'in-view' used "
1575 "with incompatible zone options",
1576 znamestr);
1577 return (ISC_R_FAILURE);
1579 return (ISC_R_SUCCESS);
1582 obj = NULL;
1583 (void)cfg_map_get(zoptions, "type", &obj);
1584 if (obj == NULL) {
1585 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1586 "zone '%s': type not present", znamestr);
1587 return (ISC_R_FAILURE);
1590 typestr = cfg_obj_asstring(obj);
1591 if (strcasecmp(typestr, "master") == 0)
1592 ztype = MASTERZONE;
1593 else if (strcasecmp(typestr, "slave") == 0)
1594 ztype = SLAVEZONE;
1595 else if (strcasecmp(typestr, "stub") == 0)
1596 ztype = STUBZONE;
1597 else if (strcasecmp(typestr, "static-stub") == 0)
1598 ztype = STATICSTUBZONE;
1599 else if (strcasecmp(typestr, "forward") == 0)
1600 ztype = FORWARDZONE;
1601 else if (strcasecmp(typestr, "hint") == 0)
1602 ztype = HINTZONE;
1603 else if (strcasecmp(typestr, "delegation-only") == 0)
1604 ztype = DELEGATIONZONE;
1605 else if (strcasecmp(typestr, "redirect") == 0)
1606 ztype = REDIRECTZONE;
1607 else {
1608 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1609 "zone '%s': invalid type %s",
1610 znamestr, typestr);
1611 return (ISC_R_FAILURE);
1614 if (ztype == REDIRECTZONE && strcmp(znamestr, ".") != 0) {
1615 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1616 "redirect zones must be called \".\"");
1617 return (ISC_R_FAILURE);
1619 obj = cfg_tuple_get(zconfig, "class");
1620 if (cfg_obj_isstring(obj)) {
1621 isc_textregion_t r;
1623 DE_CONST(cfg_obj_asstring(obj), r.base);
1624 r.length = strlen(r.base);
1625 result = dns_rdataclass_fromtext(&zclass, &r);
1626 if (result != ISC_R_SUCCESS) {
1627 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1628 "zone '%s': invalid class %s",
1629 znamestr, r.base);
1630 return (ISC_R_FAILURE);
1632 if (zclass != defclass) {
1633 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1634 "zone '%s': class '%s' does not "
1635 "match view/default class",
1636 znamestr, r.base);
1637 return (ISC_R_FAILURE);
1642 * Look for an already existing zone.
1643 * We need to make this canonical as isc_symtab_define()
1644 * deals with strings.
1646 dns_fixedname_init(&fixedname);
1647 isc_buffer_constinit(&b, znamestr, strlen(znamestr));
1648 isc_buffer_add(&b, strlen(znamestr));
1649 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1650 dns_rootname, DNS_NAME_DOWNCASE, NULL);
1651 if (tresult != ISC_R_SUCCESS) {
1652 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1653 "zone '%s': is not a valid name", znamestr);
1654 result = ISC_R_FAILURE;
1655 } else {
1656 char namebuf[DNS_NAME_FORMATSIZE];
1658 zname = dns_fixedname_name(&fixedname);
1659 dns_name_format(zname, namebuf, sizeof(namebuf));
1660 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 :
1661 ztype == REDIRECTZONE ? 2 : 3,
1662 symtab, "zone '%s': already exists "
1663 "previous definition: %s:%u", logctx, mctx);
1664 if (tresult != ISC_R_SUCCESS)
1665 result = tresult;
1666 if (dns_name_equal(zname, dns_rootname))
1667 root = ISC_TRUE;
1671 * Check if value is zero.
1673 if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS)
1674 result = ISC_R_FAILURE;
1677 * Look for inappropriate options for the given zone type.
1678 * Check that ACLs expand correctly.
1680 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1681 obj = NULL;
1682 if ((options[i].allowed & ztype) == 0 &&
1683 cfg_map_get(zoptions, options[i].name, &obj) ==
1684 ISC_R_SUCCESS)
1686 if (strcmp(options[i].name, "allow-update") != 0 ||
1687 ztype != SLAVEZONE) {
1688 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1689 "option '%s' is not allowed "
1690 "in '%s' zone '%s'",
1691 options[i].name, typestr,
1692 znamestr);
1693 result = ISC_R_FAILURE;
1694 } else
1695 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1696 "option '%s' is not allowed "
1697 "in '%s' zone '%s'",
1698 options[i].name, typestr,
1699 znamestr);
1701 obj = NULL;
1702 if ((options[i].allowed & ztype) != 0 &&
1703 (options[i].allowed & CHECKACL) != 0) {
1705 tresult = checkacl(options[i].name, actx, zconfig,
1706 voptions, config, logctx, mctx);
1707 if (tresult != ISC_R_SUCCESS)
1708 result = tresult;
1714 * Master & slave zones may have an "also-notify" field, but
1715 * shouldn't if notify is disabled.
1717 if (ztype == MASTERZONE || ztype == SLAVEZONE ) {
1718 isc_boolean_t donotify = ISC_TRUE;
1720 obj = NULL;
1721 tresult = cfg_map_get(zoptions, "notify", &obj);
1722 if (tresult != ISC_R_SUCCESS && voptions != NULL)
1723 tresult = cfg_map_get(voptions, "notify", &obj);
1724 if (tresult != ISC_R_SUCCESS && goptions != NULL)
1725 tresult = cfg_map_get(goptions, "notify", &obj);
1726 if (tresult == ISC_R_SUCCESS) {
1727 if (cfg_obj_isboolean(obj))
1728 donotify = cfg_obj_asboolean(obj);
1729 else {
1730 const char *notifystr = cfg_obj_asstring(obj);
1731 if (ztype != MASTERZONE &&
1732 strcasecmp(notifystr, "master-only") == 0)
1733 donotify = ISC_FALSE;
1737 obj = NULL;
1738 tresult = cfg_map_get(zoptions, "also-notify", &obj);
1739 if (tresult == ISC_R_SUCCESS && !donotify) {
1740 cfg_obj_log(zoptions, logctx, ISC_LOG_WARNING,
1741 "zone '%s': 'also-notify' set but "
1742 "'notify' is disabled", znamestr);
1743 } else if (tresult == ISC_R_SUCCESS) {
1744 isc_uint32_t count;
1745 tresult = validate_masters(obj, config, &count,
1746 logctx, mctx);
1747 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1748 result = tresult;
1753 * Slave & stub zones must have a "masters" field.
1755 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1756 obj = NULL;
1757 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1758 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1759 "zone '%s': missing 'masters' entry",
1760 znamestr);
1761 result = ISC_R_FAILURE;
1762 } else {
1763 isc_uint32_t count;
1764 tresult = validate_masters(obj, config, &count,
1765 logctx, mctx);
1766 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1767 result = tresult;
1768 if (tresult == ISC_R_SUCCESS && count == 0) {
1769 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1770 "zone '%s': empty 'masters' entry",
1771 znamestr);
1772 result = ISC_R_FAILURE;
1778 * Master zones can't have both "allow-update" and "update-policy".
1780 if (ztype == MASTERZONE || ztype == SLAVEZONE) {
1781 isc_boolean_t signing = ISC_FALSE;
1782 isc_result_t res1, res2, res3;
1783 const cfg_obj_t *au = NULL;
1784 const char *arg;
1786 obj = NULL;
1787 res1 = cfg_map_get(zoptions, "allow-update", &au);
1788 obj = NULL;
1789 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1790 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1791 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1792 "zone '%s': 'allow-update' is ignored "
1793 "when 'update-policy' is present",
1794 znamestr);
1795 result = ISC_R_FAILURE;
1796 } else if (res2 == ISC_R_SUCCESS) {
1797 res3 = check_update_policy(obj, logctx);
1798 if (res3 != ISC_R_SUCCESS)
1799 result = ISC_R_FAILURE;
1803 * To determine whether auto-dnssec is allowed,
1804 * we should also check for allow-update at the
1805 * view and options levels.
1807 if (res1 != ISC_R_SUCCESS && voptions != NULL)
1808 res1 = cfg_map_get(voptions, "allow-update", &au);
1809 if (res1 != ISC_R_SUCCESS && goptions != NULL)
1810 res1 = cfg_map_get(goptions, "allow-update", &au);
1812 if (res2 == ISC_R_SUCCESS)
1813 ddns = ISC_TRUE;
1814 else if (res1 == ISC_R_SUCCESS) {
1815 dns_acl_t *acl = NULL;
1816 res1 = cfg_acl_fromconfig(au, config, logctx,
1817 actx, mctx, 0, &acl);
1818 if (res1 != ISC_R_SUCCESS) {
1819 cfg_obj_log(au, logctx, ISC_LOG_ERROR,
1820 "acl expansion failed: %s",
1821 isc_result_totext(result));
1822 result = ISC_R_FAILURE;
1823 } else if (acl != NULL) {
1824 if (!dns_acl_isnone(acl))
1825 ddns = ISC_TRUE;
1826 dns_acl_detach(&acl);
1830 obj = NULL;
1831 res1 = cfg_map_get(zoptions, "inline-signing", &obj);
1832 if (res1 == ISC_R_SUCCESS)
1833 signing = cfg_obj_asboolean(obj);
1835 obj = NULL;
1836 arg = "off";
1837 res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
1838 if (res3 == ISC_R_SUCCESS)
1839 arg = cfg_obj_asstring(obj);
1840 if (strcasecmp(arg, "off") != 0 && !ddns && !signing) {
1841 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1842 "'auto-dnssec %s;' requires%s "
1843 "inline-signing to be configured for "
1844 "the zone", arg,
1845 (ztype == MASTERZONE) ?
1846 " dynamic DNS or" : "");
1847 result = ISC_R_FAILURE;
1850 obj = NULL;
1851 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
1852 if (res1 == ISC_R_SUCCESS) {
1853 isc_uint32_t type = cfg_obj_asuint32(obj);
1854 if (type < 0xff00U || type > 0xffffU)
1855 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1856 "sig-signing-type: %u out of "
1857 "range [%u..%u]", type,
1858 0xff00U, 0xffffU);
1859 result = ISC_R_FAILURE;
1862 obj = NULL;
1863 res1 = cfg_map_get(zoptions, "dnssec-dnskey-kskonly", &obj);
1864 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
1865 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1866 "dnssec-dnskey-kskonly: requires "
1867 "inline-signing when used in slave zone");
1868 result = ISC_R_FAILURE;
1871 obj = NULL;
1872 res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj);
1873 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
1874 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1875 "dnssec-loadkeys-interval: requires "
1876 "inline-signing when used in slave zone");
1877 result = ISC_R_FAILURE;
1880 obj = NULL;
1881 res1 = cfg_map_get(zoptions, "update-check-ksk", &obj);
1882 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
1883 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1884 "update-check-ksk: requires "
1885 "inline-signing when used in slave zone");
1886 result = ISC_R_FAILURE;
1891 * Check the excessively complicated "dialup" option.
1893 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1894 const cfg_obj_t *dialup = NULL;
1895 (void)cfg_map_get(zoptions, "dialup", &dialup);
1896 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1897 const char *str = cfg_obj_asstring(dialup);
1898 for (i = 0;
1899 i < sizeof(dialups) / sizeof(dialups[0]);
1900 i++)
1902 if (strcasecmp(dialups[i].name, str) != 0)
1903 continue;
1904 if ((dialups[i].allowed & ztype) == 0) {
1905 cfg_obj_log(obj, logctx,
1906 ISC_LOG_ERROR,
1907 "dialup type '%s' is not "
1908 "allowed in '%s' "
1909 "zone '%s'",
1910 str, typestr, znamestr);
1911 result = ISC_R_FAILURE;
1913 break;
1915 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1916 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1917 "invalid dialup type '%s' in zone "
1918 "'%s'", str, znamestr);
1919 result = ISC_R_FAILURE;
1925 * Check that forwarding is reasonable.
1927 obj = NULL;
1928 if (root) {
1929 if (voptions != NULL)
1930 (void)cfg_map_get(voptions, "forwarders", &obj);
1931 if (obj == NULL && goptions != NULL)
1932 (void)cfg_map_get(goptions, "forwarders", &obj);
1934 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
1935 result = ISC_R_FAILURE;
1938 * Check validity of static stub server addresses.
1940 obj = NULL;
1941 (void)cfg_map_get(zoptions, "server-addresses", &obj);
1942 if (ztype == STATICSTUBZONE && obj != NULL) {
1943 for (element = cfg_list_first(obj);
1944 element != NULL;
1945 element = cfg_list_next(element))
1947 isc_sockaddr_t sa;
1948 isc_netaddr_t na;
1949 obj = cfg_listelt_value(element);
1950 sa = *cfg_obj_assockaddr(obj);
1952 if (isc_sockaddr_getport(&sa) != 0) {
1953 result = ISC_R_FAILURE;
1954 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1955 "port is not configurable for "
1956 "static stub server-addresses");
1959 isc_netaddr_fromsockaddr(&na, &sa);
1960 if (isc_netaddr_getzone(&na) != 0) {
1961 result = ISC_R_FAILURE;
1962 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1963 "scoped address is not allowed "
1964 "for static stub "
1965 "server-addresses");
1971 * Check validity of static stub server names.
1973 obj = NULL;
1974 (void)cfg_map_get(zoptions, "server-names", &obj);
1975 if (zname != NULL && ztype == STATICSTUBZONE && obj != NULL) {
1976 for (element = cfg_list_first(obj);
1977 element != NULL;
1978 element = cfg_list_next(element))
1980 const char *snamestr;
1981 dns_fixedname_t fixed_sname;
1982 isc_buffer_t b2;
1983 dns_name_t *sname;
1985 obj = cfg_listelt_value(element);
1986 snamestr = cfg_obj_asstring(obj);
1988 dns_fixedname_init(&fixed_sname);
1989 isc_buffer_constinit(&b2, snamestr, strlen(snamestr));
1990 isc_buffer_add(&b2, strlen(snamestr));
1991 sname = dns_fixedname_name(&fixed_sname);
1992 tresult = dns_name_fromtext(sname, &b2, dns_rootname,
1993 0, NULL);
1994 if (tresult != ISC_R_SUCCESS) {
1995 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1996 "server-name '%s' is not a valid "
1997 "name", snamestr);
1998 result = ISC_R_FAILURE;
1999 } else if (dns_name_issubdomain(sname, zname)) {
2000 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2001 "server-name '%s' must not be a "
2002 "subdomain of zone name '%s'",
2003 snamestr, znamestr);
2004 result = ISC_R_FAILURE;
2011 * Check that max-zone-ttl isn't used with masterfile-format map
2013 masterformat = dns_masterformat_text;
2014 obj = NULL;
2015 (void)cfg_map_get(zoptions, "masterfile-format", &obj);
2016 if (obj != NULL) {
2017 const char *masterformatstr = cfg_obj_asstring(obj);
2018 if (strcasecmp(masterformatstr, "text") == 0)
2019 masterformat = dns_masterformat_text;
2020 else if (strcasecmp(masterformatstr, "raw") == 0)
2021 masterformat = dns_masterformat_raw;
2022 else if (strcasecmp(masterformatstr, "map") == 0)
2023 masterformat = dns_masterformat_map;
2024 else
2025 INSIST(0);
2028 if (masterformat == dns_masterformat_map) {
2029 obj = NULL;
2030 (void)cfg_map_get(zoptions, "max-zone-ttl", &obj);
2031 if (obj == NULL && voptions != NULL)
2032 (void)cfg_map_get(voptions, "max-zone-ttl", &obj);
2033 if (obj == NULL && goptions !=NULL)
2034 (void)cfg_map_get(goptions, "max-zone-ttl", &obj);
2035 if (obj != NULL) {
2036 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2037 "zone '%s': 'max-zone-ttl' is not "
2038 "compatible with 'masterfile-format map'",
2039 znamestr);
2040 result = ISC_R_FAILURE;
2045 * Warn if key-directory doesn't exist
2047 obj = NULL;
2048 tresult = cfg_map_get(zoptions, "key-directory", &obj);
2049 if (tresult == ISC_R_SUCCESS) {
2050 const char *dir = cfg_obj_asstring(obj);
2051 tresult = isc_file_isdirectory(dir);
2052 switch (tresult) {
2053 case ISC_R_SUCCESS:
2054 break;
2055 case ISC_R_FILENOTFOUND:
2056 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2057 "key-directory: '%s' does not exist",
2058 dir);
2059 break;
2060 case ISC_R_INVALIDFILE:
2061 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2062 "key-directory: '%s' is not a directory",
2063 dir);
2064 break;
2065 default:
2066 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2067 "key-directory: '%s' %s",
2068 dir, isc_result_totext(tresult));
2069 result = tresult;
2074 * Check various options.
2076 tresult = check_options(zoptions, logctx, mctx, optlevel_zone);
2077 if (tresult != ISC_R_SUCCESS)
2078 result = tresult;
2081 * If the zone type is rbt/rbt64 then master/hint zones
2082 * require file clauses.
2083 * If inline signing is used, then slave zones require a
2084 * file clause as well
2086 obj = NULL;
2087 dlz = ISC_FALSE;
2088 tresult = cfg_map_get(zoptions, "dlz", &obj);
2089 if (tresult == ISC_R_SUCCESS)
2090 dlz = ISC_TRUE;
2092 obj = NULL;
2093 tresult = cfg_map_get(zoptions, "database", &obj);
2094 if (dlz && tresult == ISC_R_SUCCESS) {
2095 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2096 "zone '%s': cannot specify both 'dlz' "
2097 "and 'database'", znamestr);
2098 result = ISC_R_FAILURE;
2099 } else if (!dlz &&
2100 (tresult == ISC_R_NOTFOUND ||
2101 (tresult == ISC_R_SUCCESS &&
2102 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
2103 strcmp("rbt64", cfg_obj_asstring(obj)) == 0))))
2105 isc_result_t res1;
2106 const cfg_obj_t *fileobj = NULL;
2107 tresult = cfg_map_get(zoptions, "file", &fileobj);
2108 obj = NULL;
2109 res1 = cfg_map_get(zoptions, "inline-signing", &obj);
2110 if ((tresult != ISC_R_SUCCESS &&
2111 (ztype == MASTERZONE || ztype == HINTZONE ||
2112 (ztype == SLAVEZONE && res1 == ISC_R_SUCCESS &&
2113 cfg_obj_asboolean(obj))))) {
2114 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2115 "zone '%s': missing 'file' entry",
2116 znamestr);
2117 result = tresult;
2118 } else if (tresult == ISC_R_SUCCESS &&
2119 (ztype == SLAVEZONE || ddns)) {
2120 tresult = fileexist(fileobj, files, ISC_TRUE, logctx);
2121 if (tresult != ISC_R_SUCCESS)
2122 result = tresult;
2123 } else if (tresult == ISC_R_SUCCESS &&
2124 (ztype == MASTERZONE || ztype == HINTZONE)) {
2125 tresult = fileexist(fileobj, files, ISC_FALSE, logctx);
2126 if (tresult != ISC_R_SUCCESS)
2127 result = tresult;
2131 return (result);
2135 typedef struct keyalgorithms {
2136 const char *name;
2137 isc_uint16_t size;
2138 } algorithmtable;
2140 isc_result_t
2141 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
2142 const cfg_obj_t *algobj = NULL;
2143 const cfg_obj_t *secretobj = NULL;
2144 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
2145 const char *algorithm;
2146 int i;
2147 size_t len = 0;
2148 isc_result_t result;
2149 isc_buffer_t buf;
2150 unsigned char secretbuf[1024];
2151 static const algorithmtable algorithms[] = {
2152 { "hmac-md5", 128 },
2153 { "hmac-md5.sig-alg.reg.int", 0 },
2154 { "hmac-md5.sig-alg.reg.int.", 0 },
2155 { "hmac-sha1", 160 },
2156 { "hmac-sha224", 224 },
2157 { "hmac-sha256", 256 },
2158 { "hmac-sha384", 384 },
2159 { "hmac-sha512", 512 },
2160 { NULL, 0 }
2163 (void)cfg_map_get(key, "algorithm", &algobj);
2164 (void)cfg_map_get(key, "secret", &secretobj);
2165 if (secretobj == NULL || algobj == NULL) {
2166 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2167 "key '%s' must have both 'secret' and "
2168 "'algorithm' defined",
2169 keyname);
2170 return (ISC_R_FAILURE);
2173 isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
2174 result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
2175 if (result != ISC_R_SUCCESS) {
2176 cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
2177 "bad secret '%s'", isc_result_totext(result));
2178 return (result);
2181 algorithm = cfg_obj_asstring(algobj);
2182 for (i = 0; algorithms[i].name != NULL; i++) {
2183 len = strlen(algorithms[i].name);
2184 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
2185 (algorithm[len] == '\0' ||
2186 (algorithms[i].size != 0 && algorithm[len] == '-')))
2187 break;
2189 if (algorithms[i].name == NULL) {
2190 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
2191 "unknown algorithm '%s'", algorithm);
2192 return (ISC_R_NOTFOUND);
2194 if (algorithm[len] == '-') {
2195 isc_uint16_t digestbits;
2196 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
2197 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
2198 if (result == ISC_R_RANGE ||
2199 digestbits > algorithms[i].size) {
2200 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
2201 "key '%s' digest-bits too large "
2202 "[%u..%u]", keyname,
2203 algorithms[i].size / 2,
2204 algorithms[i].size);
2205 return (ISC_R_RANGE);
2207 if ((digestbits % 8) != 0) {
2208 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
2209 "key '%s' digest-bits not multiple"
2210 " of 8", keyname);
2211 return (ISC_R_RANGE);
2214 * Recommended minima for hmac algorithms.
2216 if ((digestbits < (algorithms[i].size / 2U) ||
2217 (digestbits < 80U)))
2218 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
2219 "key '%s' digest-bits too small "
2220 "[<%u]", keyname,
2221 algorithms[i].size/2);
2222 } else {
2223 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
2224 "key '%s': unable to parse digest-bits",
2225 keyname);
2226 return (result);
2229 return (ISC_R_SUCCESS);
2232 static isc_result_t
2233 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, isc_boolean_t writeable,
2234 isc_log_t *logctx)
2236 isc_result_t result;
2237 isc_symvalue_t symvalue;
2238 unsigned int line;
2239 const char *file;
2241 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 0, &symvalue);
2242 if (result == ISC_R_SUCCESS) {
2243 if (writeable) {
2244 file = cfg_obj_file(symvalue.as_cpointer);
2245 line = cfg_obj_line(symvalue.as_cpointer);
2246 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2247 "writeable file '%s': already in use: "
2248 "%s:%u", cfg_obj_asstring(obj),
2249 file, line);
2250 return (ISC_R_EXISTS);
2252 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 2,
2253 &symvalue);
2254 if (result == ISC_R_SUCCESS) {
2255 file = cfg_obj_file(symvalue.as_cpointer);
2256 line = cfg_obj_line(symvalue.as_cpointer);
2257 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2258 "writeable file '%s': already in use: "
2259 "%s:%u", cfg_obj_asstring(obj),
2260 file, line);
2261 return (ISC_R_EXISTS);
2263 return (ISC_R_SUCCESS);
2266 symvalue.as_cpointer = obj;
2267 result = isc_symtab_define(symtab, cfg_obj_asstring(obj),
2268 writeable ? 2 : 1, symvalue,
2269 isc_symexists_reject);
2270 return (result);
2274 * Check key list for duplicates key names and that the key names
2275 * are valid domain names as these keys are used for TSIG.
2277 * Check the key contents for validity.
2279 static isc_result_t
2280 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
2281 isc_mem_t *mctx, isc_log_t *logctx)
2283 char namebuf[DNS_NAME_FORMATSIZE];
2284 dns_fixedname_t fname;
2285 dns_name_t *name;
2286 isc_result_t result = ISC_R_SUCCESS;
2287 isc_result_t tresult;
2288 const cfg_listelt_t *element;
2290 dns_fixedname_init(&fname);
2291 name = dns_fixedname_name(&fname);
2292 for (element = cfg_list_first(keys);
2293 element != NULL;
2294 element = cfg_list_next(element))
2296 const cfg_obj_t *key = cfg_listelt_value(element);
2297 const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
2298 isc_symvalue_t symvalue;
2299 isc_buffer_t b;
2300 char *keyname;
2302 isc_buffer_constinit(&b, keyid, strlen(keyid));
2303 isc_buffer_add(&b, strlen(keyid));
2304 tresult = dns_name_fromtext(name, &b, dns_rootname,
2305 0, NULL);
2306 if (tresult != ISC_R_SUCCESS) {
2307 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2308 "key '%s': bad key name", keyid);
2309 result = tresult;
2310 continue;
2312 tresult = bind9_check_key(key, logctx);
2313 if (tresult != ISC_R_SUCCESS)
2314 return (tresult);
2316 dns_name_format(name, namebuf, sizeof(namebuf));
2317 keyname = isc_mem_strdup(mctx, namebuf);
2318 if (keyname == NULL)
2319 return (ISC_R_NOMEMORY);
2320 symvalue.as_cpointer = key;
2321 tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
2322 isc_symexists_reject);
2323 if (tresult == ISC_R_EXISTS) {
2324 const char *file;
2325 unsigned int line;
2327 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
2328 1, &symvalue) == ISC_R_SUCCESS);
2329 file = cfg_obj_file(symvalue.as_cpointer);
2330 line = cfg_obj_line(symvalue.as_cpointer);
2332 if (file == NULL)
2333 file = "<unknown file>";
2334 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2335 "key '%s': already exists "
2336 "previous definition: %s:%u",
2337 keyid, file, line);
2338 isc_mem_free(mctx, keyname);
2339 result = tresult;
2340 } else if (tresult != ISC_R_SUCCESS) {
2341 isc_mem_free(mctx, keyname);
2342 return (tresult);
2345 return (result);
2348 static struct {
2349 const char *v4;
2350 const char *v6;
2351 } sources[] = {
2352 { "transfer-source", "transfer-source-v6" },
2353 { "notify-source", "notify-source-v6" },
2354 { "query-source", "query-source-v6" },
2355 { NULL, NULL }
2359 * RNDC keys are not normalised unlike TSIG keys.
2361 * "foo." is different to "foo".
2363 static isc_boolean_t
2364 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
2365 const cfg_listelt_t *element;
2366 const cfg_obj_t *obj;
2367 const char *str;
2369 if (keylist == NULL)
2370 return (ISC_FALSE);
2372 for (element = cfg_list_first(keylist);
2373 element != NULL;
2374 element = cfg_list_next(element))
2376 obj = cfg_listelt_value(element);
2377 str = cfg_obj_asstring(cfg_map_getname(obj));
2378 if (!strcasecmp(str, keyname))
2379 return (ISC_TRUE);
2381 return (ISC_FALSE);
2384 static isc_result_t
2385 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
2386 isc_symtab_t *symtab, isc_log_t *logctx)
2388 dns_fixedname_t fname;
2389 isc_result_t result = ISC_R_SUCCESS;
2390 isc_result_t tresult;
2391 const cfg_listelt_t *e1, *e2;
2392 const cfg_obj_t *v1, *v2, *keys;
2393 const cfg_obj_t *servers;
2394 isc_netaddr_t n1, n2;
2395 unsigned int p1, p2;
2396 const cfg_obj_t *obj;
2397 char buf[ISC_NETADDR_FORMATSIZE];
2398 char namebuf[DNS_NAME_FORMATSIZE];
2399 const char *xfr;
2400 const char *keyval;
2401 isc_buffer_t b;
2402 int source;
2403 dns_name_t *keyname;
2405 servers = NULL;
2406 if (voptions != NULL)
2407 (void)cfg_map_get(voptions, "server", &servers);
2408 if (servers == NULL)
2409 (void)cfg_map_get(config, "server", &servers);
2410 if (servers == NULL)
2411 return (ISC_R_SUCCESS);
2413 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
2414 v1 = cfg_listelt_value(e1);
2415 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
2417 * Check that unused bits are zero.
2419 tresult = isc_netaddr_prefixok(&n1, p1);
2420 if (tresult != ISC_R_SUCCESS) {
2421 INSIST(tresult == ISC_R_FAILURE);
2422 isc_netaddr_format(&n1, buf, sizeof(buf));
2423 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
2424 "server '%s/%u': invalid prefix "
2425 "(extra bits specified)", buf, p1);
2426 result = tresult;
2428 source = 0;
2429 do {
2430 obj = NULL;
2431 if (n1.family == AF_INET)
2432 xfr = sources[source].v6;
2433 else
2434 xfr = sources[source].v4;
2435 (void)cfg_map_get(v1, xfr, &obj);
2436 if (obj != NULL) {
2437 isc_netaddr_format(&n1, buf, sizeof(buf));
2438 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
2439 "server '%s/%u': %s not legal",
2440 buf, p1, xfr);
2441 result = ISC_R_FAILURE;
2443 } while (sources[++source].v4 != NULL);
2444 e2 = e1;
2445 while ((e2 = cfg_list_next(e2)) != NULL) {
2446 v2 = cfg_listelt_value(e2);
2447 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
2448 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
2449 const char *file = cfg_obj_file(v1);
2450 unsigned int line = cfg_obj_line(v1);
2452 if (file == NULL)
2453 file = "<unknown file>";
2455 isc_netaddr_format(&n2, buf, sizeof(buf));
2456 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
2457 "server '%s/%u': already exists "
2458 "previous definition: %s:%u",
2459 buf, p2, file, line);
2460 result = ISC_R_FAILURE;
2463 keys = NULL;
2464 cfg_map_get(v1, "keys", &keys);
2465 if (keys != NULL) {
2467 * Normalize key name.
2469 keyval = cfg_obj_asstring(keys);
2470 dns_fixedname_init(&fname);
2471 isc_buffer_constinit(&b, keyval, strlen(keyval));
2472 isc_buffer_add(&b, strlen(keyval));
2473 keyname = dns_fixedname_name(&fname);
2474 tresult = dns_name_fromtext(keyname, &b, dns_rootname,
2475 0, NULL);
2476 if (tresult != ISC_R_SUCCESS) {
2477 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
2478 "bad key name '%s'", keyval);
2479 result = ISC_R_FAILURE;
2480 continue;
2482 dns_name_format(keyname, namebuf, sizeof(namebuf));
2483 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
2484 if (tresult != ISC_R_SUCCESS) {
2485 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
2486 "unknown key '%s'", keyval);
2487 result = ISC_R_FAILURE;
2491 return (result);
2494 static isc_result_t
2495 check_trusted_key(const cfg_obj_t *key, isc_boolean_t managed,
2496 isc_log_t *logctx)
2498 const char *keystr, *keynamestr;
2499 dns_fixedname_t fkeyname;
2500 dns_name_t *keyname;
2501 isc_buffer_t b;
2502 isc_region_t r;
2503 isc_result_t result = ISC_R_SUCCESS;
2504 isc_result_t tresult;
2505 isc_uint32_t flags, proto, alg;
2506 unsigned char keydata[4096];
2508 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
2509 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
2510 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
2512 dns_fixedname_init(&fkeyname);
2513 keyname = dns_fixedname_name(&fkeyname);
2514 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
2516 isc_buffer_constinit(&b, keynamestr, strlen(keynamestr));
2517 isc_buffer_add(&b, strlen(keynamestr));
2518 result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
2519 if (result != ISC_R_SUCCESS) {
2520 cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n",
2521 isc_result_totext(result));
2522 result = ISC_R_FAILURE;
2525 if (flags > 0xffff) {
2526 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2527 "flags too big: %u\n", flags);
2528 result = ISC_R_FAILURE;
2530 if (proto > 0xff) {
2531 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2532 "protocol too big: %u\n", proto);
2533 result = ISC_R_FAILURE;
2535 if (alg > 0xff) {
2536 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2537 "algorithm too big: %u\n", alg);
2538 result = ISC_R_FAILURE;
2541 if (managed) {
2542 const char *initmethod;
2543 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
2545 if (strcasecmp(initmethod, "initial-key") != 0) {
2546 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2547 "managed key '%s': "
2548 "invalid initialization method '%s'",
2549 keynamestr, initmethod);
2550 result = ISC_R_FAILURE;
2554 isc_buffer_init(&b, keydata, sizeof(keydata));
2556 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
2557 tresult = isc_base64_decodestring(keystr, &b);
2559 if (tresult != ISC_R_SUCCESS) {
2560 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2561 "%s", isc_result_totext(tresult));
2562 result = ISC_R_FAILURE;
2563 } else {
2564 isc_buffer_usedregion(&b, &r);
2566 if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
2567 r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
2568 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2569 "%s key '%s' has a weak exponent",
2570 managed ? "managed" : "trusted",
2571 keynamestr);
2574 return (result);
2577 static isc_result_t
2578 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
2579 const char *viewname, dns_rdataclass_t vclass,
2580 isc_symtab_t *files, isc_log_t *logctx, isc_mem_t *mctx)
2582 const cfg_obj_t *zones = NULL;
2583 const cfg_obj_t *keys = NULL;
2584 const cfg_listelt_t *element, *element2;
2585 isc_symtab_t *symtab = NULL;
2586 isc_result_t result = ISC_R_SUCCESS;
2587 isc_result_t tresult = ISC_R_SUCCESS;
2588 cfg_aclconfctx_t *actx = NULL;
2589 const cfg_obj_t *obj;
2590 const cfg_obj_t *options = NULL;
2591 isc_boolean_t enablednssec, enablevalidation;
2592 const char *valstr = "no";
2595 * Get global options block
2597 (void)cfg_map_get(config, "options", &options);
2600 * Check that all zone statements are syntactically correct and
2601 * there are no duplicate zones.
2603 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
2604 ISC_FALSE, &symtab);
2605 if (tresult != ISC_R_SUCCESS)
2606 return (ISC_R_NOMEMORY);
2608 cfg_aclconfctx_create(mctx, &actx);
2610 if (voptions != NULL)
2611 (void)cfg_map_get(voptions, "zone", &zones);
2612 else
2613 (void)cfg_map_get(config, "zone", &zones);
2615 for (element = cfg_list_first(zones);
2616 element != NULL;
2617 element = cfg_list_next(element))
2619 const cfg_obj_t *zone = cfg_listelt_value(element);
2621 tresult = check_zoneconf(zone, voptions, config, symtab,
2622 files, vclass, actx, logctx,
2623 mctx);
2624 if (tresult != ISC_R_SUCCESS)
2625 result = ISC_R_FAILURE;
2628 isc_symtab_destroy(&symtab);
2631 * Check that forwarding is reasonable.
2633 if (voptions == NULL) {
2634 if (options != NULL)
2635 if (check_forward(options, NULL,
2636 logctx) != ISC_R_SUCCESS)
2637 result = ISC_R_FAILURE;
2638 } else {
2639 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
2640 result = ISC_R_FAILURE;
2644 * Check non-zero options at the global and view levels.
2646 if (options != NULL && check_nonzero(options, logctx) != ISC_R_SUCCESS)
2647 result = ISC_R_FAILURE;
2648 if (voptions != NULL &&check_nonzero(voptions, logctx) != ISC_R_SUCCESS)
2649 result = ISC_R_FAILURE;
2652 * Check that dual-stack-servers is reasonable.
2654 if (voptions == NULL) {
2655 if (options != NULL)
2656 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2657 result = ISC_R_FAILURE;
2658 } else {
2659 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
2660 result = ISC_R_FAILURE;
2664 * Check that rrset-order is reasonable.
2666 if (voptions != NULL) {
2667 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
2668 result = ISC_R_FAILURE;
2672 * Check that all key statements are syntactically correct and
2673 * there are no duplicate keys.
2675 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
2676 ISC_FALSE, &symtab);
2677 if (tresult != ISC_R_SUCCESS)
2678 goto cleanup;
2680 (void)cfg_map_get(config, "key", &keys);
2681 tresult = check_keylist(keys, symtab, mctx, logctx);
2682 if (tresult == ISC_R_EXISTS)
2683 result = ISC_R_FAILURE;
2684 else if (tresult != ISC_R_SUCCESS) {
2685 result = tresult;
2686 goto cleanup;
2689 if (voptions != NULL) {
2690 keys = NULL;
2691 (void)cfg_map_get(voptions, "key", &keys);
2692 tresult = check_keylist(keys, symtab, mctx, logctx);
2693 if (tresult == ISC_R_EXISTS)
2694 result = ISC_R_FAILURE;
2695 else if (tresult != ISC_R_SUCCESS) {
2696 result = tresult;
2697 goto cleanup;
2702 * Global servers can refer to keys in views.
2704 if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
2705 result = ISC_R_FAILURE;
2707 isc_symtab_destroy(&symtab);
2710 * Check that dnssec-enable/dnssec-validation are sensible.
2712 obj = NULL;
2713 if (voptions != NULL)
2714 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
2715 if (obj == NULL && options != NULL)
2716 (void)cfg_map_get(options, "dnssec-enable", &obj);
2717 if (obj == NULL)
2718 enablednssec = ISC_TRUE;
2719 else
2720 enablednssec = cfg_obj_asboolean(obj);
2722 obj = NULL;
2723 if (voptions != NULL)
2724 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
2725 if (obj == NULL && options != NULL)
2726 (void)cfg_map_get(options, "dnssec-validation", &obj);
2727 if (obj == NULL) {
2728 enablevalidation = enablednssec;
2729 valstr = "yes";
2730 } else if (cfg_obj_isboolean(obj)) {
2731 enablevalidation = cfg_obj_asboolean(obj);
2732 valstr = enablevalidation ? "yes" : "no";
2733 } else {
2734 enablevalidation = ISC_TRUE;
2735 valstr = "auto";
2738 if (enablevalidation && !enablednssec)
2739 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2740 "'dnssec-validation %s;' and 'dnssec-enable no;'",
2741 valstr);
2744 * Check trusted-keys and managed-keys.
2746 keys = NULL;
2747 if (voptions != NULL)
2748 (void)cfg_map_get(voptions, "trusted-keys", &keys);
2749 if (keys == NULL)
2750 (void)cfg_map_get(config, "trusted-keys", &keys);
2752 for (element = cfg_list_first(keys);
2753 element != NULL;
2754 element = cfg_list_next(element))
2756 const cfg_obj_t *keylist = cfg_listelt_value(element);
2757 for (element2 = cfg_list_first(keylist);
2758 element2 != NULL;
2759 element2 = cfg_list_next(element2)) {
2760 obj = cfg_listelt_value(element2);
2761 tresult = check_trusted_key(obj, ISC_FALSE, logctx);
2762 if (tresult != ISC_R_SUCCESS)
2763 result = tresult;
2767 keys = NULL;
2768 if (voptions != NULL)
2769 (void)cfg_map_get(voptions, "managed-keys", &keys);
2770 if (keys == NULL)
2771 (void)cfg_map_get(config, "managed-keys", &keys);
2773 for (element = cfg_list_first(keys);
2774 element != NULL;
2775 element = cfg_list_next(element))
2777 const cfg_obj_t *keylist = cfg_listelt_value(element);
2778 for (element2 = cfg_list_first(keylist);
2779 element2 != NULL;
2780 element2 = cfg_list_next(element2)) {
2781 obj = cfg_listelt_value(element2);
2782 tresult = check_trusted_key(obj, ISC_TRUE, logctx);
2783 if (tresult != ISC_R_SUCCESS)
2784 result = tresult;
2789 * Check options.
2791 if (voptions != NULL)
2792 tresult = check_options(voptions, logctx, mctx,
2793 optlevel_view);
2794 else
2795 tresult = check_options(config, logctx, mctx,
2796 optlevel_config);
2797 if (tresult != ISC_R_SUCCESS)
2798 result = tresult;
2800 tresult = check_viewacls(actx, voptions, config, logctx, mctx);
2801 if (tresult != ISC_R_SUCCESS)
2802 result = tresult;
2804 tresult = check_recursionacls(actx, voptions, viewname,
2805 config, logctx, mctx);
2806 if (tresult != ISC_R_SUCCESS)
2807 result = tresult;
2809 tresult = check_filteraaaa(actx, voptions, viewname, config,
2810 logctx, mctx);
2811 if (tresult != ISC_R_SUCCESS)
2812 result = tresult;
2814 tresult = check_dns64(actx, voptions, config, logctx, mctx);
2815 if (tresult != ISC_R_SUCCESS)
2816 result = tresult;
2818 cleanup:
2819 if (symtab != NULL)
2820 isc_symtab_destroy(&symtab);
2821 if (actx != NULL)
2822 cfg_aclconfctx_detach(&actx);
2824 return (result);
2827 static const char *
2828 default_channels[] = {
2829 "default_syslog",
2830 "default_stderr",
2831 "default_debug",
2832 "null",
2833 NULL
2836 static isc_result_t
2837 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
2838 isc_mem_t *mctx)
2840 const cfg_obj_t *categories = NULL;
2841 const cfg_obj_t *category;
2842 const cfg_obj_t *channels = NULL;
2843 const cfg_obj_t *channel;
2844 const cfg_listelt_t *element;
2845 const cfg_listelt_t *delement;
2846 const char *channelname;
2847 const char *catname;
2848 const cfg_obj_t *fileobj = NULL;
2849 const cfg_obj_t *syslogobj = NULL;
2850 const cfg_obj_t *nullobj = NULL;
2851 const cfg_obj_t *stderrobj = NULL;
2852 const cfg_obj_t *logobj = NULL;
2853 isc_result_t result = ISC_R_SUCCESS;
2854 isc_result_t tresult;
2855 isc_symtab_t *symtab = NULL;
2856 isc_symvalue_t symvalue;
2857 int i;
2859 (void)cfg_map_get(config, "logging", &logobj);
2860 if (logobj == NULL)
2861 return (ISC_R_SUCCESS);
2863 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
2864 if (result != ISC_R_SUCCESS)
2865 return (result);
2867 symvalue.as_cpointer = NULL;
2868 for (i = 0; default_channels[i] != NULL; i++) {
2869 tresult = isc_symtab_define(symtab, default_channels[i], 1,
2870 symvalue, isc_symexists_replace);
2871 if (tresult != ISC_R_SUCCESS)
2872 result = tresult;
2875 cfg_map_get(logobj, "channel", &channels);
2877 for (element = cfg_list_first(channels);
2878 element != NULL;
2879 element = cfg_list_next(element))
2881 channel = cfg_listelt_value(element);
2882 channelname = cfg_obj_asstring(cfg_map_getname(channel));
2883 fileobj = syslogobj = nullobj = stderrobj = NULL;
2884 (void)cfg_map_get(channel, "file", &fileobj);
2885 (void)cfg_map_get(channel, "syslog", &syslogobj);
2886 (void)cfg_map_get(channel, "null", &nullobj);
2887 (void)cfg_map_get(channel, "stderr", &stderrobj);
2888 i = 0;
2889 if (fileobj != NULL)
2890 i++;
2891 if (syslogobj != NULL)
2892 i++;
2893 if (nullobj != NULL)
2894 i++;
2895 if (stderrobj != NULL)
2896 i++;
2897 if (i != 1) {
2898 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2899 "channel '%s': exactly one of file, syslog, "
2900 "null, and stderr must be present",
2901 channelname);
2902 result = ISC_R_FAILURE;
2904 tresult = isc_symtab_define(symtab, channelname, 1,
2905 symvalue, isc_symexists_replace);
2906 if (tresult != ISC_R_SUCCESS)
2907 result = tresult;
2910 cfg_map_get(logobj, "category", &categories);
2912 for (element = cfg_list_first(categories);
2913 element != NULL;
2914 element = cfg_list_next(element))
2916 category = cfg_listelt_value(element);
2917 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
2918 if (isc_log_categorybyname(logctx, catname) == NULL) {
2919 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
2920 "undefined category: '%s'", catname);
2921 result = ISC_R_FAILURE;
2923 channels = cfg_tuple_get(category, "destinations");
2924 for (delement = cfg_list_first(channels);
2925 delement != NULL;
2926 delement = cfg_list_next(delement))
2928 channel = cfg_listelt_value(delement);
2929 channelname = cfg_obj_asstring(channel);
2930 tresult = isc_symtab_lookup(symtab, channelname, 1,
2931 &symvalue);
2932 if (tresult != ISC_R_SUCCESS) {
2933 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2934 "undefined channel: '%s'",
2935 channelname);
2936 result = tresult;
2940 isc_symtab_destroy(&symtab);
2941 return (result);
2944 static isc_result_t
2945 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
2946 isc_log_t *logctx)
2948 isc_result_t result = ISC_R_SUCCESS;
2949 const cfg_obj_t *control_keylist;
2950 const cfg_listelt_t *element;
2951 const cfg_obj_t *key;
2952 const char *keyval;
2954 control_keylist = cfg_tuple_get(control, "keys");
2955 if (cfg_obj_isvoid(control_keylist))
2956 return (ISC_R_SUCCESS);
2958 for (element = cfg_list_first(control_keylist);
2959 element != NULL;
2960 element = cfg_list_next(element))
2962 key = cfg_listelt_value(element);
2963 keyval = cfg_obj_asstring(key);
2965 if (!rndckey_exists(keylist, keyval)) {
2966 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2967 "unknown key '%s'", keyval);
2968 result = ISC_R_NOTFOUND;
2971 return (result);
2974 static isc_result_t
2975 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
2976 isc_mem_t *mctx)
2978 isc_result_t result = ISC_R_SUCCESS, tresult;
2979 cfg_aclconfctx_t *actx = NULL;
2980 const cfg_listelt_t *element, *element2;
2981 const cfg_obj_t *allow;
2982 const cfg_obj_t *control;
2983 const cfg_obj_t *controls;
2984 const cfg_obj_t *controlslist = NULL;
2985 const cfg_obj_t *inetcontrols;
2986 const cfg_obj_t *unixcontrols;
2987 const cfg_obj_t *keylist = NULL;
2988 const char *path;
2989 isc_uint32_t perm, mask;
2990 dns_acl_t *acl = NULL;
2991 isc_sockaddr_t addr;
2992 int i;
2994 (void)cfg_map_get(config, "controls", &controlslist);
2995 if (controlslist == NULL)
2996 return (ISC_R_SUCCESS);
2998 (void)cfg_map_get(config, "key", &keylist);
3000 cfg_aclconfctx_create(mctx, &actx);
3003 * INET: Check allow clause.
3004 * UNIX: Check "perm" for sanity, check path length.
3006 for (element = cfg_list_first(controlslist);
3007 element != NULL;
3008 element = cfg_list_next(element)) {
3009 controls = cfg_listelt_value(element);
3010 unixcontrols = NULL;
3011 inetcontrols = NULL;
3012 (void)cfg_map_get(controls, "unix", &unixcontrols);
3013 (void)cfg_map_get(controls, "inet", &inetcontrols);
3014 for (element2 = cfg_list_first(inetcontrols);
3015 element2 != NULL;
3016 element2 = cfg_list_next(element2)) {
3017 control = cfg_listelt_value(element2);
3018 allow = cfg_tuple_get(control, "allow");
3019 tresult = cfg_acl_fromconfig(allow, config, logctx,
3020 actx, mctx, 0, &acl);
3021 if (acl != NULL)
3022 dns_acl_detach(&acl);
3023 if (tresult != ISC_R_SUCCESS)
3024 result = tresult;
3025 tresult = bind9_check_controlskeys(control, keylist,
3026 logctx);
3027 if (tresult != ISC_R_SUCCESS)
3028 result = tresult;
3030 for (element2 = cfg_list_first(unixcontrols);
3031 element2 != NULL;
3032 element2 = cfg_list_next(element2)) {
3033 control = cfg_listelt_value(element2);
3034 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
3035 tresult = isc_sockaddr_frompath(&addr, path);
3036 if (tresult == ISC_R_NOSPACE) {
3037 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
3038 "unix control '%s': path too long",
3039 path);
3040 result = ISC_R_NOSPACE;
3042 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
3043 for (i = 0; i < 3; i++) {
3044 #ifdef NEED_SECURE_DIRECTORY
3045 mask = (0x1 << (i*3)); /* SEARCH */
3046 #else
3047 mask = (0x6 << (i*3)); /* READ + WRITE */
3048 #endif
3049 if ((perm & mask) == mask)
3050 break;
3052 if (i == 0) {
3053 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
3054 "unix control '%s' allows access "
3055 "to everyone", path);
3056 } else if (i == 3) {
3057 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
3058 "unix control '%s' allows access "
3059 "to nobody", path);
3061 tresult = bind9_check_controlskeys(control, keylist,
3062 logctx);
3063 if (tresult != ISC_R_SUCCESS)
3064 result = tresult;
3067 cfg_aclconfctx_detach(&actx);
3068 return (result);
3071 isc_result_t
3072 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
3073 isc_mem_t *mctx)
3075 const cfg_obj_t *options = NULL;
3076 const cfg_obj_t *views = NULL;
3077 const cfg_obj_t *acls = NULL;
3078 const cfg_obj_t *kals = NULL;
3079 const cfg_obj_t *obj;
3080 const cfg_listelt_t *velement;
3081 isc_result_t result = ISC_R_SUCCESS;
3082 isc_result_t tresult;
3083 isc_symtab_t *symtab = NULL;
3084 isc_symtab_t *files = NULL;
3086 static const char *builtin[] = { "localhost", "localnets",
3087 "any", "none"};
3089 (void)cfg_map_get(config, "options", &options);
3091 if (options != NULL &&
3092 check_options(options, logctx, mctx,
3093 optlevel_options) != ISC_R_SUCCESS)
3094 result = ISC_R_FAILURE;
3096 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
3097 result = ISC_R_FAILURE;
3099 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
3100 result = ISC_R_FAILURE;
3102 if (options != NULL &&
3103 check_order(options, logctx) != ISC_R_SUCCESS)
3104 result = ISC_R_FAILURE;
3106 (void)cfg_map_get(config, "view", &views);
3108 if (views != NULL && options != NULL)
3109 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
3110 result = ISC_R_FAILURE;
3113 * Use case insensitve comparision as not all file systems are
3114 * case sensitive. This will prevent people using FOO.DB and foo.db
3115 * on case sensitive file systems but that shouldn't be a major issue.
3117 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE,
3118 &files);
3119 if (tresult != ISC_R_SUCCESS)
3120 result = tresult;
3122 if (views == NULL) {
3123 if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
3124 files, logctx, mctx) != ISC_R_SUCCESS)
3125 result = ISC_R_FAILURE;
3126 } else {
3127 const cfg_obj_t *zones = NULL;
3129 (void)cfg_map_get(config, "zone", &zones);
3130 if (zones != NULL) {
3131 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
3132 "when using 'view' statements, "
3133 "all zones must be in views");
3134 result = ISC_R_FAILURE;
3138 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
3139 if (tresult != ISC_R_SUCCESS)
3140 result = tresult;
3141 for (velement = cfg_list_first(views);
3142 velement != NULL;
3143 velement = cfg_list_next(velement))
3145 const cfg_obj_t *view = cfg_listelt_value(velement);
3146 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
3147 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
3148 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
3149 dns_rdataclass_t vclass = dns_rdataclass_in;
3150 const char *key = cfg_obj_asstring(vname);
3151 isc_symvalue_t symvalue;
3153 tresult = ISC_R_SUCCESS;
3154 if (cfg_obj_isstring(vclassobj)) {
3155 isc_textregion_t r;
3157 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
3158 r.length = strlen(r.base);
3159 tresult = dns_rdataclass_fromtext(&vclass, &r);
3160 if (tresult != ISC_R_SUCCESS)
3161 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
3162 "view '%s': invalid class %s",
3163 cfg_obj_asstring(vname), r.base);
3165 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
3166 symvalue.as_cpointer = view;
3167 tresult = isc_symtab_define(symtab, key, vclass,
3168 symvalue,
3169 isc_symexists_reject);
3170 if (tresult == ISC_R_EXISTS) {
3171 const char *file;
3172 unsigned int line;
3173 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
3174 vclass, &symvalue) == ISC_R_SUCCESS);
3175 file = cfg_obj_file(symvalue.as_cpointer);
3176 line = cfg_obj_line(symvalue.as_cpointer);
3177 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
3178 "view '%s': already exists "
3179 "previous definition: %s:%u",
3180 key, file, line);
3181 result = tresult;
3182 } else if (tresult != ISC_R_SUCCESS) {
3183 result = tresult;
3184 } else if ((strcasecmp(key, "_bind") == 0 &&
3185 vclass == dns_rdataclass_ch) ||
3186 (strcasecmp(key, "_default") == 0 &&
3187 vclass == dns_rdataclass_in)) {
3188 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
3189 "attempt to redefine builtin view "
3190 "'%s'", key);
3191 result = ISC_R_EXISTS;
3194 if (tresult == ISC_R_SUCCESS)
3195 tresult = check_viewconf(config, voptions, key, vclass,
3196 files, logctx, mctx);
3197 if (tresult != ISC_R_SUCCESS)
3198 result = ISC_R_FAILURE;
3200 if (symtab != NULL)
3201 isc_symtab_destroy(&symtab);
3202 if (files != NULL)
3203 isc_symtab_destroy(&files);
3205 if (views != NULL && options != NULL) {
3206 obj = NULL;
3207 tresult = cfg_map_get(options, "cache-file", &obj);
3208 if (tresult == ISC_R_SUCCESS) {
3209 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
3210 "'cache-file' cannot be a global "
3211 "option if views are present");
3212 result = ISC_R_FAILURE;
3216 cfg_map_get(config, "acl", &acls);
3218 if (acls != NULL) {
3219 const cfg_listelt_t *elt;
3220 const cfg_listelt_t *elt2;
3221 const char *aclname;
3223 for (elt = cfg_list_first(acls);
3224 elt != NULL;
3225 elt = cfg_list_next(elt)) {
3226 const cfg_obj_t *acl = cfg_listelt_value(elt);
3227 unsigned int line = cfg_obj_line(acl);
3228 unsigned int i;
3230 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
3231 for (i = 0;
3232 i < sizeof(builtin) / sizeof(builtin[0]);
3233 i++)
3234 if (strcasecmp(aclname, builtin[i]) == 0) {
3235 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
3236 "attempt to redefine "
3237 "builtin acl '%s'",
3238 aclname);
3239 result = ISC_R_FAILURE;
3240 break;
3243 for (elt2 = cfg_list_next(elt);
3244 elt2 != NULL;
3245 elt2 = cfg_list_next(elt2)) {
3246 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
3247 const char *name;
3248 name = cfg_obj_asstring(cfg_tuple_get(acl2,
3249 "name"));
3250 if (strcasecmp(aclname, name) == 0) {
3251 const char *file = cfg_obj_file(acl);
3253 if (file == NULL)
3254 file = "<unknown file>";
3256 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
3257 "attempt to redefine "
3258 "acl '%s' previous "
3259 "definition: %s:%u",
3260 name, file, line);
3261 result = ISC_R_FAILURE;
3267 tresult = cfg_map_get(config, "kal", &kals);
3268 if (tresult == ISC_R_SUCCESS) {
3269 const cfg_listelt_t *elt;
3270 const cfg_listelt_t *elt2;
3271 const char *aclname;
3273 for (elt = cfg_list_first(kals);
3274 elt != NULL;
3275 elt = cfg_list_next(elt)) {
3276 const cfg_obj_t *acl = cfg_listelt_value(elt);
3278 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
3280 for (elt2 = cfg_list_next(elt);
3281 elt2 != NULL;
3282 elt2 = cfg_list_next(elt2)) {
3283 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
3284 const char *name;
3285 name = cfg_obj_asstring(cfg_tuple_get(acl2,
3286 "name"));
3287 if (strcasecmp(aclname, name) == 0) {
3288 const char *file = cfg_obj_file(acl);
3289 unsigned int line = cfg_obj_line(acl);
3291 if (file == NULL)
3292 file = "<unknown file>";
3294 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
3295 "attempt to redefine "
3296 "kal '%s' previous "
3297 "definition: %s:%u",
3298 name, file, line);
3299 result = ISC_R_FAILURE;
3305 return (result);