2 * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2001-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: check.c,v 1.44.18.31 2006/08/21 00:09:52 marka Exp $ */
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/symtab.h>
39 #include <dns/fixedname.h>
40 #include <dns/rdataclass.h>
41 #include <dns/rdatatype.h>
42 #include <dns/secalg.h>
44 #include <isccfg/aclconf.h>
45 #include <isccfg/cfg.h>
47 #include <bind9/check.h>
50 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
53 isc_mem_free(userarg, key);
57 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
58 isc_result_t result = ISC_R_SUCCESS;
61 dns_fixedname_t fixed;
63 dns_rdataclass_t rdclass;
64 dns_rdatatype_t rdtype;
68 dns_fixedname_init(&fixed);
69 obj = cfg_tuple_get(ent, "class");
70 if (cfg_obj_isstring(obj)) {
72 DE_CONST(cfg_obj_asstring(obj), r.base);
73 r.length = strlen(r.base);
74 tresult = dns_rdataclass_fromtext(&rdclass, &r);
75 if (tresult != ISC_R_SUCCESS) {
76 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
77 "rrset-order: invalid class '%s'",
79 result = ISC_R_FAILURE;
83 obj = cfg_tuple_get(ent, "type");
84 if (cfg_obj_isstring(obj)) {
86 DE_CONST(cfg_obj_asstring(obj), r.base);
87 r.length = strlen(r.base);
88 tresult = dns_rdatatype_fromtext(&rdtype, &r);
89 if (tresult != ISC_R_SUCCESS) {
90 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
91 "rrset-order: invalid type '%s'",
93 result = ISC_R_FAILURE;
97 obj = cfg_tuple_get(ent, "name");
98 if (cfg_obj_isstring(obj)) {
99 str = cfg_obj_asstring(obj);
100 isc_buffer_init(&b, str, strlen(str));
101 isc_buffer_add(&b, strlen(str));
102 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
103 dns_rootname, ISC_FALSE, NULL);
104 if (tresult != ISC_R_SUCCESS) {
105 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
106 "rrset-order: invalid name '%s'", str);
107 result = ISC_R_FAILURE;
111 obj = cfg_tuple_get(ent, "order");
112 if (!cfg_obj_isstring(obj) ||
113 strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
114 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
115 "rrset-order: keyword 'order' missing");
116 result = ISC_R_FAILURE;
119 obj = cfg_tuple_get(ent, "ordering");
120 if (!cfg_obj_isstring(obj)) {
121 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
122 "rrset-order: missing ordering");
123 result = ISC_R_FAILURE;
124 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") != 0 &&
125 strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
126 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
127 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
128 "rrset-order: invalid order '%s'",
129 cfg_obj_asstring(obj));
130 result = ISC_R_FAILURE;
136 check_order(const cfg_obj_t *options, isc_log_t *logctx) {
137 isc_result_t result = ISC_R_SUCCESS;
138 isc_result_t tresult;
139 const cfg_listelt_t *element;
140 const cfg_obj_t *obj = NULL;
142 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
145 for (element = cfg_list_first(obj);
147 element = cfg_list_next(element))
149 tresult = check_orderent(cfg_listelt_value(element), logctx);
150 if (tresult != ISC_R_SUCCESS)
157 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
158 const cfg_listelt_t *element;
159 const cfg_obj_t *alternates = NULL;
160 const cfg_obj_t *value;
161 const cfg_obj_t *obj;
163 dns_fixedname_t fixed;
166 isc_result_t result = ISC_R_SUCCESS;
167 isc_result_t tresult;
169 (void)cfg_map_get(options, "dual-stack-servers", &alternates);
171 if (alternates == NULL)
172 return (ISC_R_SUCCESS);
174 obj = cfg_tuple_get(alternates, "port");
175 if (cfg_obj_isuint32(obj)) {
176 isc_uint32_t val = cfg_obj_asuint32(obj);
177 if (val > ISC_UINT16_MAX) {
178 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
179 "port '%u' out of range", val);
180 result = ISC_R_FAILURE;
183 obj = cfg_tuple_get(alternates, "addresses");
184 for (element = cfg_list_first(obj);
186 element = cfg_list_next(element)) {
187 value = cfg_listelt_value(element);
188 if (cfg_obj_issockaddr(value))
190 obj = cfg_tuple_get(value, "name");
191 str = cfg_obj_asstring(obj);
192 isc_buffer_init(&buffer, str, strlen(str));
193 isc_buffer_add(&buffer, strlen(str));
194 dns_fixedname_init(&fixed);
195 name = dns_fixedname_name(&fixed);
196 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
198 if (tresult != ISC_R_SUCCESS) {
199 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
200 "bad name '%s'", str);
201 result = ISC_R_FAILURE;
203 obj = cfg_tuple_get(value, "port");
204 if (cfg_obj_isuint32(obj)) {
205 isc_uint32_t val = cfg_obj_asuint32(obj);
206 if (val > ISC_UINT16_MAX) {
207 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
208 "port '%u' out of range", val);
209 result = ISC_R_FAILURE;
217 check_forward(const cfg_obj_t *options, isc_log_t *logctx) {
218 const cfg_obj_t *forward = NULL;
219 const cfg_obj_t *forwarders = NULL;
221 (void)cfg_map_get(options, "forward", &forward);
222 (void)cfg_map_get(options, "forwarders", &forwarders);
224 if (forward != NULL && forwarders == NULL) {
225 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
226 "no matching 'forwarders' statement");
227 return (ISC_R_FAILURE);
229 return (ISC_R_SUCCESS);
233 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
234 isc_result_t result = ISC_R_SUCCESS;
235 isc_result_t tresult;
236 const cfg_listelt_t *element;
239 dns_fixedname_t fixed;
241 const cfg_obj_t *obj;
243 dns_fixedname_init(&fixed);
244 name = dns_fixedname_name(&fixed);
245 obj = cfg_tuple_get(disabled, "name");
246 str = cfg_obj_asstring(obj);
247 isc_buffer_init(&b, str, strlen(str));
248 isc_buffer_add(&b, strlen(str));
249 tresult = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
250 if (tresult != ISC_R_SUCCESS) {
251 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
252 "bad domain name '%s'", str);
256 obj = cfg_tuple_get(disabled, "algorithms");
258 for (element = cfg_list_first(obj);
260 element = cfg_list_next(element))
264 isc_result_t tresult;
266 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
267 r.length = strlen(r.base);
269 tresult = dns_secalg_fromtext(&alg, &r);
270 if (tresult != ISC_R_SUCCESS) {
272 result = isc_parse_uint8(&ui, r.base, 10);
274 if (tresult != ISC_R_SUCCESS) {
275 cfg_obj_log(cfg_listelt_value(element), logctx,
276 ISC_LOG_ERROR, "invalid algorithm '%s'",
285 nameexist(const cfg_obj_t *obj, const char *name, int value,
286 isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
293 isc_symvalue_t symvalue;
295 key = isc_mem_strdup(mctx, name);
297 return (ISC_R_NOMEMORY);
298 symvalue.as_cpointer = obj;
299 result = isc_symtab_define(symtab, key, value, symvalue,
300 isc_symexists_reject);
301 if (result == ISC_R_EXISTS) {
302 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
303 &symvalue) == ISC_R_SUCCESS);
304 file = cfg_obj_file(symvalue.as_cpointer);
305 line = cfg_obj_line(symvalue.as_cpointer);
308 file = "<unknown file>";
309 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
310 isc_mem_free(mctx, key);
311 result = ISC_R_EXISTS;
312 } else if (result != ISC_R_SUCCESS) {
313 isc_mem_free(mctx, key);
319 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
322 const cfg_obj_t *obj;
323 char namebuf[DNS_NAME_FORMATSIZE];
325 dns_fixedname_t fixed;
328 isc_result_t result = ISC_R_SUCCESS;
330 dns_fixedname_init(&fixed);
331 name = dns_fixedname_name(&fixed);
332 obj = cfg_tuple_get(secure, "name");
333 str = cfg_obj_asstring(obj);
334 isc_buffer_init(&b, str, strlen(str));
335 isc_buffer_add(&b, strlen(str));
336 result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
337 if (result != ISC_R_SUCCESS) {
338 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
339 "bad domain name '%s'", str);
341 dns_name_format(name, namebuf, sizeof(namebuf));
342 result = nameexist(secure, namebuf, 1, symtab,
343 "dnssec-must-be-secure '%s': already "
344 "exists previous definition: %s:%u",
351 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
352 const cfg_obj_t *voptions, const cfg_obj_t *config,
353 isc_log_t *logctx, isc_mem_t *mctx)
356 const cfg_obj_t *aclobj = NULL;
357 const cfg_obj_t *options;
358 dns_acl_t *acl = NULL;
360 if (zconfig != NULL) {
361 options = cfg_tuple_get(zconfig, "options");
362 cfg_map_get(options, aclname, &aclobj);
364 if (voptions != NULL && aclobj == NULL)
365 cfg_map_get(voptions, aclname, &aclobj);
366 if (config != NULL && aclobj == NULL) {
368 cfg_map_get(config, "options", &options);
370 cfg_map_get(options, aclname, &aclobj);
373 return (ISC_R_SUCCESS);
374 result = cfg_acl_fromconfig(aclobj, config, logctx, actx, mctx, &acl);
376 dns_acl_detach(&acl);
381 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
382 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
384 isc_result_t result = ISC_R_SUCCESS, tresult;
387 static const char *acls[] = { "allow-query", "allow-query-cache",
388 "allow-recursion", "blackhole", "match-clients",
389 "match-destinations", "sortlist", NULL };
391 while (acls[i] != NULL) {
392 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
394 if (tresult != ISC_R_SUCCESS)
407 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
408 isc_result_t result = ISC_R_SUCCESS;
409 isc_result_t tresult;
411 const cfg_obj_t *obj = NULL;
412 const cfg_listelt_t *element;
413 isc_symtab_t *symtab = NULL;
414 dns_fixedname_t fixed;
419 static intervaltable intervals[] = {
420 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
421 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
422 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
423 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
424 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
425 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
426 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
427 { "sig-validity-interval", 86400, 10 * 366 }, /* 10 years */
428 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
432 * Check that fields specified in units of time other than seconds
433 * have reasonable values.
435 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
438 (void)cfg_map_get(options, intervals[i].name, &obj);
441 val = cfg_obj_asuint32(obj);
442 if (val > intervals[i].max) {
443 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
444 "%s '%u' is out of range (0..%u)",
445 intervals[i].name, val,
447 result = ISC_R_RANGE;
448 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
449 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
450 "%s '%d' is out of range",
451 intervals[i].name, val);
452 result = ISC_R_RANGE;
456 (void)cfg_map_get(options, "preferred-glue", &obj);
459 str = cfg_obj_asstring(obj);
460 if (strcasecmp(str, "a") != 0 &&
461 strcasecmp(str, "aaaa") != 0 &&
462 strcasecmp(str, "none") != 0)
463 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
464 "preferred-glue unexpected value '%s'",
468 (void)cfg_map_get(options, "root-delegation-only", &obj);
470 if (!cfg_obj_isvoid(obj)) {
471 const cfg_listelt_t *element;
472 const cfg_obj_t *exclude;
474 dns_fixedname_t fixed;
478 dns_fixedname_init(&fixed);
479 name = dns_fixedname_name(&fixed);
480 for (element = cfg_list_first(obj);
482 element = cfg_list_next(element)) {
483 exclude = cfg_listelt_value(element);
484 str = cfg_obj_asstring(exclude);
485 isc_buffer_init(&b, str, strlen(str));
486 isc_buffer_add(&b, strlen(str));
487 tresult = dns_name_fromtext(name, &b,
490 if (tresult != ISC_R_SUCCESS) {
491 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
492 "bad domain name '%s'",
501 * Set supported DNSSEC algorithms.
504 (void)cfg_map_get(options, "disable-algorithms", &obj);
506 for (element = cfg_list_first(obj);
508 element = cfg_list_next(element))
510 obj = cfg_listelt_value(element);
511 tresult = disabled_algorithms(obj, logctx);
512 if (tresult != ISC_R_SUCCESS)
517 dns_fixedname_init(&fixed);
518 name = dns_fixedname_name(&fixed);
521 * Check the DLV zone name.
524 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
526 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
528 if (tresult != ISC_R_SUCCESS)
530 for (element = cfg_list_first(obj);
532 element = cfg_list_next(element))
536 obj = cfg_listelt_value(element);
538 dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain"));
539 isc_buffer_init(&b, dlv, strlen(dlv));
540 isc_buffer_add(&b, strlen(dlv));
541 tresult = dns_name_fromtext(name, &b, dns_rootname,
543 if (tresult != ISC_R_SUCCESS) {
544 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
545 "bad domain name '%s'", dlv);
548 if (symtab != NULL) {
549 tresult = nameexist(obj, dlv, 1, symtab,
550 "dnssec-lookaside '%s': "
551 "already exists previous "
554 if (tresult != ISC_R_SUCCESS &&
555 result == ISC_R_SUCCESS)
559 * XXXMPA to be removed when multiple lookaside
560 * namespaces are supported.
562 if (!dns_name_equal(dns_rootname, name)) {
563 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
564 "dnssec-lookaside '%s': "
565 "non-root not yet supported", dlv);
566 if (result == ISC_R_SUCCESS)
567 result = ISC_R_FAILURE;
569 dlv = cfg_obj_asstring(cfg_tuple_get(obj,
571 isc_buffer_init(&b, dlv, strlen(dlv));
572 isc_buffer_add(&b, strlen(dlv));
573 tresult = dns_name_fromtext(name, &b, dns_rootname,
575 if (tresult != ISC_R_SUCCESS) {
576 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
577 "bad domain name '%s'", dlv);
578 if (result == ISC_R_SUCCESS)
583 isc_symtab_destroy(&symtab);
587 * Check dnssec-must-be-secure.
590 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
592 isc_symtab_t *symtab = NULL;
593 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
595 if (tresult != ISC_R_SUCCESS)
597 for (element = cfg_list_first(obj);
599 element = cfg_list_next(element))
601 obj = cfg_listelt_value(element);
602 tresult = mustbesecure(obj, symtab, logctx, mctx);
603 if (tresult != ISC_R_SUCCESS)
607 isc_symtab_destroy(&symtab);
611 * Check empty zone configuration.
614 (void)cfg_map_get(options, "empty-server", &obj);
616 str = cfg_obj_asstring(obj);
617 isc_buffer_init(&b, str, strlen(str));
618 isc_buffer_add(&b, strlen(str));
619 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
620 dns_rootname, ISC_FALSE, NULL);
621 if (tresult != ISC_R_SUCCESS) {
622 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
623 "empty-server: invalid name '%s'", str);
624 result = ISC_R_FAILURE;
629 (void)cfg_map_get(options, "empty-contact", &obj);
631 str = cfg_obj_asstring(obj);
632 isc_buffer_init(&b, str, strlen(str));
633 isc_buffer_add(&b, strlen(str));
634 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
635 dns_rootname, ISC_FALSE, NULL);
636 if (tresult != ISC_R_SUCCESS) {
637 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
638 "empty-contact: invalid name '%s'", str);
639 result = ISC_R_FAILURE;
644 (void)cfg_map_get(options, "disable-empty-zone", &obj);
645 for (element = cfg_list_first(obj);
647 element = cfg_list_next(element))
649 obj = cfg_listelt_value(element);
650 str = cfg_obj_asstring(obj);
651 isc_buffer_init(&b, str, strlen(str));
652 isc_buffer_add(&b, strlen(str));
653 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
654 dns_rootname, ISC_FALSE, NULL);
655 if (tresult != ISC_R_SUCCESS) {
656 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
657 "disable-empty-zone: invalid name '%s'",
659 result = ISC_R_FAILURE;
667 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
669 const cfg_obj_t *masters = NULL;
670 const cfg_listelt_t *elt;
672 result = cfg_map_get(cctx, "masters", &masters);
673 if (result != ISC_R_SUCCESS)
675 for (elt = cfg_list_first(masters);
677 elt = cfg_list_next(elt)) {
678 const cfg_obj_t *list;
679 const char *listname;
681 list = cfg_listelt_value(elt);
682 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
684 if (strcasecmp(listname, name) == 0) {
686 return (ISC_R_SUCCESS);
689 return (ISC_R_NOTFOUND);
693 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
694 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
696 isc_result_t result = ISC_R_SUCCESS;
697 isc_result_t tresult;
698 isc_uint32_t count = 0;
699 isc_symtab_t *symtab = NULL;
700 isc_symvalue_t symvalue;
701 const cfg_listelt_t *element;
702 const cfg_listelt_t **stack = NULL;
703 isc_uint32_t stackcount = 0, pushed = 0;
704 const cfg_obj_t *list;
706 REQUIRE(countp != NULL);
707 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
708 if (result != ISC_R_SUCCESS) {
714 list = cfg_tuple_get(obj, "addresses");
715 element = cfg_list_first(list);
719 element = cfg_list_next(element))
721 const char *listname;
722 const cfg_obj_t *addr;
723 const cfg_obj_t *key;
725 addr = cfg_tuple_get(cfg_listelt_value(element),
727 key = cfg_tuple_get(cfg_listelt_value(element), "key");
729 if (cfg_obj_issockaddr(addr)) {
733 if (!cfg_obj_isvoid(key)) {
734 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
735 "unexpected token '%s'",
736 cfg_obj_asstring(key));
737 if (result == ISC_R_SUCCESS)
738 result = ISC_R_FAILURE;
740 listname = cfg_obj_asstring(addr);
741 symvalue.as_cpointer = addr;
742 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
743 isc_symexists_reject);
744 if (tresult == ISC_R_EXISTS)
746 tresult = get_masters_def(config, listname, &obj);
747 if (tresult != ISC_R_SUCCESS) {
748 if (result == ISC_R_SUCCESS)
750 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
751 "unable to find masters list '%s'",
756 if (stackcount == pushed) {
758 isc_uint32_t newlen = stackcount + 16;
759 size_t newsize, oldsize;
761 newsize = newlen * sizeof(*stack);
762 oldsize = stackcount * sizeof(*stack);
763 new = isc_mem_get(mctx, newsize);
766 if (stackcount != 0) {
767 memcpy(new, stack, oldsize);
768 isc_mem_put(mctx, stack, oldsize);
773 stack[pushed++] = cfg_list_next(element);
777 element = stack[--pushed];
782 isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
783 isc_symtab_destroy(&symtab);
789 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
790 isc_result_t result = ISC_R_SUCCESS;
791 isc_result_t tresult;
792 const cfg_listelt_t *element;
793 const cfg_listelt_t *element2;
794 dns_fixedname_t fixed;
798 for (element = cfg_list_first(policy);
800 element = cfg_list_next(element))
802 const cfg_obj_t *stmt = cfg_listelt_value(element);
803 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
804 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
805 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
806 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
808 dns_fixedname_init(&fixed);
809 str = cfg_obj_asstring(identity);
810 isc_buffer_init(&b, str, strlen(str));
811 isc_buffer_add(&b, strlen(str));
812 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
813 dns_rootname, ISC_FALSE, NULL);
814 if (tresult != ISC_R_SUCCESS) {
815 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
816 "'%s' is not a valid name", str);
820 dns_fixedname_init(&fixed);
821 str = cfg_obj_asstring(dname);
822 isc_buffer_init(&b, str, strlen(str));
823 isc_buffer_add(&b, strlen(str));
824 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
825 dns_rootname, ISC_FALSE, NULL);
826 if (tresult != ISC_R_SUCCESS) {
827 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
828 "'%s' is not a valid name", str);
831 if (tresult == ISC_R_SUCCESS &&
832 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
833 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
834 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
835 "'%s' is not a wildcard", str);
836 result = ISC_R_FAILURE;
839 for (element2 = cfg_list_first(typelist);
841 element2 = cfg_list_next(element2))
843 const cfg_obj_t *typeobj;
845 dns_rdatatype_t type;
847 typeobj = cfg_listelt_value(element2);
848 DE_CONST(cfg_obj_asstring(typeobj), r.base);
849 r.length = strlen(r.base);
851 tresult = dns_rdatatype_fromtext(&type, &r);
852 if (tresult != ISC_R_SUCCESS) {
853 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
854 "'%s' is not a valid type", r.base);
866 #define FORWARDZONE 16
867 #define DELEGATIONZONE 32
876 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
877 const cfg_obj_t *config, isc_symtab_t *symtab,
878 dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
879 isc_log_t *logctx, isc_mem_t *mctx)
884 const cfg_obj_t *zoptions;
885 const cfg_obj_t *obj = NULL;
886 isc_result_t result = ISC_R_SUCCESS;
887 isc_result_t tresult;
889 dns_rdataclass_t zclass;
890 dns_fixedname_t fixedname;
893 static optionstable options[] = {
894 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL },
895 { "allow-notify", SLAVEZONE | CHECKACL },
896 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
897 { "notify", MASTERZONE | SLAVEZONE },
898 { "also-notify", MASTERZONE | SLAVEZONE },
899 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
900 { "delegation-only", HINTZONE | STUBZONE },
901 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
902 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
903 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
904 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
905 { "notify-source", MASTERZONE | SLAVEZONE },
906 { "notify-source-v6", MASTERZONE | SLAVEZONE },
907 { "transfer-source", SLAVEZONE | STUBZONE },
908 { "transfer-source-v6", SLAVEZONE | STUBZONE },
909 { "max-transfer-time-in", SLAVEZONE | STUBZONE },
910 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
911 { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
912 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
913 { "max-retry-time", SLAVEZONE | STUBZONE },
914 { "min-retry-time", SLAVEZONE | STUBZONE },
915 { "max-refresh-time", SLAVEZONE | STUBZONE },
916 { "min-refresh-time", SLAVEZONE | STUBZONE },
917 { "sig-validity-interval", MASTERZONE },
918 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE },
919 { "allow-update", MASTERZONE | CHECKACL },
920 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
921 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
922 { "journal", MASTERZONE | SLAVEZONE },
923 { "ixfr-base", MASTERZONE | SLAVEZONE },
924 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
925 { "masters", SLAVEZONE | STUBZONE },
926 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
927 { "update-policy", MASTERZONE },
928 { "database", MASTERZONE | SLAVEZONE | STUBZONE },
929 { "key-directory", MASTERZONE },
930 { "check-wildcard", MASTERZONE },
931 { "check-mx", MASTERZONE },
932 { "integrity-check", MASTERZONE },
933 { "check-mx-cname", MASTERZONE },
934 { "check-srv-cname", MASTERZONE },
935 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
936 { "update-check-ksk", MASTERZONE },
939 static optionstable dialups[] = {
940 { "notify", MASTERZONE | SLAVEZONE },
941 { "notify-passive", SLAVEZONE },
942 { "refresh", SLAVEZONE | STUBZONE },
943 { "passive", SLAVEZONE | STUBZONE },
946 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
948 zoptions = cfg_tuple_get(zconfig, "options");
951 (void)cfg_map_get(zoptions, "type", &obj);
953 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
954 "zone '%s': type not present", zname);
955 return (ISC_R_FAILURE);
958 typestr = cfg_obj_asstring(obj);
959 if (strcasecmp(typestr, "master") == 0)
961 else if (strcasecmp(typestr, "slave") == 0)
963 else if (strcasecmp(typestr, "stub") == 0)
965 else if (strcasecmp(typestr, "forward") == 0)
967 else if (strcasecmp(typestr, "hint") == 0)
969 else if (strcasecmp(typestr, "delegation-only") == 0)
970 ztype = DELEGATIONZONE;
972 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
973 "zone '%s': invalid type %s",
975 return (ISC_R_FAILURE);
978 obj = cfg_tuple_get(zconfig, "class");
979 if (cfg_obj_isstring(obj)) {
982 DE_CONST(cfg_obj_asstring(obj), r.base);
983 r.length = strlen(r.base);
984 result = dns_rdataclass_fromtext(&zclass, &r);
985 if (result != ISC_R_SUCCESS) {
986 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
987 "zone '%s': invalid class %s",
989 return (ISC_R_FAILURE);
991 if (zclass != defclass) {
992 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
993 "zone '%s': class '%s' does not "
994 "match view/default class",
996 return (ISC_R_FAILURE);
1001 * Look for an already existing zone.
1002 * We need to make this cannonical as isc_symtab_define()
1003 * deals with strings.
1005 dns_fixedname_init(&fixedname);
1006 isc_buffer_init(&b, zname, strlen(zname));
1007 isc_buffer_add(&b, strlen(zname));
1008 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1009 dns_rootname, ISC_TRUE, NULL);
1010 if (result != ISC_R_SUCCESS) {
1011 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1012 "zone '%s': is not a valid name", zname);
1013 tresult = ISC_R_FAILURE;
1015 char namebuf[DNS_NAME_FORMATSIZE];
1017 dns_name_format(dns_fixedname_name(&fixedname),
1018 namebuf, sizeof(namebuf));
1019 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
1020 symtab, "zone '%s': already exists "
1021 "previous definition: %s:%u", logctx, mctx);
1022 if (tresult != ISC_R_SUCCESS)
1027 * Look for inappropriate options for the given zone type.
1028 * Check that ACLs expand correctly.
1030 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1032 if ((options[i].allowed & ztype) == 0 &&
1033 cfg_map_get(zoptions, options[i].name, &obj) ==
1036 if (strcmp(options[i].name, "allow-update") != 0 ||
1037 ztype != SLAVEZONE) {
1038 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1039 "option '%s' is not allowed "
1040 "in '%s' zone '%s'",
1041 options[i].name, typestr, zname);
1042 result = ISC_R_FAILURE;
1044 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1045 "option '%s' is not allowed "
1046 "in '%s' zone '%s'",
1047 options[i].name, typestr, zname);
1050 if ((options[i].allowed & ztype) != 0 &&
1051 (options[i].allowed & CHECKACL) != 0) {
1053 tresult = checkacl(options[i].name, actx, zconfig,
1054 voptions, config, logctx, mctx);
1055 if (tresult != ISC_R_SUCCESS)
1062 * Slave & stub zones must have a "masters" field.
1064 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1066 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1067 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1068 "zone '%s': missing 'masters' entry",
1070 result = ISC_R_FAILURE;
1073 tresult = validate_masters(obj, config, &count,
1075 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1077 if (tresult == ISC_R_SUCCESS && count == 0) {
1078 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1079 "zone '%s': empty 'masters' entry",
1081 result = ISC_R_FAILURE;
1087 * Master zones can't have both "allow-update" and "update-policy".
1089 if (ztype == MASTERZONE) {
1090 isc_result_t res1, res2;
1092 res1 = cfg_map_get(zoptions, "allow-update", &obj);
1094 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1095 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1096 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1097 "zone '%s': 'allow-update' is ignored "
1098 "when 'update-policy' is present",
1100 result = ISC_R_FAILURE;
1101 } else if (res2 == ISC_R_SUCCESS &&
1102 check_update_policy(obj, logctx) != ISC_R_SUCCESS)
1103 result = ISC_R_FAILURE;
1107 * Check the excessively complicated "dialup" option.
1109 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1110 const cfg_obj_t *dialup = NULL;
1111 (void)cfg_map_get(zoptions, "dialup", &dialup);
1112 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1113 const char *str = cfg_obj_asstring(dialup);
1115 i < sizeof(dialups) / sizeof(dialups[0]);
1118 if (strcasecmp(dialups[i].name, str) != 0)
1120 if ((dialups[i].allowed & ztype) == 0) {
1121 cfg_obj_log(obj, logctx,
1123 "dialup type '%s' is not "
1126 str, typestr, zname);
1127 result = ISC_R_FAILURE;
1131 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1132 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1133 "invalid dialup type '%s' in zone "
1134 "'%s'", str, zname);
1135 result = ISC_R_FAILURE;
1141 * Check that forwarding is reasonable.
1143 if (check_forward(zoptions, logctx) != ISC_R_SUCCESS)
1144 result = ISC_R_FAILURE;
1147 * Check various options.
1149 tresult = check_options(zoptions, logctx, mctx);
1150 if (tresult != ISC_R_SUCCESS)
1154 * If the zone type is rbt/rbt64 then master/hint zones
1155 * require file clauses.
1158 tresult = cfg_map_get(zoptions, "database", &obj);
1159 if (tresult == ISC_R_NOTFOUND ||
1160 (tresult == ISC_R_SUCCESS &&
1161 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1162 strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
1164 tresult = cfg_map_get(zoptions, "file", &obj);
1165 if (tresult != ISC_R_SUCCESS &&
1166 (ztype == MASTERZONE || ztype == HINTZONE)) {
1167 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1168 "zone '%s': missing 'file' entry",
1178 typedef struct keyalgorithms {
1184 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1185 const cfg_obj_t *algobj = NULL;
1186 const cfg_obj_t *secretobj = NULL;
1187 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1188 const char *algorithm;
1191 static const algorithmtable algorithms[] = {
1192 { "hmac-md5", 128 },
1193 { "hmac-md5.sig-alg.reg.int", 0 },
1194 { "hmac-md5.sig-alg.reg.int.", 0 },
1195 { "hmac-sha1", 160 },
1196 { "hmac-sha224", 224 },
1197 { "hmac-sha256", 256 },
1198 { "hmac-sha384", 384 },
1199 { "hmac-sha512", 512 },
1203 (void)cfg_map_get(key, "algorithm", &algobj);
1204 (void)cfg_map_get(key, "secret", &secretobj);
1205 if (secretobj == NULL || algobj == NULL) {
1206 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1207 "key '%s' must have both 'secret' and "
1208 "'algorithm' defined",
1210 return (ISC_R_FAILURE);
1213 algorithm = cfg_obj_asstring(algobj);
1214 for (i = 0; algorithms[i].name != NULL; i++) {
1215 len = strlen(algorithms[i].name);
1216 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1217 (algorithm[len] == '\0' ||
1218 (algorithms[i].size != 0 && algorithm[len] == '-')))
1221 if (algorithms[i].name == NULL) {
1222 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1223 "unknown algorithm '%s'", algorithm);
1224 return (ISC_R_NOTFOUND);
1226 if (algorithm[len] == '-') {
1227 isc_uint16_t digestbits;
1228 isc_result_t result;
1229 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1230 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1231 if (result == ISC_R_RANGE ||
1232 digestbits > algorithms[i].size) {
1233 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1234 "key '%s' digest-bits too large "
1235 "[%u..%u]", keyname,
1236 algorithms[i].size / 2,
1237 algorithms[i].size);
1238 return (ISC_R_RANGE);
1240 if ((digestbits % 8) != 0) {
1241 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1242 "key '%s' digest-bits not multiple"
1244 return (ISC_R_RANGE);
1247 * Recommended minima for hmac algorithms.
1249 if ((digestbits < (algorithms[i].size / 2U) ||
1250 (digestbits < 80U)))
1251 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
1252 "key '%s' digest-bits too small "
1254 algorithms[i].size/2);
1256 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1257 "key '%s': unable to parse digest-bits",
1262 return (ISC_R_SUCCESS);
1266 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab, isc_log_t *logctx) {
1267 isc_result_t result = ISC_R_SUCCESS;
1268 isc_result_t tresult;
1269 const cfg_listelt_t *element;
1271 for (element = cfg_list_first(keys);
1273 element = cfg_list_next(element))
1275 const cfg_obj_t *key = cfg_listelt_value(element);
1276 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1277 isc_symvalue_t symvalue;
1279 tresult = bind9_check_key(key, logctx);
1280 if (tresult != ISC_R_SUCCESS)
1283 symvalue.as_cpointer = key;
1284 tresult = isc_symtab_define(symtab, keyname, 1,
1285 symvalue, isc_symexists_reject);
1286 if (tresult == ISC_R_EXISTS) {
1290 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
1291 1, &symvalue) == ISC_R_SUCCESS);
1292 file = cfg_obj_file(symvalue.as_cpointer);
1293 line = cfg_obj_line(symvalue.as_cpointer);
1296 file = "<unknown file>";
1297 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1298 "key '%s': already exists "
1299 "previous definition: %s:%u",
1300 keyname, file, line);
1302 } else if (tresult != ISC_R_SUCCESS)
1312 { "transfer-source", "transfer-source-v6" },
1313 { "notify-source", "notify-source-v6" },
1314 { "query-source", "query-source-v6" },
1319 check_servers(const cfg_obj_t *servers, isc_log_t *logctx) {
1320 isc_result_t result = ISC_R_SUCCESS;
1321 isc_result_t tresult;
1322 const cfg_listelt_t *e1, *e2;
1323 const cfg_obj_t *v1, *v2;
1324 isc_netaddr_t n1, n2;
1325 unsigned int p1, p2;
1326 const cfg_obj_t *obj;
1327 char buf[ISC_NETADDR_FORMATSIZE];
1331 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
1332 v1 = cfg_listelt_value(e1);
1333 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
1335 * Check that unused bits are zero.
1337 tresult = isc_netaddr_prefixok(&n1, p1);
1338 if (tresult != ISC_R_SUCCESS) {
1339 INSIST(tresult == ISC_R_FAILURE);
1340 isc_netaddr_format(&n1, buf, sizeof(buf));
1341 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1342 "server '%s/%u': invalid prefix "
1343 "(extra bits specified)", buf, p1);
1349 if (n1.family == AF_INET)
1350 xfr = sources[source].v6;
1352 xfr = sources[source].v4;
1353 (void)cfg_map_get(v1, xfr, &obj);
1355 isc_netaddr_format(&n1, buf, sizeof(buf));
1356 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1357 "server '%s': %s not legal",
1359 result = ISC_R_FAILURE;
1361 } while (sources[++source].v4 != NULL);
1363 while ((e2 = cfg_list_next(e2)) != NULL) {
1364 v2 = cfg_listelt_value(e2);
1365 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
1366 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
1367 const char *file = cfg_obj_file(v1);
1368 unsigned int line = cfg_obj_line(v1);
1371 file = "<unknown file>";
1373 isc_netaddr_format(&n2, buf, sizeof(buf));
1374 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
1375 "server '%s/%u': already exists "
1376 "previous definition: %s:%u",
1377 buf, p2, file, line);
1378 result = ISC_R_FAILURE;
1386 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
1387 dns_rdataclass_t vclass, isc_log_t *logctx, isc_mem_t *mctx)
1389 const cfg_obj_t *servers = NULL;
1390 const cfg_obj_t *zones = NULL;
1391 const cfg_obj_t *keys = NULL;
1392 const cfg_listelt_t *element;
1393 isc_symtab_t *symtab = NULL;
1394 isc_result_t result = ISC_R_SUCCESS;
1395 isc_result_t tresult = ISC_R_SUCCESS;
1396 cfg_aclconfctx_t actx;
1397 const cfg_obj_t *obj;
1398 isc_boolean_t enablednssec, enablevalidation;
1401 * Check that all zone statements are syntactically correct and
1402 * there are no duplicate zones.
1404 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1405 ISC_FALSE, &symtab);
1406 if (tresult != ISC_R_SUCCESS)
1407 return (ISC_R_NOMEMORY);
1409 cfg_aclconfctx_init(&actx);
1411 if (voptions != NULL)
1412 (void)cfg_map_get(voptions, "zone", &zones);
1414 (void)cfg_map_get(config, "zone", &zones);
1416 for (element = cfg_list_first(zones);
1418 element = cfg_list_next(element))
1420 isc_result_t tresult;
1421 const cfg_obj_t *zone = cfg_listelt_value(element);
1423 tresult = check_zoneconf(zone, voptions, config, symtab,
1424 vclass, &actx, logctx, mctx);
1425 if (tresult != ISC_R_SUCCESS)
1426 result = ISC_R_FAILURE;
1429 isc_symtab_destroy(&symtab);
1432 * Check that all key statements are syntactically correct and
1433 * there are no duplicate keys.
1435 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
1436 if (tresult != ISC_R_SUCCESS)
1437 return (ISC_R_NOMEMORY);
1439 (void)cfg_map_get(config, "key", &keys);
1440 tresult = check_keylist(keys, symtab, logctx);
1441 if (tresult == ISC_R_EXISTS)
1442 result = ISC_R_FAILURE;
1443 else if (tresult != ISC_R_SUCCESS) {
1444 isc_symtab_destroy(&symtab);
1448 if (voptions != NULL) {
1450 (void)cfg_map_get(voptions, "key", &keys);
1451 tresult = check_keylist(keys, symtab, logctx);
1452 if (tresult == ISC_R_EXISTS)
1453 result = ISC_R_FAILURE;
1454 else if (tresult != ISC_R_SUCCESS) {
1455 isc_symtab_destroy(&symtab);
1460 isc_symtab_destroy(&symtab);
1463 * Check that forwarding is reasonable.
1465 if (voptions == NULL) {
1466 const cfg_obj_t *options = NULL;
1467 (void)cfg_map_get(config, "options", &options);
1468 if (options != NULL)
1469 if (check_forward(options, logctx) != ISC_R_SUCCESS)
1470 result = ISC_R_FAILURE;
1472 if (check_forward(voptions, logctx) != ISC_R_SUCCESS)
1473 result = ISC_R_FAILURE;
1476 * Check that dual-stack-servers is reasonable.
1478 if (voptions == NULL) {
1479 const cfg_obj_t *options = NULL;
1480 (void)cfg_map_get(config, "options", &options);
1481 if (options != NULL)
1482 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1483 result = ISC_R_FAILURE;
1485 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
1486 result = ISC_R_FAILURE;
1490 * Check that rrset-order is reasonable.
1492 if (voptions != NULL) {
1493 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
1494 result = ISC_R_FAILURE;
1497 if (voptions != NULL) {
1498 (void)cfg_map_get(voptions, "server", &servers);
1499 if (servers != NULL &&
1500 check_servers(servers, logctx) != ISC_R_SUCCESS)
1501 result = ISC_R_FAILURE;
1505 * Check that dnssec-enable/dnssec-validation are sensible.
1508 if (voptions != NULL)
1509 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
1511 (void)cfg_map_get(config, "dnssec-enable", &obj);
1513 enablednssec = ISC_TRUE;
1515 enablednssec = cfg_obj_asboolean(obj);
1518 if (voptions != NULL)
1519 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
1521 (void)cfg_map_get(config, "dnssec-validation", &obj);
1523 enablevalidation = ISC_FALSE; /* XXXMPA Change for 9.5. */
1525 enablevalidation = cfg_obj_asboolean(obj);
1527 if (enablevalidation && !enablednssec)
1528 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1529 "'dnssec-validation yes;' and 'dnssec-enable no;'");
1531 if (voptions != NULL)
1532 tresult = check_options(voptions, logctx, mctx);
1534 tresult = check_options(config, logctx, mctx);
1535 if (tresult != ISC_R_SUCCESS)
1538 tresult = check_viewacls(&actx, voptions, config, logctx, mctx);
1539 if (tresult != ISC_R_SUCCESS)
1542 cfg_aclconfctx_destroy(&actx);
1548 default_channels[] = {
1557 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
1560 const cfg_obj_t *categories = NULL;
1561 const cfg_obj_t *category;
1562 const cfg_obj_t *channels = NULL;
1563 const cfg_obj_t *channel;
1564 const cfg_listelt_t *element;
1565 const cfg_listelt_t *delement;
1566 const char *channelname;
1567 const char *catname;
1568 const cfg_obj_t *fileobj = NULL;
1569 const cfg_obj_t *syslogobj = NULL;
1570 const cfg_obj_t *nullobj = NULL;
1571 const cfg_obj_t *stderrobj = NULL;
1572 const cfg_obj_t *logobj = NULL;
1573 isc_result_t result = ISC_R_SUCCESS;
1574 isc_result_t tresult;
1575 isc_symtab_t *symtab = NULL;
1576 isc_symvalue_t symvalue;
1579 (void)cfg_map_get(config, "logging", &logobj);
1581 return (ISC_R_SUCCESS);
1583 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1584 if (result != ISC_R_SUCCESS)
1587 symvalue.as_cpointer = NULL;
1588 for (i = 0; default_channels[i] != NULL; i++) {
1589 tresult = isc_symtab_define(symtab, default_channels[i], 1,
1590 symvalue, isc_symexists_replace);
1591 if (tresult != ISC_R_SUCCESS)
1595 cfg_map_get(logobj, "channel", &channels);
1597 for (element = cfg_list_first(channels);
1599 element = cfg_list_next(element))
1601 channel = cfg_listelt_value(element);
1602 channelname = cfg_obj_asstring(cfg_map_getname(channel));
1603 fileobj = syslogobj = nullobj = stderrobj = NULL;
1604 (void)cfg_map_get(channel, "file", &fileobj);
1605 (void)cfg_map_get(channel, "syslog", &syslogobj);
1606 (void)cfg_map_get(channel, "null", &nullobj);
1607 (void)cfg_map_get(channel, "stderr", &stderrobj);
1609 if (fileobj != NULL)
1611 if (syslogobj != NULL)
1613 if (nullobj != NULL)
1615 if (stderrobj != NULL)
1618 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
1619 "channel '%s': exactly one of file, syslog, "
1620 "null, and stderr must be present",
1622 result = ISC_R_FAILURE;
1624 tresult = isc_symtab_define(symtab, channelname, 1,
1625 symvalue, isc_symexists_replace);
1626 if (tresult != ISC_R_SUCCESS)
1630 cfg_map_get(logobj, "category", &categories);
1632 for (element = cfg_list_first(categories);
1634 element = cfg_list_next(element))
1636 category = cfg_listelt_value(element);
1637 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
1638 if (isc_log_categorybyname(logctx, catname) == NULL) {
1639 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
1640 "undefined category: '%s'", catname);
1641 result = ISC_R_FAILURE;
1643 channels = cfg_tuple_get(category, "destinations");
1644 for (delement = cfg_list_first(channels);
1646 delement = cfg_list_next(delement))
1648 channel = cfg_listelt_value(delement);
1649 channelname = cfg_obj_asstring(channel);
1650 tresult = isc_symtab_lookup(symtab, channelname, 1,
1652 if (tresult != ISC_R_SUCCESS) {
1653 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
1654 "undefined channel: '%s'",
1660 isc_symtab_destroy(&symtab);
1665 key_exists(const cfg_obj_t *keylist, const char *keyname) {
1666 const cfg_listelt_t *element;
1668 const cfg_obj_t *obj;
1670 if (keylist == NULL)
1671 return (ISC_R_NOTFOUND);
1672 for (element = cfg_list_first(keylist);
1674 element = cfg_list_next(element))
1676 obj = cfg_listelt_value(element);
1677 str = cfg_obj_asstring(cfg_map_getname(obj));
1678 if (strcasecmp(str, keyname) == 0)
1679 return (ISC_R_SUCCESS);
1681 return (ISC_R_NOTFOUND);
1685 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
1688 isc_result_t result = ISC_R_SUCCESS, tresult;
1689 const cfg_obj_t *control_keylist;
1690 const cfg_listelt_t *element;
1691 const cfg_obj_t *key;
1693 control_keylist = cfg_tuple_get(control, "keys");
1694 if (cfg_obj_isvoid(control_keylist))
1695 return (ISC_R_SUCCESS);
1697 for (element = cfg_list_first(control_keylist);
1699 element = cfg_list_next(element))
1701 key = cfg_listelt_value(element);
1702 tresult = key_exists(keylist, cfg_obj_asstring(key));
1703 if (tresult != ISC_R_SUCCESS) {
1704 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1705 "unknown key '%s'", cfg_obj_asstring(key));
1713 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
1716 isc_result_t result = ISC_R_SUCCESS, tresult;
1717 cfg_aclconfctx_t actx;
1718 const cfg_listelt_t *element, *element2;
1719 const cfg_obj_t *allow;
1720 const cfg_obj_t *control;
1721 const cfg_obj_t *controls;
1722 const cfg_obj_t *controlslist = NULL;
1723 const cfg_obj_t *inetcontrols;
1724 const cfg_obj_t *unixcontrols;
1725 const cfg_obj_t *keylist = NULL;
1727 isc_uint32_t perm, mask;
1728 dns_acl_t *acl = NULL;
1729 isc_sockaddr_t addr;
1732 (void)cfg_map_get(config, "controls", &controlslist);
1733 if (controlslist == NULL)
1734 return (ISC_R_SUCCESS);
1736 (void)cfg_map_get(config, "key", &keylist);
1738 cfg_aclconfctx_init(&actx);
1741 * INET: Check allow clause.
1742 * UNIX: Check "perm" for sanity, check path length.
1744 for (element = cfg_list_first(controlslist);
1746 element = cfg_list_next(element)) {
1747 controls = cfg_listelt_value(element);
1748 unixcontrols = NULL;
1749 inetcontrols = NULL;
1750 (void)cfg_map_get(controls, "unix", &unixcontrols);
1751 (void)cfg_map_get(controls, "inet", &inetcontrols);
1752 for (element2 = cfg_list_first(inetcontrols);
1754 element2 = cfg_list_next(element2)) {
1755 control = cfg_listelt_value(element2);
1756 allow = cfg_tuple_get(control, "allow");
1757 tresult = cfg_acl_fromconfig(allow, config, logctx,
1760 dns_acl_detach(&acl);
1761 if (tresult != ISC_R_SUCCESS)
1763 tresult = bind9_check_controlskeys(control, keylist,
1765 if (tresult != ISC_R_SUCCESS)
1768 for (element2 = cfg_list_first(unixcontrols);
1770 element2 = cfg_list_next(element2)) {
1771 control = cfg_listelt_value(element2);
1772 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
1773 tresult = isc_sockaddr_frompath(&addr, path);
1774 if (tresult == ISC_R_NOSPACE) {
1775 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
1776 "unix control '%s': path too long",
1778 result = ISC_R_NOSPACE;
1780 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
1781 for (i = 0; i < 3; i++) {
1782 #ifdef NEED_SECURE_DIRECTORY
1783 mask = (0x1 << (i*3)); /* SEARCH */
1785 mask = (0x6 << (i*3)); /* READ + WRITE */
1787 if ((perm & mask) == mask)
1791 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
1792 "unix control '%s' allows access "
1793 "to everyone", path);
1794 } else if (i == 3) {
1795 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
1796 "unix control '%s' allows access "
1799 tresult = bind9_check_controlskeys(control, keylist,
1801 if (tresult != ISC_R_SUCCESS)
1805 cfg_aclconfctx_destroy(&actx);
1810 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
1813 const cfg_obj_t *options = NULL;
1814 const cfg_obj_t *servers = NULL;
1815 const cfg_obj_t *views = NULL;
1816 const cfg_obj_t *acls = NULL;
1817 const cfg_obj_t *kals = NULL;
1818 const cfg_obj_t *obj;
1819 const cfg_listelt_t *velement;
1820 isc_result_t result = ISC_R_SUCCESS;
1821 isc_result_t tresult;
1822 isc_symtab_t *symtab = NULL;
1824 static const char *builtin[] = { "localhost", "localnets",
1827 (void)cfg_map_get(config, "options", &options);
1829 if (options != NULL &&
1830 check_options(options, logctx, mctx) != ISC_R_SUCCESS)
1831 result = ISC_R_FAILURE;
1833 (void)cfg_map_get(config, "server", &servers);
1834 if (servers != NULL &&
1835 check_servers(servers, logctx) != ISC_R_SUCCESS)
1836 result = ISC_R_FAILURE;
1838 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
1839 result = ISC_R_FAILURE;
1841 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
1842 result = ISC_R_FAILURE;
1844 if (options != NULL &&
1845 check_order(options, logctx) != ISC_R_SUCCESS)
1846 result = ISC_R_FAILURE;
1848 (void)cfg_map_get(config, "view", &views);
1850 if (views != NULL && options != NULL)
1851 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1852 result = ISC_R_FAILURE;
1854 if (views == NULL) {
1855 if (check_viewconf(config, NULL, dns_rdataclass_in,
1856 logctx, mctx) != ISC_R_SUCCESS)
1857 result = ISC_R_FAILURE;
1859 const cfg_obj_t *zones = NULL;
1861 (void)cfg_map_get(config, "zone", &zones);
1862 if (zones != NULL) {
1863 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
1864 "when using 'view' statements, "
1865 "all zones must be in views");
1866 result = ISC_R_FAILURE;
1870 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
1871 if (tresult != ISC_R_SUCCESS)
1873 for (velement = cfg_list_first(views);
1875 velement = cfg_list_next(velement))
1877 const cfg_obj_t *view = cfg_listelt_value(velement);
1878 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
1879 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
1880 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
1881 dns_rdataclass_t vclass = dns_rdataclass_in;
1882 isc_result_t tresult = ISC_R_SUCCESS;
1883 const char *key = cfg_obj_asstring(vname);
1884 isc_symvalue_t symvalue;
1886 if (cfg_obj_isstring(vclassobj)) {
1889 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
1890 r.length = strlen(r.base);
1891 tresult = dns_rdataclass_fromtext(&vclass, &r);
1892 if (tresult != ISC_R_SUCCESS)
1893 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
1894 "view '%s': invalid class %s",
1895 cfg_obj_asstring(vname), r.base);
1897 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
1898 symvalue.as_cpointer = view;
1899 tresult = isc_symtab_define(symtab, key, vclass,
1901 isc_symexists_reject);
1902 if (tresult == ISC_R_EXISTS) {
1905 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
1906 vclass, &symvalue) == ISC_R_SUCCESS);
1907 file = cfg_obj_file(symvalue.as_cpointer);
1908 line = cfg_obj_line(symvalue.as_cpointer);
1909 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
1910 "view '%s': already exists "
1911 "previous definition: %s:%u",
1914 } else if (result != ISC_R_SUCCESS) {
1916 } else if ((strcasecmp(key, "_bind") == 0 &&
1917 vclass == dns_rdataclass_ch) ||
1918 (strcasecmp(key, "_default") == 0 &&
1919 vclass == dns_rdataclass_in)) {
1920 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
1921 "attempt to redefine builtin view "
1923 result = ISC_R_EXISTS;
1926 if (tresult == ISC_R_SUCCESS)
1927 tresult = check_viewconf(config, voptions,
1928 vclass, logctx, mctx);
1929 if (tresult != ISC_R_SUCCESS)
1930 result = ISC_R_FAILURE;
1933 isc_symtab_destroy(&symtab);
1935 if (views != NULL && options != NULL) {
1937 tresult = cfg_map_get(options, "cache-file", &obj);
1938 if (tresult == ISC_R_SUCCESS) {
1939 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1940 "'cache-file' cannot be a global "
1941 "option if views are present");
1942 result = ISC_R_FAILURE;
1946 tresult = cfg_map_get(config, "acl", &acls);
1947 if (tresult == ISC_R_SUCCESS) {
1948 const cfg_listelt_t *elt;
1949 const cfg_listelt_t *elt2;
1950 const char *aclname;
1952 for (elt = cfg_list_first(acls);
1954 elt = cfg_list_next(elt)) {
1955 const cfg_obj_t *acl = cfg_listelt_value(elt);
1958 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
1960 i < sizeof(builtin) / sizeof(builtin[0]);
1962 if (strcasecmp(aclname, builtin[i]) == 0) {
1963 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
1964 "attempt to redefine "
1967 result = ISC_R_FAILURE;
1971 for (elt2 = cfg_list_next(elt);
1973 elt2 = cfg_list_next(elt2)) {
1974 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
1976 name = cfg_obj_asstring(cfg_tuple_get(acl2,
1978 if (strcasecmp(aclname, name) == 0) {
1979 const char *file = cfg_obj_file(acl);
1980 unsigned int line = cfg_obj_line(acl);
1983 file = "<unknown file>";
1985 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
1986 "attempt to redefine "
1987 "acl '%s' previous "
1988 "definition: %s:%u",
1990 result = ISC_R_FAILURE;
1996 tresult = cfg_map_get(config, "kal", &kals);
1997 if (tresult == ISC_R_SUCCESS) {
1998 const cfg_listelt_t *elt;
1999 const cfg_listelt_t *elt2;
2000 const char *aclname;
2002 for (elt = cfg_list_first(kals);
2004 elt = cfg_list_next(elt)) {
2005 const cfg_obj_t *acl = cfg_listelt_value(elt);
2007 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2009 for (elt2 = cfg_list_next(elt);
2011 elt2 = cfg_list_next(elt2)) {
2012 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2014 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2016 if (strcasecmp(aclname, name) == 0) {
2017 const char *file = cfg_obj_file(acl);
2018 unsigned int line = cfg_obj_line(acl);
2021 file = "<unknown file>";
2023 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2024 "attempt to redefine "
2025 "kal '%s' previous "
2026 "definition: %s:%u",
2028 result = ISC_R_FAILURE;