2 * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2001-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: check.c,v 1.95.12.6 2010-03-04 23:47:53 tbox Exp $ */
26 #include <isc/base64.h>
27 #include <isc/buffer.h>
30 #include <isc/netaddr.h>
31 #include <isc/parseint.h>
32 #include <isc/region.h>
33 #include <isc/result.h>
34 #include <isc/sockaddr.h>
35 #include <isc/string.h>
36 #include <isc/symtab.h>
40 #include <dns/fixedname.h>
41 #include <dns/rdataclass.h>
42 #include <dns/rdatatype.h>
43 #include <dns/secalg.h>
47 #include <isccfg/aclconf.h>
48 #include <isccfg/cfg.h>
50 #include <bind9/check.h>
53 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
56 isc_mem_free(userarg, key);
60 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
61 isc_result_t result = ISC_R_SUCCESS;
64 dns_fixedname_t fixed;
66 dns_rdataclass_t rdclass;
67 dns_rdatatype_t rdtype;
71 dns_fixedname_init(&fixed);
72 obj = cfg_tuple_get(ent, "class");
73 if (cfg_obj_isstring(obj)) {
75 DE_CONST(cfg_obj_asstring(obj), r.base);
76 r.length = strlen(r.base);
77 tresult = dns_rdataclass_fromtext(&rdclass, &r);
78 if (tresult != ISC_R_SUCCESS) {
79 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
80 "rrset-order: invalid class '%s'",
82 result = ISC_R_FAILURE;
86 obj = cfg_tuple_get(ent, "type");
87 if (cfg_obj_isstring(obj)) {
89 DE_CONST(cfg_obj_asstring(obj), r.base);
90 r.length = strlen(r.base);
91 tresult = dns_rdatatype_fromtext(&rdtype, &r);
92 if (tresult != ISC_R_SUCCESS) {
93 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
94 "rrset-order: invalid type '%s'",
96 result = ISC_R_FAILURE;
100 obj = cfg_tuple_get(ent, "name");
101 if (cfg_obj_isstring(obj)) {
102 str = cfg_obj_asstring(obj);
103 isc_buffer_init(&b, str, strlen(str));
104 isc_buffer_add(&b, strlen(str));
105 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
106 dns_rootname, ISC_FALSE, NULL);
107 if (tresult != ISC_R_SUCCESS) {
108 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
109 "rrset-order: invalid name '%s'", str);
110 result = ISC_R_FAILURE;
114 obj = cfg_tuple_get(ent, "order");
115 if (!cfg_obj_isstring(obj) ||
116 strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
117 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
118 "rrset-order: keyword 'order' missing");
119 result = ISC_R_FAILURE;
122 obj = cfg_tuple_get(ent, "ordering");
123 if (!cfg_obj_isstring(obj)) {
124 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
125 "rrset-order: missing ordering");
126 result = ISC_R_FAILURE;
127 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
128 #if !DNS_RDATASET_FIXED
129 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
130 "rrset-order: order 'fixed' was disabled at "
133 } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
134 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
135 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
136 "rrset-order: invalid order '%s'",
137 cfg_obj_asstring(obj));
138 result = ISC_R_FAILURE;
144 check_order(const cfg_obj_t *options, isc_log_t *logctx) {
145 isc_result_t result = ISC_R_SUCCESS;
146 isc_result_t tresult;
147 const cfg_listelt_t *element;
148 const cfg_obj_t *obj = NULL;
150 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
153 for (element = cfg_list_first(obj);
155 element = cfg_list_next(element))
157 tresult = check_orderent(cfg_listelt_value(element), logctx);
158 if (tresult != ISC_R_SUCCESS)
165 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
166 const cfg_listelt_t *element;
167 const cfg_obj_t *alternates = NULL;
168 const cfg_obj_t *value;
169 const cfg_obj_t *obj;
171 dns_fixedname_t fixed;
174 isc_result_t result = ISC_R_SUCCESS;
175 isc_result_t tresult;
177 (void)cfg_map_get(options, "dual-stack-servers", &alternates);
179 if (alternates == NULL)
180 return (ISC_R_SUCCESS);
182 obj = cfg_tuple_get(alternates, "port");
183 if (cfg_obj_isuint32(obj)) {
184 isc_uint32_t val = cfg_obj_asuint32(obj);
185 if (val > ISC_UINT16_MAX) {
186 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
187 "port '%u' out of range", val);
188 result = ISC_R_FAILURE;
191 obj = cfg_tuple_get(alternates, "addresses");
192 for (element = cfg_list_first(obj);
194 element = cfg_list_next(element)) {
195 value = cfg_listelt_value(element);
196 if (cfg_obj_issockaddr(value))
198 obj = cfg_tuple_get(value, "name");
199 str = cfg_obj_asstring(obj);
200 isc_buffer_init(&buffer, str, strlen(str));
201 isc_buffer_add(&buffer, strlen(str));
202 dns_fixedname_init(&fixed);
203 name = dns_fixedname_name(&fixed);
204 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
206 if (tresult != ISC_R_SUCCESS) {
207 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
208 "bad name '%s'", str);
209 result = ISC_R_FAILURE;
211 obj = cfg_tuple_get(value, "port");
212 if (cfg_obj_isuint32(obj)) {
213 isc_uint32_t val = cfg_obj_asuint32(obj);
214 if (val > ISC_UINT16_MAX) {
215 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
216 "port '%u' out of range", val);
217 result = ISC_R_FAILURE;
225 check_forward(const cfg_obj_t *options, const cfg_obj_t *global,
228 const cfg_obj_t *forward = NULL;
229 const cfg_obj_t *forwarders = NULL;
231 (void)cfg_map_get(options, "forward", &forward);
232 (void)cfg_map_get(options, "forwarders", &forwarders);
234 if (forwarders != NULL && global != NULL) {
235 const char *file = cfg_obj_file(global);
236 unsigned int line = cfg_obj_line(global);
237 cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
238 "forwarders declared in root zone and "
239 "in general configuration: %s:%u",
241 return (ISC_R_FAILURE);
243 if (forward != NULL && forwarders == NULL) {
244 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
245 "no matching 'forwarders' statement");
246 return (ISC_R_FAILURE);
248 return (ISC_R_SUCCESS);
252 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
253 isc_result_t result = ISC_R_SUCCESS;
254 isc_result_t tresult;
255 const cfg_listelt_t *element;
258 dns_fixedname_t fixed;
260 const cfg_obj_t *obj;
262 dns_fixedname_init(&fixed);
263 name = dns_fixedname_name(&fixed);
264 obj = cfg_tuple_get(disabled, "name");
265 str = cfg_obj_asstring(obj);
266 isc_buffer_init(&b, str, strlen(str));
267 isc_buffer_add(&b, strlen(str));
268 tresult = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
269 if (tresult != ISC_R_SUCCESS) {
270 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
271 "bad domain name '%s'", str);
275 obj = cfg_tuple_get(disabled, "algorithms");
277 for (element = cfg_list_first(obj);
279 element = cfg_list_next(element))
283 isc_result_t tresult;
285 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
286 r.length = strlen(r.base);
288 tresult = dns_secalg_fromtext(&alg, &r);
289 if (tresult != ISC_R_SUCCESS) {
291 result = isc_parse_uint8(&ui, r.base, 10);
293 if (tresult != ISC_R_SUCCESS) {
294 cfg_obj_log(cfg_listelt_value(element), logctx,
295 ISC_LOG_ERROR, "invalid algorithm '%s'",
304 nameexist(const cfg_obj_t *obj, const char *name, int value,
305 isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
312 isc_symvalue_t symvalue;
314 key = isc_mem_strdup(mctx, name);
316 return (ISC_R_NOMEMORY);
317 symvalue.as_cpointer = obj;
318 result = isc_symtab_define(symtab, key, value, symvalue,
319 isc_symexists_reject);
320 if (result == ISC_R_EXISTS) {
321 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
322 &symvalue) == ISC_R_SUCCESS);
323 file = cfg_obj_file(symvalue.as_cpointer);
324 line = cfg_obj_line(symvalue.as_cpointer);
327 file = "<unknown file>";
328 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
329 isc_mem_free(mctx, key);
330 result = ISC_R_EXISTS;
331 } else if (result != ISC_R_SUCCESS) {
332 isc_mem_free(mctx, key);
338 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
341 const cfg_obj_t *obj;
342 char namebuf[DNS_NAME_FORMATSIZE];
344 dns_fixedname_t fixed;
347 isc_result_t result = ISC_R_SUCCESS;
349 dns_fixedname_init(&fixed);
350 name = dns_fixedname_name(&fixed);
351 obj = cfg_tuple_get(secure, "name");
352 str = cfg_obj_asstring(obj);
353 isc_buffer_init(&b, str, strlen(str));
354 isc_buffer_add(&b, strlen(str));
355 result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
356 if (result != ISC_R_SUCCESS) {
357 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
358 "bad domain name '%s'", str);
360 dns_name_format(name, namebuf, sizeof(namebuf));
361 result = nameexist(secure, namebuf, 1, symtab,
362 "dnssec-must-be-secure '%s': already "
363 "exists previous definition: %s:%u",
370 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
371 const cfg_obj_t *voptions, const cfg_obj_t *config,
372 isc_log_t *logctx, isc_mem_t *mctx)
375 const cfg_obj_t *aclobj = NULL;
376 const cfg_obj_t *options;
377 dns_acl_t *acl = NULL;
379 if (zconfig != NULL) {
380 options = cfg_tuple_get(zconfig, "options");
381 cfg_map_get(options, aclname, &aclobj);
383 if (voptions != NULL && aclobj == NULL)
384 cfg_map_get(voptions, aclname, &aclobj);
385 if (config != NULL && aclobj == NULL) {
387 cfg_map_get(config, "options", &options);
389 cfg_map_get(options, aclname, &aclobj);
392 return (ISC_R_SUCCESS);
393 result = cfg_acl_fromconfig(aclobj, config, logctx,
394 actx, mctx, 0, &acl);
396 dns_acl_detach(&acl);
401 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
402 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
404 isc_result_t result = ISC_R_SUCCESS, tresult;
407 static const char *acls[] = { "allow-query", "allow-query-on",
408 "allow-query-cache", "allow-query-cache-on",
409 "blackhole", "match-clients", "match-destinations",
412 while (acls[i] != NULL) {
413 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
415 if (tresult != ISC_R_SUCCESS)
422 * Check allow-recursion and allow-recursion-on acls, and also log a
423 * warning if they're inconsistent with the "recursion" option.
426 check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
427 const char *viewname, const cfg_obj_t *config,
428 isc_log_t *logctx, isc_mem_t *mctx)
430 const cfg_obj_t *options, *aclobj, *obj = NULL;
431 dns_acl_t *acl = NULL;
432 isc_result_t result = ISC_R_SUCCESS, tresult;
433 isc_boolean_t recursion;
434 const char *forview = " for view ";
437 static const char *acls[] = { "allow-recursion", "allow-recursion-on",
440 if (voptions != NULL)
441 cfg_map_get(voptions, "recursion", &obj);
442 if (obj == NULL && config != NULL) {
444 cfg_map_get(config, "options", &options);
446 cfg_map_get(options, "recursion", &obj);
449 recursion = ISC_TRUE;
451 recursion = cfg_obj_asboolean(obj);
453 if (viewname == NULL) {
458 for (i = 0; acls[i] != NULL; i++) {
459 aclobj = options = NULL;
462 if (voptions != NULL)
463 cfg_map_get(voptions, acls[i], &aclobj);
464 if (config != NULL && aclobj == NULL) {
466 cfg_map_get(config, "options", &options);
468 cfg_map_get(options, acls[i], &aclobj);
473 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
474 actx, mctx, 0, &acl);
476 if (tresult != ISC_R_SUCCESS)
482 if (recursion == ISC_FALSE && !dns_acl_isnone(acl)) {
483 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
484 "both \"recursion no;\" and "
486 acls[i], forview, viewname);
490 dns_acl_detach(&acl);
503 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
504 isc_result_t result = ISC_R_SUCCESS;
505 isc_result_t tresult;
507 const cfg_obj_t *obj = NULL;
508 const cfg_obj_t *resignobj = NULL;
509 const cfg_listelt_t *element;
510 isc_symtab_t *symtab = NULL;
511 dns_fixedname_t fixed;
516 static intervaltable intervals[] = {
517 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
518 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
519 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
520 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
521 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
522 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
523 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
524 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
528 * Check that fields specified in units of time other than seconds
529 * have reasonable values.
531 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
534 (void)cfg_map_get(options, intervals[i].name, &obj);
537 val = cfg_obj_asuint32(obj);
538 if (val > intervals[i].max) {
539 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
540 "%s '%u' is out of range (0..%u)",
541 intervals[i].name, val,
543 result = ISC_R_RANGE;
544 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
545 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
546 "%s '%d' is out of range",
547 intervals[i].name, val);
548 result = ISC_R_RANGE;
553 cfg_map_get(options, "sig-validity-interval", &obj);
555 isc_uint32_t validity, resign = 0;
557 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
558 resignobj = cfg_tuple_get(obj, "re-sign");
559 if (!cfg_obj_isvoid(resignobj))
560 resign = cfg_obj_asuint32(resignobj);
562 if (validity > 3660 || validity == 0) { /* 10 years */
563 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
564 "%s '%u' is out of range (1..3660)",
565 "sig-validity-interval", validity);
566 result = ISC_R_RANGE;
569 if (!cfg_obj_isvoid(resignobj)) {
570 if (resign > 3660 || resign == 0) { /* 10 years */
571 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
572 "%s '%u' is out of range (1..3660)",
573 "sig-validity-interval (re-sign)",
575 result = ISC_R_RANGE;
576 } else if ((validity > 7 && validity < resign) ||
577 (validity <= 7 && validity * 24 < resign)) {
578 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
579 "validity interval (%u days) "
580 "less than re-signing interval "
581 "(%u %s)", validity, resign,
582 (validity > 7) ? "days" : "hours");
583 result = ISC_R_RANGE;
589 (void)cfg_map_get(options, "preferred-glue", &obj);
592 str = cfg_obj_asstring(obj);
593 if (strcasecmp(str, "a") != 0 &&
594 strcasecmp(str, "aaaa") != 0 &&
595 strcasecmp(str, "none") != 0)
596 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
597 "preferred-glue unexpected value '%s'",
602 (void)cfg_map_get(options, "root-delegation-only", &obj);
604 if (!cfg_obj_isvoid(obj)) {
605 const cfg_listelt_t *element;
606 const cfg_obj_t *exclude;
608 dns_fixedname_t fixed;
612 dns_fixedname_init(&fixed);
613 name = dns_fixedname_name(&fixed);
614 for (element = cfg_list_first(obj);
616 element = cfg_list_next(element)) {
617 exclude = cfg_listelt_value(element);
618 str = cfg_obj_asstring(exclude);
619 isc_buffer_init(&b, str, strlen(str));
620 isc_buffer_add(&b, strlen(str));
621 tresult = dns_name_fromtext(name, &b,
624 if (tresult != ISC_R_SUCCESS) {
625 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
626 "bad domain name '%s'",
635 * Set supported DNSSEC algorithms.
638 (void)cfg_map_get(options, "disable-algorithms", &obj);
640 for (element = cfg_list_first(obj);
642 element = cfg_list_next(element))
644 obj = cfg_listelt_value(element);
645 tresult = disabled_algorithms(obj, logctx);
646 if (tresult != ISC_R_SUCCESS)
651 dns_fixedname_init(&fixed);
652 name = dns_fixedname_name(&fixed);
655 * Check the DLV zone name.
658 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
660 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
662 if (tresult != ISC_R_SUCCESS)
664 for (element = cfg_list_first(obj);
666 element = cfg_list_next(element))
670 obj = cfg_listelt_value(element);
672 dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain"));
673 isc_buffer_init(&b, dlv, strlen(dlv));
674 isc_buffer_add(&b, strlen(dlv));
675 tresult = dns_name_fromtext(name, &b, dns_rootname,
677 if (tresult != ISC_R_SUCCESS) {
678 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
679 "bad domain name '%s'", dlv);
683 if (symtab != NULL) {
684 tresult = nameexist(obj, dlv, 1, symtab,
685 "dnssec-lookaside '%s': "
686 "already exists previous "
689 if (tresult != ISC_R_SUCCESS &&
690 result == ISC_R_SUCCESS)
694 * XXXMPA to be removed when multiple lookaside
695 * namespaces are supported.
697 if (!dns_name_equal(dns_rootname, name)) {
698 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
699 "dnssec-lookaside '%s': "
700 "non-root not yet supported", dlv);
701 if (result == ISC_R_SUCCESS)
702 result = ISC_R_FAILURE;
704 dlv = cfg_obj_asstring(cfg_tuple_get(obj,
706 isc_buffer_init(&b, dlv, strlen(dlv));
707 isc_buffer_add(&b, strlen(dlv));
708 tresult = dns_name_fromtext(name, &b, dns_rootname,
710 if (tresult != ISC_R_SUCCESS) {
711 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
712 "bad domain name '%s'", dlv);
713 if (result == ISC_R_SUCCESS)
718 isc_symtab_destroy(&symtab);
722 * Check dnssec-must-be-secure.
725 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
727 isc_symtab_t *symtab = NULL;
728 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
730 if (tresult != ISC_R_SUCCESS)
732 for (element = cfg_list_first(obj);
734 element = cfg_list_next(element))
736 obj = cfg_listelt_value(element);
737 tresult = mustbesecure(obj, symtab, logctx, mctx);
738 if (tresult != ISC_R_SUCCESS)
742 isc_symtab_destroy(&symtab);
746 * Check empty zone configuration.
749 (void)cfg_map_get(options, "empty-server", &obj);
751 str = cfg_obj_asstring(obj);
752 isc_buffer_init(&b, str, strlen(str));
753 isc_buffer_add(&b, strlen(str));
754 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
755 dns_rootname, ISC_FALSE, NULL);
756 if (tresult != ISC_R_SUCCESS) {
757 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
758 "empty-server: invalid name '%s'", str);
759 result = ISC_R_FAILURE;
764 (void)cfg_map_get(options, "empty-contact", &obj);
766 str = cfg_obj_asstring(obj);
767 isc_buffer_init(&b, str, strlen(str));
768 isc_buffer_add(&b, strlen(str));
769 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
770 dns_rootname, ISC_FALSE, NULL);
771 if (tresult != ISC_R_SUCCESS) {
772 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
773 "empty-contact: invalid name '%s'", str);
774 result = ISC_R_FAILURE;
779 (void)cfg_map_get(options, "disable-empty-zone", &obj);
780 for (element = cfg_list_first(obj);
782 element = cfg_list_next(element))
784 obj = cfg_listelt_value(element);
785 str = cfg_obj_asstring(obj);
786 isc_buffer_init(&b, str, strlen(str));
787 isc_buffer_add(&b, strlen(str));
788 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
789 dns_rootname, ISC_FALSE, NULL);
790 if (tresult != ISC_R_SUCCESS) {
791 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
792 "disable-empty-zone: invalid name '%s'",
794 result = ISC_R_FAILURE;
799 * Check that server-id is not too long.
800 * 1024 bytes should be big enough.
803 (void)cfg_map_get(options, "server-id", &obj);
804 if (obj != NULL && cfg_obj_isstring(obj) &&
805 strlen(cfg_obj_asstring(obj)) > 1024U) {
806 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
807 "'server-id' too big (>1024 bytes)");
808 result = ISC_R_FAILURE;
815 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
817 const cfg_obj_t *masters = NULL;
818 const cfg_listelt_t *elt;
820 result = cfg_map_get(cctx, "masters", &masters);
821 if (result != ISC_R_SUCCESS)
823 for (elt = cfg_list_first(masters);
825 elt = cfg_list_next(elt)) {
826 const cfg_obj_t *list;
827 const char *listname;
829 list = cfg_listelt_value(elt);
830 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
832 if (strcasecmp(listname, name) == 0) {
834 return (ISC_R_SUCCESS);
837 return (ISC_R_NOTFOUND);
841 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
842 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
844 isc_result_t result = ISC_R_SUCCESS;
845 isc_result_t tresult;
846 isc_uint32_t count = 0;
847 isc_symtab_t *symtab = NULL;
848 isc_symvalue_t symvalue;
849 const cfg_listelt_t *element;
850 const cfg_listelt_t **stack = NULL;
851 isc_uint32_t stackcount = 0, pushed = 0;
852 const cfg_obj_t *list;
854 REQUIRE(countp != NULL);
855 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
856 if (result != ISC_R_SUCCESS) {
862 list = cfg_tuple_get(obj, "addresses");
863 element = cfg_list_first(list);
867 element = cfg_list_next(element))
869 const char *listname;
870 const cfg_obj_t *addr;
871 const cfg_obj_t *key;
873 addr = cfg_tuple_get(cfg_listelt_value(element),
875 key = cfg_tuple_get(cfg_listelt_value(element), "key");
877 if (cfg_obj_issockaddr(addr)) {
881 if (!cfg_obj_isvoid(key)) {
882 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
883 "unexpected token '%s'",
884 cfg_obj_asstring(key));
885 if (result == ISC_R_SUCCESS)
886 result = ISC_R_FAILURE;
888 listname = cfg_obj_asstring(addr);
889 symvalue.as_cpointer = addr;
890 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
891 isc_symexists_reject);
892 if (tresult == ISC_R_EXISTS)
894 tresult = get_masters_def(config, listname, &obj);
895 if (tresult != ISC_R_SUCCESS) {
896 if (result == ISC_R_SUCCESS)
898 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
899 "unable to find masters list '%s'",
904 if (stackcount == pushed) {
906 isc_uint32_t newlen = stackcount + 16;
907 size_t newsize, oldsize;
909 newsize = newlen * sizeof(*stack);
910 oldsize = stackcount * sizeof(*stack);
911 new = isc_mem_get(mctx, newsize);
914 if (stackcount != 0) {
917 DE_CONST(stack, ptr);
918 memcpy(new, stack, oldsize);
919 isc_mem_put(mctx, ptr, oldsize);
924 stack[pushed++] = cfg_list_next(element);
928 element = stack[--pushed];
935 DE_CONST(stack, ptr);
936 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
938 isc_symtab_destroy(&symtab);
944 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
945 isc_result_t result = ISC_R_SUCCESS;
946 isc_result_t tresult;
947 const cfg_listelt_t *element;
948 const cfg_listelt_t *element2;
949 dns_fixedname_t fixed;
953 for (element = cfg_list_first(policy);
955 element = cfg_list_next(element))
957 const cfg_obj_t *stmt = cfg_listelt_value(element);
958 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
959 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
960 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
961 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
963 dns_fixedname_init(&fixed);
964 str = cfg_obj_asstring(identity);
965 isc_buffer_init(&b, str, strlen(str));
966 isc_buffer_add(&b, strlen(str));
967 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
968 dns_rootname, ISC_FALSE, NULL);
969 if (tresult != ISC_R_SUCCESS) {
970 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
971 "'%s' is not a valid name", str);
975 dns_fixedname_init(&fixed);
976 str = cfg_obj_asstring(dname);
977 isc_buffer_init(&b, str, strlen(str));
978 isc_buffer_add(&b, strlen(str));
979 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
980 dns_rootname, ISC_FALSE, NULL);
981 if (tresult != ISC_R_SUCCESS) {
982 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
983 "'%s' is not a valid name", str);
986 if (tresult == ISC_R_SUCCESS &&
987 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
988 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
989 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
990 "'%s' is not a wildcard", str);
991 result = ISC_R_FAILURE;
994 for (element2 = cfg_list_first(typelist);
996 element2 = cfg_list_next(element2))
998 const cfg_obj_t *typeobj;
1000 dns_rdatatype_t type;
1002 typeobj = cfg_listelt_value(element2);
1003 DE_CONST(cfg_obj_asstring(typeobj), r.base);
1004 r.length = strlen(r.base);
1006 tresult = dns_rdatatype_fromtext(&type, &r);
1007 if (tresult != ISC_R_SUCCESS) {
1008 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
1009 "'%s' is not a valid type", r.base);
1017 #define MASTERZONE 1
1021 #define FORWARDZONE 16
1022 #define DELEGATIONZONE 32
1031 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
1032 const cfg_obj_t *config, isc_symtab_t *symtab,
1033 dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
1034 isc_log_t *logctx, isc_mem_t *mctx)
1037 const char *typestr;
1039 const cfg_obj_t *zoptions;
1040 const cfg_obj_t *obj = NULL;
1041 isc_result_t result = ISC_R_SUCCESS;
1042 isc_result_t tresult;
1044 dns_rdataclass_t zclass;
1045 dns_fixedname_t fixedname;
1047 isc_boolean_t root = ISC_FALSE;
1049 static optionstable options[] = {
1050 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL },
1051 { "allow-notify", SLAVEZONE | CHECKACL },
1052 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
1053 { "notify", MASTERZONE | SLAVEZONE },
1054 { "also-notify", MASTERZONE | SLAVEZONE },
1055 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
1056 { "delegation-only", HINTZONE | STUBZONE | DELEGATIONZONE },
1057 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
1058 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
1059 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
1060 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
1061 { "notify-source", MASTERZONE | SLAVEZONE },
1062 { "notify-source-v6", MASTERZONE | SLAVEZONE },
1063 { "transfer-source", SLAVEZONE | STUBZONE },
1064 { "transfer-source-v6", SLAVEZONE | STUBZONE },
1065 { "max-transfer-time-in", SLAVEZONE | STUBZONE },
1066 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
1067 { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
1068 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
1069 { "max-retry-time", SLAVEZONE | STUBZONE },
1070 { "min-retry-time", SLAVEZONE | STUBZONE },
1071 { "max-refresh-time", SLAVEZONE | STUBZONE },
1072 { "min-refresh-time", SLAVEZONE | STUBZONE },
1073 { "sig-validity-interval", MASTERZONE },
1074 { "sig-re-signing-interval", MASTERZONE },
1075 { "sig-signing-nodes", MASTERZONE },
1076 { "sig-signing-type", MASTERZONE },
1077 { "sig-signing-signatures", MASTERZONE },
1078 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE },
1079 { "allow-update", MASTERZONE | CHECKACL },
1080 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
1081 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1082 { "journal", MASTERZONE | SLAVEZONE },
1083 { "ixfr-base", MASTERZONE | SLAVEZONE },
1084 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
1085 { "masters", SLAVEZONE | STUBZONE },
1086 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
1087 { "update-policy", MASTERZONE },
1088 { "database", MASTERZONE | SLAVEZONE | STUBZONE },
1089 { "key-directory", MASTERZONE },
1090 { "check-wildcard", MASTERZONE },
1091 { "check-mx", MASTERZONE },
1092 { "integrity-check", MASTERZONE },
1093 { "check-mx-cname", MASTERZONE },
1094 { "check-srv-cname", MASTERZONE },
1095 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1096 { "update-check-ksk", MASTERZONE },
1097 { "try-tcp-refresh", SLAVEZONE },
1100 static optionstable dialups[] = {
1101 { "notify", MASTERZONE | SLAVEZONE },
1102 { "notify-passive", SLAVEZONE },
1103 { "refresh", SLAVEZONE | STUBZONE },
1104 { "passive", SLAVEZONE | STUBZONE },
1107 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1109 zoptions = cfg_tuple_get(zconfig, "options");
1112 (void)cfg_map_get(zoptions, "type", &obj);
1114 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1115 "zone '%s': type not present", zname);
1116 return (ISC_R_FAILURE);
1119 typestr = cfg_obj_asstring(obj);
1120 if (strcasecmp(typestr, "master") == 0)
1122 else if (strcasecmp(typestr, "slave") == 0)
1124 else if (strcasecmp(typestr, "stub") == 0)
1126 else if (strcasecmp(typestr, "forward") == 0)
1127 ztype = FORWARDZONE;
1128 else if (strcasecmp(typestr, "hint") == 0)
1130 else if (strcasecmp(typestr, "delegation-only") == 0)
1131 ztype = DELEGATIONZONE;
1133 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1134 "zone '%s': invalid type %s",
1136 return (ISC_R_FAILURE);
1139 obj = cfg_tuple_get(zconfig, "class");
1140 if (cfg_obj_isstring(obj)) {
1143 DE_CONST(cfg_obj_asstring(obj), r.base);
1144 r.length = strlen(r.base);
1145 result = dns_rdataclass_fromtext(&zclass, &r);
1146 if (result != ISC_R_SUCCESS) {
1147 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1148 "zone '%s': invalid class %s",
1150 return (ISC_R_FAILURE);
1152 if (zclass != defclass) {
1153 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1154 "zone '%s': class '%s' does not "
1155 "match view/default class",
1157 return (ISC_R_FAILURE);
1162 * Look for an already existing zone.
1163 * We need to make this canonical as isc_symtab_define()
1164 * deals with strings.
1166 dns_fixedname_init(&fixedname);
1167 isc_buffer_init(&b, zname, strlen(zname));
1168 isc_buffer_add(&b, strlen(zname));
1169 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1170 dns_rootname, ISC_TRUE, NULL);
1171 if (tresult != ISC_R_SUCCESS) {
1172 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1173 "zone '%s': is not a valid name", zname);
1174 result = ISC_R_FAILURE;
1176 char namebuf[DNS_NAME_FORMATSIZE];
1178 dns_name_format(dns_fixedname_name(&fixedname),
1179 namebuf, sizeof(namebuf));
1180 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
1181 symtab, "zone '%s': already exists "
1182 "previous definition: %s:%u", logctx, mctx);
1183 if (tresult != ISC_R_SUCCESS)
1185 if (dns_name_equal(dns_fixedname_name(&fixedname),
1191 * Look for inappropriate options for the given zone type.
1192 * Check that ACLs expand correctly.
1194 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1196 if ((options[i].allowed & ztype) == 0 &&
1197 cfg_map_get(zoptions, options[i].name, &obj) ==
1200 if (strcmp(options[i].name, "allow-update") != 0 ||
1201 ztype != SLAVEZONE) {
1202 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1203 "option '%s' is not allowed "
1204 "in '%s' zone '%s'",
1205 options[i].name, typestr, zname);
1206 result = ISC_R_FAILURE;
1208 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1209 "option '%s' is not allowed "
1210 "in '%s' zone '%s'",
1211 options[i].name, typestr, zname);
1214 if ((options[i].allowed & ztype) != 0 &&
1215 (options[i].allowed & CHECKACL) != 0) {
1217 tresult = checkacl(options[i].name, actx, zconfig,
1218 voptions, config, logctx, mctx);
1219 if (tresult != ISC_R_SUCCESS)
1226 * Slave & stub zones must have a "masters" field.
1228 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1230 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1231 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1232 "zone '%s': missing 'masters' entry",
1234 result = ISC_R_FAILURE;
1237 tresult = validate_masters(obj, config, &count,
1239 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1241 if (tresult == ISC_R_SUCCESS && count == 0) {
1242 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1243 "zone '%s': empty 'masters' entry",
1245 result = ISC_R_FAILURE;
1251 * Master zones can't have both "allow-update" and "update-policy".
1253 if (ztype == MASTERZONE) {
1254 isc_result_t res1, res2;
1256 res1 = cfg_map_get(zoptions, "allow-update", &obj);
1258 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1259 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1260 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1261 "zone '%s': 'allow-update' is ignored "
1262 "when 'update-policy' is present",
1264 result = ISC_R_FAILURE;
1265 } else if (res2 == ISC_R_SUCCESS &&
1266 check_update_policy(obj, logctx) != ISC_R_SUCCESS)
1267 result = ISC_R_FAILURE;
1269 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
1270 if (res1 == ISC_R_SUCCESS) {
1271 isc_uint32_t type = cfg_obj_asuint32(obj);
1272 if (type < 0xff00U || type > 0xffffU)
1273 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1274 "sig-signing-type: %u out of "
1275 "range [%u..%u]", type,
1277 result = ISC_R_FAILURE;
1282 * Check the excessively complicated "dialup" option.
1284 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1285 const cfg_obj_t *dialup = NULL;
1286 (void)cfg_map_get(zoptions, "dialup", &dialup);
1287 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1288 const char *str = cfg_obj_asstring(dialup);
1290 i < sizeof(dialups) / sizeof(dialups[0]);
1293 if (strcasecmp(dialups[i].name, str) != 0)
1295 if ((dialups[i].allowed & ztype) == 0) {
1296 cfg_obj_log(obj, logctx,
1298 "dialup type '%s' is not "
1301 str, typestr, zname);
1302 result = ISC_R_FAILURE;
1306 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1307 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1308 "invalid dialup type '%s' in zone "
1309 "'%s'", str, zname);
1310 result = ISC_R_FAILURE;
1316 * Check that forwarding is reasonable.
1320 if (voptions != NULL)
1321 (void)cfg_map_get(voptions, "forwarders", &obj);
1323 const cfg_obj_t *options = NULL;
1324 (void)cfg_map_get(config, "options", &options);
1325 if (options != NULL)
1326 (void)cfg_map_get(options, "forwarders", &obj);
1329 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
1330 result = ISC_R_FAILURE;
1333 * Check various options.
1335 tresult = check_options(zoptions, logctx, mctx);
1336 if (tresult != ISC_R_SUCCESS)
1340 * If the zone type is rbt/rbt64 then master/hint zones
1341 * require file clauses.
1344 tresult = cfg_map_get(zoptions, "database", &obj);
1345 if (tresult == ISC_R_NOTFOUND ||
1346 (tresult == ISC_R_SUCCESS &&
1347 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1348 strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
1350 tresult = cfg_map_get(zoptions, "file", &obj);
1351 if (tresult != ISC_R_SUCCESS &&
1352 (ztype == MASTERZONE || ztype == HINTZONE)) {
1353 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1354 "zone '%s': missing 'file' entry",
1364 typedef struct keyalgorithms {
1370 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1371 const cfg_obj_t *algobj = NULL;
1372 const cfg_obj_t *secretobj = NULL;
1373 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1374 const char *algorithm;
1377 static const algorithmtable algorithms[] = {
1378 { "hmac-md5", 128 },
1379 { "hmac-md5.sig-alg.reg.int", 0 },
1380 { "hmac-md5.sig-alg.reg.int.", 0 },
1381 { "hmac-sha1", 160 },
1382 { "hmac-sha224", 224 },
1383 { "hmac-sha256", 256 },
1384 { "hmac-sha384", 384 },
1385 { "hmac-sha512", 512 },
1389 (void)cfg_map_get(key, "algorithm", &algobj);
1390 (void)cfg_map_get(key, "secret", &secretobj);
1391 if (secretobj == NULL || algobj == NULL) {
1392 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1393 "key '%s' must have both 'secret' and "
1394 "'algorithm' defined",
1396 return (ISC_R_FAILURE);
1399 algorithm = cfg_obj_asstring(algobj);
1400 for (i = 0; algorithms[i].name != NULL; i++) {
1401 len = strlen(algorithms[i].name);
1402 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1403 (algorithm[len] == '\0' ||
1404 (algorithms[i].size != 0 && algorithm[len] == '-')))
1407 if (algorithms[i].name == NULL) {
1408 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1409 "unknown algorithm '%s'", algorithm);
1410 return (ISC_R_NOTFOUND);
1412 if (algorithm[len] == '-') {
1413 isc_uint16_t digestbits;
1414 isc_result_t result;
1415 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1416 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1417 if (result == ISC_R_RANGE ||
1418 digestbits > algorithms[i].size) {
1419 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1420 "key '%s' digest-bits too large "
1421 "[%u..%u]", keyname,
1422 algorithms[i].size / 2,
1423 algorithms[i].size);
1424 return (ISC_R_RANGE);
1426 if ((digestbits % 8) != 0) {
1427 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1428 "key '%s' digest-bits not multiple"
1430 return (ISC_R_RANGE);
1433 * Recommended minima for hmac algorithms.
1435 if ((digestbits < (algorithms[i].size / 2U) ||
1436 (digestbits < 80U)))
1437 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
1438 "key '%s' digest-bits too small "
1440 algorithms[i].size/2);
1442 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1443 "key '%s': unable to parse digest-bits",
1448 return (ISC_R_SUCCESS);
1452 * Check key list for duplicates key names and that the key names
1453 * are valid domain names as these keys are used for TSIG.
1455 * Check the key contents for validity.
1458 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
1459 isc_mem_t *mctx, isc_log_t *logctx)
1461 char namebuf[DNS_NAME_FORMATSIZE];
1462 dns_fixedname_t fname;
1464 isc_result_t result = ISC_R_SUCCESS;
1465 isc_result_t tresult;
1466 const cfg_listelt_t *element;
1468 dns_fixedname_init(&fname);
1469 name = dns_fixedname_name(&fname);
1470 for (element = cfg_list_first(keys);
1472 element = cfg_list_next(element))
1474 const cfg_obj_t *key = cfg_listelt_value(element);
1475 const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
1476 isc_symvalue_t symvalue;
1480 isc_buffer_init(&b, keyid, strlen(keyid));
1481 isc_buffer_add(&b, strlen(keyid));
1482 tresult = dns_name_fromtext(name, &b, dns_rootname,
1484 if (tresult != ISC_R_SUCCESS) {
1485 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1486 "key '%s': bad key name", keyid);
1490 tresult = bind9_check_key(key, logctx);
1491 if (tresult != ISC_R_SUCCESS)
1494 dns_name_format(name, namebuf, sizeof(namebuf));
1495 keyname = isc_mem_strdup(mctx, namebuf);
1496 if (keyname == NULL)
1497 return (ISC_R_NOMEMORY);
1498 symvalue.as_cpointer = key;
1499 tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
1500 isc_symexists_reject);
1501 if (tresult == ISC_R_EXISTS) {
1505 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
1506 1, &symvalue) == ISC_R_SUCCESS);
1507 file = cfg_obj_file(symvalue.as_cpointer);
1508 line = cfg_obj_line(symvalue.as_cpointer);
1511 file = "<unknown file>";
1512 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1513 "key '%s': already exists "
1514 "previous definition: %s:%u",
1516 isc_mem_free(mctx, keyname);
1518 } else if (tresult != ISC_R_SUCCESS) {
1519 isc_mem_free(mctx, keyname);
1530 { "transfer-source", "transfer-source-v6" },
1531 { "notify-source", "notify-source-v6" },
1532 { "query-source", "query-source-v6" },
1537 * RNDC keys are not normalised unlike TSIG keys.
1539 * "foo." is different to "foo".
1541 static isc_boolean_t
1542 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
1543 const cfg_listelt_t *element;
1544 const cfg_obj_t *obj;
1547 if (keylist == NULL)
1550 for (element = cfg_list_first(keylist);
1552 element = cfg_list_next(element))
1554 obj = cfg_listelt_value(element);
1555 str = cfg_obj_asstring(cfg_map_getname(obj));
1556 if (!strcasecmp(str, keyname))
1563 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
1564 isc_symtab_t *symtab, isc_log_t *logctx)
1566 dns_fixedname_t fname;
1567 isc_result_t result = ISC_R_SUCCESS;
1568 isc_result_t tresult;
1569 const cfg_listelt_t *e1, *e2;
1570 const cfg_obj_t *v1, *v2, *keys;
1571 const cfg_obj_t *servers;
1572 isc_netaddr_t n1, n2;
1573 unsigned int p1, p2;
1574 const cfg_obj_t *obj;
1575 char buf[ISC_NETADDR_FORMATSIZE];
1576 char namebuf[DNS_NAME_FORMATSIZE];
1581 dns_name_t *keyname;
1584 if (voptions != NULL)
1585 (void)cfg_map_get(voptions, "server", &servers);
1586 if (servers == NULL)
1587 (void)cfg_map_get(config, "server", &servers);
1588 if (servers == NULL)
1589 return (ISC_R_SUCCESS);
1591 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
1592 v1 = cfg_listelt_value(e1);
1593 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
1595 * Check that unused bits are zero.
1597 tresult = isc_netaddr_prefixok(&n1, p1);
1598 if (tresult != ISC_R_SUCCESS) {
1599 INSIST(tresult == ISC_R_FAILURE);
1600 isc_netaddr_format(&n1, buf, sizeof(buf));
1601 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1602 "server '%s/%u': invalid prefix "
1603 "(extra bits specified)", buf, p1);
1609 if (n1.family == AF_INET)
1610 xfr = sources[source].v6;
1612 xfr = sources[source].v4;
1613 (void)cfg_map_get(v1, xfr, &obj);
1615 isc_netaddr_format(&n1, buf, sizeof(buf));
1616 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1617 "server '%s/%u': %s not legal",
1619 result = ISC_R_FAILURE;
1621 } while (sources[++source].v4 != NULL);
1623 while ((e2 = cfg_list_next(e2)) != NULL) {
1624 v2 = cfg_listelt_value(e2);
1625 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
1626 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
1627 const char *file = cfg_obj_file(v1);
1628 unsigned int line = cfg_obj_line(v1);
1631 file = "<unknown file>";
1633 isc_netaddr_format(&n2, buf, sizeof(buf));
1634 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
1635 "server '%s/%u': already exists "
1636 "previous definition: %s:%u",
1637 buf, p2, file, line);
1638 result = ISC_R_FAILURE;
1642 cfg_map_get(v1, "keys", &keys);
1645 * Normalize key name.
1647 keyval = cfg_obj_asstring(keys);
1648 dns_fixedname_init(&fname);
1649 isc_buffer_init(&b, keyval, strlen(keyval));
1650 isc_buffer_add(&b, strlen(keyval));
1651 keyname = dns_fixedname_name(&fname);
1652 tresult = dns_name_fromtext(keyname, &b, dns_rootname,
1654 if (tresult != ISC_R_SUCCESS) {
1655 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
1656 "bad key name '%s'", keyval);
1657 result = ISC_R_FAILURE;
1660 dns_name_format(keyname, namebuf, sizeof(namebuf));
1661 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
1662 if (tresult != ISC_R_SUCCESS) {
1663 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
1664 "unknown key '%s'", keyval);
1665 result = ISC_R_FAILURE;
1673 check_trusted_key(const cfg_obj_t *key, isc_log_t *logctx)
1675 const char *keystr, *keynamestr;
1676 dns_fixedname_t fkeyname;
1677 dns_name_t *keyname;
1678 isc_buffer_t keydatabuf;
1680 isc_result_t result = ISC_R_SUCCESS;
1681 isc_result_t tresult;
1682 isc_uint32_t flags, proto, alg;
1683 unsigned char keydata[4096];
1685 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
1686 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
1687 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
1688 keyname = dns_fixedname_name(&fkeyname);
1689 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
1691 if (flags > 0xffff) {
1692 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
1693 "flags too big: %u\n", flags);
1694 result = ISC_R_FAILURE;
1697 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
1698 "protocol too big: %u\n", proto);
1699 result = ISC_R_FAILURE;
1702 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
1703 "algorithm too big: %u\n", alg);
1704 result = ISC_R_FAILURE;
1707 isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
1709 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
1710 tresult = isc_base64_decodestring(keystr, &keydatabuf);
1712 if (tresult != ISC_R_SUCCESS) {
1713 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1714 "%s", isc_result_totext(tresult));
1715 result = ISC_R_FAILURE;
1717 isc_buffer_usedregion(&keydatabuf, &r);
1719 if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
1720 r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
1721 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
1722 "trusted key '%s' has a weak exponent",
1730 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
1731 const char *viewname, dns_rdataclass_t vclass,
1732 isc_log_t *logctx, isc_mem_t *mctx)
1734 const cfg_obj_t *zones = NULL;
1735 const cfg_obj_t *keys = NULL;
1736 const cfg_listelt_t *element, *element2;
1737 isc_symtab_t *symtab = NULL;
1738 isc_result_t result = ISC_R_SUCCESS;
1739 isc_result_t tresult = ISC_R_SUCCESS;
1740 cfg_aclconfctx_t actx;
1741 const cfg_obj_t *obj;
1742 isc_boolean_t enablednssec, enablevalidation;
1745 * Check that all zone statements are syntactically correct and
1746 * there are no duplicate zones.
1748 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1749 ISC_FALSE, &symtab);
1750 if (tresult != ISC_R_SUCCESS)
1751 return (ISC_R_NOMEMORY);
1753 cfg_aclconfctx_init(&actx);
1755 if (voptions != NULL)
1756 (void)cfg_map_get(voptions, "zone", &zones);
1758 (void)cfg_map_get(config, "zone", &zones);
1760 for (element = cfg_list_first(zones);
1762 element = cfg_list_next(element))
1764 isc_result_t tresult;
1765 const cfg_obj_t *zone = cfg_listelt_value(element);
1767 tresult = check_zoneconf(zone, voptions, config, symtab,
1768 vclass, &actx, logctx, mctx);
1769 if (tresult != ISC_R_SUCCESS)
1770 result = ISC_R_FAILURE;
1773 isc_symtab_destroy(&symtab);
1776 * Check that forwarding is reasonable.
1778 if (voptions == NULL) {
1779 const cfg_obj_t *options = NULL;
1780 (void)cfg_map_get(config, "options", &options);
1781 if (options != NULL)
1782 if (check_forward(options, NULL,
1783 logctx) != ISC_R_SUCCESS)
1784 result = ISC_R_FAILURE;
1786 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
1787 result = ISC_R_FAILURE;
1791 * Check that dual-stack-servers is reasonable.
1793 if (voptions == NULL) {
1794 const cfg_obj_t *options = NULL;
1795 (void)cfg_map_get(config, "options", &options);
1796 if (options != NULL)
1797 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1798 result = ISC_R_FAILURE;
1800 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
1801 result = ISC_R_FAILURE;
1805 * Check that rrset-order is reasonable.
1807 if (voptions != NULL) {
1808 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
1809 result = ISC_R_FAILURE;
1813 * Check that all key statements are syntactically correct and
1814 * there are no duplicate keys.
1816 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1817 ISC_FALSE, &symtab);
1818 if (tresult != ISC_R_SUCCESS)
1819 return (ISC_R_NOMEMORY);
1821 (void)cfg_map_get(config, "key", &keys);
1822 tresult = check_keylist(keys, symtab, mctx, logctx);
1823 if (tresult == ISC_R_EXISTS)
1824 result = ISC_R_FAILURE;
1825 else if (tresult != ISC_R_SUCCESS) {
1826 isc_symtab_destroy(&symtab);
1830 if (voptions != NULL) {
1832 (void)cfg_map_get(voptions, "key", &keys);
1833 tresult = check_keylist(keys, symtab, mctx, logctx);
1834 if (tresult == ISC_R_EXISTS)
1835 result = ISC_R_FAILURE;
1836 else if (tresult != ISC_R_SUCCESS) {
1837 isc_symtab_destroy(&symtab);
1843 * Global servers can refer to keys in views.
1845 if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
1846 result = ISC_R_FAILURE;
1848 isc_symtab_destroy(&symtab);
1851 * Check that dnssec-enable/dnssec-validation are sensible.
1854 if (voptions != NULL)
1855 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
1857 (void)cfg_map_get(config, "dnssec-enable", &obj);
1859 enablednssec = ISC_TRUE;
1861 enablednssec = cfg_obj_asboolean(obj);
1864 if (voptions != NULL)
1865 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
1867 (void)cfg_map_get(config, "dnssec-validation", &obj);
1869 enablevalidation = ISC_FALSE; /* XXXMPA Change for 9.5. */
1871 enablevalidation = cfg_obj_asboolean(obj);
1873 if (enablevalidation && !enablednssec)
1874 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1875 "'dnssec-validation yes;' and 'dnssec-enable no;'");
1878 * Check trusted-keys and managed-keys.
1881 if (voptions != NULL)
1882 (void)cfg_map_get(voptions, "trusted-keys", &keys);
1884 (void)cfg_map_get(config, "trusted-keys", &keys);
1886 for (element = cfg_list_first(keys);
1888 element = cfg_list_next(element))
1890 const cfg_obj_t *keylist = cfg_listelt_value(element);
1891 for (element2 = cfg_list_first(keylist);
1893 element2 = cfg_list_next(element2)) {
1894 obj = cfg_listelt_value(element2);
1895 tresult = check_trusted_key(obj, logctx);
1896 if (tresult != ISC_R_SUCCESS)
1904 if (voptions != NULL)
1905 tresult = check_options(voptions, logctx, mctx);
1907 tresult = check_options(config, logctx, mctx);
1908 if (tresult != ISC_R_SUCCESS)
1911 tresult = check_viewacls(&actx, voptions, config, logctx, mctx);
1912 if (tresult != ISC_R_SUCCESS)
1915 tresult = check_recursionacls(&actx, voptions, viewname,
1916 config, logctx, mctx);
1917 if (tresult != ISC_R_SUCCESS)
1920 cfg_aclconfctx_destroy(&actx);
1926 default_channels[] = {
1935 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
1938 const cfg_obj_t *categories = NULL;
1939 const cfg_obj_t *category;
1940 const cfg_obj_t *channels = NULL;
1941 const cfg_obj_t *channel;
1942 const cfg_listelt_t *element;
1943 const cfg_listelt_t *delement;
1944 const char *channelname;
1945 const char *catname;
1946 const cfg_obj_t *fileobj = NULL;
1947 const cfg_obj_t *syslogobj = NULL;
1948 const cfg_obj_t *nullobj = NULL;
1949 const cfg_obj_t *stderrobj = NULL;
1950 const cfg_obj_t *logobj = NULL;
1951 isc_result_t result = ISC_R_SUCCESS;
1952 isc_result_t tresult;
1953 isc_symtab_t *symtab = NULL;
1954 isc_symvalue_t symvalue;
1957 (void)cfg_map_get(config, "logging", &logobj);
1959 return (ISC_R_SUCCESS);
1961 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1962 if (result != ISC_R_SUCCESS)
1965 symvalue.as_cpointer = NULL;
1966 for (i = 0; default_channels[i] != NULL; i++) {
1967 tresult = isc_symtab_define(symtab, default_channels[i], 1,
1968 symvalue, isc_symexists_replace);
1969 if (tresult != ISC_R_SUCCESS)
1973 cfg_map_get(logobj, "channel", &channels);
1975 for (element = cfg_list_first(channels);
1977 element = cfg_list_next(element))
1979 channel = cfg_listelt_value(element);
1980 channelname = cfg_obj_asstring(cfg_map_getname(channel));
1981 fileobj = syslogobj = nullobj = stderrobj = NULL;
1982 (void)cfg_map_get(channel, "file", &fileobj);
1983 (void)cfg_map_get(channel, "syslog", &syslogobj);
1984 (void)cfg_map_get(channel, "null", &nullobj);
1985 (void)cfg_map_get(channel, "stderr", &stderrobj);
1987 if (fileobj != NULL)
1989 if (syslogobj != NULL)
1991 if (nullobj != NULL)
1993 if (stderrobj != NULL)
1996 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
1997 "channel '%s': exactly one of file, syslog, "
1998 "null, and stderr must be present",
2000 result = ISC_R_FAILURE;
2002 tresult = isc_symtab_define(symtab, channelname, 1,
2003 symvalue, isc_symexists_replace);
2004 if (tresult != ISC_R_SUCCESS)
2008 cfg_map_get(logobj, "category", &categories);
2010 for (element = cfg_list_first(categories);
2012 element = cfg_list_next(element))
2014 category = cfg_listelt_value(element);
2015 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
2016 if (isc_log_categorybyname(logctx, catname) == NULL) {
2017 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
2018 "undefined category: '%s'", catname);
2019 result = ISC_R_FAILURE;
2021 channels = cfg_tuple_get(category, "destinations");
2022 for (delement = cfg_list_first(channels);
2024 delement = cfg_list_next(delement))
2026 channel = cfg_listelt_value(delement);
2027 channelname = cfg_obj_asstring(channel);
2028 tresult = isc_symtab_lookup(symtab, channelname, 1,
2030 if (tresult != ISC_R_SUCCESS) {
2031 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2032 "undefined channel: '%s'",
2038 isc_symtab_destroy(&symtab);
2043 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
2046 isc_result_t result = ISC_R_SUCCESS;
2047 const cfg_obj_t *control_keylist;
2048 const cfg_listelt_t *element;
2049 const cfg_obj_t *key;
2052 control_keylist = cfg_tuple_get(control, "keys");
2053 if (cfg_obj_isvoid(control_keylist))
2054 return (ISC_R_SUCCESS);
2056 for (element = cfg_list_first(control_keylist);
2058 element = cfg_list_next(element))
2060 key = cfg_listelt_value(element);
2061 keyval = cfg_obj_asstring(key);
2063 if (!rndckey_exists(keylist, keyval)) {
2064 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2065 "unknown key '%s'", keyval);
2066 result = ISC_R_NOTFOUND;
2073 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
2076 isc_result_t result = ISC_R_SUCCESS, tresult;
2077 cfg_aclconfctx_t actx;
2078 const cfg_listelt_t *element, *element2;
2079 const cfg_obj_t *allow;
2080 const cfg_obj_t *control;
2081 const cfg_obj_t *controls;
2082 const cfg_obj_t *controlslist = NULL;
2083 const cfg_obj_t *inetcontrols;
2084 const cfg_obj_t *unixcontrols;
2085 const cfg_obj_t *keylist = NULL;
2087 isc_uint32_t perm, mask;
2088 dns_acl_t *acl = NULL;
2089 isc_sockaddr_t addr;
2092 (void)cfg_map_get(config, "controls", &controlslist);
2093 if (controlslist == NULL)
2094 return (ISC_R_SUCCESS);
2096 (void)cfg_map_get(config, "key", &keylist);
2098 cfg_aclconfctx_init(&actx);
2101 * INET: Check allow clause.
2102 * UNIX: Check "perm" for sanity, check path length.
2104 for (element = cfg_list_first(controlslist);
2106 element = cfg_list_next(element)) {
2107 controls = cfg_listelt_value(element);
2108 unixcontrols = NULL;
2109 inetcontrols = NULL;
2110 (void)cfg_map_get(controls, "unix", &unixcontrols);
2111 (void)cfg_map_get(controls, "inet", &inetcontrols);
2112 for (element2 = cfg_list_first(inetcontrols);
2114 element2 = cfg_list_next(element2)) {
2115 control = cfg_listelt_value(element2);
2116 allow = cfg_tuple_get(control, "allow");
2117 tresult = cfg_acl_fromconfig(allow, config, logctx,
2118 &actx, mctx, 0, &acl);
2120 dns_acl_detach(&acl);
2121 if (tresult != ISC_R_SUCCESS)
2123 tresult = bind9_check_controlskeys(control, keylist,
2125 if (tresult != ISC_R_SUCCESS)
2128 for (element2 = cfg_list_first(unixcontrols);
2130 element2 = cfg_list_next(element2)) {
2131 control = cfg_listelt_value(element2);
2132 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
2133 tresult = isc_sockaddr_frompath(&addr, path);
2134 if (tresult == ISC_R_NOSPACE) {
2135 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
2136 "unix control '%s': path too long",
2138 result = ISC_R_NOSPACE;
2140 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
2141 for (i = 0; i < 3; i++) {
2142 #ifdef NEED_SECURE_DIRECTORY
2143 mask = (0x1 << (i*3)); /* SEARCH */
2145 mask = (0x6 << (i*3)); /* READ + WRITE */
2147 if ((perm & mask) == mask)
2151 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2152 "unix control '%s' allows access "
2153 "to everyone", path);
2154 } else if (i == 3) {
2155 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2156 "unix control '%s' allows access "
2159 tresult = bind9_check_controlskeys(control, keylist,
2161 if (tresult != ISC_R_SUCCESS)
2165 cfg_aclconfctx_destroy(&actx);
2170 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
2173 const cfg_obj_t *options = NULL;
2174 const cfg_obj_t *views = NULL;
2175 const cfg_obj_t *acls = NULL;
2176 const cfg_obj_t *kals = NULL;
2177 const cfg_obj_t *obj;
2178 const cfg_listelt_t *velement;
2179 isc_result_t result = ISC_R_SUCCESS;
2180 isc_result_t tresult;
2181 isc_symtab_t *symtab = NULL;
2183 static const char *builtin[] = { "localhost", "localnets",
2186 (void)cfg_map_get(config, "options", &options);
2188 if (options != NULL &&
2189 check_options(options, logctx, mctx) != ISC_R_SUCCESS)
2190 result = ISC_R_FAILURE;
2192 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
2193 result = ISC_R_FAILURE;
2195 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
2196 result = ISC_R_FAILURE;
2198 if (options != NULL &&
2199 check_order(options, logctx) != ISC_R_SUCCESS)
2200 result = ISC_R_FAILURE;
2202 (void)cfg_map_get(config, "view", &views);
2204 if (views != NULL && options != NULL)
2205 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2206 result = ISC_R_FAILURE;
2208 if (views == NULL) {
2209 if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
2210 logctx, mctx) != ISC_R_SUCCESS)
2211 result = ISC_R_FAILURE;
2213 const cfg_obj_t *zones = NULL;
2215 (void)cfg_map_get(config, "zone", &zones);
2216 if (zones != NULL) {
2217 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
2218 "when using 'view' statements, "
2219 "all zones must be in views");
2220 result = ISC_R_FAILURE;
2224 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
2225 if (tresult != ISC_R_SUCCESS)
2227 for (velement = cfg_list_first(views);
2229 velement = cfg_list_next(velement))
2231 const cfg_obj_t *view = cfg_listelt_value(velement);
2232 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
2233 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
2234 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
2235 dns_rdataclass_t vclass = dns_rdataclass_in;
2236 isc_result_t tresult = ISC_R_SUCCESS;
2237 const char *key = cfg_obj_asstring(vname);
2238 isc_symvalue_t symvalue;
2240 if (cfg_obj_isstring(vclassobj)) {
2243 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
2244 r.length = strlen(r.base);
2245 tresult = dns_rdataclass_fromtext(&vclass, &r);
2246 if (tresult != ISC_R_SUCCESS)
2247 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
2248 "view '%s': invalid class %s",
2249 cfg_obj_asstring(vname), r.base);
2251 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
2252 symvalue.as_cpointer = view;
2253 tresult = isc_symtab_define(symtab, key, vclass,
2255 isc_symexists_reject);
2256 if (tresult == ISC_R_EXISTS) {
2259 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
2260 vclass, &symvalue) == ISC_R_SUCCESS);
2261 file = cfg_obj_file(symvalue.as_cpointer);
2262 line = cfg_obj_line(symvalue.as_cpointer);
2263 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2264 "view '%s': already exists "
2265 "previous definition: %s:%u",
2268 } else if (tresult != ISC_R_SUCCESS) {
2270 } else if ((strcasecmp(key, "_bind") == 0 &&
2271 vclass == dns_rdataclass_ch) ||
2272 (strcasecmp(key, "_default") == 0 &&
2273 vclass == dns_rdataclass_in)) {
2274 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2275 "attempt to redefine builtin view "
2277 result = ISC_R_EXISTS;
2280 if (tresult == ISC_R_SUCCESS)
2281 tresult = check_viewconf(config, voptions, key,
2282 vclass, logctx, mctx);
2283 if (tresult != ISC_R_SUCCESS)
2284 result = ISC_R_FAILURE;
2287 isc_symtab_destroy(&symtab);
2289 if (views != NULL && options != NULL) {
2291 tresult = cfg_map_get(options, "cache-file", &obj);
2292 if (tresult == ISC_R_SUCCESS) {
2293 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2294 "'cache-file' cannot be a global "
2295 "option if views are present");
2296 result = ISC_R_FAILURE;
2300 cfg_map_get(config, "acl", &acls);
2303 const cfg_listelt_t *elt;
2304 const cfg_listelt_t *elt2;
2305 const char *aclname;
2307 for (elt = cfg_list_first(acls);
2309 elt = cfg_list_next(elt)) {
2310 const cfg_obj_t *acl = cfg_listelt_value(elt);
2311 unsigned int line = cfg_obj_line(acl);
2314 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2316 i < sizeof(builtin) / sizeof(builtin[0]);
2318 if (strcasecmp(aclname, builtin[i]) == 0) {
2319 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
2320 "attempt to redefine "
2323 result = ISC_R_FAILURE;
2327 for (elt2 = cfg_list_next(elt);
2329 elt2 = cfg_list_next(elt2)) {
2330 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2332 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2334 if (strcasecmp(aclname, name) == 0) {
2335 const char *file = cfg_obj_file(acl);
2338 file = "<unknown file>";
2340 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2341 "attempt to redefine "
2342 "acl '%s' previous "
2343 "definition: %s:%u",
2345 result = ISC_R_FAILURE;
2351 tresult = cfg_map_get(config, "kal", &kals);
2352 if (tresult == ISC_R_SUCCESS) {
2353 const cfg_listelt_t *elt;
2354 const cfg_listelt_t *elt2;
2355 const char *aclname;
2357 for (elt = cfg_list_first(kals);
2359 elt = cfg_list_next(elt)) {
2360 const cfg_obj_t *acl = cfg_listelt_value(elt);
2362 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2364 for (elt2 = cfg_list_next(elt);
2366 elt2 = cfg_list_next(elt2)) {
2367 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2369 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2371 if (strcasecmp(aclname, name) == 0) {
2372 const char *file = cfg_obj_file(acl);
2373 unsigned int line = cfg_obj_line(acl);
2376 file = "<unknown file>";
2378 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2379 "attempt to redefine "
2380 "kal '%s' previous "
2381 "definition: %s:%u",
2383 result = ISC_R_FAILURE;