4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2001-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: check.c,v 1.114 2009/12/04 21:09:33 marka Exp */
28 #include <isc/base64.h>
29 #include <isc/buffer.h>
32 #include <isc/netaddr.h>
33 #include <isc/parseint.h>
34 #include <isc/region.h>
35 #include <isc/result.h>
36 #include <isc/sockaddr.h>
37 #include <isc/string.h>
38 #include <isc/symtab.h>
42 #include <dns/fixedname.h>
43 #include <dns/rdataclass.h>
44 #include <dns/rdatatype.h>
45 #include <dns/secalg.h>
47 #include <isccfg/aclconf.h>
48 #include <isccfg/cfg.h>
50 #include <bind9/check.h>
53 freekey(char *key
, unsigned int type
, isc_symvalue_t value
, void *userarg
) {
56 isc_mem_free(userarg
, key
);
60 check_orderent(const cfg_obj_t
*ent
, isc_log_t
*logctx
) {
61 isc_result_t result
= ISC_R_SUCCESS
;
64 dns_fixedname_t fixed
;
66 dns_rdataclass_t rdclass
;
67 dns_rdatatype_t rdtype
;
71 dns_fixedname_init(&fixed
);
72 obj
= cfg_tuple_get(ent
, "class");
73 if (cfg_obj_isstring(obj
)) {
75 DE_CONST(cfg_obj_asstring(obj
), r
.base
);
76 r
.length
= strlen(r
.base
);
77 tresult
= dns_rdataclass_fromtext(&rdclass
, &r
);
78 if (tresult
!= ISC_R_SUCCESS
) {
79 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
80 "rrset-order: invalid class '%s'",
82 result
= ISC_R_FAILURE
;
86 obj
= cfg_tuple_get(ent
, "type");
87 if (cfg_obj_isstring(obj
)) {
89 DE_CONST(cfg_obj_asstring(obj
), r
.base
);
90 r
.length
= strlen(r
.base
);
91 tresult
= dns_rdatatype_fromtext(&rdtype
, &r
);
92 if (tresult
!= ISC_R_SUCCESS
) {
93 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
94 "rrset-order: invalid type '%s'",
96 result
= ISC_R_FAILURE
;
100 obj
= cfg_tuple_get(ent
, "name");
101 if (cfg_obj_isstring(obj
)) {
102 str
= cfg_obj_asstring(obj
);
103 isc_buffer_init(&b
, str
, strlen(str
));
104 isc_buffer_add(&b
, strlen(str
));
105 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
106 dns_rootname
, 0, NULL
);
107 if (tresult
!= ISC_R_SUCCESS
) {
108 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
109 "rrset-order: invalid name '%s'", str
);
110 result
= ISC_R_FAILURE
;
114 obj
= cfg_tuple_get(ent
, "order");
115 if (!cfg_obj_isstring(obj
) ||
116 strcasecmp("order", cfg_obj_asstring(obj
)) != 0) {
117 cfg_obj_log(ent
, logctx
, ISC_LOG_ERROR
,
118 "rrset-order: keyword 'order' missing");
119 result
= ISC_R_FAILURE
;
122 obj
= cfg_tuple_get(ent
, "ordering");
123 if (!cfg_obj_isstring(obj
)) {
124 cfg_obj_log(ent
, logctx
, ISC_LOG_ERROR
,
125 "rrset-order: missing ordering");
126 result
= ISC_R_FAILURE
;
127 } else if (strcasecmp(cfg_obj_asstring(obj
), "fixed") == 0) {
128 #if !DNS_RDATASET_FIXED
129 cfg_obj_log(obj
, logctx
, ISC_LOG_WARNING
,
130 "rrset-order: order 'fixed' was disabled at "
133 } else if (strcasecmp(cfg_obj_asstring(obj
), "random") != 0 &&
134 strcasecmp(cfg_obj_asstring(obj
), "cyclic") != 0) {
135 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
136 "rrset-order: invalid order '%s'",
137 cfg_obj_asstring(obj
));
138 result
= ISC_R_FAILURE
;
144 check_order(const cfg_obj_t
*options
, isc_log_t
*logctx
) {
145 isc_result_t result
= ISC_R_SUCCESS
;
146 isc_result_t tresult
;
147 const cfg_listelt_t
*element
;
148 const cfg_obj_t
*obj
= NULL
;
150 if (cfg_map_get(options
, "rrset-order", &obj
) != ISC_R_SUCCESS
)
153 for (element
= cfg_list_first(obj
);
155 element
= cfg_list_next(element
))
157 tresult
= check_orderent(cfg_listelt_value(element
), logctx
);
158 if (tresult
!= ISC_R_SUCCESS
)
165 check_dual_stack(const cfg_obj_t
*options
, isc_log_t
*logctx
) {
166 const cfg_listelt_t
*element
;
167 const cfg_obj_t
*alternates
= NULL
;
168 const cfg_obj_t
*value
;
169 const cfg_obj_t
*obj
;
171 dns_fixedname_t fixed
;
174 isc_result_t result
= ISC_R_SUCCESS
;
175 isc_result_t tresult
;
177 (void)cfg_map_get(options
, "dual-stack-servers", &alternates
);
179 if (alternates
== NULL
)
180 return (ISC_R_SUCCESS
);
182 obj
= cfg_tuple_get(alternates
, "port");
183 if (cfg_obj_isuint32(obj
)) {
184 isc_uint32_t val
= cfg_obj_asuint32(obj
);
185 if (val
> ISC_UINT16_MAX
) {
186 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
187 "port '%u' out of range", val
);
188 result
= ISC_R_FAILURE
;
191 obj
= cfg_tuple_get(alternates
, "addresses");
192 for (element
= cfg_list_first(obj
);
194 element
= cfg_list_next(element
)) {
195 value
= cfg_listelt_value(element
);
196 if (cfg_obj_issockaddr(value
))
198 obj
= cfg_tuple_get(value
, "name");
199 str
= cfg_obj_asstring(obj
);
200 isc_buffer_init(&buffer
, str
, strlen(str
));
201 isc_buffer_add(&buffer
, strlen(str
));
202 dns_fixedname_init(&fixed
);
203 name
= dns_fixedname_name(&fixed
);
204 tresult
= dns_name_fromtext(name
, &buffer
, dns_rootname
,
206 if (tresult
!= ISC_R_SUCCESS
) {
207 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
208 "bad name '%s'", str
);
209 result
= ISC_R_FAILURE
;
211 obj
= cfg_tuple_get(value
, "port");
212 if (cfg_obj_isuint32(obj
)) {
213 isc_uint32_t val
= cfg_obj_asuint32(obj
);
214 if (val
> ISC_UINT16_MAX
) {
215 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
216 "port '%u' out of range", val
);
217 result
= ISC_R_FAILURE
;
225 check_forward(const cfg_obj_t
*options
, const cfg_obj_t
*global
,
228 const cfg_obj_t
*forward
= NULL
;
229 const cfg_obj_t
*forwarders
= NULL
;
231 (void)cfg_map_get(options
, "forward", &forward
);
232 (void)cfg_map_get(options
, "forwarders", &forwarders
);
234 if (forwarders
!= NULL
&& global
!= NULL
) {
235 const char *file
= cfg_obj_file(global
);
236 unsigned int line
= cfg_obj_line(global
);
237 cfg_obj_log(forwarders
, logctx
, ISC_LOG_ERROR
,
238 "forwarders declared in root zone and "
239 "in general configuration: %s:%u",
241 return (ISC_R_FAILURE
);
243 if (forward
!= NULL
&& forwarders
== NULL
) {
244 cfg_obj_log(forward
, logctx
, ISC_LOG_ERROR
,
245 "no matching 'forwarders' statement");
246 return (ISC_R_FAILURE
);
248 return (ISC_R_SUCCESS
);
252 disabled_algorithms(const cfg_obj_t
*disabled
, isc_log_t
*logctx
) {
253 isc_result_t result
= ISC_R_SUCCESS
;
254 isc_result_t tresult
;
255 const cfg_listelt_t
*element
;
258 dns_fixedname_t fixed
;
260 const cfg_obj_t
*obj
;
262 dns_fixedname_init(&fixed
);
263 name
= dns_fixedname_name(&fixed
);
264 obj
= cfg_tuple_get(disabled
, "name");
265 str
= cfg_obj_asstring(obj
);
266 isc_buffer_init(&b
, str
, strlen(str
));
267 isc_buffer_add(&b
, strlen(str
));
268 tresult
= dns_name_fromtext(name
, &b
, dns_rootname
, 0, NULL
);
269 if (tresult
!= ISC_R_SUCCESS
) {
270 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
271 "bad domain name '%s'", str
);
275 obj
= cfg_tuple_get(disabled
, "algorithms");
277 for (element
= cfg_list_first(obj
);
279 element
= cfg_list_next(element
))
283 isc_result_t tresult
;
285 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element
)), r
.base
);
286 r
.length
= strlen(r
.base
);
288 tresult
= dns_secalg_fromtext(&alg
, &r
);
289 if (tresult
!= ISC_R_SUCCESS
) {
291 result
= isc_parse_uint8(&ui
, r
.base
, 10);
293 if (tresult
!= ISC_R_SUCCESS
) {
294 cfg_obj_log(cfg_listelt_value(element
), logctx
,
295 ISC_LOG_ERROR
, "invalid algorithm '%s'",
304 nameexist(const cfg_obj_t
*obj
, const char *name
, int value
,
305 isc_symtab_t
*symtab
, const char *fmt
, isc_log_t
*logctx
,
312 isc_symvalue_t symvalue
;
314 key
= isc_mem_strdup(mctx
, name
);
316 return (ISC_R_NOMEMORY
);
317 symvalue
.as_cpointer
= obj
;
318 result
= isc_symtab_define(symtab
, key
, value
, symvalue
,
319 isc_symexists_reject
);
320 if (result
== ISC_R_EXISTS
) {
321 RUNTIME_CHECK(isc_symtab_lookup(symtab
, key
, value
,
322 &symvalue
) == ISC_R_SUCCESS
);
323 file
= cfg_obj_file(symvalue
.as_cpointer
);
324 line
= cfg_obj_line(symvalue
.as_cpointer
);
327 file
= "<unknown file>";
328 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
, fmt
, key
, file
, line
);
329 isc_mem_free(mctx
, key
);
330 result
= ISC_R_EXISTS
;
331 } else if (result
!= ISC_R_SUCCESS
) {
332 isc_mem_free(mctx
, key
);
338 mustbesecure(const cfg_obj_t
*secure
, isc_symtab_t
*symtab
, isc_log_t
*logctx
,
341 const cfg_obj_t
*obj
;
342 char namebuf
[DNS_NAME_FORMATSIZE
];
344 dns_fixedname_t fixed
;
347 isc_result_t result
= ISC_R_SUCCESS
;
349 dns_fixedname_init(&fixed
);
350 name
= dns_fixedname_name(&fixed
);
351 obj
= cfg_tuple_get(secure
, "name");
352 str
= cfg_obj_asstring(obj
);
353 isc_buffer_init(&b
, str
, strlen(str
));
354 isc_buffer_add(&b
, strlen(str
));
355 result
= dns_name_fromtext(name
, &b
, dns_rootname
, 0, NULL
);
356 if (result
!= ISC_R_SUCCESS
) {
357 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
358 "bad domain name '%s'", str
);
360 dns_name_format(name
, namebuf
, sizeof(namebuf
));
361 result
= nameexist(secure
, namebuf
, 1, symtab
,
362 "dnssec-must-be-secure '%s': already "
363 "exists previous definition: %s:%u",
370 checkacl(const char *aclname
, cfg_aclconfctx_t
*actx
, const cfg_obj_t
*zconfig
,
371 const cfg_obj_t
*voptions
, const cfg_obj_t
*config
,
372 isc_log_t
*logctx
, isc_mem_t
*mctx
)
375 const cfg_obj_t
*aclobj
= NULL
;
376 const cfg_obj_t
*options
;
377 dns_acl_t
*acl
= NULL
;
379 if (zconfig
!= NULL
) {
380 options
= cfg_tuple_get(zconfig
, "options");
381 cfg_map_get(options
, aclname
, &aclobj
);
383 if (voptions
!= NULL
&& aclobj
== NULL
)
384 cfg_map_get(voptions
, aclname
, &aclobj
);
385 if (config
!= NULL
&& aclobj
== NULL
) {
387 cfg_map_get(config
, "options", &options
);
389 cfg_map_get(options
, aclname
, &aclobj
);
392 return (ISC_R_SUCCESS
);
393 result
= cfg_acl_fromconfig(aclobj
, config
, logctx
,
394 actx
, mctx
, 0, &acl
);
396 dns_acl_detach(&acl
);
401 check_viewacls(cfg_aclconfctx_t
*actx
, const cfg_obj_t
*voptions
,
402 const cfg_obj_t
*config
, isc_log_t
*logctx
, isc_mem_t
*mctx
)
404 isc_result_t result
= ISC_R_SUCCESS
, tresult
;
407 static const char *acls
[] = { "allow-query", "allow-query-on",
408 "allow-query-cache", "allow-query-cache-on",
409 "blackhole", "match-clients", "match-destinations",
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
))
669 const cfg_obj_t
*anchor
;
671 obj
= cfg_listelt_value(element
);
673 dlv
= cfg_obj_asstring(cfg_tuple_get(obj
, "domain"));
674 anchor
= cfg_tuple_get(obj
, "trust-anchor");
677 * If domain is "auto" and trust anchor is missing,
678 * skip remaining tests
680 if (!strcmp(dlv
, "auto") && cfg_obj_isvoid(anchor
))
683 isc_buffer_init(&b
, dlv
, strlen(dlv
));
684 isc_buffer_add(&b
, strlen(dlv
));
685 tresult
= dns_name_fromtext(name
, &b
, dns_rootname
,
687 if (tresult
!= ISC_R_SUCCESS
) {
688 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
689 "bad domain name '%s'", dlv
);
693 if (symtab
!= NULL
) {
694 tresult
= nameexist(obj
, dlv
, 1, symtab
,
695 "dnssec-lookaside '%s': "
696 "already exists previous "
699 if (tresult
!= ISC_R_SUCCESS
&&
700 result
== ISC_R_SUCCESS
)
704 * XXXMPA to be removed when multiple lookaside
705 * namespaces are supported.
707 if (!dns_name_equal(dns_rootname
, name
)) {
708 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
709 "dnssec-lookaside '%s': "
710 "non-root not yet supported", dlv
);
711 if (result
== ISC_R_SUCCESS
)
712 result
= ISC_R_FAILURE
;
715 if (!cfg_obj_isvoid(anchor
)) {
716 dlv
= cfg_obj_asstring(anchor
);
717 isc_buffer_init(&b
, dlv
, strlen(dlv
));
718 isc_buffer_add(&b
, strlen(dlv
));
719 tresult
= dns_name_fromtext(name
, &b
,
723 if (tresult
!= ISC_R_SUCCESS
) {
724 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
725 "bad domain name '%s'",
727 if (result
== ISC_R_SUCCESS
)
731 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
732 "dnssec-lookaside requires "
733 "either 'auto' or a domain and "
735 if (result
== ISC_R_SUCCESS
)
736 result
= ISC_R_FAILURE
;
741 isc_symtab_destroy(&symtab
);
745 * Check dnssec-must-be-secure.
748 (void)cfg_map_get(options
, "dnssec-must-be-secure", &obj
);
750 isc_symtab_t
*symtab
= NULL
;
751 tresult
= isc_symtab_create(mctx
, 100, freekey
, mctx
,
753 if (tresult
!= ISC_R_SUCCESS
)
755 for (element
= cfg_list_first(obj
);
757 element
= cfg_list_next(element
))
759 obj
= cfg_listelt_value(element
);
760 tresult
= mustbesecure(obj
, symtab
, logctx
, mctx
);
761 if (tresult
!= ISC_R_SUCCESS
)
765 isc_symtab_destroy(&symtab
);
769 * Check empty zone configuration.
772 (void)cfg_map_get(options
, "empty-server", &obj
);
774 str
= cfg_obj_asstring(obj
);
775 isc_buffer_init(&b
, str
, strlen(str
));
776 isc_buffer_add(&b
, strlen(str
));
777 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
778 dns_rootname
, 0, NULL
);
779 if (tresult
!= ISC_R_SUCCESS
) {
780 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
781 "empty-server: invalid name '%s'", str
);
782 result
= ISC_R_FAILURE
;
787 (void)cfg_map_get(options
, "empty-contact", &obj
);
789 str
= cfg_obj_asstring(obj
);
790 isc_buffer_init(&b
, str
, strlen(str
));
791 isc_buffer_add(&b
, strlen(str
));
792 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
793 dns_rootname
, 0, NULL
);
794 if (tresult
!= ISC_R_SUCCESS
) {
795 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
796 "empty-contact: invalid name '%s'", str
);
797 result
= ISC_R_FAILURE
;
802 (void)cfg_map_get(options
, "disable-empty-zone", &obj
);
803 for (element
= cfg_list_first(obj
);
805 element
= cfg_list_next(element
))
807 obj
= cfg_listelt_value(element
);
808 str
= cfg_obj_asstring(obj
);
809 isc_buffer_init(&b
, str
, strlen(str
));
810 isc_buffer_add(&b
, strlen(str
));
811 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
812 dns_rootname
, 0, NULL
);
813 if (tresult
!= ISC_R_SUCCESS
) {
814 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
815 "disable-empty-zone: invalid name '%s'",
817 result
= ISC_R_FAILURE
;
822 * Check that server-id is not too long.
823 * 1024 bytes should be big enough.
826 (void)cfg_map_get(options
, "server-id", &obj
);
827 if (obj
!= NULL
&& cfg_obj_isstring(obj
) &&
828 strlen(cfg_obj_asstring(obj
)) > 1024U) {
829 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
830 "'server-id' too big (>1024 bytes)");
831 result
= ISC_R_FAILURE
;
838 get_masters_def(const cfg_obj_t
*cctx
, const char *name
, const cfg_obj_t
**ret
) {
840 const cfg_obj_t
*masters
= NULL
;
841 const cfg_listelt_t
*elt
;
843 result
= cfg_map_get(cctx
, "masters", &masters
);
844 if (result
!= ISC_R_SUCCESS
)
846 for (elt
= cfg_list_first(masters
);
848 elt
= cfg_list_next(elt
)) {
849 const cfg_obj_t
*list
;
850 const char *listname
;
852 list
= cfg_listelt_value(elt
);
853 listname
= cfg_obj_asstring(cfg_tuple_get(list
, "name"));
855 if (strcasecmp(listname
, name
) == 0) {
857 return (ISC_R_SUCCESS
);
860 return (ISC_R_NOTFOUND
);
864 validate_masters(const cfg_obj_t
*obj
, const cfg_obj_t
*config
,
865 isc_uint32_t
*countp
, isc_log_t
*logctx
, isc_mem_t
*mctx
)
867 isc_result_t result
= ISC_R_SUCCESS
;
868 isc_result_t tresult
;
869 isc_uint32_t count
= 0;
870 isc_symtab_t
*symtab
= NULL
;
871 isc_symvalue_t symvalue
;
872 const cfg_listelt_t
*element
;
873 const cfg_listelt_t
**stack
= NULL
;
874 isc_uint32_t stackcount
= 0, pushed
= 0;
875 const cfg_obj_t
*list
;
877 REQUIRE(countp
!= NULL
);
878 result
= isc_symtab_create(mctx
, 100, NULL
, NULL
, ISC_FALSE
, &symtab
);
879 if (result
!= ISC_R_SUCCESS
) {
885 list
= cfg_tuple_get(obj
, "addresses");
886 element
= cfg_list_first(list
);
890 element
= cfg_list_next(element
))
892 const char *listname
;
893 const cfg_obj_t
*addr
;
894 const cfg_obj_t
*key
;
896 addr
= cfg_tuple_get(cfg_listelt_value(element
),
898 key
= cfg_tuple_get(cfg_listelt_value(element
), "key");
900 if (cfg_obj_issockaddr(addr
)) {
904 if (!cfg_obj_isvoid(key
)) {
905 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
906 "unexpected token '%s'",
907 cfg_obj_asstring(key
));
908 if (result
== ISC_R_SUCCESS
)
909 result
= ISC_R_FAILURE
;
911 listname
= cfg_obj_asstring(addr
);
912 symvalue
.as_cpointer
= addr
;
913 tresult
= isc_symtab_define(symtab
, listname
, 1, symvalue
,
914 isc_symexists_reject
);
915 if (tresult
== ISC_R_EXISTS
)
917 tresult
= get_masters_def(config
, listname
, &obj
);
918 if (tresult
!= ISC_R_SUCCESS
) {
919 if (result
== ISC_R_SUCCESS
)
921 cfg_obj_log(addr
, logctx
, ISC_LOG_ERROR
,
922 "unable to find masters list '%s'",
927 if (stackcount
== pushed
) {
929 isc_uint32_t newlen
= stackcount
+ 16;
930 size_t newsize
, oldsize
;
932 newsize
= newlen
* sizeof(*stack
);
933 oldsize
= stackcount
* sizeof(*stack
);
934 new = isc_mem_get(mctx
, newsize
);
937 if (stackcount
!= 0) {
940 DE_CONST(stack
, ptr
);
941 memcpy(new, stack
, oldsize
);
942 isc_mem_put(mctx
, ptr
, oldsize
);
947 stack
[pushed
++] = cfg_list_next(element
);
951 element
= stack
[--pushed
];
958 DE_CONST(stack
, ptr
);
959 isc_mem_put(mctx
, ptr
, stackcount
* sizeof(*stack
));
961 isc_symtab_destroy(&symtab
);
967 check_update_policy(const cfg_obj_t
*policy
, isc_log_t
*logctx
) {
968 isc_result_t result
= ISC_R_SUCCESS
;
969 isc_result_t tresult
;
970 const cfg_listelt_t
*element
;
971 const cfg_listelt_t
*element2
;
972 dns_fixedname_t fixed
;
976 /* Check for "update-policy local;" */
977 if (cfg_obj_isstring(policy
) &&
978 strcmp("local", cfg_obj_asstring(policy
)) == 0)
979 return (ISC_R_SUCCESS
);
981 /* Now check the grant policy */
982 for (element
= cfg_list_first(policy
);
984 element
= cfg_list_next(element
))
986 const cfg_obj_t
*stmt
= cfg_listelt_value(element
);
987 const cfg_obj_t
*identity
= cfg_tuple_get(stmt
, "identity");
988 const cfg_obj_t
*matchtype
= cfg_tuple_get(stmt
, "matchtype");
989 const cfg_obj_t
*dname
= cfg_tuple_get(stmt
, "name");
990 const cfg_obj_t
*typelist
= cfg_tuple_get(stmt
, "types");
992 dns_fixedname_init(&fixed
);
993 str
= cfg_obj_asstring(identity
);
994 isc_buffer_init(&b
, str
, strlen(str
));
995 isc_buffer_add(&b
, strlen(str
));
996 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
997 dns_rootname
, 0, NULL
);
998 if (tresult
!= ISC_R_SUCCESS
) {
999 cfg_obj_log(identity
, logctx
, ISC_LOG_ERROR
,
1000 "'%s' is not a valid name", str
);
1004 if (tresult
== ISC_R_SUCCESS
&&
1005 strcasecmp(cfg_obj_asstring(matchtype
), "zonesub") != 0) {
1006 dns_fixedname_init(&fixed
);
1007 str
= cfg_obj_asstring(dname
);
1008 isc_buffer_init(&b
, str
, strlen(str
));
1009 isc_buffer_add(&b
, strlen(str
));
1010 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
),
1011 &b
, dns_rootname
, 0, NULL
);
1012 if (tresult
!= ISC_R_SUCCESS
) {
1013 cfg_obj_log(dname
, logctx
, ISC_LOG_ERROR
,
1014 "'%s' is not a valid name", str
);
1019 if (tresult
== ISC_R_SUCCESS
&&
1020 strcasecmp(cfg_obj_asstring(matchtype
), "wildcard") == 0 &&
1021 !dns_name_iswildcard(dns_fixedname_name(&fixed
))) {
1022 cfg_obj_log(identity
, logctx
, ISC_LOG_ERROR
,
1023 "'%s' is not a wildcard", str
);
1024 result
= ISC_R_FAILURE
;
1027 for (element2
= cfg_list_first(typelist
);
1029 element2
= cfg_list_next(element2
))
1031 const cfg_obj_t
*typeobj
;
1033 dns_rdatatype_t type
;
1035 typeobj
= cfg_listelt_value(element2
);
1036 DE_CONST(cfg_obj_asstring(typeobj
), r
.base
);
1037 r
.length
= strlen(r
.base
);
1039 tresult
= dns_rdatatype_fromtext(&type
, &r
);
1040 if (tresult
!= ISC_R_SUCCESS
) {
1041 cfg_obj_log(typeobj
, logctx
, ISC_LOG_ERROR
,
1042 "'%s' is not a valid type", r
.base
);
1050 #define MASTERZONE 1
1054 #define FORWARDZONE 16
1055 #define DELEGATIONZONE 32
1064 check_zoneconf(const cfg_obj_t
*zconfig
, const cfg_obj_t
*voptions
,
1065 const cfg_obj_t
*config
, isc_symtab_t
*symtab
,
1066 dns_rdataclass_t defclass
, cfg_aclconfctx_t
*actx
,
1067 isc_log_t
*logctx
, isc_mem_t
*mctx
)
1070 const char *typestr
;
1072 const cfg_obj_t
*zoptions
;
1073 const cfg_obj_t
*obj
= NULL
;
1074 isc_result_t result
= ISC_R_SUCCESS
;
1075 isc_result_t tresult
;
1077 dns_rdataclass_t zclass
;
1078 dns_fixedname_t fixedname
;
1080 isc_boolean_t root
= ISC_FALSE
;
1082 static optionstable options
[] = {
1083 { "allow-query", MASTERZONE
| SLAVEZONE
| STUBZONE
| CHECKACL
},
1084 { "allow-notify", SLAVEZONE
| CHECKACL
},
1085 { "allow-transfer", MASTERZONE
| SLAVEZONE
| CHECKACL
},
1086 { "notify", MASTERZONE
| SLAVEZONE
},
1087 { "also-notify", MASTERZONE
| SLAVEZONE
},
1088 { "dialup", MASTERZONE
| SLAVEZONE
| STUBZONE
},
1089 { "delegation-only", HINTZONE
| STUBZONE
| DELEGATIONZONE
},
1090 { "forward", MASTERZONE
| SLAVEZONE
| STUBZONE
| FORWARDZONE
},
1091 { "forwarders", MASTERZONE
| SLAVEZONE
| STUBZONE
| FORWARDZONE
},
1092 { "maintain-ixfr-base", MASTERZONE
| SLAVEZONE
},
1093 { "max-ixfr-log-size", MASTERZONE
| SLAVEZONE
},
1094 { "notify-source", MASTERZONE
| SLAVEZONE
},
1095 { "notify-source-v6", MASTERZONE
| SLAVEZONE
},
1096 { "transfer-source", SLAVEZONE
| STUBZONE
},
1097 { "transfer-source-v6", SLAVEZONE
| STUBZONE
},
1098 { "max-transfer-time-in", SLAVEZONE
| STUBZONE
},
1099 { "max-transfer-time-out", MASTERZONE
| SLAVEZONE
},
1100 { "max-transfer-idle-in", SLAVEZONE
| STUBZONE
},
1101 { "max-transfer-idle-out", MASTERZONE
| SLAVEZONE
},
1102 { "max-retry-time", SLAVEZONE
| STUBZONE
},
1103 { "min-retry-time", SLAVEZONE
| STUBZONE
},
1104 { "max-refresh-time", SLAVEZONE
| STUBZONE
},
1105 { "min-refresh-time", SLAVEZONE
| STUBZONE
},
1106 { "dnssec-secure-to-insecure", MASTERZONE
},
1107 { "sig-validity-interval", MASTERZONE
},
1108 { "sig-re-signing-interval", MASTERZONE
},
1109 { "sig-signing-nodes", MASTERZONE
},
1110 { "sig-signing-type", MASTERZONE
},
1111 { "sig-signing-signatures", MASTERZONE
},
1112 { "zone-statistics", MASTERZONE
| SLAVEZONE
| STUBZONE
},
1113 { "allow-update", MASTERZONE
| CHECKACL
},
1114 { "allow-update-forwarding", SLAVEZONE
| CHECKACL
},
1115 { "file", MASTERZONE
| SLAVEZONE
| STUBZONE
| HINTZONE
},
1116 { "journal", MASTERZONE
| SLAVEZONE
},
1117 { "ixfr-base", MASTERZONE
| SLAVEZONE
},
1118 { "ixfr-tmp-file", MASTERZONE
| SLAVEZONE
},
1119 { "masters", SLAVEZONE
| STUBZONE
},
1120 { "pubkey", MASTERZONE
| SLAVEZONE
| STUBZONE
},
1121 { "update-policy", MASTERZONE
},
1122 { "database", MASTERZONE
| SLAVEZONE
| STUBZONE
},
1123 { "key-directory", MASTERZONE
},
1124 { "check-wildcard", MASTERZONE
},
1125 { "check-mx", MASTERZONE
},
1126 { "check-dup-records", MASTERZONE
},
1127 { "integrity-check", MASTERZONE
},
1128 { "check-mx-cname", MASTERZONE
},
1129 { "check-srv-cname", MASTERZONE
},
1130 { "masterfile-format", MASTERZONE
| SLAVEZONE
| STUBZONE
| HINTZONE
},
1131 { "update-check-ksk", MASTERZONE
},
1132 { "dnssec-dnskey-kskonly", MASTERZONE
},
1133 { "auto-dnssec", MASTERZONE
},
1134 { "try-tcp-refresh", SLAVEZONE
},
1137 static optionstable dialups
[] = {
1138 { "notify", MASTERZONE
| SLAVEZONE
},
1139 { "notify-passive", SLAVEZONE
},
1140 { "refresh", SLAVEZONE
| STUBZONE
},
1141 { "passive", SLAVEZONE
| STUBZONE
},
1144 zname
= cfg_obj_asstring(cfg_tuple_get(zconfig
, "name"));
1146 zoptions
= cfg_tuple_get(zconfig
, "options");
1149 (void)cfg_map_get(zoptions
, "type", &obj
);
1151 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
1152 "zone '%s': type not present", zname
);
1153 return (ISC_R_FAILURE
);
1156 typestr
= cfg_obj_asstring(obj
);
1157 if (strcasecmp(typestr
, "master") == 0)
1159 else if (strcasecmp(typestr
, "slave") == 0)
1161 else if (strcasecmp(typestr
, "stub") == 0)
1163 else if (strcasecmp(typestr
, "forward") == 0)
1164 ztype
= FORWARDZONE
;
1165 else if (strcasecmp(typestr
, "hint") == 0)
1167 else if (strcasecmp(typestr
, "delegation-only") == 0)
1168 ztype
= DELEGATIONZONE
;
1170 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1171 "zone '%s': invalid type %s",
1173 return (ISC_R_FAILURE
);
1176 obj
= cfg_tuple_get(zconfig
, "class");
1177 if (cfg_obj_isstring(obj
)) {
1180 DE_CONST(cfg_obj_asstring(obj
), r
.base
);
1181 r
.length
= strlen(r
.base
);
1182 result
= dns_rdataclass_fromtext(&zclass
, &r
);
1183 if (result
!= ISC_R_SUCCESS
) {
1184 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1185 "zone '%s': invalid class %s",
1187 return (ISC_R_FAILURE
);
1189 if (zclass
!= defclass
) {
1190 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1191 "zone '%s': class '%s' does not "
1192 "match view/default class",
1194 return (ISC_R_FAILURE
);
1199 * Look for an already existing zone.
1200 * We need to make this canonical as isc_symtab_define()
1201 * deals with strings.
1203 dns_fixedname_init(&fixedname
);
1204 isc_buffer_init(&b
, zname
, strlen(zname
));
1205 isc_buffer_add(&b
, strlen(zname
));
1206 tresult
= dns_name_fromtext(dns_fixedname_name(&fixedname
), &b
,
1207 dns_rootname
, DNS_NAME_DOWNCASE
, NULL
);
1208 if (tresult
!= ISC_R_SUCCESS
) {
1209 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
1210 "zone '%s': is not a valid name", zname
);
1211 result
= ISC_R_FAILURE
;
1213 char namebuf
[DNS_NAME_FORMATSIZE
];
1215 dns_name_format(dns_fixedname_name(&fixedname
),
1216 namebuf
, sizeof(namebuf
));
1217 tresult
= nameexist(zconfig
, namebuf
, ztype
== HINTZONE
? 1 : 2,
1218 symtab
, "zone '%s': already exists "
1219 "previous definition: %s:%u", logctx
, mctx
);
1220 if (tresult
!= ISC_R_SUCCESS
)
1222 if (dns_name_equal(dns_fixedname_name(&fixedname
),
1228 * Look for inappropriate options for the given zone type.
1229 * Check that ACLs expand correctly.
1231 for (i
= 0; i
< sizeof(options
) / sizeof(options
[0]); i
++) {
1233 if ((options
[i
].allowed
& ztype
) == 0 &&
1234 cfg_map_get(zoptions
, options
[i
].name
, &obj
) ==
1237 if (strcmp(options
[i
].name
, "allow-update") != 0 ||
1238 ztype
!= SLAVEZONE
) {
1239 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1240 "option '%s' is not allowed "
1241 "in '%s' zone '%s'",
1242 options
[i
].name
, typestr
, zname
);
1243 result
= ISC_R_FAILURE
;
1245 cfg_obj_log(obj
, logctx
, ISC_LOG_WARNING
,
1246 "option '%s' is not allowed "
1247 "in '%s' zone '%s'",
1248 options
[i
].name
, typestr
, zname
);
1251 if ((options
[i
].allowed
& ztype
) != 0 &&
1252 (options
[i
].allowed
& CHECKACL
) != 0) {
1254 tresult
= checkacl(options
[i
].name
, actx
, zconfig
,
1255 voptions
, config
, logctx
, mctx
);
1256 if (tresult
!= ISC_R_SUCCESS
)
1263 * Slave & stub zones must have a "masters" field.
1265 if (ztype
== SLAVEZONE
|| ztype
== STUBZONE
) {
1267 if (cfg_map_get(zoptions
, "masters", &obj
) != ISC_R_SUCCESS
) {
1268 cfg_obj_log(zoptions
, logctx
, ISC_LOG_ERROR
,
1269 "zone '%s': missing 'masters' entry",
1271 result
= ISC_R_FAILURE
;
1274 tresult
= validate_masters(obj
, config
, &count
,
1276 if (tresult
!= ISC_R_SUCCESS
&& result
== ISC_R_SUCCESS
)
1278 if (tresult
== ISC_R_SUCCESS
&& count
== 0) {
1279 cfg_obj_log(zoptions
, logctx
, ISC_LOG_ERROR
,
1280 "zone '%s': empty 'masters' entry",
1282 result
= ISC_R_FAILURE
;
1288 * Master zones can't have both "allow-update" and "update-policy".
1290 if (ztype
== MASTERZONE
) {
1291 isc_result_t res1
, res2
, res3
;
1296 res1
= cfg_map_get(zoptions
, "allow-update", &obj
);
1298 res2
= cfg_map_get(zoptions
, "update-policy", &obj
);
1299 if (res1
== ISC_R_SUCCESS
&& res2
== ISC_R_SUCCESS
) {
1300 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1301 "zone '%s': 'allow-update' is ignored "
1302 "when 'update-policy' is present",
1304 result
= ISC_R_FAILURE
;
1305 } else if (res2
== ISC_R_SUCCESS
&&
1306 check_update_policy(obj
, logctx
) != ISC_R_SUCCESS
)
1307 result
= ISC_R_FAILURE
;
1308 ddns
= ISC_TF(res1
== ISC_R_SUCCESS
|| res2
== ISC_R_SUCCESS
);
1312 res3
= cfg_map_get(zoptions
, "auto-dnssec", &obj
);
1313 if (res3
== ISC_R_SUCCESS
)
1314 arg
= cfg_obj_asstring(obj
);
1315 if (strcasecmp(arg
, "off") != 0 && !ddns
) {
1316 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1317 "'auto-dnssec %s;' requires "
1318 "dynamic DNS to be configured in the zone",
1320 result
= ISC_R_FAILURE
;
1322 if (strcasecmp(arg
, "create") == 0) {
1323 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1324 "'auto-dnssec create;' is not "
1326 result
= ISC_R_FAILURE
;
1330 res1
= cfg_map_get(zoptions
, "sig-signing-type", &obj
);
1331 if (res1
== ISC_R_SUCCESS
) {
1332 isc_uint32_t type
= cfg_obj_asuint32(obj
);
1333 if (type
< 0xff00U
|| type
> 0xffffU
)
1334 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1335 "sig-signing-type: %u out of "
1336 "range [%u..%u]", type
,
1338 result
= ISC_R_FAILURE
;
1343 * Check the excessively complicated "dialup" option.
1345 if (ztype
== MASTERZONE
|| ztype
== SLAVEZONE
|| ztype
== STUBZONE
) {
1346 const cfg_obj_t
*dialup
= NULL
;
1347 (void)cfg_map_get(zoptions
, "dialup", &dialup
);
1348 if (dialup
!= NULL
&& cfg_obj_isstring(dialup
)) {
1349 const char *str
= cfg_obj_asstring(dialup
);
1351 i
< sizeof(dialups
) / sizeof(dialups
[0]);
1354 if (strcasecmp(dialups
[i
].name
, str
) != 0)
1356 if ((dialups
[i
].allowed
& ztype
) == 0) {
1357 cfg_obj_log(obj
, logctx
,
1359 "dialup type '%s' is not "
1362 str
, typestr
, zname
);
1363 result
= ISC_R_FAILURE
;
1367 if (i
== sizeof(dialups
) / sizeof(dialups
[0])) {
1368 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1369 "invalid dialup type '%s' in zone "
1370 "'%s'", str
, zname
);
1371 result
= ISC_R_FAILURE
;
1377 * Check that forwarding is reasonable.
1381 if (voptions
!= NULL
)
1382 (void)cfg_map_get(voptions
, "forwarders", &obj
);
1384 const cfg_obj_t
*options
= NULL
;
1385 (void)cfg_map_get(config
, "options", &options
);
1386 if (options
!= NULL
)
1387 (void)cfg_map_get(options
, "forwarders", &obj
);
1390 if (check_forward(zoptions
, obj
, logctx
) != ISC_R_SUCCESS
)
1391 result
= ISC_R_FAILURE
;
1394 * Check various options.
1396 tresult
= check_options(zoptions
, logctx
, mctx
);
1397 if (tresult
!= ISC_R_SUCCESS
)
1401 * If the zone type is rbt/rbt64 then master/hint zones
1402 * require file clauses.
1405 tresult
= cfg_map_get(zoptions
, "database", &obj
);
1406 if (tresult
== ISC_R_NOTFOUND
||
1407 (tresult
== ISC_R_SUCCESS
&&
1408 (strcmp("rbt", cfg_obj_asstring(obj
)) == 0 ||
1409 strcmp("rbt64", cfg_obj_asstring(obj
)) == 0))) {
1411 tresult
= cfg_map_get(zoptions
, "file", &obj
);
1412 if (tresult
!= ISC_R_SUCCESS
&&
1413 (ztype
== MASTERZONE
|| ztype
== HINTZONE
)) {
1414 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
1415 "zone '%s': missing 'file' entry",
1425 typedef struct keyalgorithms
{
1431 bind9_check_key(const cfg_obj_t
*key
, isc_log_t
*logctx
) {
1432 const cfg_obj_t
*algobj
= NULL
;
1433 const cfg_obj_t
*secretobj
= NULL
;
1434 const char *keyname
= cfg_obj_asstring(cfg_map_getname(key
));
1435 const char *algorithm
;
1438 isc_result_t result
;
1440 unsigned char secretbuf
[1024];
1441 static const algorithmtable algorithms
[] = {
1442 { "hmac-md5", 128 },
1443 { "hmac-md5.sig-alg.reg.int", 0 },
1444 { "hmac-md5.sig-alg.reg.int.", 0 },
1445 { "hmac-sha1", 160 },
1446 { "hmac-sha224", 224 },
1447 { "hmac-sha256", 256 },
1448 { "hmac-sha384", 384 },
1449 { "hmac-sha512", 512 },
1453 (void)cfg_map_get(key
, "algorithm", &algobj
);
1454 (void)cfg_map_get(key
, "secret", &secretobj
);
1455 if (secretobj
== NULL
|| algobj
== NULL
) {
1456 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
1457 "key '%s' must have both 'secret' and "
1458 "'algorithm' defined",
1460 return (ISC_R_FAILURE
);
1463 isc_buffer_init(&buf
, secretbuf
, sizeof(secretbuf
));
1464 result
= isc_base64_decodestring(cfg_obj_asstring(secretobj
), &buf
);
1465 if (result
!= ISC_R_SUCCESS
) {
1466 cfg_obj_log(secretobj
, logctx
, ISC_LOG_ERROR
,
1467 "bad secret '%s'", isc_result_totext(result
));
1471 algorithm
= cfg_obj_asstring(algobj
);
1472 for (i
= 0; algorithms
[i
].name
!= NULL
; i
++) {
1473 len
= strlen(algorithms
[i
].name
);
1474 if (strncasecmp(algorithms
[i
].name
, algorithm
, len
) == 0 &&
1475 (algorithm
[len
] == '\0' ||
1476 (algorithms
[i
].size
!= 0 && algorithm
[len
] == '-')))
1479 if (algorithms
[i
].name
== NULL
) {
1480 cfg_obj_log(algobj
, logctx
, ISC_LOG_ERROR
,
1481 "unknown algorithm '%s'", algorithm
);
1482 return (ISC_R_NOTFOUND
);
1484 if (algorithm
[len
] == '-') {
1485 isc_uint16_t digestbits
;
1486 isc_result_t result
;
1487 result
= isc_parse_uint16(&digestbits
, algorithm
+ len
+ 1, 10);
1488 if (result
== ISC_R_SUCCESS
|| result
== ISC_R_RANGE
) {
1489 if (result
== ISC_R_RANGE
||
1490 digestbits
> algorithms
[i
].size
) {
1491 cfg_obj_log(algobj
, logctx
, ISC_LOG_ERROR
,
1492 "key '%s' digest-bits too large "
1493 "[%u..%u]", keyname
,
1494 algorithms
[i
].size
/ 2,
1495 algorithms
[i
].size
);
1496 return (ISC_R_RANGE
);
1498 if ((digestbits
% 8) != 0) {
1499 cfg_obj_log(algobj
, logctx
, ISC_LOG_ERROR
,
1500 "key '%s' digest-bits not multiple"
1502 return (ISC_R_RANGE
);
1505 * Recommended minima for hmac algorithms.
1507 if ((digestbits
< (algorithms
[i
].size
/ 2U) ||
1508 (digestbits
< 80U)))
1509 cfg_obj_log(algobj
, logctx
, ISC_LOG_WARNING
,
1510 "key '%s' digest-bits too small "
1512 algorithms
[i
].size
/2);
1514 cfg_obj_log(algobj
, logctx
, ISC_LOG_ERROR
,
1515 "key '%s': unable to parse digest-bits",
1520 return (ISC_R_SUCCESS
);
1524 * Check key list for duplicates key names and that the key names
1525 * are valid domain names as these keys are used for TSIG.
1527 * Check the key contents for validity.
1530 check_keylist(const cfg_obj_t
*keys
, isc_symtab_t
*symtab
,
1531 isc_mem_t
*mctx
, isc_log_t
*logctx
)
1533 char namebuf
[DNS_NAME_FORMATSIZE
];
1534 dns_fixedname_t fname
;
1536 isc_result_t result
= ISC_R_SUCCESS
;
1537 isc_result_t tresult
;
1538 const cfg_listelt_t
*element
;
1540 dns_fixedname_init(&fname
);
1541 name
= dns_fixedname_name(&fname
);
1542 for (element
= cfg_list_first(keys
);
1544 element
= cfg_list_next(element
))
1546 const cfg_obj_t
*key
= cfg_listelt_value(element
);
1547 const char *keyid
= cfg_obj_asstring(cfg_map_getname(key
));
1548 isc_symvalue_t symvalue
;
1552 isc_buffer_init(&b
, keyid
, strlen(keyid
));
1553 isc_buffer_add(&b
, strlen(keyid
));
1554 tresult
= dns_name_fromtext(name
, &b
, dns_rootname
,
1556 if (tresult
!= ISC_R_SUCCESS
) {
1557 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
1558 "key '%s': bad key name", keyid
);
1562 tresult
= bind9_check_key(key
, logctx
);
1563 if (tresult
!= ISC_R_SUCCESS
)
1566 dns_name_format(name
, namebuf
, sizeof(namebuf
));
1567 keyname
= isc_mem_strdup(mctx
, namebuf
);
1568 if (keyname
== NULL
)
1569 return (ISC_R_NOMEMORY
);
1570 symvalue
.as_cpointer
= key
;
1571 tresult
= isc_symtab_define(symtab
, keyname
, 1, symvalue
,
1572 isc_symexists_reject
);
1573 if (tresult
== ISC_R_EXISTS
) {
1577 RUNTIME_CHECK(isc_symtab_lookup(symtab
, keyname
,
1578 1, &symvalue
) == ISC_R_SUCCESS
);
1579 file
= cfg_obj_file(symvalue
.as_cpointer
);
1580 line
= cfg_obj_line(symvalue
.as_cpointer
);
1583 file
= "<unknown file>";
1584 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
1585 "key '%s': already exists "
1586 "previous definition: %s:%u",
1588 isc_mem_free(mctx
, keyname
);
1590 } else if (tresult
!= ISC_R_SUCCESS
) {
1591 isc_mem_free(mctx
, keyname
);
1602 { "transfer-source", "transfer-source-v6" },
1603 { "notify-source", "notify-source-v6" },
1604 { "query-source", "query-source-v6" },
1609 * RNDC keys are not normalised unlike TSIG keys.
1611 * "foo." is different to "foo".
1613 static isc_boolean_t
1614 rndckey_exists(const cfg_obj_t
*keylist
, const char *keyname
) {
1615 const cfg_listelt_t
*element
;
1616 const cfg_obj_t
*obj
;
1619 if (keylist
== NULL
)
1622 for (element
= cfg_list_first(keylist
);
1624 element
= cfg_list_next(element
))
1626 obj
= cfg_listelt_value(element
);
1627 str
= cfg_obj_asstring(cfg_map_getname(obj
));
1628 if (!strcasecmp(str
, keyname
))
1635 check_servers(const cfg_obj_t
*config
, const cfg_obj_t
*voptions
,
1636 isc_symtab_t
*symtab
, isc_log_t
*logctx
)
1638 dns_fixedname_t fname
;
1639 isc_result_t result
= ISC_R_SUCCESS
;
1640 isc_result_t tresult
;
1641 const cfg_listelt_t
*e1
, *e2
;
1642 const cfg_obj_t
*v1
, *v2
, *keys
;
1643 const cfg_obj_t
*servers
;
1644 isc_netaddr_t n1
, n2
;
1645 unsigned int p1
, p2
;
1646 const cfg_obj_t
*obj
;
1647 char buf
[ISC_NETADDR_FORMATSIZE
];
1648 char namebuf
[DNS_NAME_FORMATSIZE
];
1653 dns_name_t
*keyname
;
1656 if (voptions
!= NULL
)
1657 (void)cfg_map_get(voptions
, "server", &servers
);
1658 if (servers
== NULL
)
1659 (void)cfg_map_get(config
, "server", &servers
);
1660 if (servers
== NULL
)
1661 return (ISC_R_SUCCESS
);
1663 for (e1
= cfg_list_first(servers
); e1
!= NULL
; e1
= cfg_list_next(e1
)) {
1664 v1
= cfg_listelt_value(e1
);
1665 cfg_obj_asnetprefix(cfg_map_getname(v1
), &n1
, &p1
);
1667 * Check that unused bits are zero.
1669 tresult
= isc_netaddr_prefixok(&n1
, p1
);
1670 if (tresult
!= ISC_R_SUCCESS
) {
1671 INSIST(tresult
== ISC_R_FAILURE
);
1672 isc_netaddr_format(&n1
, buf
, sizeof(buf
));
1673 cfg_obj_log(v1
, logctx
, ISC_LOG_ERROR
,
1674 "server '%s/%u': invalid prefix "
1675 "(extra bits specified)", buf
, p1
);
1681 if (n1
.family
== AF_INET
)
1682 xfr
= sources
[source
].v6
;
1684 xfr
= sources
[source
].v4
;
1685 (void)cfg_map_get(v1
, xfr
, &obj
);
1687 isc_netaddr_format(&n1
, buf
, sizeof(buf
));
1688 cfg_obj_log(v1
, logctx
, ISC_LOG_ERROR
,
1689 "server '%s/%u': %s not legal",
1691 result
= ISC_R_FAILURE
;
1693 } while (sources
[++source
].v4
!= NULL
);
1695 while ((e2
= cfg_list_next(e2
)) != NULL
) {
1696 v2
= cfg_listelt_value(e2
);
1697 cfg_obj_asnetprefix(cfg_map_getname(v2
), &n2
, &p2
);
1698 if (p1
== p2
&& isc_netaddr_equal(&n1
, &n2
)) {
1699 const char *file
= cfg_obj_file(v1
);
1700 unsigned int line
= cfg_obj_line(v1
);
1703 file
= "<unknown file>";
1705 isc_netaddr_format(&n2
, buf
, sizeof(buf
));
1706 cfg_obj_log(v2
, logctx
, ISC_LOG_ERROR
,
1707 "server '%s/%u': already exists "
1708 "previous definition: %s:%u",
1709 buf
, p2
, file
, line
);
1710 result
= ISC_R_FAILURE
;
1714 cfg_map_get(v1
, "keys", &keys
);
1717 * Normalize key name.
1719 keyval
= cfg_obj_asstring(keys
);
1720 dns_fixedname_init(&fname
);
1721 isc_buffer_init(&b
, keyval
, strlen(keyval
));
1722 isc_buffer_add(&b
, strlen(keyval
));
1723 keyname
= dns_fixedname_name(&fname
);
1724 tresult
= dns_name_fromtext(keyname
, &b
, dns_rootname
,
1726 if (tresult
!= ISC_R_SUCCESS
) {
1727 cfg_obj_log(keys
, logctx
, ISC_LOG_ERROR
,
1728 "bad key name '%s'", keyval
);
1729 result
= ISC_R_FAILURE
;
1732 dns_name_format(keyname
, namebuf
, sizeof(namebuf
));
1733 tresult
= isc_symtab_lookup(symtab
, namebuf
, 1, NULL
);
1734 if (tresult
!= ISC_R_SUCCESS
) {
1735 cfg_obj_log(keys
, logctx
, ISC_LOG_ERROR
,
1736 "unknown key '%s'", keyval
);
1737 result
= ISC_R_FAILURE
;
1745 check_viewconf(const cfg_obj_t
*config
, const cfg_obj_t
*voptions
,
1746 const char *viewname
, dns_rdataclass_t vclass
,
1747 isc_log_t
*logctx
, isc_mem_t
*mctx
)
1749 const cfg_obj_t
*zones
= NULL
;
1750 const cfg_obj_t
*keys
= NULL
;
1751 const cfg_listelt_t
*element
;
1752 isc_symtab_t
*symtab
= NULL
;
1753 isc_result_t result
= ISC_R_SUCCESS
;
1754 isc_result_t tresult
= ISC_R_SUCCESS
;
1755 cfg_aclconfctx_t actx
;
1756 const cfg_obj_t
*obj
;
1757 isc_boolean_t enablednssec
, enablevalidation
;
1760 * Check that all zone statements are syntactically correct and
1761 * there are no duplicate zones.
1763 tresult
= isc_symtab_create(mctx
, 100, freekey
, mctx
,
1764 ISC_FALSE
, &symtab
);
1765 if (tresult
!= ISC_R_SUCCESS
)
1766 return (ISC_R_NOMEMORY
);
1768 cfg_aclconfctx_init(&actx
);
1770 if (voptions
!= NULL
)
1771 (void)cfg_map_get(voptions
, "zone", &zones
);
1773 (void)cfg_map_get(config
, "zone", &zones
);
1775 for (element
= cfg_list_first(zones
);
1777 element
= cfg_list_next(element
))
1779 isc_result_t tresult
;
1780 const cfg_obj_t
*zone
= cfg_listelt_value(element
);
1782 tresult
= check_zoneconf(zone
, voptions
, config
, symtab
,
1783 vclass
, &actx
, logctx
, mctx
);
1784 if (tresult
!= ISC_R_SUCCESS
)
1785 result
= ISC_R_FAILURE
;
1788 isc_symtab_destroy(&symtab
);
1791 * Check that forwarding 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_forward(options
, NULL
,
1798 logctx
) != ISC_R_SUCCESS
)
1799 result
= ISC_R_FAILURE
;
1801 if (check_forward(voptions
, NULL
, logctx
) != ISC_R_SUCCESS
)
1802 result
= ISC_R_FAILURE
;
1806 * Check that dual-stack-servers is reasonable.
1808 if (voptions
== NULL
) {
1809 const cfg_obj_t
*options
= NULL
;
1810 (void)cfg_map_get(config
, "options", &options
);
1811 if (options
!= NULL
)
1812 if (check_dual_stack(options
, logctx
) != ISC_R_SUCCESS
)
1813 result
= ISC_R_FAILURE
;
1815 if (check_dual_stack(voptions
, logctx
) != ISC_R_SUCCESS
)
1816 result
= ISC_R_FAILURE
;
1820 * Check that rrset-order is reasonable.
1822 if (voptions
!= NULL
) {
1823 if (check_order(voptions
, logctx
) != ISC_R_SUCCESS
)
1824 result
= ISC_R_FAILURE
;
1828 * Check that all key statements are syntactically correct and
1829 * there are no duplicate keys.
1831 tresult
= isc_symtab_create(mctx
, 100, freekey
, mctx
,
1832 ISC_FALSE
, &symtab
);
1833 if (tresult
!= ISC_R_SUCCESS
)
1834 return (ISC_R_NOMEMORY
);
1836 (void)cfg_map_get(config
, "key", &keys
);
1837 tresult
= check_keylist(keys
, symtab
, mctx
, logctx
);
1838 if (tresult
== ISC_R_EXISTS
)
1839 result
= ISC_R_FAILURE
;
1840 else if (tresult
!= ISC_R_SUCCESS
) {
1841 isc_symtab_destroy(&symtab
);
1845 if (voptions
!= NULL
) {
1847 (void)cfg_map_get(voptions
, "key", &keys
);
1848 tresult
= check_keylist(keys
, symtab
, mctx
, logctx
);
1849 if (tresult
== ISC_R_EXISTS
)
1850 result
= ISC_R_FAILURE
;
1851 else if (tresult
!= ISC_R_SUCCESS
) {
1852 isc_symtab_destroy(&symtab
);
1858 * Global servers can refer to keys in views.
1860 if (check_servers(config
, voptions
, symtab
, logctx
) != ISC_R_SUCCESS
)
1861 result
= ISC_R_FAILURE
;
1863 isc_symtab_destroy(&symtab
);
1866 * Check that dnssec-enable/dnssec-validation are sensible.
1869 if (voptions
!= NULL
)
1870 (void)cfg_map_get(voptions
, "dnssec-enable", &obj
);
1872 (void)cfg_map_get(config
, "dnssec-enable", &obj
);
1874 enablednssec
= ISC_TRUE
;
1876 enablednssec
= cfg_obj_asboolean(obj
);
1879 if (voptions
!= NULL
)
1880 (void)cfg_map_get(voptions
, "dnssec-validation", &obj
);
1882 (void)cfg_map_get(config
, "dnssec-validation", &obj
);
1884 enablevalidation
= ISC_FALSE
; /* XXXMPA Change for 9.5. */
1886 enablevalidation
= cfg_obj_asboolean(obj
);
1888 if (enablevalidation
&& !enablednssec
)
1889 cfg_obj_log(obj
, logctx
, ISC_LOG_WARNING
,
1890 "'dnssec-validation yes;' and 'dnssec-enable no;'");
1892 if (voptions
!= NULL
)
1893 tresult
= check_options(voptions
, logctx
, mctx
);
1895 tresult
= check_options(config
, logctx
, mctx
);
1896 if (tresult
!= ISC_R_SUCCESS
)
1899 tresult
= check_viewacls(&actx
, voptions
, config
, logctx
, mctx
);
1900 if (tresult
!= ISC_R_SUCCESS
)
1903 tresult
= check_recursionacls(&actx
, voptions
, viewname
,
1904 config
, logctx
, mctx
);
1905 if (tresult
!= ISC_R_SUCCESS
)
1908 cfg_aclconfctx_destroy(&actx
);
1914 default_channels
[] = {
1923 bind9_check_logging(const cfg_obj_t
*config
, isc_log_t
*logctx
,
1926 const cfg_obj_t
*categories
= NULL
;
1927 const cfg_obj_t
*category
;
1928 const cfg_obj_t
*channels
= NULL
;
1929 const cfg_obj_t
*channel
;
1930 const cfg_listelt_t
*element
;
1931 const cfg_listelt_t
*delement
;
1932 const char *channelname
;
1933 const char *catname
;
1934 const cfg_obj_t
*fileobj
= NULL
;
1935 const cfg_obj_t
*syslogobj
= NULL
;
1936 const cfg_obj_t
*nullobj
= NULL
;
1937 const cfg_obj_t
*stderrobj
= NULL
;
1938 const cfg_obj_t
*logobj
= NULL
;
1939 isc_result_t result
= ISC_R_SUCCESS
;
1940 isc_result_t tresult
;
1941 isc_symtab_t
*symtab
= NULL
;
1942 isc_symvalue_t symvalue
;
1945 (void)cfg_map_get(config
, "logging", &logobj
);
1947 return (ISC_R_SUCCESS
);
1949 result
= isc_symtab_create(mctx
, 100, NULL
, NULL
, ISC_FALSE
, &symtab
);
1950 if (result
!= ISC_R_SUCCESS
)
1953 symvalue
.as_cpointer
= NULL
;
1954 for (i
= 0; default_channels
[i
] != NULL
; i
++) {
1955 tresult
= isc_symtab_define(symtab
, default_channels
[i
], 1,
1956 symvalue
, isc_symexists_replace
);
1957 if (tresult
!= ISC_R_SUCCESS
)
1961 cfg_map_get(logobj
, "channel", &channels
);
1963 for (element
= cfg_list_first(channels
);
1965 element
= cfg_list_next(element
))
1967 channel
= cfg_listelt_value(element
);
1968 channelname
= cfg_obj_asstring(cfg_map_getname(channel
));
1969 fileobj
= syslogobj
= nullobj
= stderrobj
= NULL
;
1970 (void)cfg_map_get(channel
, "file", &fileobj
);
1971 (void)cfg_map_get(channel
, "syslog", &syslogobj
);
1972 (void)cfg_map_get(channel
, "null", &nullobj
);
1973 (void)cfg_map_get(channel
, "stderr", &stderrobj
);
1975 if (fileobj
!= NULL
)
1977 if (syslogobj
!= NULL
)
1979 if (nullobj
!= NULL
)
1981 if (stderrobj
!= NULL
)
1984 cfg_obj_log(channel
, logctx
, ISC_LOG_ERROR
,
1985 "channel '%s': exactly one of file, syslog, "
1986 "null, and stderr must be present",
1988 result
= ISC_R_FAILURE
;
1990 tresult
= isc_symtab_define(symtab
, channelname
, 1,
1991 symvalue
, isc_symexists_replace
);
1992 if (tresult
!= ISC_R_SUCCESS
)
1996 cfg_map_get(logobj
, "category", &categories
);
1998 for (element
= cfg_list_first(categories
);
2000 element
= cfg_list_next(element
))
2002 category
= cfg_listelt_value(element
);
2003 catname
= cfg_obj_asstring(cfg_tuple_get(category
, "name"));
2004 if (isc_log_categorybyname(logctx
, catname
) == NULL
) {
2005 cfg_obj_log(category
, logctx
, ISC_LOG_ERROR
,
2006 "undefined category: '%s'", catname
);
2007 result
= ISC_R_FAILURE
;
2009 channels
= cfg_tuple_get(category
, "destinations");
2010 for (delement
= cfg_list_first(channels
);
2012 delement
= cfg_list_next(delement
))
2014 channel
= cfg_listelt_value(delement
);
2015 channelname
= cfg_obj_asstring(channel
);
2016 tresult
= isc_symtab_lookup(symtab
, channelname
, 1,
2018 if (tresult
!= ISC_R_SUCCESS
) {
2019 cfg_obj_log(channel
, logctx
, ISC_LOG_ERROR
,
2020 "undefined channel: '%s'",
2026 isc_symtab_destroy(&symtab
);
2031 bind9_check_controlskeys(const cfg_obj_t
*control
, const cfg_obj_t
*keylist
,
2034 isc_result_t result
= ISC_R_SUCCESS
;
2035 const cfg_obj_t
*control_keylist
;
2036 const cfg_listelt_t
*element
;
2037 const cfg_obj_t
*key
;
2040 control_keylist
= cfg_tuple_get(control
, "keys");
2041 if (cfg_obj_isvoid(control_keylist
))
2042 return (ISC_R_SUCCESS
);
2044 for (element
= cfg_list_first(control_keylist
);
2046 element
= cfg_list_next(element
))
2048 key
= cfg_listelt_value(element
);
2049 keyval
= cfg_obj_asstring(key
);
2051 if (!rndckey_exists(keylist
, keyval
)) {
2052 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
2053 "unknown key '%s'", keyval
);
2054 result
= ISC_R_NOTFOUND
;
2061 bind9_check_controls(const cfg_obj_t
*config
, isc_log_t
*logctx
,
2064 isc_result_t result
= ISC_R_SUCCESS
, tresult
;
2065 cfg_aclconfctx_t actx
;
2066 const cfg_listelt_t
*element
, *element2
;
2067 const cfg_obj_t
*allow
;
2068 const cfg_obj_t
*control
;
2069 const cfg_obj_t
*controls
;
2070 const cfg_obj_t
*controlslist
= NULL
;
2071 const cfg_obj_t
*inetcontrols
;
2072 const cfg_obj_t
*unixcontrols
;
2073 const cfg_obj_t
*keylist
= NULL
;
2075 isc_uint32_t perm
, mask
;
2076 dns_acl_t
*acl
= NULL
;
2077 isc_sockaddr_t addr
;
2080 (void)cfg_map_get(config
, "controls", &controlslist
);
2081 if (controlslist
== NULL
)
2082 return (ISC_R_SUCCESS
);
2084 (void)cfg_map_get(config
, "key", &keylist
);
2086 cfg_aclconfctx_init(&actx
);
2089 * INET: Check allow clause.
2090 * UNIX: Check "perm" for sanity, check path length.
2092 for (element
= cfg_list_first(controlslist
);
2094 element
= cfg_list_next(element
)) {
2095 controls
= cfg_listelt_value(element
);
2096 unixcontrols
= NULL
;
2097 inetcontrols
= NULL
;
2098 (void)cfg_map_get(controls
, "unix", &unixcontrols
);
2099 (void)cfg_map_get(controls
, "inet", &inetcontrols
);
2100 for (element2
= cfg_list_first(inetcontrols
);
2102 element2
= cfg_list_next(element2
)) {
2103 control
= cfg_listelt_value(element2
);
2104 allow
= cfg_tuple_get(control
, "allow");
2105 tresult
= cfg_acl_fromconfig(allow
, config
, logctx
,
2106 &actx
, mctx
, 0, &acl
);
2108 dns_acl_detach(&acl
);
2109 if (tresult
!= ISC_R_SUCCESS
)
2111 tresult
= bind9_check_controlskeys(control
, keylist
,
2113 if (tresult
!= ISC_R_SUCCESS
)
2116 for (element2
= cfg_list_first(unixcontrols
);
2118 element2
= cfg_list_next(element2
)) {
2119 control
= cfg_listelt_value(element2
);
2120 path
= cfg_obj_asstring(cfg_tuple_get(control
, "path"));
2121 tresult
= isc_sockaddr_frompath(&addr
, path
);
2122 if (tresult
== ISC_R_NOSPACE
) {
2123 cfg_obj_log(control
, logctx
, ISC_LOG_ERROR
,
2124 "unix control '%s': path too long",
2126 result
= ISC_R_NOSPACE
;
2128 perm
= cfg_obj_asuint32(cfg_tuple_get(control
, "perm"));
2129 for (i
= 0; i
< 3; i
++) {
2130 #ifdef NEED_SECURE_DIRECTORY
2131 mask
= (0x1 << (i
*3)); /* SEARCH */
2133 mask
= (0x6 << (i
*3)); /* READ + WRITE */
2135 if ((perm
& mask
) == mask
)
2139 cfg_obj_log(control
, logctx
, ISC_LOG_WARNING
,
2140 "unix control '%s' allows access "
2141 "to everyone", path
);
2142 } else if (i
== 3) {
2143 cfg_obj_log(control
, logctx
, ISC_LOG_WARNING
,
2144 "unix control '%s' allows access "
2147 tresult
= bind9_check_controlskeys(control
, keylist
,
2149 if (tresult
!= ISC_R_SUCCESS
)
2153 cfg_aclconfctx_destroy(&actx
);
2158 bind9_check_namedconf(const cfg_obj_t
*config
, isc_log_t
*logctx
,
2161 const cfg_obj_t
*options
= NULL
;
2162 const cfg_obj_t
*views
= NULL
;
2163 const cfg_obj_t
*acls
= NULL
;
2164 const cfg_obj_t
*kals
= NULL
;
2165 const cfg_obj_t
*obj
;
2166 const cfg_listelt_t
*velement
;
2167 isc_result_t result
= ISC_R_SUCCESS
;
2168 isc_result_t tresult
;
2169 isc_symtab_t
*symtab
= NULL
;
2171 static const char *builtin
[] = { "localhost", "localnets",
2174 (void)cfg_map_get(config
, "options", &options
);
2176 if (options
!= NULL
&&
2177 check_options(options
, logctx
, mctx
) != ISC_R_SUCCESS
)
2178 result
= ISC_R_FAILURE
;
2180 if (bind9_check_logging(config
, logctx
, mctx
) != ISC_R_SUCCESS
)
2181 result
= ISC_R_FAILURE
;
2183 if (bind9_check_controls(config
, logctx
, mctx
) != ISC_R_SUCCESS
)
2184 result
= ISC_R_FAILURE
;
2186 if (options
!= NULL
&&
2187 check_order(options
, logctx
) != ISC_R_SUCCESS
)
2188 result
= ISC_R_FAILURE
;
2190 (void)cfg_map_get(config
, "view", &views
);
2192 if (views
!= NULL
&& options
!= NULL
)
2193 if (check_dual_stack(options
, logctx
) != ISC_R_SUCCESS
)
2194 result
= ISC_R_FAILURE
;
2196 if (views
== NULL
) {
2197 if (check_viewconf(config
, NULL
, NULL
, dns_rdataclass_in
,
2198 logctx
, mctx
) != ISC_R_SUCCESS
)
2199 result
= ISC_R_FAILURE
;
2201 const cfg_obj_t
*zones
= NULL
;
2203 (void)cfg_map_get(config
, "zone", &zones
);
2204 if (zones
!= NULL
) {
2205 cfg_obj_log(zones
, logctx
, ISC_LOG_ERROR
,
2206 "when using 'view' statements, "
2207 "all zones must be in views");
2208 result
= ISC_R_FAILURE
;
2212 tresult
= isc_symtab_create(mctx
, 100, NULL
, NULL
, ISC_TRUE
, &symtab
);
2213 if (tresult
!= ISC_R_SUCCESS
)
2215 for (velement
= cfg_list_first(views
);
2217 velement
= cfg_list_next(velement
))
2219 const cfg_obj_t
*view
= cfg_listelt_value(velement
);
2220 const cfg_obj_t
*vname
= cfg_tuple_get(view
, "name");
2221 const cfg_obj_t
*voptions
= cfg_tuple_get(view
, "options");
2222 const cfg_obj_t
*vclassobj
= cfg_tuple_get(view
, "class");
2223 dns_rdataclass_t vclass
= dns_rdataclass_in
;
2224 isc_result_t tresult
= ISC_R_SUCCESS
;
2225 const char *key
= cfg_obj_asstring(vname
);
2226 isc_symvalue_t symvalue
;
2228 if (cfg_obj_isstring(vclassobj
)) {
2231 DE_CONST(cfg_obj_asstring(vclassobj
), r
.base
);
2232 r
.length
= strlen(r
.base
);
2233 tresult
= dns_rdataclass_fromtext(&vclass
, &r
);
2234 if (tresult
!= ISC_R_SUCCESS
)
2235 cfg_obj_log(vclassobj
, logctx
, ISC_LOG_ERROR
,
2236 "view '%s': invalid class %s",
2237 cfg_obj_asstring(vname
), r
.base
);
2239 if (tresult
== ISC_R_SUCCESS
&& symtab
!= NULL
) {
2240 symvalue
.as_cpointer
= view
;
2241 tresult
= isc_symtab_define(symtab
, key
, vclass
,
2243 isc_symexists_reject
);
2244 if (tresult
== ISC_R_EXISTS
) {
2247 RUNTIME_CHECK(isc_symtab_lookup(symtab
, key
,
2248 vclass
, &symvalue
) == ISC_R_SUCCESS
);
2249 file
= cfg_obj_file(symvalue
.as_cpointer
);
2250 line
= cfg_obj_line(symvalue
.as_cpointer
);
2251 cfg_obj_log(view
, logctx
, ISC_LOG_ERROR
,
2252 "view '%s': already exists "
2253 "previous definition: %s:%u",
2256 } else if (tresult
!= ISC_R_SUCCESS
) {
2258 } else if ((strcasecmp(key
, "_bind") == 0 &&
2259 vclass
== dns_rdataclass_ch
) ||
2260 (strcasecmp(key
, "_default") == 0 &&
2261 vclass
== dns_rdataclass_in
)) {
2262 cfg_obj_log(view
, logctx
, ISC_LOG_ERROR
,
2263 "attempt to redefine builtin view "
2265 result
= ISC_R_EXISTS
;
2268 if (tresult
== ISC_R_SUCCESS
)
2269 tresult
= check_viewconf(config
, voptions
, key
,
2270 vclass
, logctx
, mctx
);
2271 if (tresult
!= ISC_R_SUCCESS
)
2272 result
= ISC_R_FAILURE
;
2275 isc_symtab_destroy(&symtab
);
2277 if (views
!= NULL
&& options
!= NULL
) {
2279 tresult
= cfg_map_get(options
, "cache-file", &obj
);
2280 if (tresult
== ISC_R_SUCCESS
) {
2281 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
2282 "'cache-file' cannot be a global "
2283 "option if views are present");
2284 result
= ISC_R_FAILURE
;
2288 cfg_map_get(config
, "acl", &acls
);
2291 const cfg_listelt_t
*elt
;
2292 const cfg_listelt_t
*elt2
;
2293 const char *aclname
;
2295 for (elt
= cfg_list_first(acls
);
2297 elt
= cfg_list_next(elt
)) {
2298 const cfg_obj_t
*acl
= cfg_listelt_value(elt
);
2299 unsigned int line
= cfg_obj_line(acl
);
2302 aclname
= cfg_obj_asstring(cfg_tuple_get(acl
, "name"));
2304 i
< sizeof(builtin
) / sizeof(builtin
[0]);
2306 if (strcasecmp(aclname
, builtin
[i
]) == 0) {
2307 cfg_obj_log(acl
, logctx
, ISC_LOG_ERROR
,
2308 "attempt to redefine "
2311 result
= ISC_R_FAILURE
;
2315 for (elt2
= cfg_list_next(elt
);
2317 elt2
= cfg_list_next(elt2
)) {
2318 const cfg_obj_t
*acl2
= cfg_listelt_value(elt2
);
2320 name
= cfg_obj_asstring(cfg_tuple_get(acl2
,
2322 if (strcasecmp(aclname
, name
) == 0) {
2323 const char *file
= cfg_obj_file(acl
);
2326 file
= "<unknown file>";
2328 cfg_obj_log(acl2
, logctx
, ISC_LOG_ERROR
,
2329 "attempt to redefine "
2330 "acl '%s' previous "
2331 "definition: %s:%u",
2333 result
= ISC_R_FAILURE
;
2339 tresult
= cfg_map_get(config
, "kal", &kals
);
2340 if (tresult
== ISC_R_SUCCESS
) {
2341 const cfg_listelt_t
*elt
;
2342 const cfg_listelt_t
*elt2
;
2343 const char *aclname
;
2345 for (elt
= cfg_list_first(kals
);
2347 elt
= cfg_list_next(elt
)) {
2348 const cfg_obj_t
*acl
= cfg_listelt_value(elt
);
2350 aclname
= cfg_obj_asstring(cfg_tuple_get(acl
, "name"));
2352 for (elt2
= cfg_list_next(elt
);
2354 elt2
= cfg_list_next(elt2
)) {
2355 const cfg_obj_t
*acl2
= cfg_listelt_value(elt2
);
2357 name
= cfg_obj_asstring(cfg_tuple_get(acl2
,
2359 if (strcasecmp(aclname
, name
) == 0) {
2360 const char *file
= cfg_obj_file(acl
);
2361 unsigned int line
= cfg_obj_line(acl
);
2364 file
= "<unknown file>";
2366 cfg_obj_log(acl2
, logctx
, ISC_LOG_ERROR
,
2367 "attempt to redefine "
2368 "kal '%s' previous "
2369 "definition: %s:%u",
2371 result
= ISC_R_FAILURE
;