2 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2001-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: check.c,v 1.86.10.11 2009/06/03 07:08:20 marka Exp $ */
26 #include <isc/buffer.h>
29 #include <isc/netaddr.h>
30 #include <isc/parseint.h>
31 #include <isc/region.h>
32 #include <isc/result.h>
33 #include <isc/sockaddr.h>
34 #include <isc/string.h>
35 #include <isc/symtab.h>
39 #include <dns/fixedname.h>
40 #include <dns/rdataclass.h>
41 #include <dns/rdatatype.h>
42 #include <dns/secalg.h>
44 #include <isccfg/aclconf.h>
45 #include <isccfg/cfg.h>
47 #include <bind9/check.h>
50 freekey(char *key
, unsigned int type
, isc_symvalue_t value
, void *userarg
) {
53 isc_mem_free(userarg
, key
);
57 check_orderent(const cfg_obj_t
*ent
, isc_log_t
*logctx
) {
58 isc_result_t result
= ISC_R_SUCCESS
;
61 dns_fixedname_t fixed
;
63 dns_rdataclass_t rdclass
;
64 dns_rdatatype_t rdtype
;
68 dns_fixedname_init(&fixed
);
69 obj
= cfg_tuple_get(ent
, "class");
70 if (cfg_obj_isstring(obj
)) {
72 DE_CONST(cfg_obj_asstring(obj
), r
.base
);
73 r
.length
= strlen(r
.base
);
74 tresult
= dns_rdataclass_fromtext(&rdclass
, &r
);
75 if (tresult
!= ISC_R_SUCCESS
) {
76 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
77 "rrset-order: invalid class '%s'",
79 result
= ISC_R_FAILURE
;
83 obj
= cfg_tuple_get(ent
, "type");
84 if (cfg_obj_isstring(obj
)) {
86 DE_CONST(cfg_obj_asstring(obj
), r
.base
);
87 r
.length
= strlen(r
.base
);
88 tresult
= dns_rdatatype_fromtext(&rdtype
, &r
);
89 if (tresult
!= ISC_R_SUCCESS
) {
90 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
91 "rrset-order: invalid type '%s'",
93 result
= ISC_R_FAILURE
;
97 obj
= cfg_tuple_get(ent
, "name");
98 if (cfg_obj_isstring(obj
)) {
99 str
= cfg_obj_asstring(obj
);
100 isc_buffer_init(&b
, str
, strlen(str
));
101 isc_buffer_add(&b
, strlen(str
));
102 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
103 dns_rootname
, ISC_FALSE
, NULL
);
104 if (tresult
!= ISC_R_SUCCESS
) {
105 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
106 "rrset-order: invalid name '%s'", str
);
107 result
= ISC_R_FAILURE
;
111 obj
= cfg_tuple_get(ent
, "order");
112 if (!cfg_obj_isstring(obj
) ||
113 strcasecmp("order", cfg_obj_asstring(obj
)) != 0) {
114 cfg_obj_log(ent
, logctx
, ISC_LOG_ERROR
,
115 "rrset-order: keyword 'order' missing");
116 result
= ISC_R_FAILURE
;
119 obj
= cfg_tuple_get(ent
, "ordering");
120 if (!cfg_obj_isstring(obj
)) {
121 cfg_obj_log(ent
, logctx
, ISC_LOG_ERROR
,
122 "rrset-order: missing ordering");
123 result
= ISC_R_FAILURE
;
124 } else if (strcasecmp(cfg_obj_asstring(obj
), "fixed") == 0) {
125 #if !DNS_RDATASET_FIXED
126 cfg_obj_log(obj
, logctx
, ISC_LOG_WARNING
,
127 "rrset-order: order 'fixed' was disabled at "
130 } else if (strcasecmp(cfg_obj_asstring(obj
), "random") != 0 &&
131 strcasecmp(cfg_obj_asstring(obj
), "cyclic") != 0) {
132 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
133 "rrset-order: invalid order '%s'",
134 cfg_obj_asstring(obj
));
135 result
= ISC_R_FAILURE
;
141 check_order(const cfg_obj_t
*options
, isc_log_t
*logctx
) {
142 isc_result_t result
= ISC_R_SUCCESS
;
143 isc_result_t tresult
;
144 const cfg_listelt_t
*element
;
145 const cfg_obj_t
*obj
= NULL
;
147 if (cfg_map_get(options
, "rrset-order", &obj
) != ISC_R_SUCCESS
)
150 for (element
= cfg_list_first(obj
);
152 element
= cfg_list_next(element
))
154 tresult
= check_orderent(cfg_listelt_value(element
), logctx
);
155 if (tresult
!= ISC_R_SUCCESS
)
162 check_dual_stack(const cfg_obj_t
*options
, isc_log_t
*logctx
) {
163 const cfg_listelt_t
*element
;
164 const cfg_obj_t
*alternates
= NULL
;
165 const cfg_obj_t
*value
;
166 const cfg_obj_t
*obj
;
168 dns_fixedname_t fixed
;
171 isc_result_t result
= ISC_R_SUCCESS
;
172 isc_result_t tresult
;
174 (void)cfg_map_get(options
, "dual-stack-servers", &alternates
);
176 if (alternates
== NULL
)
177 return (ISC_R_SUCCESS
);
179 obj
= cfg_tuple_get(alternates
, "port");
180 if (cfg_obj_isuint32(obj
)) {
181 isc_uint32_t val
= cfg_obj_asuint32(obj
);
182 if (val
> ISC_UINT16_MAX
) {
183 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
184 "port '%u' out of range", val
);
185 result
= ISC_R_FAILURE
;
188 obj
= cfg_tuple_get(alternates
, "addresses");
189 for (element
= cfg_list_first(obj
);
191 element
= cfg_list_next(element
)) {
192 value
= cfg_listelt_value(element
);
193 if (cfg_obj_issockaddr(value
))
195 obj
= cfg_tuple_get(value
, "name");
196 str
= cfg_obj_asstring(obj
);
197 isc_buffer_init(&buffer
, str
, strlen(str
));
198 isc_buffer_add(&buffer
, strlen(str
));
199 dns_fixedname_init(&fixed
);
200 name
= dns_fixedname_name(&fixed
);
201 tresult
= dns_name_fromtext(name
, &buffer
, dns_rootname
,
203 if (tresult
!= ISC_R_SUCCESS
) {
204 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
205 "bad name '%s'", str
);
206 result
= ISC_R_FAILURE
;
208 obj
= cfg_tuple_get(value
, "port");
209 if (cfg_obj_isuint32(obj
)) {
210 isc_uint32_t val
= cfg_obj_asuint32(obj
);
211 if (val
> ISC_UINT16_MAX
) {
212 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
213 "port '%u' out of range", val
);
214 result
= ISC_R_FAILURE
;
222 check_forward(const cfg_obj_t
*options
, const cfg_obj_t
*global
,
225 const cfg_obj_t
*forward
= NULL
;
226 const cfg_obj_t
*forwarders
= NULL
;
228 (void)cfg_map_get(options
, "forward", &forward
);
229 (void)cfg_map_get(options
, "forwarders", &forwarders
);
231 if (forwarders
!= NULL
&& global
!= NULL
) {
232 const char *file
= cfg_obj_file(global
);
233 unsigned int line
= cfg_obj_line(global
);
234 cfg_obj_log(forwarders
, logctx
, ISC_LOG_ERROR
,
235 "forwarders declared in root zone and "
236 "in general configuration: %s:%u",
238 return (ISC_R_FAILURE
);
240 if (forward
!= NULL
&& forwarders
== NULL
) {
241 cfg_obj_log(forward
, logctx
, ISC_LOG_ERROR
,
242 "no matching 'forwarders' statement");
243 return (ISC_R_FAILURE
);
245 return (ISC_R_SUCCESS
);
249 disabled_algorithms(const cfg_obj_t
*disabled
, isc_log_t
*logctx
) {
250 isc_result_t result
= ISC_R_SUCCESS
;
251 isc_result_t tresult
;
252 const cfg_listelt_t
*element
;
255 dns_fixedname_t fixed
;
257 const cfg_obj_t
*obj
;
259 dns_fixedname_init(&fixed
);
260 name
= dns_fixedname_name(&fixed
);
261 obj
= cfg_tuple_get(disabled
, "name");
262 str
= cfg_obj_asstring(obj
);
263 isc_buffer_init(&b
, str
, strlen(str
));
264 isc_buffer_add(&b
, strlen(str
));
265 tresult
= dns_name_fromtext(name
, &b
, dns_rootname
, ISC_FALSE
, NULL
);
266 if (tresult
!= ISC_R_SUCCESS
) {
267 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
268 "bad domain name '%s'", str
);
272 obj
= cfg_tuple_get(disabled
, "algorithms");
274 for (element
= cfg_list_first(obj
);
276 element
= cfg_list_next(element
))
280 isc_result_t tresult
;
282 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element
)), r
.base
);
283 r
.length
= strlen(r
.base
);
285 tresult
= dns_secalg_fromtext(&alg
, &r
);
286 if (tresult
!= ISC_R_SUCCESS
) {
288 result
= isc_parse_uint8(&ui
, r
.base
, 10);
290 if (tresult
!= ISC_R_SUCCESS
) {
291 cfg_obj_log(cfg_listelt_value(element
), logctx
,
292 ISC_LOG_ERROR
, "invalid algorithm '%s'",
301 nameexist(const cfg_obj_t
*obj
, const char *name
, int value
,
302 isc_symtab_t
*symtab
, const char *fmt
, isc_log_t
*logctx
,
309 isc_symvalue_t symvalue
;
311 key
= isc_mem_strdup(mctx
, name
);
313 return (ISC_R_NOMEMORY
);
314 symvalue
.as_cpointer
= obj
;
315 result
= isc_symtab_define(symtab
, key
, value
, symvalue
,
316 isc_symexists_reject
);
317 if (result
== ISC_R_EXISTS
) {
318 RUNTIME_CHECK(isc_symtab_lookup(symtab
, key
, value
,
319 &symvalue
) == ISC_R_SUCCESS
);
320 file
= cfg_obj_file(symvalue
.as_cpointer
);
321 line
= cfg_obj_line(symvalue
.as_cpointer
);
324 file
= "<unknown file>";
325 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
, fmt
, key
, file
, line
);
326 isc_mem_free(mctx
, key
);
327 result
= ISC_R_EXISTS
;
328 } else if (result
!= ISC_R_SUCCESS
) {
329 isc_mem_free(mctx
, key
);
335 mustbesecure(const cfg_obj_t
*secure
, isc_symtab_t
*symtab
, isc_log_t
*logctx
,
338 const cfg_obj_t
*obj
;
339 char namebuf
[DNS_NAME_FORMATSIZE
];
341 dns_fixedname_t fixed
;
344 isc_result_t result
= ISC_R_SUCCESS
;
346 dns_fixedname_init(&fixed
);
347 name
= dns_fixedname_name(&fixed
);
348 obj
= cfg_tuple_get(secure
, "name");
349 str
= cfg_obj_asstring(obj
);
350 isc_buffer_init(&b
, str
, strlen(str
));
351 isc_buffer_add(&b
, strlen(str
));
352 result
= dns_name_fromtext(name
, &b
, dns_rootname
, ISC_FALSE
, NULL
);
353 if (result
!= ISC_R_SUCCESS
) {
354 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
355 "bad domain name '%s'", str
);
357 dns_name_format(name
, namebuf
, sizeof(namebuf
));
358 result
= nameexist(secure
, namebuf
, 1, symtab
,
359 "dnssec-must-be-secure '%s': already "
360 "exists previous definition: %s:%u",
367 checkacl(const char *aclname
, cfg_aclconfctx_t
*actx
, const cfg_obj_t
*zconfig
,
368 const cfg_obj_t
*voptions
, const cfg_obj_t
*config
,
369 isc_log_t
*logctx
, isc_mem_t
*mctx
)
372 const cfg_obj_t
*aclobj
= NULL
;
373 const cfg_obj_t
*options
;
374 dns_acl_t
*acl
= NULL
;
376 if (zconfig
!= NULL
) {
377 options
= cfg_tuple_get(zconfig
, "options");
378 cfg_map_get(options
, aclname
, &aclobj
);
380 if (voptions
!= NULL
&& aclobj
== NULL
)
381 cfg_map_get(voptions
, aclname
, &aclobj
);
382 if (config
!= NULL
&& aclobj
== NULL
) {
384 cfg_map_get(config
, "options", &options
);
386 cfg_map_get(options
, aclname
, &aclobj
);
389 return (ISC_R_SUCCESS
);
390 result
= cfg_acl_fromconfig(aclobj
, config
, logctx
,
391 actx
, mctx
, 0, &acl
);
393 dns_acl_detach(&acl
);
398 check_viewacls(cfg_aclconfctx_t
*actx
, const cfg_obj_t
*voptions
,
399 const cfg_obj_t
*config
, isc_log_t
*logctx
, isc_mem_t
*mctx
)
401 isc_result_t result
= ISC_R_SUCCESS
, tresult
;
404 static const char *acls
[] = { "allow-query", "allow-query-on",
405 "allow-query-cache", "allow-query-cache-on",
406 "blackhole", "match-clients", "match-destinations",
409 while (acls
[i
] != NULL
) {
410 tresult
= checkacl(acls
[i
++], actx
, NULL
, voptions
, config
,
412 if (tresult
!= ISC_R_SUCCESS
)
419 * Check allow-recursion and allow-recursion-on acls, and also log a
420 * warning if they're inconsistent with the "recursion" option.
423 check_recursionacls(cfg_aclconfctx_t
*actx
, const cfg_obj_t
*voptions
,
424 const char *viewname
, const cfg_obj_t
*config
,
425 isc_log_t
*logctx
, isc_mem_t
*mctx
)
427 const cfg_obj_t
*options
, *aclobj
, *obj
= NULL
;
428 dns_acl_t
*acl
= NULL
;
429 isc_result_t result
= ISC_R_SUCCESS
, tresult
;
430 isc_boolean_t recursion
;
431 const char *forview
= " for view ";
434 static const char *acls
[] = { "allow-recursion", "allow-recursion-on",
437 if (voptions
!= NULL
)
438 cfg_map_get(voptions
, "recursion", &obj
);
439 if (obj
== NULL
&& config
!= NULL
) {
441 cfg_map_get(config
, "options", &options
);
443 cfg_map_get(options
, "recursion", &obj
);
446 recursion
= ISC_TRUE
;
448 recursion
= cfg_obj_asboolean(obj
);
450 if (viewname
== NULL
) {
455 for (i
= 0; acls
[i
] != NULL
; i
++) {
456 aclobj
= options
= NULL
;
459 if (voptions
!= NULL
)
460 cfg_map_get(voptions
, acls
[i
], &aclobj
);
461 if (config
!= NULL
&& aclobj
== NULL
) {
463 cfg_map_get(config
, "options", &options
);
465 cfg_map_get(options
, acls
[i
], &aclobj
);
470 tresult
= cfg_acl_fromconfig(aclobj
, config
, logctx
,
471 actx
, mctx
, 0, &acl
);
473 if (tresult
!= ISC_R_SUCCESS
)
479 if (recursion
== ISC_FALSE
&& !dns_acl_isnone(acl
)) {
480 cfg_obj_log(aclobj
, logctx
, ISC_LOG_WARNING
,
481 "both \"recursion no;\" and "
483 acls
[i
], forview
, viewname
);
487 dns_acl_detach(&acl
);
500 check_options(const cfg_obj_t
*options
, isc_log_t
*logctx
, isc_mem_t
*mctx
) {
501 isc_result_t result
= ISC_R_SUCCESS
;
502 isc_result_t tresult
;
504 const cfg_obj_t
*obj
= NULL
;
505 const cfg_listelt_t
*element
;
506 isc_symtab_t
*symtab
= NULL
;
507 dns_fixedname_t fixed
;
512 static intervaltable intervals
[] = {
513 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
514 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
515 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
516 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
517 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
518 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
519 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
520 { "sig-validity-interval", 86400, 10 * 366 }, /* 10 years */
521 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
525 * Check that fields specified in units of time other than seconds
526 * have reasonable values.
528 for (i
= 0; i
< sizeof(intervals
) / sizeof(intervals
[0]); i
++) {
531 (void)cfg_map_get(options
, intervals
[i
].name
, &obj
);
534 val
= cfg_obj_asuint32(obj
);
535 if (val
> intervals
[i
].max
) {
536 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
537 "%s '%u' is out of range (0..%u)",
538 intervals
[i
].name
, val
,
540 result
= ISC_R_RANGE
;
541 } else if (val
> (ISC_UINT32_MAX
/ intervals
[i
].scale
)) {
542 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
543 "%s '%d' is out of range",
544 intervals
[i
].name
, val
);
545 result
= ISC_R_RANGE
;
549 (void)cfg_map_get(options
, "preferred-glue", &obj
);
552 str
= cfg_obj_asstring(obj
);
553 if (strcasecmp(str
, "a") != 0 &&
554 strcasecmp(str
, "aaaa") != 0 &&
555 strcasecmp(str
, "none") != 0)
556 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
557 "preferred-glue unexpected value '%s'",
561 (void)cfg_map_get(options
, "root-delegation-only", &obj
);
563 if (!cfg_obj_isvoid(obj
)) {
564 const cfg_listelt_t
*element
;
565 const cfg_obj_t
*exclude
;
567 dns_fixedname_t fixed
;
571 dns_fixedname_init(&fixed
);
572 name
= dns_fixedname_name(&fixed
);
573 for (element
= cfg_list_first(obj
);
575 element
= cfg_list_next(element
)) {
576 exclude
= cfg_listelt_value(element
);
577 str
= cfg_obj_asstring(exclude
);
578 isc_buffer_init(&b
, str
, strlen(str
));
579 isc_buffer_add(&b
, strlen(str
));
580 tresult
= dns_name_fromtext(name
, &b
,
583 if (tresult
!= ISC_R_SUCCESS
) {
584 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
585 "bad domain name '%s'",
594 * Set supported DNSSEC algorithms.
597 (void)cfg_map_get(options
, "disable-algorithms", &obj
);
599 for (element
= cfg_list_first(obj
);
601 element
= cfg_list_next(element
))
603 obj
= cfg_listelt_value(element
);
604 tresult
= disabled_algorithms(obj
, logctx
);
605 if (tresult
!= ISC_R_SUCCESS
)
610 dns_fixedname_init(&fixed
);
611 name
= dns_fixedname_name(&fixed
);
614 * Check the DLV zone name.
617 (void)cfg_map_get(options
, "dnssec-lookaside", &obj
);
619 tresult
= isc_symtab_create(mctx
, 100, freekey
, mctx
,
621 if (tresult
!= ISC_R_SUCCESS
)
623 for (element
= cfg_list_first(obj
);
625 element
= cfg_list_next(element
))
629 obj
= cfg_listelt_value(element
);
631 dlv
= cfg_obj_asstring(cfg_tuple_get(obj
, "domain"));
632 isc_buffer_init(&b
, dlv
, strlen(dlv
));
633 isc_buffer_add(&b
, strlen(dlv
));
634 tresult
= dns_name_fromtext(name
, &b
, dns_rootname
,
636 if (tresult
!= ISC_R_SUCCESS
) {
637 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
638 "bad domain name '%s'", dlv
);
642 if (symtab
!= NULL
) {
643 tresult
= nameexist(obj
, dlv
, 1, symtab
,
644 "dnssec-lookaside '%s': "
645 "already exists previous "
648 if (tresult
!= ISC_R_SUCCESS
&&
649 result
== ISC_R_SUCCESS
)
653 * XXXMPA to be removed when multiple lookaside
654 * namespaces are supported.
656 if (!dns_name_equal(dns_rootname
, name
)) {
657 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
658 "dnssec-lookaside '%s': "
659 "non-root not yet supported", dlv
);
660 if (result
== ISC_R_SUCCESS
)
661 result
= ISC_R_FAILURE
;
663 dlv
= cfg_obj_asstring(cfg_tuple_get(obj
,
665 isc_buffer_init(&b
, dlv
, strlen(dlv
));
666 isc_buffer_add(&b
, strlen(dlv
));
667 tresult
= dns_name_fromtext(name
, &b
, dns_rootname
,
669 if (tresult
!= ISC_R_SUCCESS
) {
670 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
671 "bad domain name '%s'", dlv
);
672 if (result
== ISC_R_SUCCESS
)
677 isc_symtab_destroy(&symtab
);
681 * Check dnssec-must-be-secure.
684 (void)cfg_map_get(options
, "dnssec-must-be-secure", &obj
);
686 isc_symtab_t
*symtab
= NULL
;
687 tresult
= isc_symtab_create(mctx
, 100, freekey
, mctx
,
689 if (tresult
!= ISC_R_SUCCESS
)
691 for (element
= cfg_list_first(obj
);
693 element
= cfg_list_next(element
))
695 obj
= cfg_listelt_value(element
);
696 tresult
= mustbesecure(obj
, symtab
, logctx
, mctx
);
697 if (tresult
!= ISC_R_SUCCESS
)
701 isc_symtab_destroy(&symtab
);
705 * Check empty zone configuration.
708 (void)cfg_map_get(options
, "empty-server", &obj
);
710 str
= cfg_obj_asstring(obj
);
711 isc_buffer_init(&b
, str
, strlen(str
));
712 isc_buffer_add(&b
, strlen(str
));
713 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
714 dns_rootname
, ISC_FALSE
, NULL
);
715 if (tresult
!= ISC_R_SUCCESS
) {
716 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
717 "empty-server: invalid name '%s'", str
);
718 result
= ISC_R_FAILURE
;
723 (void)cfg_map_get(options
, "empty-contact", &obj
);
725 str
= cfg_obj_asstring(obj
);
726 isc_buffer_init(&b
, str
, strlen(str
));
727 isc_buffer_add(&b
, strlen(str
));
728 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
729 dns_rootname
, ISC_FALSE
, NULL
);
730 if (tresult
!= ISC_R_SUCCESS
) {
731 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
732 "empty-contact: invalid name '%s'", str
);
733 result
= ISC_R_FAILURE
;
738 (void)cfg_map_get(options
, "disable-empty-zone", &obj
);
739 for (element
= cfg_list_first(obj
);
741 element
= cfg_list_next(element
))
743 obj
= cfg_listelt_value(element
);
744 str
= cfg_obj_asstring(obj
);
745 isc_buffer_init(&b
, str
, strlen(str
));
746 isc_buffer_add(&b
, strlen(str
));
747 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
748 dns_rootname
, ISC_FALSE
, NULL
);
749 if (tresult
!= ISC_R_SUCCESS
) {
750 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
751 "disable-empty-zone: invalid name '%s'",
753 result
= ISC_R_FAILURE
;
758 * Check that server-id is not too long.
759 * 1024 bytes should be big enough.
762 (void)cfg_map_get(options
, "server-id", &obj
);
763 if (obj
!= NULL
&& cfg_obj_isstring(obj
) &&
764 strlen(cfg_obj_asstring(obj
)) > 1024U) {
765 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
766 "'server-id' too big (>1024 bytes)");
767 result
= ISC_R_FAILURE
;
774 get_masters_def(const cfg_obj_t
*cctx
, const char *name
, const cfg_obj_t
**ret
) {
776 const cfg_obj_t
*masters
= NULL
;
777 const cfg_listelt_t
*elt
;
779 result
= cfg_map_get(cctx
, "masters", &masters
);
780 if (result
!= ISC_R_SUCCESS
)
782 for (elt
= cfg_list_first(masters
);
784 elt
= cfg_list_next(elt
)) {
785 const cfg_obj_t
*list
;
786 const char *listname
;
788 list
= cfg_listelt_value(elt
);
789 listname
= cfg_obj_asstring(cfg_tuple_get(list
, "name"));
791 if (strcasecmp(listname
, name
) == 0) {
793 return (ISC_R_SUCCESS
);
796 return (ISC_R_NOTFOUND
);
800 validate_masters(const cfg_obj_t
*obj
, const cfg_obj_t
*config
,
801 isc_uint32_t
*countp
, isc_log_t
*logctx
, isc_mem_t
*mctx
)
803 isc_result_t result
= ISC_R_SUCCESS
;
804 isc_result_t tresult
;
805 isc_uint32_t count
= 0;
806 isc_symtab_t
*symtab
= NULL
;
807 isc_symvalue_t symvalue
;
808 const cfg_listelt_t
*element
;
809 const cfg_listelt_t
**stack
= NULL
;
810 isc_uint32_t stackcount
= 0, pushed
= 0;
811 const cfg_obj_t
*list
;
813 REQUIRE(countp
!= NULL
);
814 result
= isc_symtab_create(mctx
, 100, NULL
, NULL
, ISC_FALSE
, &symtab
);
815 if (result
!= ISC_R_SUCCESS
) {
821 list
= cfg_tuple_get(obj
, "addresses");
822 element
= cfg_list_first(list
);
826 element
= cfg_list_next(element
))
828 const char *listname
;
829 const cfg_obj_t
*addr
;
830 const cfg_obj_t
*key
;
832 addr
= cfg_tuple_get(cfg_listelt_value(element
),
834 key
= cfg_tuple_get(cfg_listelt_value(element
), "key");
836 if (cfg_obj_issockaddr(addr
)) {
840 if (!cfg_obj_isvoid(key
)) {
841 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
842 "unexpected token '%s'",
843 cfg_obj_asstring(key
));
844 if (result
== ISC_R_SUCCESS
)
845 result
= ISC_R_FAILURE
;
847 listname
= cfg_obj_asstring(addr
);
848 symvalue
.as_cpointer
= addr
;
849 tresult
= isc_symtab_define(symtab
, listname
, 1, symvalue
,
850 isc_symexists_reject
);
851 if (tresult
== ISC_R_EXISTS
)
853 tresult
= get_masters_def(config
, listname
, &obj
);
854 if (tresult
!= ISC_R_SUCCESS
) {
855 if (result
== ISC_R_SUCCESS
)
857 cfg_obj_log(addr
, logctx
, ISC_LOG_ERROR
,
858 "unable to find masters list '%s'",
863 if (stackcount
== pushed
) {
865 isc_uint32_t newlen
= stackcount
+ 16;
866 size_t newsize
, oldsize
;
868 newsize
= newlen
* sizeof(*stack
);
869 oldsize
= stackcount
* sizeof(*stack
);
870 new = isc_mem_get(mctx
, newsize
);
873 if (stackcount
!= 0) {
876 DE_CONST(stack
, ptr
);
877 memcpy(new, stack
, oldsize
);
878 isc_mem_put(mctx
, ptr
, oldsize
);
883 stack
[pushed
++] = cfg_list_next(element
);
887 element
= stack
[--pushed
];
894 DE_CONST(stack
, ptr
);
895 isc_mem_put(mctx
, ptr
, stackcount
* sizeof(*stack
));
897 isc_symtab_destroy(&symtab
);
903 check_update_policy(const cfg_obj_t
*policy
, isc_log_t
*logctx
) {
904 isc_result_t result
= ISC_R_SUCCESS
;
905 isc_result_t tresult
;
906 const cfg_listelt_t
*element
;
907 const cfg_listelt_t
*element2
;
908 dns_fixedname_t fixed
;
912 for (element
= cfg_list_first(policy
);
914 element
= cfg_list_next(element
))
916 const cfg_obj_t
*stmt
= cfg_listelt_value(element
);
917 const cfg_obj_t
*identity
= cfg_tuple_get(stmt
, "identity");
918 const cfg_obj_t
*matchtype
= cfg_tuple_get(stmt
, "matchtype");
919 const cfg_obj_t
*dname
= cfg_tuple_get(stmt
, "name");
920 const cfg_obj_t
*typelist
= cfg_tuple_get(stmt
, "types");
922 dns_fixedname_init(&fixed
);
923 str
= cfg_obj_asstring(identity
);
924 isc_buffer_init(&b
, str
, strlen(str
));
925 isc_buffer_add(&b
, strlen(str
));
926 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
927 dns_rootname
, ISC_FALSE
, NULL
);
928 if (tresult
!= ISC_R_SUCCESS
) {
929 cfg_obj_log(identity
, logctx
, ISC_LOG_ERROR
,
930 "'%s' is not a valid name", str
);
934 dns_fixedname_init(&fixed
);
935 str
= cfg_obj_asstring(dname
);
936 isc_buffer_init(&b
, str
, strlen(str
));
937 isc_buffer_add(&b
, strlen(str
));
938 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
939 dns_rootname
, ISC_FALSE
, NULL
);
940 if (tresult
!= ISC_R_SUCCESS
) {
941 cfg_obj_log(dname
, logctx
, ISC_LOG_ERROR
,
942 "'%s' is not a valid name", str
);
945 if (tresult
== ISC_R_SUCCESS
&&
946 strcasecmp(cfg_obj_asstring(matchtype
), "wildcard") == 0 &&
947 !dns_name_iswildcard(dns_fixedname_name(&fixed
))) {
948 cfg_obj_log(identity
, logctx
, ISC_LOG_ERROR
,
949 "'%s' is not a wildcard", str
);
950 result
= ISC_R_FAILURE
;
953 for (element2
= cfg_list_first(typelist
);
955 element2
= cfg_list_next(element2
))
957 const cfg_obj_t
*typeobj
;
959 dns_rdatatype_t type
;
961 typeobj
= cfg_listelt_value(element2
);
962 DE_CONST(cfg_obj_asstring(typeobj
), r
.base
);
963 r
.length
= strlen(r
.base
);
965 tresult
= dns_rdatatype_fromtext(&type
, &r
);
966 if (tresult
!= ISC_R_SUCCESS
) {
967 cfg_obj_log(typeobj
, logctx
, ISC_LOG_ERROR
,
968 "'%s' is not a valid type", r
.base
);
980 #define FORWARDZONE 16
981 #define DELEGATIONZONE 32
990 check_zoneconf(const cfg_obj_t
*zconfig
, const cfg_obj_t
*voptions
,
991 const cfg_obj_t
*config
, isc_symtab_t
*symtab
,
992 dns_rdataclass_t defclass
, cfg_aclconfctx_t
*actx
,
993 isc_log_t
*logctx
, isc_mem_t
*mctx
)
998 const cfg_obj_t
*zoptions
;
999 const cfg_obj_t
*obj
= NULL
;
1000 isc_result_t result
= ISC_R_SUCCESS
;
1001 isc_result_t tresult
;
1003 dns_rdataclass_t zclass
;
1004 dns_fixedname_t fixedname
;
1006 isc_boolean_t root
= ISC_FALSE
;
1008 static optionstable options
[] = {
1009 { "allow-query", MASTERZONE
| SLAVEZONE
| STUBZONE
| CHECKACL
},
1010 { "allow-notify", SLAVEZONE
| CHECKACL
},
1011 { "allow-transfer", MASTERZONE
| SLAVEZONE
| CHECKACL
},
1012 { "notify", MASTERZONE
| SLAVEZONE
},
1013 { "also-notify", MASTERZONE
| SLAVEZONE
},
1014 { "dialup", MASTERZONE
| SLAVEZONE
| STUBZONE
},
1015 { "delegation-only", HINTZONE
| STUBZONE
| DELEGATIONZONE
},
1016 { "forward", MASTERZONE
| SLAVEZONE
| STUBZONE
| FORWARDZONE
},
1017 { "forwarders", MASTERZONE
| SLAVEZONE
| STUBZONE
| FORWARDZONE
},
1018 { "maintain-ixfr-base", MASTERZONE
| SLAVEZONE
},
1019 { "max-ixfr-log-size", MASTERZONE
| SLAVEZONE
},
1020 { "notify-source", MASTERZONE
| SLAVEZONE
},
1021 { "notify-source-v6", MASTERZONE
| SLAVEZONE
},
1022 { "transfer-source", SLAVEZONE
| STUBZONE
},
1023 { "transfer-source-v6", SLAVEZONE
| STUBZONE
},
1024 { "max-transfer-time-in", SLAVEZONE
| STUBZONE
},
1025 { "max-transfer-time-out", MASTERZONE
| SLAVEZONE
},
1026 { "max-transfer-idle-in", SLAVEZONE
| STUBZONE
},
1027 { "max-transfer-idle-out", MASTERZONE
| SLAVEZONE
},
1028 { "max-retry-time", SLAVEZONE
| STUBZONE
},
1029 { "min-retry-time", SLAVEZONE
| STUBZONE
},
1030 { "max-refresh-time", SLAVEZONE
| STUBZONE
},
1031 { "min-refresh-time", SLAVEZONE
| STUBZONE
},
1032 { "sig-validity-interval", MASTERZONE
},
1033 { "zone-statistics", MASTERZONE
| SLAVEZONE
| STUBZONE
},
1034 { "allow-update", MASTERZONE
| CHECKACL
},
1035 { "allow-update-forwarding", SLAVEZONE
| CHECKACL
},
1036 { "file", MASTERZONE
| SLAVEZONE
| STUBZONE
| HINTZONE
},
1037 { "journal", MASTERZONE
| SLAVEZONE
},
1038 { "ixfr-base", MASTERZONE
| SLAVEZONE
},
1039 { "ixfr-tmp-file", MASTERZONE
| SLAVEZONE
},
1040 { "masters", SLAVEZONE
| STUBZONE
},
1041 { "pubkey", MASTERZONE
| SLAVEZONE
| STUBZONE
},
1042 { "update-policy", MASTERZONE
},
1043 { "database", MASTERZONE
| SLAVEZONE
| STUBZONE
},
1044 { "key-directory", MASTERZONE
},
1045 { "check-wildcard", MASTERZONE
},
1046 { "check-mx", MASTERZONE
},
1047 { "integrity-check", MASTERZONE
},
1048 { "check-mx-cname", MASTERZONE
},
1049 { "check-srv-cname", MASTERZONE
},
1050 { "masterfile-format", MASTERZONE
| SLAVEZONE
| STUBZONE
| HINTZONE
},
1051 { "update-check-ksk", MASTERZONE
},
1052 { "try-tcp-refresh", SLAVEZONE
},
1055 static optionstable dialups
[] = {
1056 { "notify", MASTERZONE
| SLAVEZONE
},
1057 { "notify-passive", SLAVEZONE
},
1058 { "refresh", SLAVEZONE
| STUBZONE
},
1059 { "passive", SLAVEZONE
| STUBZONE
},
1062 zname
= cfg_obj_asstring(cfg_tuple_get(zconfig
, "name"));
1064 zoptions
= cfg_tuple_get(zconfig
, "options");
1067 (void)cfg_map_get(zoptions
, "type", &obj
);
1069 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
1070 "zone '%s': type not present", zname
);
1071 return (ISC_R_FAILURE
);
1074 typestr
= cfg_obj_asstring(obj
);
1075 if (strcasecmp(typestr
, "master") == 0)
1077 else if (strcasecmp(typestr
, "slave") == 0)
1079 else if (strcasecmp(typestr
, "stub") == 0)
1081 else if (strcasecmp(typestr
, "forward") == 0)
1082 ztype
= FORWARDZONE
;
1083 else if (strcasecmp(typestr
, "hint") == 0)
1085 else if (strcasecmp(typestr
, "delegation-only") == 0)
1086 ztype
= DELEGATIONZONE
;
1088 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1089 "zone '%s': invalid type %s",
1091 return (ISC_R_FAILURE
);
1094 obj
= cfg_tuple_get(zconfig
, "class");
1095 if (cfg_obj_isstring(obj
)) {
1098 DE_CONST(cfg_obj_asstring(obj
), r
.base
);
1099 r
.length
= strlen(r
.base
);
1100 result
= dns_rdataclass_fromtext(&zclass
, &r
);
1101 if (result
!= ISC_R_SUCCESS
) {
1102 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1103 "zone '%s': invalid class %s",
1105 return (ISC_R_FAILURE
);
1107 if (zclass
!= defclass
) {
1108 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1109 "zone '%s': class '%s' does not "
1110 "match view/default class",
1112 return (ISC_R_FAILURE
);
1117 * Look for an already existing zone.
1118 * We need to make this canonical as isc_symtab_define()
1119 * deals with strings.
1121 dns_fixedname_init(&fixedname
);
1122 isc_buffer_init(&b
, zname
, strlen(zname
));
1123 isc_buffer_add(&b
, strlen(zname
));
1124 tresult
= dns_name_fromtext(dns_fixedname_name(&fixedname
), &b
,
1125 dns_rootname
, ISC_TRUE
, NULL
);
1126 if (tresult
!= ISC_R_SUCCESS
) {
1127 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
1128 "zone '%s': is not a valid name", zname
);
1129 result
= ISC_R_FAILURE
;
1131 char namebuf
[DNS_NAME_FORMATSIZE
];
1133 dns_name_format(dns_fixedname_name(&fixedname
),
1134 namebuf
, sizeof(namebuf
));
1135 tresult
= nameexist(zconfig
, namebuf
, ztype
== HINTZONE
? 1 : 2,
1136 symtab
, "zone '%s': already exists "
1137 "previous definition: %s:%u", logctx
, mctx
);
1138 if (tresult
!= ISC_R_SUCCESS
)
1140 if (dns_name_equal(dns_fixedname_name(&fixedname
),
1146 * Look for inappropriate options for the given zone type.
1147 * Check that ACLs expand correctly.
1149 for (i
= 0; i
< sizeof(options
) / sizeof(options
[0]); i
++) {
1151 if ((options
[i
].allowed
& ztype
) == 0 &&
1152 cfg_map_get(zoptions
, options
[i
].name
, &obj
) ==
1155 if (strcmp(options
[i
].name
, "allow-update") != 0 ||
1156 ztype
!= SLAVEZONE
) {
1157 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1158 "option '%s' is not allowed "
1159 "in '%s' zone '%s'",
1160 options
[i
].name
, typestr
, zname
);
1161 result
= ISC_R_FAILURE
;
1163 cfg_obj_log(obj
, logctx
, ISC_LOG_WARNING
,
1164 "option '%s' is not allowed "
1165 "in '%s' zone '%s'",
1166 options
[i
].name
, typestr
, zname
);
1169 if ((options
[i
].allowed
& ztype
) != 0 &&
1170 (options
[i
].allowed
& CHECKACL
) != 0) {
1172 tresult
= checkacl(options
[i
].name
, actx
, zconfig
,
1173 voptions
, config
, logctx
, mctx
);
1174 if (tresult
!= ISC_R_SUCCESS
)
1181 * Slave & stub zones must have a "masters" field.
1183 if (ztype
== SLAVEZONE
|| ztype
== STUBZONE
) {
1185 if (cfg_map_get(zoptions
, "masters", &obj
) != ISC_R_SUCCESS
) {
1186 cfg_obj_log(zoptions
, logctx
, ISC_LOG_ERROR
,
1187 "zone '%s': missing 'masters' entry",
1189 result
= ISC_R_FAILURE
;
1192 tresult
= validate_masters(obj
, config
, &count
,
1194 if (tresult
!= ISC_R_SUCCESS
&& result
== ISC_R_SUCCESS
)
1196 if (tresult
== ISC_R_SUCCESS
&& count
== 0) {
1197 cfg_obj_log(zoptions
, logctx
, ISC_LOG_ERROR
,
1198 "zone '%s': empty 'masters' entry",
1200 result
= ISC_R_FAILURE
;
1206 * Master zones can't have both "allow-update" and "update-policy".
1208 if (ztype
== MASTERZONE
) {
1209 isc_result_t res1
, res2
;
1211 res1
= cfg_map_get(zoptions
, "allow-update", &obj
);
1213 res2
= cfg_map_get(zoptions
, "update-policy", &obj
);
1214 if (res1
== ISC_R_SUCCESS
&& res2
== ISC_R_SUCCESS
) {
1215 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1216 "zone '%s': 'allow-update' is ignored "
1217 "when 'update-policy' is present",
1219 result
= ISC_R_FAILURE
;
1220 } else if (res2
== ISC_R_SUCCESS
&&
1221 check_update_policy(obj
, logctx
) != ISC_R_SUCCESS
)
1222 result
= ISC_R_FAILURE
;
1226 * Check the excessively complicated "dialup" option.
1228 if (ztype
== MASTERZONE
|| ztype
== SLAVEZONE
|| ztype
== STUBZONE
) {
1229 const cfg_obj_t
*dialup
= NULL
;
1230 (void)cfg_map_get(zoptions
, "dialup", &dialup
);
1231 if (dialup
!= NULL
&& cfg_obj_isstring(dialup
)) {
1232 const char *str
= cfg_obj_asstring(dialup
);
1234 i
< sizeof(dialups
) / sizeof(dialups
[0]);
1237 if (strcasecmp(dialups
[i
].name
, str
) != 0)
1239 if ((dialups
[i
].allowed
& ztype
) == 0) {
1240 cfg_obj_log(obj
, logctx
,
1242 "dialup type '%s' is not "
1245 str
, typestr
, zname
);
1246 result
= ISC_R_FAILURE
;
1250 if (i
== sizeof(dialups
) / sizeof(dialups
[0])) {
1251 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1252 "invalid dialup type '%s' in zone "
1253 "'%s'", str
, zname
);
1254 result
= ISC_R_FAILURE
;
1260 * Check that forwarding is reasonable.
1264 if (voptions
!= NULL
)
1265 (void)cfg_map_get(voptions
, "forwarders", &obj
);
1267 const cfg_obj_t
*options
= NULL
;
1268 (void)cfg_map_get(config
, "options", &options
);
1269 if (options
!= NULL
)
1270 (void)cfg_map_get(options
, "forwarders", &obj
);
1273 if (check_forward(zoptions
, obj
, logctx
) != ISC_R_SUCCESS
)
1274 result
= ISC_R_FAILURE
;
1277 * Check various options.
1279 tresult
= check_options(zoptions
, logctx
, mctx
);
1280 if (tresult
!= ISC_R_SUCCESS
)
1284 * If the zone type is rbt/rbt64 then master/hint zones
1285 * require file clauses.
1288 tresult
= cfg_map_get(zoptions
, "database", &obj
);
1289 if (tresult
== ISC_R_NOTFOUND
||
1290 (tresult
== ISC_R_SUCCESS
&&
1291 (strcmp("rbt", cfg_obj_asstring(obj
)) == 0 ||
1292 strcmp("rbt64", cfg_obj_asstring(obj
)) == 0))) {
1294 tresult
= cfg_map_get(zoptions
, "file", &obj
);
1295 if (tresult
!= ISC_R_SUCCESS
&&
1296 (ztype
== MASTERZONE
|| ztype
== HINTZONE
)) {
1297 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
1298 "zone '%s': missing 'file' entry",
1308 typedef struct keyalgorithms
{
1314 bind9_check_key(const cfg_obj_t
*key
, isc_log_t
*logctx
) {
1315 const cfg_obj_t
*algobj
= NULL
;
1316 const cfg_obj_t
*secretobj
= NULL
;
1317 const char *keyname
= cfg_obj_asstring(cfg_map_getname(key
));
1318 const char *algorithm
;
1321 static const algorithmtable algorithms
[] = {
1322 { "hmac-md5", 128 },
1323 { "hmac-md5.sig-alg.reg.int", 0 },
1324 { "hmac-md5.sig-alg.reg.int.", 0 },
1325 { "hmac-sha1", 160 },
1326 { "hmac-sha224", 224 },
1327 { "hmac-sha256", 256 },
1328 { "hmac-sha384", 384 },
1329 { "hmac-sha512", 512 },
1333 (void)cfg_map_get(key
, "algorithm", &algobj
);
1334 (void)cfg_map_get(key
, "secret", &secretobj
);
1335 if (secretobj
== NULL
|| algobj
== NULL
) {
1336 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
1337 "key '%s' must have both 'secret' and "
1338 "'algorithm' defined",
1340 return (ISC_R_FAILURE
);
1343 algorithm
= cfg_obj_asstring(algobj
);
1344 for (i
= 0; algorithms
[i
].name
!= NULL
; i
++) {
1345 len
= strlen(algorithms
[i
].name
);
1346 if (strncasecmp(algorithms
[i
].name
, algorithm
, len
) == 0 &&
1347 (algorithm
[len
] == '\0' ||
1348 (algorithms
[i
].size
!= 0 && algorithm
[len
] == '-')))
1351 if (algorithms
[i
].name
== NULL
) {
1352 cfg_obj_log(algobj
, logctx
, ISC_LOG_ERROR
,
1353 "unknown algorithm '%s'", algorithm
);
1354 return (ISC_R_NOTFOUND
);
1356 if (algorithm
[len
] == '-') {
1357 isc_uint16_t digestbits
;
1358 isc_result_t result
;
1359 result
= isc_parse_uint16(&digestbits
, algorithm
+ len
+ 1, 10);
1360 if (result
== ISC_R_SUCCESS
|| result
== ISC_R_RANGE
) {
1361 if (result
== ISC_R_RANGE
||
1362 digestbits
> algorithms
[i
].size
) {
1363 cfg_obj_log(algobj
, logctx
, ISC_LOG_ERROR
,
1364 "key '%s' digest-bits too large "
1365 "[%u..%u]", keyname
,
1366 algorithms
[i
].size
/ 2,
1367 algorithms
[i
].size
);
1368 return (ISC_R_RANGE
);
1370 if ((digestbits
% 8) != 0) {
1371 cfg_obj_log(algobj
, logctx
, ISC_LOG_ERROR
,
1372 "key '%s' digest-bits not multiple"
1374 return (ISC_R_RANGE
);
1377 * Recommended minima for hmac algorithms.
1379 if ((digestbits
< (algorithms
[i
].size
/ 2U) ||
1380 (digestbits
< 80U)))
1381 cfg_obj_log(algobj
, logctx
, ISC_LOG_WARNING
,
1382 "key '%s' digest-bits too small "
1384 algorithms
[i
].size
/2);
1386 cfg_obj_log(algobj
, logctx
, ISC_LOG_ERROR
,
1387 "key '%s': unable to parse digest-bits",
1392 return (ISC_R_SUCCESS
);
1396 * Check key list for duplicates key names and that the key names
1397 * are valid domain names as these keys are used for TSIG.
1399 * Check the key contents for validity.
1402 check_keylist(const cfg_obj_t
*keys
, isc_symtab_t
*symtab
,
1403 isc_mem_t
*mctx
, isc_log_t
*logctx
)
1405 char namebuf
[DNS_NAME_FORMATSIZE
];
1406 dns_fixedname_t fname
;
1408 isc_result_t result
= ISC_R_SUCCESS
;
1409 isc_result_t tresult
;
1410 const cfg_listelt_t
*element
;
1412 dns_fixedname_init(&fname
);
1413 name
= dns_fixedname_name(&fname
);
1414 for (element
= cfg_list_first(keys
);
1416 element
= cfg_list_next(element
))
1418 const cfg_obj_t
*key
= cfg_listelt_value(element
);
1419 const char *keyid
= cfg_obj_asstring(cfg_map_getname(key
));
1420 isc_symvalue_t symvalue
;
1424 isc_buffer_init(&b
, keyid
, strlen(keyid
));
1425 isc_buffer_add(&b
, strlen(keyid
));
1426 tresult
= dns_name_fromtext(name
, &b
, dns_rootname
,
1428 if (tresult
!= ISC_R_SUCCESS
) {
1429 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
1430 "key '%s': bad key name", keyid
);
1434 tresult
= bind9_check_key(key
, logctx
);
1435 if (tresult
!= ISC_R_SUCCESS
)
1438 dns_name_format(name
, namebuf
, sizeof(namebuf
));
1439 keyname
= isc_mem_strdup(mctx
, namebuf
);
1440 if (keyname
== NULL
)
1441 return (ISC_R_NOMEMORY
);
1442 symvalue
.as_cpointer
= key
;
1443 tresult
= isc_symtab_define(symtab
, keyname
, 1, symvalue
,
1444 isc_symexists_reject
);
1445 if (tresult
== ISC_R_EXISTS
) {
1449 RUNTIME_CHECK(isc_symtab_lookup(symtab
, keyname
,
1450 1, &symvalue
) == ISC_R_SUCCESS
);
1451 file
= cfg_obj_file(symvalue
.as_cpointer
);
1452 line
= cfg_obj_line(symvalue
.as_cpointer
);
1455 file
= "<unknown file>";
1456 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
1457 "key '%s': already exists "
1458 "previous definition: %s:%u",
1460 isc_mem_free(mctx
, keyname
);
1462 } else if (tresult
!= ISC_R_SUCCESS
) {
1463 isc_mem_free(mctx
, keyname
);
1474 { "transfer-source", "transfer-source-v6" },
1475 { "notify-source", "notify-source-v6" },
1476 { "query-source", "query-source-v6" },
1481 * RNDC keys are not normalised unlike TSIG keys.
1483 * "foo." is different to "foo".
1485 static isc_boolean_t
1486 rndckey_exists(const cfg_obj_t
*keylist
, const char *keyname
) {
1487 const cfg_listelt_t
*element
;
1488 const cfg_obj_t
*obj
;
1491 if (keylist
== NULL
)
1494 for (element
= cfg_list_first(keylist
);
1496 element
= cfg_list_next(element
))
1498 obj
= cfg_listelt_value(element
);
1499 str
= cfg_obj_asstring(cfg_map_getname(obj
));
1500 if (!strcasecmp(str
, keyname
))
1507 check_servers(const cfg_obj_t
*config
, const cfg_obj_t
*voptions
,
1508 isc_symtab_t
*symtab
, isc_log_t
*logctx
)
1510 dns_fixedname_t fname
;
1511 isc_result_t result
= ISC_R_SUCCESS
;
1512 isc_result_t tresult
;
1513 const cfg_listelt_t
*e1
, *e2
;
1514 const cfg_obj_t
*v1
, *v2
, *keys
;
1515 const cfg_obj_t
*servers
;
1516 isc_netaddr_t n1
, n2
;
1517 unsigned int p1
, p2
;
1518 const cfg_obj_t
*obj
;
1519 char buf
[ISC_NETADDR_FORMATSIZE
];
1520 char namebuf
[DNS_NAME_FORMATSIZE
];
1525 dns_name_t
*keyname
;
1528 if (voptions
!= NULL
)
1529 (void)cfg_map_get(voptions
, "server", &servers
);
1530 if (servers
== NULL
)
1531 (void)cfg_map_get(config
, "server", &servers
);
1532 if (servers
== NULL
)
1533 return (ISC_R_SUCCESS
);
1535 for (e1
= cfg_list_first(servers
); e1
!= NULL
; e1
= cfg_list_next(e1
)) {
1536 v1
= cfg_listelt_value(e1
);
1537 cfg_obj_asnetprefix(cfg_map_getname(v1
), &n1
, &p1
);
1539 * Check that unused bits are zero.
1541 tresult
= isc_netaddr_prefixok(&n1
, p1
);
1542 if (tresult
!= ISC_R_SUCCESS
) {
1543 INSIST(tresult
== ISC_R_FAILURE
);
1544 isc_netaddr_format(&n1
, buf
, sizeof(buf
));
1545 cfg_obj_log(v1
, logctx
, ISC_LOG_ERROR
,
1546 "server '%s/%u': invalid prefix "
1547 "(extra bits specified)", buf
, p1
);
1553 if (n1
.family
== AF_INET
)
1554 xfr
= sources
[source
].v6
;
1556 xfr
= sources
[source
].v4
;
1557 (void)cfg_map_get(v1
, xfr
, &obj
);
1559 isc_netaddr_format(&n1
, buf
, sizeof(buf
));
1560 cfg_obj_log(v1
, logctx
, ISC_LOG_ERROR
,
1561 "server '%s/%u': %s not legal",
1563 result
= ISC_R_FAILURE
;
1565 } while (sources
[++source
].v4
!= NULL
);
1567 while ((e2
= cfg_list_next(e2
)) != NULL
) {
1568 v2
= cfg_listelt_value(e2
);
1569 cfg_obj_asnetprefix(cfg_map_getname(v2
), &n2
, &p2
);
1570 if (p1
== p2
&& isc_netaddr_equal(&n1
, &n2
)) {
1571 const char *file
= cfg_obj_file(v1
);
1572 unsigned int line
= cfg_obj_line(v1
);
1575 file
= "<unknown file>";
1577 isc_netaddr_format(&n2
, buf
, sizeof(buf
));
1578 cfg_obj_log(v2
, logctx
, ISC_LOG_ERROR
,
1579 "server '%s/%u': already exists "
1580 "previous definition: %s:%u",
1581 buf
, p2
, file
, line
);
1582 result
= ISC_R_FAILURE
;
1586 cfg_map_get(v1
, "keys", &keys
);
1589 * Normalize key name.
1591 keyval
= cfg_obj_asstring(keys
);
1592 dns_fixedname_init(&fname
);
1593 isc_buffer_init(&b
, keyval
, strlen(keyval
));
1594 isc_buffer_add(&b
, strlen(keyval
));
1595 keyname
= dns_fixedname_name(&fname
);
1596 tresult
= dns_name_fromtext(keyname
, &b
, dns_rootname
,
1598 if (tresult
!= ISC_R_SUCCESS
) {
1599 cfg_obj_log(keys
, logctx
, ISC_LOG_ERROR
,
1600 "bad key name '%s'", keyval
);
1601 result
= ISC_R_FAILURE
;
1604 dns_name_format(keyname
, namebuf
, sizeof(namebuf
));
1605 tresult
= isc_symtab_lookup(symtab
, namebuf
, 1, NULL
);
1606 if (tresult
!= ISC_R_SUCCESS
) {
1607 cfg_obj_log(keys
, logctx
, ISC_LOG_ERROR
,
1608 "unknown key '%s'", keyval
);
1609 result
= ISC_R_FAILURE
;
1617 check_viewconf(const cfg_obj_t
*config
, const cfg_obj_t
*voptions
,
1618 const char *viewname
, dns_rdataclass_t vclass
,
1619 isc_log_t
*logctx
, isc_mem_t
*mctx
)
1621 const cfg_obj_t
*zones
= NULL
;
1622 const cfg_obj_t
*keys
= NULL
;
1623 const cfg_listelt_t
*element
;
1624 isc_symtab_t
*symtab
= NULL
;
1625 isc_result_t result
= ISC_R_SUCCESS
;
1626 isc_result_t tresult
= ISC_R_SUCCESS
;
1627 cfg_aclconfctx_t actx
;
1628 const cfg_obj_t
*obj
;
1629 isc_boolean_t enablednssec
, enablevalidation
;
1632 * Check that all zone statements are syntactically correct and
1633 * there are no duplicate zones.
1635 tresult
= isc_symtab_create(mctx
, 100, freekey
, mctx
,
1636 ISC_FALSE
, &symtab
);
1637 if (tresult
!= ISC_R_SUCCESS
)
1638 return (ISC_R_NOMEMORY
);
1640 cfg_aclconfctx_init(&actx
);
1642 if (voptions
!= NULL
)
1643 (void)cfg_map_get(voptions
, "zone", &zones
);
1645 (void)cfg_map_get(config
, "zone", &zones
);
1647 for (element
= cfg_list_first(zones
);
1649 element
= cfg_list_next(element
))
1651 isc_result_t tresult
;
1652 const cfg_obj_t
*zone
= cfg_listelt_value(element
);
1654 tresult
= check_zoneconf(zone
, voptions
, config
, symtab
,
1655 vclass
, &actx
, logctx
, mctx
);
1656 if (tresult
!= ISC_R_SUCCESS
)
1657 result
= ISC_R_FAILURE
;
1660 isc_symtab_destroy(&symtab
);
1663 * Check that forwarding is reasonable.
1665 if (voptions
== NULL
) {
1666 const cfg_obj_t
*options
= NULL
;
1667 (void)cfg_map_get(config
, "options", &options
);
1668 if (options
!= NULL
)
1669 if (check_forward(options
, NULL
,
1670 logctx
) != ISC_R_SUCCESS
)
1671 result
= ISC_R_FAILURE
;
1673 if (check_forward(voptions
, NULL
, logctx
) != ISC_R_SUCCESS
)
1674 result
= ISC_R_FAILURE
;
1678 * Check that dual-stack-servers is reasonable.
1680 if (voptions
== NULL
) {
1681 const cfg_obj_t
*options
= NULL
;
1682 (void)cfg_map_get(config
, "options", &options
);
1683 if (options
!= NULL
)
1684 if (check_dual_stack(options
, logctx
) != ISC_R_SUCCESS
)
1685 result
= ISC_R_FAILURE
;
1687 if (check_dual_stack(voptions
, logctx
) != ISC_R_SUCCESS
)
1688 result
= ISC_R_FAILURE
;
1692 * Check that rrset-order is reasonable.
1694 if (voptions
!= NULL
) {
1695 if (check_order(voptions
, logctx
) != ISC_R_SUCCESS
)
1696 result
= ISC_R_FAILURE
;
1700 * Check that all key statements are syntactically correct and
1701 * there are no duplicate keys.
1703 tresult
= isc_symtab_create(mctx
, 100, freekey
, mctx
,
1704 ISC_FALSE
, &symtab
);
1705 if (tresult
!= ISC_R_SUCCESS
)
1706 return (ISC_R_NOMEMORY
);
1708 (void)cfg_map_get(config
, "key", &keys
);
1709 tresult
= check_keylist(keys
, symtab
, mctx
, logctx
);
1710 if (tresult
== ISC_R_EXISTS
)
1711 result
= ISC_R_FAILURE
;
1712 else if (tresult
!= ISC_R_SUCCESS
) {
1713 isc_symtab_destroy(&symtab
);
1717 if (voptions
!= NULL
) {
1719 (void)cfg_map_get(voptions
, "key", &keys
);
1720 tresult
= check_keylist(keys
, symtab
, mctx
, logctx
);
1721 if (tresult
== ISC_R_EXISTS
)
1722 result
= ISC_R_FAILURE
;
1723 else if (tresult
!= ISC_R_SUCCESS
) {
1724 isc_symtab_destroy(&symtab
);
1730 * Global servers can refer to keys in views.
1732 if (check_servers(config
, voptions
, symtab
, logctx
) != ISC_R_SUCCESS
)
1733 result
= ISC_R_FAILURE
;
1735 isc_symtab_destroy(&symtab
);
1738 * Check that dnssec-enable/dnssec-validation are sensible.
1741 if (voptions
!= NULL
)
1742 (void)cfg_map_get(voptions
, "dnssec-enable", &obj
);
1744 (void)cfg_map_get(config
, "dnssec-enable", &obj
);
1746 enablednssec
= ISC_TRUE
;
1748 enablednssec
= cfg_obj_asboolean(obj
);
1751 if (voptions
!= NULL
)
1752 (void)cfg_map_get(voptions
, "dnssec-validation", &obj
);
1754 (void)cfg_map_get(config
, "dnssec-validation", &obj
);
1756 enablevalidation
= ISC_FALSE
; /* XXXMPA Change for 9.5. */
1758 enablevalidation
= cfg_obj_asboolean(obj
);
1760 if (enablevalidation
&& !enablednssec
)
1761 cfg_obj_log(obj
, logctx
, ISC_LOG_WARNING
,
1762 "'dnssec-validation yes;' and 'dnssec-enable no;'");
1764 if (voptions
!= NULL
)
1765 tresult
= check_options(voptions
, logctx
, mctx
);
1767 tresult
= check_options(config
, logctx
, mctx
);
1768 if (tresult
!= ISC_R_SUCCESS
)
1771 tresult
= check_viewacls(&actx
, voptions
, config
, logctx
, mctx
);
1772 if (tresult
!= ISC_R_SUCCESS
)
1775 tresult
= check_recursionacls(&actx
, voptions
, viewname
,
1776 config
, logctx
, mctx
);
1777 if (tresult
!= ISC_R_SUCCESS
)
1780 cfg_aclconfctx_destroy(&actx
);
1786 default_channels
[] = {
1795 bind9_check_logging(const cfg_obj_t
*config
, isc_log_t
*logctx
,
1798 const cfg_obj_t
*categories
= NULL
;
1799 const cfg_obj_t
*category
;
1800 const cfg_obj_t
*channels
= NULL
;
1801 const cfg_obj_t
*channel
;
1802 const cfg_listelt_t
*element
;
1803 const cfg_listelt_t
*delement
;
1804 const char *channelname
;
1805 const char *catname
;
1806 const cfg_obj_t
*fileobj
= NULL
;
1807 const cfg_obj_t
*syslogobj
= NULL
;
1808 const cfg_obj_t
*nullobj
= NULL
;
1809 const cfg_obj_t
*stderrobj
= NULL
;
1810 const cfg_obj_t
*logobj
= NULL
;
1811 isc_result_t result
= ISC_R_SUCCESS
;
1812 isc_result_t tresult
;
1813 isc_symtab_t
*symtab
= NULL
;
1814 isc_symvalue_t symvalue
;
1817 (void)cfg_map_get(config
, "logging", &logobj
);
1819 return (ISC_R_SUCCESS
);
1821 result
= isc_symtab_create(mctx
, 100, NULL
, NULL
, ISC_FALSE
, &symtab
);
1822 if (result
!= ISC_R_SUCCESS
)
1825 symvalue
.as_cpointer
= NULL
;
1826 for (i
= 0; default_channels
[i
] != NULL
; i
++) {
1827 tresult
= isc_symtab_define(symtab
, default_channels
[i
], 1,
1828 symvalue
, isc_symexists_replace
);
1829 if (tresult
!= ISC_R_SUCCESS
)
1833 cfg_map_get(logobj
, "channel", &channels
);
1835 for (element
= cfg_list_first(channels
);
1837 element
= cfg_list_next(element
))
1839 channel
= cfg_listelt_value(element
);
1840 channelname
= cfg_obj_asstring(cfg_map_getname(channel
));
1841 fileobj
= syslogobj
= nullobj
= stderrobj
= NULL
;
1842 (void)cfg_map_get(channel
, "file", &fileobj
);
1843 (void)cfg_map_get(channel
, "syslog", &syslogobj
);
1844 (void)cfg_map_get(channel
, "null", &nullobj
);
1845 (void)cfg_map_get(channel
, "stderr", &stderrobj
);
1847 if (fileobj
!= NULL
)
1849 if (syslogobj
!= NULL
)
1851 if (nullobj
!= NULL
)
1853 if (stderrobj
!= NULL
)
1856 cfg_obj_log(channel
, logctx
, ISC_LOG_ERROR
,
1857 "channel '%s': exactly one of file, syslog, "
1858 "null, and stderr must be present",
1860 result
= ISC_R_FAILURE
;
1862 tresult
= isc_symtab_define(symtab
, channelname
, 1,
1863 symvalue
, isc_symexists_replace
);
1864 if (tresult
!= ISC_R_SUCCESS
)
1868 cfg_map_get(logobj
, "category", &categories
);
1870 for (element
= cfg_list_first(categories
);
1872 element
= cfg_list_next(element
))
1874 category
= cfg_listelt_value(element
);
1875 catname
= cfg_obj_asstring(cfg_tuple_get(category
, "name"));
1876 if (isc_log_categorybyname(logctx
, catname
) == NULL
) {
1877 cfg_obj_log(category
, logctx
, ISC_LOG_ERROR
,
1878 "undefined category: '%s'", catname
);
1879 result
= ISC_R_FAILURE
;
1881 channels
= cfg_tuple_get(category
, "destinations");
1882 for (delement
= cfg_list_first(channels
);
1884 delement
= cfg_list_next(delement
))
1886 channel
= cfg_listelt_value(delement
);
1887 channelname
= cfg_obj_asstring(channel
);
1888 tresult
= isc_symtab_lookup(symtab
, channelname
, 1,
1890 if (tresult
!= ISC_R_SUCCESS
) {
1891 cfg_obj_log(channel
, logctx
, ISC_LOG_ERROR
,
1892 "undefined channel: '%s'",
1898 isc_symtab_destroy(&symtab
);
1903 bind9_check_controlskeys(const cfg_obj_t
*control
, const cfg_obj_t
*keylist
,
1906 isc_result_t result
= ISC_R_SUCCESS
;
1907 const cfg_obj_t
*control_keylist
;
1908 const cfg_listelt_t
*element
;
1909 const cfg_obj_t
*key
;
1912 control_keylist
= cfg_tuple_get(control
, "keys");
1913 if (cfg_obj_isvoid(control_keylist
))
1914 return (ISC_R_SUCCESS
);
1916 for (element
= cfg_list_first(control_keylist
);
1918 element
= cfg_list_next(element
))
1920 key
= cfg_listelt_value(element
);
1921 keyval
= cfg_obj_asstring(key
);
1923 if (!rndckey_exists(keylist
, keyval
)) {
1924 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
1925 "unknown key '%s'", keyval
);
1926 result
= ISC_R_NOTFOUND
;
1933 bind9_check_controls(const cfg_obj_t
*config
, isc_log_t
*logctx
,
1936 isc_result_t result
= ISC_R_SUCCESS
, tresult
;
1937 cfg_aclconfctx_t actx
;
1938 const cfg_listelt_t
*element
, *element2
;
1939 const cfg_obj_t
*allow
;
1940 const cfg_obj_t
*control
;
1941 const cfg_obj_t
*controls
;
1942 const cfg_obj_t
*controlslist
= NULL
;
1943 const cfg_obj_t
*inetcontrols
;
1944 const cfg_obj_t
*unixcontrols
;
1945 const cfg_obj_t
*keylist
= NULL
;
1947 isc_uint32_t perm
, mask
;
1948 dns_acl_t
*acl
= NULL
;
1949 isc_sockaddr_t addr
;
1952 (void)cfg_map_get(config
, "controls", &controlslist
);
1953 if (controlslist
== NULL
)
1954 return (ISC_R_SUCCESS
);
1956 (void)cfg_map_get(config
, "key", &keylist
);
1958 cfg_aclconfctx_init(&actx
);
1961 * INET: Check allow clause.
1962 * UNIX: Check "perm" for sanity, check path length.
1964 for (element
= cfg_list_first(controlslist
);
1966 element
= cfg_list_next(element
)) {
1967 controls
= cfg_listelt_value(element
);
1968 unixcontrols
= NULL
;
1969 inetcontrols
= NULL
;
1970 (void)cfg_map_get(controls
, "unix", &unixcontrols
);
1971 (void)cfg_map_get(controls
, "inet", &inetcontrols
);
1972 for (element2
= cfg_list_first(inetcontrols
);
1974 element2
= cfg_list_next(element2
)) {
1975 control
= cfg_listelt_value(element2
);
1976 allow
= cfg_tuple_get(control
, "allow");
1977 tresult
= cfg_acl_fromconfig(allow
, config
, logctx
,
1978 &actx
, mctx
, 0, &acl
);
1980 dns_acl_detach(&acl
);
1981 if (tresult
!= ISC_R_SUCCESS
)
1983 tresult
= bind9_check_controlskeys(control
, keylist
,
1985 if (tresult
!= ISC_R_SUCCESS
)
1988 for (element2
= cfg_list_first(unixcontrols
);
1990 element2
= cfg_list_next(element2
)) {
1991 control
= cfg_listelt_value(element2
);
1992 path
= cfg_obj_asstring(cfg_tuple_get(control
, "path"));
1993 tresult
= isc_sockaddr_frompath(&addr
, path
);
1994 if (tresult
== ISC_R_NOSPACE
) {
1995 cfg_obj_log(control
, logctx
, ISC_LOG_ERROR
,
1996 "unix control '%s': path too long",
1998 result
= ISC_R_NOSPACE
;
2000 perm
= cfg_obj_asuint32(cfg_tuple_get(control
, "perm"));
2001 for (i
= 0; i
< 3; i
++) {
2002 #ifdef NEED_SECURE_DIRECTORY
2003 mask
= (0x1 << (i
*3)); /* SEARCH */
2005 mask
= (0x6 << (i
*3)); /* READ + WRITE */
2007 if ((perm
& mask
) == mask
)
2011 cfg_obj_log(control
, logctx
, ISC_LOG_WARNING
,
2012 "unix control '%s' allows access "
2013 "to everyone", path
);
2014 } else if (i
== 3) {
2015 cfg_obj_log(control
, logctx
, ISC_LOG_WARNING
,
2016 "unix control '%s' allows access "
2019 tresult
= bind9_check_controlskeys(control
, keylist
,
2021 if (tresult
!= ISC_R_SUCCESS
)
2025 cfg_aclconfctx_destroy(&actx
);
2030 bind9_check_namedconf(const cfg_obj_t
*config
, isc_log_t
*logctx
,
2033 const cfg_obj_t
*options
= NULL
;
2034 const cfg_obj_t
*views
= NULL
;
2035 const cfg_obj_t
*acls
= NULL
;
2036 const cfg_obj_t
*kals
= NULL
;
2037 const cfg_obj_t
*obj
;
2038 const cfg_listelt_t
*velement
;
2039 isc_result_t result
= ISC_R_SUCCESS
;
2040 isc_result_t tresult
;
2041 isc_symtab_t
*symtab
= NULL
;
2043 static const char *builtin
[] = { "localhost", "localnets",
2046 (void)cfg_map_get(config
, "options", &options
);
2048 if (options
!= NULL
&&
2049 check_options(options
, logctx
, mctx
) != ISC_R_SUCCESS
)
2050 result
= ISC_R_FAILURE
;
2052 if (bind9_check_logging(config
, logctx
, mctx
) != ISC_R_SUCCESS
)
2053 result
= ISC_R_FAILURE
;
2055 if (bind9_check_controls(config
, logctx
, mctx
) != ISC_R_SUCCESS
)
2056 result
= ISC_R_FAILURE
;
2058 if (options
!= NULL
&&
2059 check_order(options
, logctx
) != ISC_R_SUCCESS
)
2060 result
= ISC_R_FAILURE
;
2062 (void)cfg_map_get(config
, "view", &views
);
2064 if (views
!= NULL
&& options
!= NULL
)
2065 if (check_dual_stack(options
, logctx
) != ISC_R_SUCCESS
)
2066 result
= ISC_R_FAILURE
;
2068 if (views
== NULL
) {
2069 if (check_viewconf(config
, NULL
, NULL
, dns_rdataclass_in
,
2070 logctx
, mctx
) != ISC_R_SUCCESS
)
2071 result
= ISC_R_FAILURE
;
2073 const cfg_obj_t
*zones
= NULL
;
2075 (void)cfg_map_get(config
, "zone", &zones
);
2076 if (zones
!= NULL
) {
2077 cfg_obj_log(zones
, logctx
, ISC_LOG_ERROR
,
2078 "when using 'view' statements, "
2079 "all zones must be in views");
2080 result
= ISC_R_FAILURE
;
2084 tresult
= isc_symtab_create(mctx
, 100, NULL
, NULL
, ISC_TRUE
, &symtab
);
2085 if (tresult
!= ISC_R_SUCCESS
)
2087 for (velement
= cfg_list_first(views
);
2089 velement
= cfg_list_next(velement
))
2091 const cfg_obj_t
*view
= cfg_listelt_value(velement
);
2092 const cfg_obj_t
*vname
= cfg_tuple_get(view
, "name");
2093 const cfg_obj_t
*voptions
= cfg_tuple_get(view
, "options");
2094 const cfg_obj_t
*vclassobj
= cfg_tuple_get(view
, "class");
2095 dns_rdataclass_t vclass
= dns_rdataclass_in
;
2096 isc_result_t tresult
= ISC_R_SUCCESS
;
2097 const char *key
= cfg_obj_asstring(vname
);
2098 isc_symvalue_t symvalue
;
2100 if (cfg_obj_isstring(vclassobj
)) {
2103 DE_CONST(cfg_obj_asstring(vclassobj
), r
.base
);
2104 r
.length
= strlen(r
.base
);
2105 tresult
= dns_rdataclass_fromtext(&vclass
, &r
);
2106 if (tresult
!= ISC_R_SUCCESS
)
2107 cfg_obj_log(vclassobj
, logctx
, ISC_LOG_ERROR
,
2108 "view '%s': invalid class %s",
2109 cfg_obj_asstring(vname
), r
.base
);
2111 if (tresult
== ISC_R_SUCCESS
&& symtab
!= NULL
) {
2112 symvalue
.as_cpointer
= view
;
2113 tresult
= isc_symtab_define(symtab
, key
, vclass
,
2115 isc_symexists_reject
);
2116 if (tresult
== ISC_R_EXISTS
) {
2119 RUNTIME_CHECK(isc_symtab_lookup(symtab
, key
,
2120 vclass
, &symvalue
) == ISC_R_SUCCESS
);
2121 file
= cfg_obj_file(symvalue
.as_cpointer
);
2122 line
= cfg_obj_line(symvalue
.as_cpointer
);
2123 cfg_obj_log(view
, logctx
, ISC_LOG_ERROR
,
2124 "view '%s': already exists "
2125 "previous definition: %s:%u",
2128 } else if (tresult
!= ISC_R_SUCCESS
) {
2130 } else if ((strcasecmp(key
, "_bind") == 0 &&
2131 vclass
== dns_rdataclass_ch
) ||
2132 (strcasecmp(key
, "_default") == 0 &&
2133 vclass
== dns_rdataclass_in
)) {
2134 cfg_obj_log(view
, logctx
, ISC_LOG_ERROR
,
2135 "attempt to redefine builtin view "
2137 result
= ISC_R_EXISTS
;
2140 if (tresult
== ISC_R_SUCCESS
)
2141 tresult
= check_viewconf(config
, voptions
, key
,
2142 vclass
, logctx
, mctx
);
2143 if (tresult
!= ISC_R_SUCCESS
)
2144 result
= ISC_R_FAILURE
;
2147 isc_symtab_destroy(&symtab
);
2149 if (views
!= NULL
&& options
!= NULL
) {
2151 tresult
= cfg_map_get(options
, "cache-file", &obj
);
2152 if (tresult
== ISC_R_SUCCESS
) {
2153 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
2154 "'cache-file' cannot be a global "
2155 "option if views are present");
2156 result
= ISC_R_FAILURE
;
2160 cfg_map_get(config
, "acl", &acls
);
2163 const cfg_listelt_t
*elt
;
2164 const cfg_listelt_t
*elt2
;
2165 const char *aclname
;
2167 for (elt
= cfg_list_first(acls
);
2169 elt
= cfg_list_next(elt
)) {
2170 const cfg_obj_t
*acl
= cfg_listelt_value(elt
);
2171 unsigned int line
= cfg_obj_line(acl
);
2174 aclname
= cfg_obj_asstring(cfg_tuple_get(acl
, "name"));
2176 i
< sizeof(builtin
) / sizeof(builtin
[0]);
2178 if (strcasecmp(aclname
, builtin
[i
]) == 0) {
2179 cfg_obj_log(acl
, logctx
, ISC_LOG_ERROR
,
2180 "attempt to redefine "
2183 result
= ISC_R_FAILURE
;
2187 for (elt2
= cfg_list_next(elt
);
2189 elt2
= cfg_list_next(elt2
)) {
2190 const cfg_obj_t
*acl2
= cfg_listelt_value(elt2
);
2192 name
= cfg_obj_asstring(cfg_tuple_get(acl2
,
2194 if (strcasecmp(aclname
, name
) == 0) {
2195 const char *file
= cfg_obj_file(acl
);
2198 file
= "<unknown file>";
2200 cfg_obj_log(acl2
, logctx
, ISC_LOG_ERROR
,
2201 "attempt to redefine "
2202 "acl '%s' previous "
2203 "definition: %s:%u",
2205 result
= ISC_R_FAILURE
;
2211 tresult
= cfg_map_get(config
, "kal", &kals
);
2212 if (tresult
== ISC_R_SUCCESS
) {
2213 const cfg_listelt_t
*elt
;
2214 const cfg_listelt_t
*elt2
;
2215 const char *aclname
;
2217 for (elt
= cfg_list_first(kals
);
2219 elt
= cfg_list_next(elt
)) {
2220 const cfg_obj_t
*acl
= cfg_listelt_value(elt
);
2222 aclname
= cfg_obj_asstring(cfg_tuple_get(acl
, "name"));
2224 for (elt2
= cfg_list_next(elt
);
2226 elt2
= cfg_list_next(elt2
)) {
2227 const cfg_obj_t
*acl2
= cfg_listelt_value(elt2
);
2229 name
= cfg_obj_asstring(cfg_tuple_get(acl2
,
2231 if (strcasecmp(aclname
, name
) == 0) {
2232 const char *file
= cfg_obj_file(acl
);
2233 unsigned int line
= cfg_obj_line(acl
);
2236 file
= "<unknown file>";
2238 cfg_obj_log(acl2
, logctx
, ISC_LOG_ERROR
,
2239 "attempt to redefine "
2240 "kal '%s' previous "
2241 "definition: %s:%u",
2243 result
= ISC_R_FAILURE
;