1 /*
2 * Copyright (C) 2004-2016 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2001-2003 Internet Software Consortium.
4 *
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.
8 *
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.
16 */
17
18 /*! \file */
19
20 #include <config.h>
21
22 #include <stdlib.h>
23
24 #include <isc/base64.h>
25 #include <isc/buffer.h>
26 #include <isc/file.h>
27 #include <isc/log.h>
28 #include <isc/mem.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>
36 #include <isc/util.h>
37
38 #include <dns/acl.h>
39 #include <dns/fixedname.h>
40 #include <dns/rdataclass.h>
41 #include <dns/rdatatype.h>
42 #include <dns/secalg.h>
43
44 #include <dst/dst.h>
45
46 #include <isccfg/aclconf.h>
47 #include <isccfg/cfg.h>
48
49 #include <bind9/check.h>
50
51 static isc_result_t
52 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, isc_boolean_t writeable,
53 isc_log_t *logctxlogc);
54
55 static void
freekey(char * key,unsigned int type,isc_symvalue_t value,void * userarg)56 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
57 UNUSED(type);
58 UNUSED(value);
59 isc_mem_free(userarg, key);
60 }
61
62 static isc_result_t
check_orderent(const cfg_obj_t * ent,isc_log_t * logctx)63 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
64 isc_result_t result = ISC_R_SUCCESS;
65 isc_result_t tresult;
66 isc_textregion_t r;
67 dns_fixedname_t fixed;
68 const cfg_obj_t *obj;
69 dns_rdataclass_t rdclass;
70 dns_rdatatype_t rdtype;
71 isc_buffer_t b;
72 const char *str;
73
74 dns_fixedname_init(&fixed);
75 obj = cfg_tuple_get(ent, "class");
76 if (cfg_obj_isstring(obj)) {
77
78 DE_CONST(cfg_obj_asstring(obj), r.base);
79 r.length = strlen(r.base);
80 tresult = dns_rdataclass_fromtext(&rdclass, &r);
81 if (tresult != ISC_R_SUCCESS) {
82 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
83 "rrset-order: invalid class '%s'",
84 r.base);
85 result = ISC_R_FAILURE;
86 }
87 }
88
89 obj = cfg_tuple_get(ent, "type");
90 if (cfg_obj_isstring(obj)) {
91 DE_CONST(cfg_obj_asstring(obj), r.base);
92 r.length = strlen(r.base);
93 tresult = dns_rdatatype_fromtext(&rdtype, &r);
94 if (tresult != ISC_R_SUCCESS) {
95 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
96 "rrset-order: invalid type '%s'",
97 r.base);
98 result = ISC_R_FAILURE;
99 }
100 }
101
102 obj = cfg_tuple_get(ent, "name");
103 if (cfg_obj_isstring(obj)) {
104 str = cfg_obj_asstring(obj);
105 isc_buffer_constinit(&b, str, strlen(str));
106 isc_buffer_add(&b, strlen(str));
107 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
108 dns_rootname, 0, NULL);
109 if (tresult != ISC_R_SUCCESS) {
110 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
111 "rrset-order: invalid name '%s'", str);
112 result = ISC_R_FAILURE;
113 }
114 }
115
116 obj = cfg_tuple_get(ent, "order");
117 if (!cfg_obj_isstring(obj) ||
118 strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
119 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
120 "rrset-order: keyword 'order' missing");
121 result = ISC_R_FAILURE;
122 }
123
124 obj = cfg_tuple_get(ent, "ordering");
125 if (!cfg_obj_isstring(obj)) {
126 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
127 "rrset-order: missing ordering");
128 result = ISC_R_FAILURE;
129 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
130 #if !DNS_RDATASET_FIXED
131 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
132 "rrset-order: order 'fixed' was disabled at "
133 "compilation time");
134 #endif
135 } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
136 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
137 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
138 "rrset-order: invalid order '%s'",
139 cfg_obj_asstring(obj));
140 result = ISC_R_FAILURE;
141 }
142 return (result);
143 }
144
145 static isc_result_t
check_order(const cfg_obj_t * options,isc_log_t * logctx)146 check_order(const cfg_obj_t *options, isc_log_t *logctx) {
147 isc_result_t result = ISC_R_SUCCESS;
148 isc_result_t tresult;
149 const cfg_listelt_t *element;
150 const cfg_obj_t *obj = NULL;
151
152 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
153 return (result);
154
155 for (element = cfg_list_first(obj);
156 element != NULL;
157 element = cfg_list_next(element))
158 {
159 tresult = check_orderent(cfg_listelt_value(element), logctx);
160 if (tresult != ISC_R_SUCCESS)
161 result = tresult;
162 }
163 return (result);
164 }
165
166 static isc_result_t
check_dual_stack(const cfg_obj_t * options,isc_log_t * logctx)167 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
168 const cfg_listelt_t *element;
169 const cfg_obj_t *alternates = NULL;
170 const cfg_obj_t *value;
171 const cfg_obj_t *obj;
172 const char *str;
173 dns_fixedname_t fixed;
174 dns_name_t *name;
175 isc_buffer_t buffer;
176 isc_result_t result = ISC_R_SUCCESS;
177 isc_result_t tresult;
178
179 (void)cfg_map_get(options, "dual-stack-servers", &alternates);
180
181 if (alternates == NULL)
182 return (ISC_R_SUCCESS);
183
184 obj = cfg_tuple_get(alternates, "port");
185 if (cfg_obj_isuint32(obj)) {
186 isc_uint32_t val = cfg_obj_asuint32(obj);
187 if (val > ISC_UINT16_MAX) {
188 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
189 "port '%u' out of range", val);
190 result = ISC_R_FAILURE;
191 }
192 }
193 obj = cfg_tuple_get(alternates, "addresses");
194 for (element = cfg_list_first(obj);
195 element != NULL;
196 element = cfg_list_next(element)) {
197 value = cfg_listelt_value(element);
198 if (cfg_obj_issockaddr(value))
199 continue;
200 obj = cfg_tuple_get(value, "name");
201 str = cfg_obj_asstring(obj);
202 isc_buffer_constinit(&buffer, str, strlen(str));
203 isc_buffer_add(&buffer, strlen(str));
204 dns_fixedname_init(&fixed);
205 name = dns_fixedname_name(&fixed);
206 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
207 0, NULL);
208 if (tresult != ISC_R_SUCCESS) {
209 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
210 "bad name '%s'", str);
211 result = ISC_R_FAILURE;
212 }
213 obj = cfg_tuple_get(value, "port");
214 if (cfg_obj_isuint32(obj)) {
215 isc_uint32_t val = cfg_obj_asuint32(obj);
216 if (val > ISC_UINT16_MAX) {
217 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
218 "port '%u' out of range", val);
219 result = ISC_R_FAILURE;
220 }
221 }
222 }
223 return (result);
224 }
225
226 static isc_result_t
check_forward(const cfg_obj_t * options,const cfg_obj_t * global,isc_log_t * logctx)227 check_forward(const cfg_obj_t *options, const cfg_obj_t *global,
228 isc_log_t *logctx)
229 {
230 const cfg_obj_t *forward = NULL;
231 const cfg_obj_t *forwarders = NULL;
232
233 (void)cfg_map_get(options, "forward", &forward);
234 (void)cfg_map_get(options, "forwarders", &forwarders);
235
236 if (forwarders != NULL && global != NULL) {
237 const char *file = cfg_obj_file(global);
238 unsigned int line = cfg_obj_line(global);
239 cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
240 "forwarders declared in root zone and "
241 "in general configuration: %s:%u",
242 file, line);
243 return (ISC_R_FAILURE);
244 }
245 if (forward != NULL && forwarders == NULL) {
246 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
247 "no matching 'forwarders' statement");
248 return (ISC_R_FAILURE);
249 }
250 return (ISC_R_SUCCESS);
251 }
252
253 static isc_result_t
disabled_algorithms(const cfg_obj_t * disabled,isc_log_t * logctx)254 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
255 isc_result_t result = ISC_R_SUCCESS;
256 isc_result_t tresult;
257 const cfg_listelt_t *element;
258 const char *str;
259 isc_buffer_t b;
260 dns_fixedname_t fixed;
261 dns_name_t *name;
262 const cfg_obj_t *obj;
263
264 dns_fixedname_init(&fixed);
265 name = dns_fixedname_name(&fixed);
266 obj = cfg_tuple_get(disabled, "name");
267 str = cfg_obj_asstring(obj);
268 isc_buffer_constinit(&b, str, strlen(str));
269 isc_buffer_add(&b, strlen(str));
270 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
271 if (tresult != ISC_R_SUCCESS) {
272 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
273 "bad domain name '%s'", str);
274 result = tresult;
275 }
276
277 obj = cfg_tuple_get(disabled, "algorithms");
278
279 for (element = cfg_list_first(obj);
280 element != NULL;
281 element = cfg_list_next(element))
282 {
283 isc_textregion_t r;
284 dns_secalg_t alg;
285
286 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
287 r.length = strlen(r.base);
288
289 tresult = dns_secalg_fromtext(&alg, &r);
290 if (tresult != ISC_R_SUCCESS) {
291 cfg_obj_log(cfg_listelt_value(element), logctx,
292 ISC_LOG_ERROR, "invalid algorithm '%s'",
293 r.base);
294 result = tresult;
295 }
296 }
297 return (result);
298 }
299
300 static isc_result_t
nameexist(const cfg_obj_t * obj,const char * name,int value,isc_symtab_t * symtab,const char * fmt,isc_log_t * logctx,isc_mem_t * mctx)301 nameexist(const cfg_obj_t *obj, const char *name, int value,
302 isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
303 isc_mem_t *mctx)
304 {
305 char *key;
306 const char *file;
307 unsigned int line;
308 isc_result_t result;
309 isc_symvalue_t symvalue;
310
311 key = isc_mem_strdup(mctx, name);
312 if (key == NULL)
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);
322
323 if (file == NULL)
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);
330 }
331 return (result);
332 }
333
334 static isc_result_t
mustbesecure(const cfg_obj_t * secure,isc_symtab_t * symtab,isc_log_t * logctx,isc_mem_t * mctx)335 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
336 isc_mem_t *mctx)
337 {
338 const cfg_obj_t *obj;
339 char namebuf[DNS_NAME_FORMATSIZE];
340 const char *str;
341 dns_fixedname_t fixed;
342 dns_name_t *name;
343 isc_buffer_t b;
344 isc_result_t result = ISC_R_SUCCESS;
345
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_constinit(&b, str, strlen(str));
351 isc_buffer_add(&b, strlen(str));
352 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
353 if (result != ISC_R_SUCCESS) {
354 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
355 "bad domain name '%s'", str);
356 } else {
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",
361 logctx, mctx);
362 }
363 return (result);
364 }
365
366 static isc_result_t
checkacl(const char * aclname,cfg_aclconfctx_t * actx,const cfg_obj_t * zconfig,const cfg_obj_t * voptions,const cfg_obj_t * config,isc_log_t * logctx,isc_mem_t * mctx)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)
370 {
371 isc_result_t result;
372 const cfg_obj_t *aclobj = NULL;
373 const cfg_obj_t *options;
374 dns_acl_t *acl = NULL;
375
376 if (zconfig != NULL) {
377 options = cfg_tuple_get(zconfig, "options");
378 cfg_map_get(options, aclname, &aclobj);
379 }
380 if (voptions != NULL && aclobj == NULL)
381 cfg_map_get(voptions, aclname, &aclobj);
382 if (config != NULL && aclobj == NULL) {
383 options = NULL;
384 cfg_map_get(config, "options", &options);
385 if (options != NULL)
386 cfg_map_get(options, aclname, &aclobj);
387 }
388 if (aclobj == NULL)
389 return (ISC_R_SUCCESS);
390 result = cfg_acl_fromconfig(aclobj, config, logctx,
391 actx, mctx, 0, &acl);
392 if (acl != NULL)
393 dns_acl_detach(&acl);
394 return (result);
395 }
396
397 static isc_result_t
check_viewacls(cfg_aclconfctx_t * actx,const cfg_obj_t * voptions,const cfg_obj_t * config,isc_log_t * logctx,isc_mem_t * mctx)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)
400 {
401 isc_result_t result = ISC_R_SUCCESS, tresult;
402 int i = 0;
403
404 static const char *acls[] = { "allow-query", "allow-query-on",
405 "allow-query-cache", "allow-query-cache-on",
406 "blackhole", "match-clients", "match-destinations",
407 "sortlist", "filter-aaaa", NULL };
408
409 while (acls[i] != NULL) {
410 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
411 logctx, mctx);
412 if (tresult != ISC_R_SUCCESS)
413 result = tresult;
414 }
415 return (result);
416 }
417
418 static const unsigned char zeros[16];
419
420 static isc_result_t
check_dns64(cfg_aclconfctx_t * actx,const cfg_obj_t * voptions,const cfg_obj_t * config,isc_log_t * logctx,isc_mem_t * mctx)421 check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
422 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
423 {
424 isc_result_t result = ISC_R_SUCCESS;
425 const cfg_obj_t *dns64 = NULL;
426 const cfg_obj_t *options;
427 const cfg_listelt_t *element;
428 const cfg_obj_t *map, *obj;
429 isc_netaddr_t na, sa;
430 unsigned int prefixlen;
431 int nbytes;
432 int i;
433
434 static const char *acls[] = { "clients", "exclude", "mapped", NULL};
435
436 if (voptions != NULL)
437 cfg_map_get(voptions, "dns64", &dns64);
438 if (config != NULL && dns64 == NULL) {
439 options = NULL;
440 cfg_map_get(config, "options", &options);
441 if (options != NULL)
442 cfg_map_get(options, "dns64", &dns64);
443 }
444 if (dns64 == NULL)
445 return (ISC_R_SUCCESS);
446
447 for (element = cfg_list_first(dns64);
448 element != NULL;
449 element = cfg_list_next(element))
450 {
451 map = cfg_listelt_value(element);
452 obj = cfg_map_getname(map);
453
454 cfg_obj_asnetprefix(obj, &na, &prefixlen);
455 if (na.family != AF_INET6) {
456 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
457 "dns64 requires a IPv6 prefix");
458 result = ISC_R_FAILURE;
459 continue;
460 }
461
462 if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 &&
463 prefixlen != 56 && prefixlen != 64 && prefixlen != 96) {
464 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
465 "bad prefix length %u [32/40/48/56/64/96]",
466 prefixlen);
467 result = ISC_R_FAILURE;
468 continue;
469 }
470
471 for (i = 0; acls[i] != NULL; i++) {
472 obj = NULL;
473 (void)cfg_map_get(map, acls[i], &obj);
474 if (obj != NULL) {
475 dns_acl_t *acl = NULL;
476 isc_result_t tresult;
477
478 tresult = cfg_acl_fromconfig(obj, config,
479 logctx, actx,
480 mctx, 0, &acl);
481 if (acl != NULL)
482 dns_acl_detach(&acl);
483 if (tresult != ISC_R_SUCCESS)
484 result = tresult;
485 }
486 }
487
488 obj = NULL;
489 (void)cfg_map_get(map, "suffix", &obj);
490 if (obj != NULL) {
491 isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj));
492 if (sa.family != AF_INET6) {
493 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
494 "dns64 requires a IPv6 suffix");
495 result = ISC_R_FAILURE;
496 continue;
497 }
498 nbytes = prefixlen / 8 + 4;
499 if (prefixlen >= 32 && prefixlen <= 64)
500 nbytes++;
501 if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) {
502 char netaddrbuf[ISC_NETADDR_FORMATSIZE];
503 isc_netaddr_format(&sa, netaddrbuf,
504 sizeof(netaddrbuf));
505 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
506 "bad suffix '%s' leading "
507 "%u octets not zeros",
508 netaddrbuf, nbytes);
509 result = ISC_R_FAILURE;
510 }
511 }
512 }
513
514 return (result);
515 }
516
517
518 /*
519 * Check allow-recursion and allow-recursion-on acls, and also log a
520 * warning if they're inconsistent with the "recursion" option.
521 */
522 static isc_result_t
check_recursionacls(cfg_aclconfctx_t * actx,const cfg_obj_t * voptions,const char * viewname,const cfg_obj_t * config,isc_log_t * logctx,isc_mem_t * mctx)523 check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
524 const char *viewname, const cfg_obj_t *config,
525 isc_log_t *logctx, isc_mem_t *mctx)
526 {
527 const cfg_obj_t *options, *aclobj, *obj = NULL;
528 dns_acl_t *acl = NULL;
529 isc_result_t result = ISC_R_SUCCESS, tresult;
530 isc_boolean_t recursion;
531 const char *forview = " for view ";
532 int i = 0;
533
534 static const char *acls[] = { "allow-recursion", "allow-recursion-on",
535 NULL };
536
537 if (voptions != NULL)
538 cfg_map_get(voptions, "recursion", &obj);
539 if (obj == NULL && config != NULL) {
540 options = NULL;
541 cfg_map_get(config, "options", &options);
542 if (options != NULL)
543 cfg_map_get(options, "recursion", &obj);
544 }
545 if (obj == NULL)
546 recursion = ISC_TRUE;
547 else
548 recursion = cfg_obj_asboolean(obj);
549
550 if (viewname == NULL) {
551 viewname = "";
552 forview = "";
553 }
554
555 for (i = 0; acls[i] != NULL; i++) {
556 aclobj = options = NULL;
557 acl = NULL;
558
559 if (voptions != NULL)
560 cfg_map_get(voptions, acls[i], &aclobj);
561 if (config != NULL && aclobj == NULL) {
562 options = NULL;
563 cfg_map_get(config, "options", &options);
564 if (options != NULL)
565 cfg_map_get(options, acls[i], &aclobj);
566 }
567 if (aclobj == NULL)
568 continue;
569
570 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
571 actx, mctx, 0, &acl);
572
573 if (tresult != ISC_R_SUCCESS)
574 result = tresult;
575
576 if (acl == NULL)
577 continue;
578
579 if (recursion == ISC_FALSE && !dns_acl_isnone(acl)) {
580 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
581 "both \"recursion no;\" and "
582 "\"%s\" active%s%s",
583 acls[i], forview, viewname);
584 }
585
586 if (acl != NULL)
587 dns_acl_detach(&acl);
588 }
589
590 return (result);
591 }
592
593 static isc_result_t
check_filteraaaa(cfg_aclconfctx_t * actx,const cfg_obj_t * voptions,const char * viewname,const cfg_obj_t * config,isc_log_t * logctx,isc_mem_t * mctx)594 check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
595 const char *viewname, const cfg_obj_t *config,
596 isc_log_t *logctx, isc_mem_t *mctx)
597 {
598 const cfg_obj_t *options, *aclobj, *obj = NULL;
599 dns_acl_t *acl = NULL;
600 isc_result_t result = ISC_R_SUCCESS, tresult;
601 dns_v4_aaaa_t filter;
602 const char *forview = " for view ";
603
604 if (voptions != NULL)
605 cfg_map_get(voptions, "filter-aaaa-on-v4", &obj);
606 if (obj == NULL && config != NULL) {
607 options = NULL;
608 cfg_map_get(config, "options", &options);
609 if (options != NULL)
610 cfg_map_get(options, "filter-aaaa-on-v4", &obj);
611 }
612
613 if (obj == NULL)
614 filter = dns_v4_aaaa_ok; /* default */
615 else if (cfg_obj_isboolean(obj))
616 filter = cfg_obj_asboolean(obj) ? dns_v4_aaaa_filter :
617 dns_v4_aaaa_ok;
618 else
619 filter = dns_v4_aaaa_break_dnssec; /* break-dnssec */
620
621 if (viewname == NULL) {
622 viewname = "";
623 forview = "";
624 }
625
626 aclobj = options = NULL;
627 acl = NULL;
628
629 if (voptions != NULL)
630 cfg_map_get(voptions, "filter-aaaa", &aclobj);
631 if (config != NULL && aclobj == NULL) {
632 options = NULL;
633 cfg_map_get(config, "options", &options);
634 if (options != NULL)
635 cfg_map_get(options, "filter-aaaa", &aclobj);
636 }
637 if (aclobj == NULL)
638 return (result);
639
640 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
641 actx, mctx, 0, &acl);
642
643 if (tresult != ISC_R_SUCCESS) {
644 result = tresult;
645 } else if (filter != dns_v4_aaaa_ok && dns_acl_isnone(acl)) {
646 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
647 "both \"filter-aaaa-on-v4 %s;\" and "
648 "\"filter-aaaa\" is 'none;'%s%s",
649 filter == dns_v4_aaaa_break_dnssec ?
650 "break-dnssec" : "yes", forview, viewname);
651 result = ISC_R_FAILURE;
652 } else if (filter == dns_v4_aaaa_ok && !dns_acl_isnone(acl)) {
653 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
654 "both \"filter-aaaa-on-v4 no;\" and "
655 "\"filter-aaaa\" is set%s%s", forview, viewname);
656 result = ISC_R_FAILURE;
657 }
658
659 if (acl != NULL)
660 dns_acl_detach(&acl);
661
662 return (result);
663 }
664
665 typedef struct {
666 const char *name;
667 unsigned int scale;
668 unsigned int max;
669 } intervaltable;
670
671 typedef enum {
672 optlevel_config,
673 optlevel_options,
674 optlevel_view,
675 optlevel_zone
676 } optlevel_t;
677
678 static isc_result_t
check_name(const char * str)679 check_name(const char *str) {
680 dns_fixedname_t fixed;
681
682 dns_fixedname_init(&fixed);
683 return (dns_name_fromstring(dns_fixedname_name(&fixed), str, 0, NULL));
684 }
685
686 static isc_result_t
check_options(const cfg_obj_t * options,isc_log_t * logctx,isc_mem_t * mctx,optlevel_t optlevel)687 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
688 optlevel_t optlevel)
689 {
690 isc_result_t result = ISC_R_SUCCESS;
691 isc_result_t tresult;
692 unsigned int i;
693 const cfg_obj_t *obj = NULL;
694 const cfg_obj_t *resignobj = NULL;
695 const cfg_listelt_t *element;
696 isc_symtab_t *symtab = NULL;
697 dns_fixedname_t fixed;
698 const char *str;
699 dns_name_t *name;
700
701 static intervaltable intervals[] = {
702 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
703 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
704 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
705 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
706 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
707 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
708 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
709 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
710 };
711
712 static const char *server_contact[] = {
713 "empty-server", "empty-contact",
714 "dns64-server", "dns64-contact",
715 NULL
716 };
717
718 /*
719 * Check that fields specified in units of time other than seconds
720 * have reasonable values.
721 */
722 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
723 isc_uint32_t val;
724 obj = NULL;
725 (void)cfg_map_get(options, intervals[i].name, &obj);
726 if (obj == NULL)
727 continue;
728 val = cfg_obj_asuint32(obj);
729 if (val > intervals[i].max) {
730 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
731 "%s '%u' is out of range (0..%u)",
732 intervals[i].name, val,
733 intervals[i].max);
734 result = ISC_R_RANGE;
735 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
736 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
737 "%s '%d' is out of range",
738 intervals[i].name, val);
739 result = ISC_R_RANGE;
740 }
741 }
742
743 obj = NULL;
744 cfg_map_get(options, "max-rsa-exponent-size", &obj);
745 if (obj != NULL) {
746 isc_uint32_t val;
747
748 val = cfg_obj_asuint32(obj);
749 if (val != 0 && (val < 35 || val > 4096)) {
750 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
751 "max-rsa-exponent-size '%u' is out of "
752 "range (35..4096)", val);
753 result = ISC_R_RANGE;
754 }
755 }
756
757 obj = NULL;
758 cfg_map_get(options, "sig-validity-interval", &obj);
759 if (obj != NULL) {
760 isc_uint32_t validity, resign = 0;
761
762 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
763 resignobj = cfg_tuple_get(obj, "re-sign");
764 if (!cfg_obj_isvoid(resignobj))
765 resign = cfg_obj_asuint32(resignobj);
766
767 if (validity > 3660 || validity == 0) { /* 10 years */
768 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
769 "%s '%u' is out of range (1..3660)",
770 "sig-validity-interval", validity);
771 result = ISC_R_RANGE;
772 }
773
774 if (!cfg_obj_isvoid(resignobj)) {
775 if (resign > 3660 || resign == 0) { /* 10 years */
776 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
777 "%s '%u' is out of range (1..3660)",
778 "sig-validity-interval (re-sign)",
779 validity);
780 result = ISC_R_RANGE;
781 } else if ((validity > 7 && validity < resign) ||
782 (validity <= 7 && validity * 24 < resign)) {
783 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
784 "validity interval (%u days) "
785 "less than re-signing interval "
786 "(%u %s)", validity, resign,
787 (validity > 7) ? "days" : "hours");
788 result = ISC_R_RANGE;
789 }
790 }
791 }
792
793 obj = NULL;
794 (void)cfg_map_get(options, "preferred-glue", &obj);
795 if (obj != NULL) {
796 str = cfg_obj_asstring(obj);
797 if (strcasecmp(str, "a") != 0 &&
798 strcasecmp(str, "aaaa") != 0 &&
799 strcasecmp(str, "none") != 0)
800 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
801 "preferred-glue unexpected value '%s'",
802 str);
803 }
804
805 obj = NULL;
806 (void)cfg_map_get(options, "root-delegation-only", &obj);
807 if (obj != NULL) {
808 if (!cfg_obj_isvoid(obj)) {
809 for (element = cfg_list_first(obj);
810 element != NULL;
811 element = cfg_list_next(element)) {
812 const cfg_obj_t *exclude;
813
814 exclude = cfg_listelt_value(element);
815 str = cfg_obj_asstring(exclude);
816 tresult = check_name(str);
817 if (tresult != ISC_R_SUCCESS) {
818 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
819 "bad domain name '%s'",
820 str);
821 result = tresult;
822 }
823 }
824 }
825 }
826
827 /*
828 * Set supported DNSSEC algorithms.
829 */
830 obj = NULL;
831 (void)cfg_map_get(options, "disable-algorithms", &obj);
832 if (obj != NULL) {
833 for (element = cfg_list_first(obj);
834 element != NULL;
835 element = cfg_list_next(element))
836 {
837 obj = cfg_listelt_value(element);
838 tresult = disabled_algorithms(obj, logctx);
839 if (tresult != ISC_R_SUCCESS)
840 result = tresult;
841 }
842 }
843
844 dns_fixedname_init(&fixed);
845 name = dns_fixedname_name(&fixed);
846
847 /*
848 * Check the DLV zone name.
849 */
850 obj = NULL;
851 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
852 if (obj != NULL) {
853 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
854 ISC_FALSE, &symtab);
855 if (tresult != ISC_R_SUCCESS)
856 result = tresult;
857 for (element = cfg_list_first(obj);
858 element != NULL;
859 element = cfg_list_next(element))
860 {
861 const char *dlv;
862 const cfg_obj_t *dlvobj, *anchor;
863
864 obj = cfg_listelt_value(element);
865
866 anchor = cfg_tuple_get(obj, "trust-anchor");
867 dlvobj = cfg_tuple_get(obj, "domain");
868 dlv = cfg_obj_asstring(dlvobj);
869
870 /*
871 * If domain is "auto" or "no" and trust anchor
872 * is missing, skip remaining tests
873 */
874 if (cfg_obj_isvoid(anchor)) {
875 if (!strcasecmp(dlv, "no") ||
876 !strcasecmp(dlv, "auto"))
877 continue;
878 }
879
880 tresult = dns_name_fromstring(name, dlv, 0, NULL);
881 if (tresult != ISC_R_SUCCESS) {
882 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
883 "bad domain name '%s'", dlv);
884 result = tresult;
885 continue;
886 }
887 if (symtab != NULL) {
888 tresult = nameexist(obj, dlv, 1, symtab,
889 "dnssec-lookaside '%s': "
890 "already exists previous "
891 "definition: %s:%u",
892 logctx, mctx);
893 if (tresult != ISC_R_SUCCESS &&
894 result == ISC_R_SUCCESS)
895 result = tresult;
896 }
897
898 /*
899 * XXXMPA to be removed when multiple lookaside
900 * namespaces are supported.
901 */
902 if (!dns_name_equal(dns_rootname, name)) {
903 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
904 "dnssec-lookaside '%s': "
905 "non-root not yet supported", dlv);
906 if (result == ISC_R_SUCCESS)
907 result = ISC_R_FAILURE;
908 }
909
910 if (!cfg_obj_isvoid(anchor)) {
911 dlv = cfg_obj_asstring(anchor);
912 tresult = check_name(dlv);
913 if (tresult != ISC_R_SUCCESS) {
914 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
915 "bad domain name '%s'",
916 dlv);
917 if (result == ISC_R_SUCCESS)
918 result = tresult;
919 }
920 } else {
921 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
922 "dnssec-lookaside requires "
923 "either 'auto' or 'no', or a "
924 "domain and trust anchor");
925 if (result == ISC_R_SUCCESS)
926 result = ISC_R_FAILURE;
927 }
928 }
929
930 if (symtab != NULL)
931 isc_symtab_destroy(&symtab);
932 }
933
934 /*
935 * Check auto-dnssec at the view/options level
936 */
937 obj = NULL;
938 (void)cfg_map_get(options, "auto-dnssec", &obj);
939 if (obj != NULL) {
940 const char *arg = cfg_obj_asstring(obj);
941 if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) {
942 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
943 "auto-dnssec may only be activated at the "
944 "zone level");
945 result = ISC_R_FAILURE;
946 }
947 }
948
949 /*
950 * Check dnssec-must-be-secure.
951 */
952 obj = NULL;
953 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
954 if (obj != NULL) {
955 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
956 ISC_FALSE, &symtab);
957 if (tresult != ISC_R_SUCCESS)
958 result = tresult;
959 for (element = cfg_list_first(obj);
960 element != NULL;
961 element = cfg_list_next(element))
962 {
963 obj = cfg_listelt_value(element);
964 tresult = mustbesecure(obj, symtab, logctx, mctx);
965 if (tresult != ISC_R_SUCCESS)
966 result = tresult;
967 }
968 if (symtab != NULL)
969 isc_symtab_destroy(&symtab);
970 }
971
972 /*
973 * Check server/contacts for syntactic validity.
974 */
975 for (i= 0; server_contact[i] != NULL; i++) {
976 obj = NULL;
977 (void)cfg_map_get(options, server_contact[i], &obj);
978 if (obj != NULL) {
979 str = cfg_obj_asstring(obj);
980 if (check_name(str) != ISC_R_SUCCESS) {
981 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
982 "%s: invalid name '%s'",
983 server_contact[i], str);
984 result = ISC_R_FAILURE;
985 }
986 }
987 }
988
989 /*
990 * Check empty zone configuration.
991 */
992 obj = NULL;
993 (void)cfg_map_get(options, "disable-empty-zone", &obj);
994 for (element = cfg_list_first(obj);
995 element != NULL;
996 element = cfg_list_next(element))
997 {
998 obj = cfg_listelt_value(element);
999 str = cfg_obj_asstring(obj);
1000 if (check_name(str) != ISC_R_SUCCESS) {
1001 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1002 "disable-empty-zone: invalid name '%s'",
1003 str);
1004 result = ISC_R_FAILURE;
1005 }
1006 }
1007
1008 /*
1009 * Check that server-id is not too long.
1010 * 1024 bytes should be big enough.
1011 */
1012 obj = NULL;
1013 (void)cfg_map_get(options, "server-id", &obj);
1014 if (obj != NULL && cfg_obj_isstring(obj) &&
1015 strlen(cfg_obj_asstring(obj)) > 1024U) {
1016 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1017 "'server-id' too big (>1024 bytes)");
1018 result = ISC_R_FAILURE;
1019 }
1020
1021 return (result);
1022 }
1023
1024 static isc_result_t
get_masters_def(const cfg_obj_t * cctx,const char * name,const cfg_obj_t ** ret)1025 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
1026 isc_result_t result;
1027 const cfg_obj_t *masters = NULL;
1028 const cfg_listelt_t *elt;
1029
1030 result = cfg_map_get(cctx, "masters", &masters);
1031 if (result != ISC_R_SUCCESS)
1032 return (result);
1033 for (elt = cfg_list_first(masters);
1034 elt != NULL;
1035 elt = cfg_list_next(elt)) {
1036 const cfg_obj_t *list;
1037 const char *listname;
1038
1039 list = cfg_listelt_value(elt);
1040 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
1041
1042 if (strcasecmp(listname, name) == 0) {
1043 *ret = list;
1044 return (ISC_R_SUCCESS);
1045 }
1046 }
1047 return (ISC_R_NOTFOUND);
1048 }
1049
1050 static isc_result_t
validate_masters(const cfg_obj_t * obj,const cfg_obj_t * config,isc_uint32_t * countp,isc_log_t * logctx,isc_mem_t * mctx)1051 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
1052 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
1053 {
1054 isc_result_t result = ISC_R_SUCCESS;
1055 isc_result_t tresult;
1056 isc_uint32_t count = 0;
1057 isc_symtab_t *symtab = NULL;
1058 isc_symvalue_t symvalue;
1059 const cfg_listelt_t *element;
1060 const cfg_listelt_t **stack = NULL;
1061 isc_uint32_t stackcount = 0, pushed = 0;
1062 const cfg_obj_t *list;
1063
1064 REQUIRE(countp != NULL);
1065 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1066 if (result != ISC_R_SUCCESS) {
1067 *countp = count;
1068 return (result);
1069 }
1070
1071 newlist:
1072 list = cfg_tuple_get(obj, "addresses");
1073 element = cfg_list_first(list);
1074 resume:
1075 for ( ;
1076 element != NULL;
1077 element = cfg_list_next(element))
1078 {
1079 const char *listname;
1080 const cfg_obj_t *addr;
1081 const cfg_obj_t *key;
1082
1083 addr = cfg_tuple_get(cfg_listelt_value(element),
1084 "masterselement");
1085 key = cfg_tuple_get(cfg_listelt_value(element), "key");
1086
1087 if (cfg_obj_issockaddr(addr)) {
1088 count++;
1089 continue;
1090 }
1091 if (!cfg_obj_isvoid(key)) {
1092 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1093 "unexpected token '%s'",
1094 cfg_obj_asstring(key));
1095 if (result == ISC_R_SUCCESS)
1096 result = ISC_R_FAILURE;
1097 }
1098 listname = cfg_obj_asstring(addr);
1099 symvalue.as_cpointer = addr;
1100 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
1101 isc_symexists_reject);
1102 if (tresult == ISC_R_EXISTS)
1103 continue;
1104 tresult = get_masters_def(config, listname, &obj);
1105 if (tresult != ISC_R_SUCCESS) {
1106 if (result == ISC_R_SUCCESS)
1107 result = tresult;
1108 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
1109 "unable to find masters list '%s'",
1110 listname);
1111 continue;
1112 }
1113 /* Grow stack? */
1114 if (stackcount == pushed) {
1115 void * new;
1116 isc_uint32_t newlen = stackcount + 16;
1117 size_t newsize, oldsize;
1118
1119 newsize = newlen * sizeof(*stack);
1120 oldsize = stackcount * sizeof(*stack);
1121 new = isc_mem_get(mctx, newsize);
1122 if (new == NULL)
1123 goto cleanup;
1124 if (stackcount != 0) {
1125 void *ptr;
1126
1127 DE_CONST(stack, ptr);
1128 memmove(new, stack, oldsize);
1129 isc_mem_put(mctx, ptr, oldsize);
1130 }
1131 stack = new;
1132 stackcount = newlen;
1133 }
1134 stack[pushed++] = cfg_list_next(element);
1135 goto newlist;
1136 }
1137 if (pushed != 0) {
1138 element = stack[--pushed];
1139 goto resume;
1140 }
1141 cleanup:
1142 if (stack != NULL) {
1143 void *ptr;
1144
1145 DE_CONST(stack, ptr);
1146 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
1147 }
1148 isc_symtab_destroy(&symtab);
1149 *countp = count;
1150 return (result);
1151 }
1152
1153 static isc_result_t
check_update_policy(const cfg_obj_t * policy,isc_log_t * logctx)1154 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
1155 isc_result_t result = ISC_R_SUCCESS;
1156 isc_result_t tresult;
1157 const cfg_listelt_t *element;
1158 const cfg_listelt_t *element2;
1159 dns_fixedname_t fixed;
1160 const char *str;
1161 isc_buffer_t b;
1162
1163 /* Check for "update-policy local;" */
1164 if (cfg_obj_isstring(policy) &&
1165 strcmp("local", cfg_obj_asstring(policy)) == 0)
1166 return (ISC_R_SUCCESS);
1167
1168 /* Now check the grant policy */
1169 for (element = cfg_list_first(policy);
1170 element != NULL;
1171 element = cfg_list_next(element))
1172 {
1173 const cfg_obj_t *stmt = cfg_listelt_value(element);
1174 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
1175 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
1176 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
1177 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
1178
1179 dns_fixedname_init(&fixed);
1180 str = cfg_obj_asstring(identity);
1181 isc_buffer_constinit(&b, str, strlen(str));
1182 isc_buffer_add(&b, strlen(str));
1183 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1184 dns_rootname, 0, NULL);
1185 if (tresult != ISC_R_SUCCESS) {
1186 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1187 "'%s' is not a valid name", str);
1188 result = tresult;
1189 }
1190
1191 if (tresult == ISC_R_SUCCESS &&
1192 strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) {
1193 dns_fixedname_init(&fixed);
1194 str = cfg_obj_asstring(dname);
1195 isc_buffer_constinit(&b, str, strlen(str));
1196 isc_buffer_add(&b, strlen(str));
1197 tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
1198 &b, dns_rootname, 0, NULL);
1199 if (tresult != ISC_R_SUCCESS) {
1200 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
1201 "'%s' is not a valid name", str);
1202 result = tresult;
1203 }
1204 }
1205
1206 if (tresult == ISC_R_SUCCESS &&
1207 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
1208 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
1209 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1210 "'%s' is not a wildcard", str);
1211 result = ISC_R_FAILURE;
1212 }
1213
1214 for (element2 = cfg_list_first(typelist);
1215 element2 != NULL;
1216 element2 = cfg_list_next(element2))
1217 {
1218 const cfg_obj_t *typeobj;
1219 isc_textregion_t r;
1220 dns_rdatatype_t type;
1221
1222 typeobj = cfg_listelt_value(element2);
1223 DE_CONST(cfg_obj_asstring(typeobj), r.base);
1224 r.length = strlen(r.base);
1225
1226 tresult = dns_rdatatype_fromtext(&type, &r);
1227 if (tresult != ISC_R_SUCCESS) {
1228 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
1229 "'%s' is not a valid type", r.base);
1230 result = tresult;
1231 }
1232 }
1233 }
1234 return (result);
1235 }
1236
1237 #define MASTERZONE 1
1238 #define SLAVEZONE 2
1239 #define STUBZONE 4
1240 #define HINTZONE 8
1241 #define FORWARDZONE 16
1242 #define DELEGATIONZONE 32
1243 #define STATICSTUBZONE 64
1244 #define REDIRECTZONE 128
1245 #define STREDIRECTZONE 0 /* Set to REDIRECTZONE to allow xfr-in. */
1246 #define CHECKACL 512
1247
1248 typedef struct {
1249 const char *name;
1250 int allowed;
1251 } optionstable;
1252
1253 static isc_result_t
check_nonzero(const cfg_obj_t * options,isc_log_t * logctx)1254 check_nonzero(const cfg_obj_t *options, isc_log_t *logctx) {
1255 isc_result_t result = ISC_R_SUCCESS;
1256 const cfg_obj_t *obj = NULL;
1257 unsigned int i;
1258
1259 static const char *nonzero[] = { "max-retry-time", "min-retry-time",
1260 "max-refresh-time", "min-refresh-time" };
1261 /*
1262 * Check if value is zero.
1263 */
1264 for (i = 0; i < sizeof(nonzero) / sizeof(nonzero[0]); i++) {
1265 obj = NULL;
1266 if (cfg_map_get(options, nonzero[i], &obj) == ISC_R_SUCCESS &&
1267 cfg_obj_asuint32(obj) == 0) {
1268 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1269 "'%s' must not be zero", nonzero[i]);
1270 result = ISC_R_FAILURE;
1271 }
1272 }
1273 return (result);
1274 }
1275
1276 static isc_result_t
check_zoneconf(const cfg_obj_t * zconfig,const cfg_obj_t * voptions,const cfg_obj_t * config,isc_symtab_t * symtab,isc_symtab_t * files,dns_rdataclass_t defclass,cfg_aclconfctx_t * actx,isc_log_t * logctx,isc_mem_t * mctx)1277 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
1278 const cfg_obj_t *config, isc_symtab_t *symtab,
1279 isc_symtab_t *files, dns_rdataclass_t defclass,
1280 cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx)
1281 {
1282 const char *znamestr;
1283 const char *typestr;
1284 unsigned int ztype;
1285 const cfg_obj_t *zoptions, *goptions = NULL;
1286 const cfg_obj_t *obj = NULL;
1287 isc_result_t result = ISC_R_SUCCESS;
1288 isc_result_t tresult;
1289 unsigned int i;
1290 dns_rdataclass_t zclass;
1291 dns_fixedname_t fixedname;
1292 dns_name_t *zname = NULL;
1293 isc_buffer_t b;
1294 isc_boolean_t root = ISC_FALSE;
1295 isc_boolean_t rfc1918 = ISC_FALSE;
1296 isc_boolean_t ula = ISC_FALSE;
1297 const cfg_listelt_t *element;
1298 isc_boolean_t ddns = ISC_FALSE;
1299
1300 static optionstable options[] = {
1301 { "allow-notify", SLAVEZONE | CHECKACL },
1302 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE |
1303 CHECKACL | STATICSTUBZONE },
1304 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
1305 { "allow-update", MASTERZONE | CHECKACL },
1306 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
1307 { "also-notify", MASTERZONE | SLAVEZONE },
1308 { "auto-dnssec", MASTERZONE | SLAVEZONE },
1309 { "check-dup-records", MASTERZONE },
1310 { "check-mx", MASTERZONE },
1311 { "check-mx-cname", MASTERZONE },
1312 { "check-srv-cname", MASTERZONE },
1313 { "check-wildcard", MASTERZONE },
1314 { "database", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE },
1315 { "delegation-only", HINTZONE | STUBZONE | FORWARDZONE |
1316 DELEGATIONZONE },
1317 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE | STREDIRECTZONE },
1318 { "dnssec-dnskey-kskonly", MASTERZONE | SLAVEZONE },
1319 { "dnssec-loadkeys-interval", MASTERZONE | SLAVEZONE },
1320 { "dnssec-secure-to-insecure", MASTERZONE },
1321 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE | REDIRECTZONE },
1322 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | STATICSTUBZONE |
1323 FORWARDZONE },
1324 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | STATICSTUBZONE |
1325 FORWARDZONE },
1326 { "integrity-check", MASTERZONE },
1327 { "ixfr-base", MASTERZONE | SLAVEZONE },
1328 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
1329 { "journal", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1330 { "key-directory", MASTERZONE | SLAVEZONE },
1331 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1332 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE |
1333 REDIRECTZONE },
1334 { "masters", SLAVEZONE | STUBZONE | REDIRECTZONE },
1335 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1336 { "max-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1337 { "max-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1338 { "max-transfer-idle-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1339 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
1340 { "max-transfer-time-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1341 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
1342 { "min-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1343 { "min-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1344 { "notify", MASTERZONE | SLAVEZONE },
1345 { "notify-source", MASTERZONE | SLAVEZONE },
1346 { "notify-source-v6", MASTERZONE | SLAVEZONE },
1347 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
1348 { "request-ixfr", SLAVEZONE | REDIRECTZONE },
1349 { "server-addresses", STATICSTUBZONE },
1350 { "server-names", STATICSTUBZONE },
1351 { "sig-re-signing-interval", MASTERZONE | SLAVEZONE },
1352 { "sig-signing-nodes", MASTERZONE | SLAVEZONE },
1353 { "sig-signing-signatures", MASTERZONE | SLAVEZONE },
1354 { "sig-signing-type", MASTERZONE | SLAVEZONE },
1355 { "sig-validity-interval", MASTERZONE | SLAVEZONE },
1356 { "signing", MASTERZONE | SLAVEZONE },
1357 { "transfer-source", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1358 { "transfer-source-v6", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1359 { "try-tcp-refresh", SLAVEZONE | STREDIRECTZONE },
1360 { "update-check-ksk", MASTERZONE | SLAVEZONE },
1361 { "update-policy", MASTERZONE },
1362 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE |
1363 STATICSTUBZONE | REDIRECTZONE },
1364 };
1365
1366 static optionstable dialups[] = {
1367 { "notify", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1368 { "notify-passive", SLAVEZONE | STREDIRECTZONE },
1369 { "refresh", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1370 { "passive", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1371 };
1372
1373 znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1374
1375 zoptions = cfg_tuple_get(zconfig, "options");
1376
1377 if (config != NULL)
1378 cfg_map_get(config, "options", &goptions);
1379
1380 obj = NULL;
1381 (void)cfg_map_get(zoptions, "type", &obj);
1382 if (obj == NULL) {
1383 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1384 "zone '%s': type not present", znamestr);
1385 return (ISC_R_FAILURE);
1386 }
1387
1388 typestr = cfg_obj_asstring(obj);
1389 if (strcasecmp(typestr, "master") == 0)
1390 ztype = MASTERZONE;
1391 else if (strcasecmp(typestr, "slave") == 0)
1392 ztype = SLAVEZONE;
1393 else if (strcasecmp(typestr, "stub") == 0)
1394 ztype = STUBZONE;
1395 else if (strcasecmp(typestr, "static-stub") == 0)
1396 ztype = STATICSTUBZONE;
1397 else if (strcasecmp(typestr, "forward") == 0)
1398 ztype = FORWARDZONE;
1399 else if (strcasecmp(typestr, "hint") == 0)
1400 ztype = HINTZONE;
1401 else if (strcasecmp(typestr, "delegation-only") == 0)
1402 ztype = DELEGATIONZONE;
1403 else if (strcasecmp(typestr, "redirect") == 0)
1404 ztype = REDIRECTZONE;
1405 else {
1406 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1407 "zone '%s': invalid type %s",
1408 znamestr, typestr);
1409 return (ISC_R_FAILURE);
1410 }
1411
1412 if (ztype == REDIRECTZONE && strcmp(znamestr, ".") != 0) {
1413 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1414 "redirect zones must be called \".\"");
1415 return (ISC_R_FAILURE);
1416 }
1417 obj = cfg_tuple_get(zconfig, "class");
1418 if (cfg_obj_isstring(obj)) {
1419 isc_textregion_t r;
1420
1421 DE_CONST(cfg_obj_asstring(obj), r.base);
1422 r.length = strlen(r.base);
1423 result = dns_rdataclass_fromtext(&zclass, &r);
1424 if (result != ISC_R_SUCCESS) {
1425 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1426 "zone '%s': invalid class %s",
1427 znamestr, r.base);
1428 return (ISC_R_FAILURE);
1429 }
1430 if (zclass != defclass) {
1431 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1432 "zone '%s': class '%s' does not "
1433 "match view/default class",
1434 znamestr, r.base);
1435 return (ISC_R_FAILURE);
1436 }
1437 }
1438
1439 /*
1440 * Look for an already existing zone.
1441 * We need to make this canonical as isc_symtab_define()
1442 * deals with strings.
1443 */
1444 dns_fixedname_init(&fixedname);
1445 isc_buffer_constinit(&b, znamestr, strlen(znamestr));
1446 isc_buffer_add(&b, strlen(znamestr));
1447 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1448 dns_rootname, DNS_NAME_DOWNCASE, NULL);
1449 if (tresult != ISC_R_SUCCESS) {
1450 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1451 "zone '%s': is not a valid name", znamestr);
1452 result = ISC_R_FAILURE;
1453 } else {
1454 char namebuf[DNS_NAME_FORMATSIZE];
1455
1456 zname = dns_fixedname_name(&fixedname);
1457 dns_name_format(zname, namebuf, sizeof(namebuf));
1458 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 :
1459 ztype == REDIRECTZONE ? 2 : 3,
1460 symtab, "zone '%s': already exists "
1461 "previous definition: %s:%u", logctx, mctx);
1462 if (tresult != ISC_R_SUCCESS)
1463 result = tresult;
1464 if (dns_name_equal(zname, dns_rootname))
1465 root = ISC_TRUE;
1466 else if (dns_name_isrfc1918(zname))
1467 rfc1918 = ISC_TRUE;
1468 else if (dns_name_isula(zname))
1469 ula = ISC_TRUE;
1470 }
1471
1472 /*
1473 * Check if value is zero.
1474 */
1475 if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS)
1476 result = ISC_R_FAILURE;
1477
1478 /*
1479 * Look for inappropriate options for the given zone type.
1480 * Check that ACLs expand correctly.
1481 */
1482 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1483 obj = NULL;
1484 if ((options[i].allowed & ztype) == 0 &&
1485 cfg_map_get(zoptions, options[i].name, &obj) ==
1486 ISC_R_SUCCESS)
1487 {
1488 if (strcmp(options[i].name, "allow-update") != 0 ||
1489 ztype != SLAVEZONE) {
1490 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1491 "option '%s' is not allowed "
1492 "in '%s' zone '%s'",
1493 options[i].name, typestr,
1494 znamestr);
1495 result = ISC_R_FAILURE;
1496 } else
1497 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1498 "option '%s' is not allowed "
1499 "in '%s' zone '%s'",
1500 options[i].name, typestr,
1501 znamestr);
1502 }
1503 obj = NULL;
1504 if ((options[i].allowed & ztype) != 0 &&
1505 (options[i].allowed & CHECKACL) != 0) {
1506
1507 tresult = checkacl(options[i].name, actx, zconfig,
1508 voptions, config, logctx, mctx);
1509 if (tresult != ISC_R_SUCCESS)
1510 result = tresult;
1511 }
1512
1513 }
1514
1515 /*
1516 * Master & slave zones may have an "also-notify" field, but
1517 * shouldn't if notify is disabled.
1518 */
1519 if (ztype == MASTERZONE || ztype == SLAVEZONE ) {
1520 isc_boolean_t donotify = ISC_TRUE;
1521
1522 obj = NULL;
1523 tresult = cfg_map_get(zoptions, "notify", &obj);
1524 if (tresult != ISC_R_SUCCESS && voptions != NULL)
1525 tresult = cfg_map_get(voptions, "notify", &obj);
1526 if (tresult != ISC_R_SUCCESS && goptions != NULL)
1527 tresult = cfg_map_get(goptions, "notify", &obj);
1528 if (tresult == ISC_R_SUCCESS) {
1529 if (cfg_obj_isboolean(obj))
1530 donotify = cfg_obj_asboolean(obj);
1531 else {
1532 const char *notifystr = cfg_obj_asstring(obj);
1533 if (ztype != MASTERZONE &&
1534 strcasecmp(notifystr, "master-only") == 0)
1535 donotify = ISC_FALSE;
1536 }
1537 }
1538
1539 obj = NULL;
1540 tresult = cfg_map_get(zoptions, "also-notify", &obj);
1541 if (tresult == ISC_R_SUCCESS && !donotify) {
1542 cfg_obj_log(zoptions, logctx, ISC_LOG_WARNING,
1543 "zone '%s': 'also-notify' set but "
1544 "'notify' is disabled", znamestr);
1545 } else if (tresult == ISC_R_SUCCESS) {
1546 isc_uint32_t count;
1547 tresult = validate_masters(obj, config, &count,
1548 logctx, mctx);
1549 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1550 result = tresult;
1551 }
1552 }
1553
1554 /*
1555 * Slave & stub zones must have a "masters" field.
1556 */
1557 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1558 obj = NULL;
1559 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1560 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1561 "zone '%s': missing 'masters' entry",
1562 znamestr);
1563 result = ISC_R_FAILURE;
1564 } else {
1565 isc_uint32_t count;
1566 tresult = validate_masters(obj, config, &count,
1567 logctx, mctx);
1568 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1569 result = tresult;
1570 if (tresult == ISC_R_SUCCESS && count == 0) {
1571 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1572 "zone '%s': empty 'masters' entry",
1573 znamestr);
1574 result = ISC_R_FAILURE;
1575 }
1576 }
1577 }
1578
1579 /*
1580 * Master zones can't have both "allow-update" and "update-policy".
1581 */
1582 if (ztype == MASTERZONE || ztype == SLAVEZONE) {
1583 isc_boolean_t signing = ISC_FALSE;
1584 isc_result_t res1, res2, res3;
1585 const cfg_obj_t *au = NULL;
1586 const char *arg;
1587
1588 obj = NULL;
1589 res1 = cfg_map_get(zoptions, "allow-update", &au);
1590 obj = NULL;
1591 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1592 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1593 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1594 "zone '%s': 'allow-update' is ignored "
1595 "when 'update-policy' is present",
1596 znamestr);
1597 result = ISC_R_FAILURE;
1598 } else if (res2 == ISC_R_SUCCESS) {
1599 res3 = check_update_policy(obj, logctx);
1600 if (res3 != ISC_R_SUCCESS)
1601 result = ISC_R_FAILURE;
1602 }
1603
1604 /*
1605 * To determine whether auto-dnssec is allowed,
1606 * we should also check for allow-update at the
1607 * view and options levels.
1608 */
1609 if (res1 != ISC_R_SUCCESS && voptions != NULL)
1610 res1 = cfg_map_get(voptions, "allow-update", &au);
1611 if (res1 != ISC_R_SUCCESS && goptions != NULL)
1612 res1 = cfg_map_get(goptions, "allow-update", &au);
1613
1614 if (res2 == ISC_R_SUCCESS)
1615 ddns = ISC_TRUE;
1616 else if (res1 == ISC_R_SUCCESS) {
1617 dns_acl_t *acl = NULL;
1618 res1 = cfg_acl_fromconfig(au, config, logctx,
1619 actx, mctx, 0, &acl);
1620 if (res1 != ISC_R_SUCCESS) {
1621 cfg_obj_log(au, logctx, ISC_LOG_ERROR,
1622 "acl expansion failed: %s",
1623 isc_result_totext(result));
1624 result = ISC_R_FAILURE;
1625 } else if (acl != NULL) {
1626 if (!dns_acl_isnone(acl))
1627 ddns = ISC_TRUE;
1628 dns_acl_detach(&acl);
1629 }
1630 }
1631
1632 obj = NULL;
1633 res1 = cfg_map_get(zoptions, "inline-signing", &obj);
1634 if (res1 == ISC_R_SUCCESS)
1635 signing = cfg_obj_asboolean(obj);
1636
1637 obj = NULL;
1638 arg = "off";
1639 res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
1640 if (res3 == ISC_R_SUCCESS)
1641 arg = cfg_obj_asstring(obj);
1642 if (strcasecmp(arg, "off") != 0 && !ddns && !signing) {
1643 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1644 "'auto-dnssec %s;' requires%s "
1645 "inline-signing to be configured for "
1646 "the zone", arg,
1647 (ztype == MASTERZONE) ?
1648 " dynamic DNS or" : "");
1649 result = ISC_R_FAILURE;
1650 }
1651
1652 obj = NULL;
1653 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
1654 if (res1 == ISC_R_SUCCESS) {
1655 isc_uint32_t type = cfg_obj_asuint32(obj);
1656 if (type < 0xff00U || type > 0xffffU)
1657 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1658 "sig-signing-type: %u out of "
1659 "range [%u..%u]", type,
1660 0xff00U, 0xffffU);
1661 result = ISC_R_FAILURE;
1662 }
1663
1664 obj = NULL;
1665 res1 = cfg_map_get(zoptions, "dnssec-dnskey-kskonly", &obj);
1666 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
1667 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1668 "dnssec-dnskey-kskonly: requires "
1669 "inline-signing when used in slave zone");
1670 result = ISC_R_FAILURE;
1671 }
1672
1673 obj = NULL;
1674 res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj);
1675 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
1676 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1677 "dnssec-loadkeys-interval: requires "
1678 "inline-signing when used in slave zone");
1679 result = ISC_R_FAILURE;
1680 }
1681
1682 obj = NULL;
1683 res1 = cfg_map_get(zoptions, "update-check-ksk", &obj);
1684 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
1685 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1686 "update-check-ksk: requires "
1687 "inline-signing when used in slave zone");
1688 result = ISC_R_FAILURE;
1689 }
1690 }
1691
1692 /*
1693 * Check the excessively complicated "dialup" option.
1694 */
1695 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1696 const cfg_obj_t *dialup = NULL;
1697 (void)cfg_map_get(zoptions, "dialup", &dialup);
1698 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1699 const char *str = cfg_obj_asstring(dialup);
1700 for (i = 0;
1701 i < sizeof(dialups) / sizeof(dialups[0]);
1702 i++)
1703 {
1704 if (strcasecmp(dialups[i].name, str) != 0)
1705 continue;
1706 if ((dialups[i].allowed & ztype) == 0) {
1707 cfg_obj_log(obj, logctx,
1708 ISC_LOG_ERROR,
1709 "dialup type '%s' is not "
1710 "allowed in '%s' "
1711 "zone '%s'",
1712 str, typestr, znamestr);
1713 result = ISC_R_FAILURE;
1714 }
1715 break;
1716 }
1717 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1718 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1719 "invalid dialup type '%s' in zone "
1720 "'%s'", str, znamestr);
1721 result = ISC_R_FAILURE;
1722 }
1723 }
1724 }
1725
1726 /*
1727 * Check that forwarding is reasonable.
1728 */
1729 obj = NULL;
1730 if (root) {
1731 if (voptions != NULL)
1732 (void)cfg_map_get(voptions, "forwarders", &obj);
1733 if (obj == NULL && goptions != NULL)
1734 (void)cfg_map_get(goptions, "forwarders", &obj);
1735 }
1736 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
1737 result = ISC_R_FAILURE;
1738
1739 /*
1740 * Check that a RFC 1918 / ULA reverse zone is not forward first
1741 * unless explictly configured to be so.
1742 */
1743 if (ztype == FORWARDZONE && (rfc1918 || ula)) {
1744 obj = NULL;
1745 (void)cfg_map_get(zoptions, "forward", &obj);
1746 if (obj == NULL) {
1747 /*
1748 * Forward mode not explicity configured.
1749 */
1750 if (voptions != NULL)
1751 cfg_map_get(voptions, "forward", &obj);
1752 if (obj == NULL && goptions != NULL)
1753 cfg_map_get(goptions, "forward", &obj);
1754 if (obj == NULL ||
1755 strcasecmp(cfg_obj_asstring(obj), "first") == 0)
1756 cfg_obj_log(zconfig, logctx, ISC_LOG_WARNING,
1757 "inherited 'forward first;' for "
1758 "%s zone '%s' - did you want "
1759 "'forward only;'?",
1760 rfc1918 ? "rfc1918" : "ula",
1761 znamestr);
1762 }
1763 }
1764
1765 /*
1766 * Check validity of static stub server addresses.
1767 */
1768 obj = NULL;
1769 (void)cfg_map_get(zoptions, "server-addresses", &obj);
1770 if (ztype == STATICSTUBZONE && obj != NULL) {
1771 for (element = cfg_list_first(obj);
1772 element != NULL;
1773 element = cfg_list_next(element))
1774 {
1775 isc_sockaddr_t sa;
1776 isc_netaddr_t na;
1777 obj = cfg_listelt_value(element);
1778 sa = *cfg_obj_assockaddr(obj);
1779
1780 if (isc_sockaddr_getport(&sa) != 0) {
1781 result = ISC_R_FAILURE;
1782 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1783 "port is not configurable for "
1784 "static stub server-addresses");
1785 }
1786
1787 isc_netaddr_fromsockaddr(&na, &sa);
1788 if (isc_netaddr_getzone(&na) != 0) {
1789 result = ISC_R_FAILURE;
1790 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1791 "scoped address is not allowed "
1792 "for static stub "
1793 "server-addresses");
1794 }
1795 }
1796 }
1797
1798 /*
1799 * Check validity of static stub server names.
1800 */
1801 obj = NULL;
1802 (void)cfg_map_get(zoptions, "server-names", &obj);
1803 if (zname != NULL && ztype == STATICSTUBZONE && obj != NULL) {
1804 for (element = cfg_list_first(obj);
1805 element != NULL;
1806 element = cfg_list_next(element))
1807 {
1808 const char *snamestr;
1809 dns_fixedname_t fixed_sname;
1810 isc_buffer_t b2;
1811 dns_name_t *sname;
1812
1813 obj = cfg_listelt_value(element);
1814 snamestr = cfg_obj_asstring(obj);
1815
1816 dns_fixedname_init(&fixed_sname);
1817 isc_buffer_constinit(&b2, snamestr, strlen(snamestr));
1818 isc_buffer_add(&b2, strlen(snamestr));
1819 sname = dns_fixedname_name(&fixed_sname);
1820 tresult = dns_name_fromtext(sname, &b2, dns_rootname,
1821 0, NULL);
1822 if (tresult != ISC_R_SUCCESS) {
1823 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1824 "server-name '%s' is not a valid "
1825 "name", snamestr);
1826 result = ISC_R_FAILURE;
1827 } else if (dns_name_issubdomain(sname, zname)) {
1828 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1829 "server-name '%s' must not be a "
1830 "subdomain of zone name '%s'",
1831 snamestr, znamestr);
1832 result = ISC_R_FAILURE;
1833 }
1834 }
1835 }
1836
1837 /*
1838 * Warn if key-directory doesn't exist
1839 */
1840 obj = NULL;
1841 tresult = cfg_map_get(zoptions, "key-directory", &obj);
1842 if (tresult == ISC_R_SUCCESS) {
1843 const char *dir = cfg_obj_asstring(obj);
1844 tresult = isc_file_isdirectory(dir);
1845 switch (tresult) {
1846 case ISC_R_SUCCESS:
1847 break;
1848 case ISC_R_FILENOTFOUND:
1849 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1850 "key-directory: '%s' does not exist",
1851 dir);
1852 break;
1853 case ISC_R_INVALIDFILE:
1854 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1855 "key-directory: '%s' is not a directory",
1856 dir);
1857 break;
1858 default:
1859 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1860 "key-directory: '%s' %s",
1861 dir, isc_result_totext(tresult));
1862 result = tresult;
1863 }
1864 }
1865
1866 /*
1867 * Check various options.
1868 */
1869 tresult = check_options(zoptions, logctx, mctx, optlevel_zone);
1870 if (tresult != ISC_R_SUCCESS)
1871 result = tresult;
1872
1873 /*
1874 * If the zone type is rbt/rbt64 then master/hint zones
1875 * require file clauses.
1876 * If inline signing is used, then slave zones require a
1877 * file clause as well
1878 */
1879 obj = NULL;
1880 tresult = cfg_map_get(zoptions, "database", &obj);
1881 if (tresult == ISC_R_NOTFOUND ||
1882 (tresult == ISC_R_SUCCESS &&
1883 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1884 strcmp("rbt64", cfg_obj_asstring(obj)) == 0)))
1885 {
1886 isc_result_t res1;
1887 const cfg_obj_t *fileobj = NULL;
1888 tresult = cfg_map_get(zoptions, "file", &fileobj);
1889 obj = NULL;
1890 res1 = cfg_map_get(zoptions, "inline-signing", &obj);
1891 if ((tresult != ISC_R_SUCCESS &&
1892 (ztype == MASTERZONE || ztype == HINTZONE ||
1893 (ztype == SLAVEZONE && res1 == ISC_R_SUCCESS &&
1894 cfg_obj_asboolean(obj))))) {
1895 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1896 "zone '%s': missing 'file' entry",
1897 znamestr);
1898 result = tresult;
1899 } else if (tresult == ISC_R_SUCCESS &&
1900 (ztype == SLAVEZONE || ddns)) {
1901 tresult = fileexist(fileobj, files, ISC_TRUE, logctx);
1902 if (tresult != ISC_R_SUCCESS)
1903 result = tresult;
1904 } else if (tresult == ISC_R_SUCCESS &&
1905 (ztype == MASTERZONE || ztype == HINTZONE)) {
1906 tresult = fileexist(fileobj, files, ISC_FALSE, logctx);
1907 if (tresult != ISC_R_SUCCESS)
1908 result = tresult;
1909 }
1910 }
1911
1912 return (result);
1913 }
1914
1915
1916 typedef struct keyalgorithms {
1917 const char *name;
1918 isc_uint16_t size;
1919 } algorithmtable;
1920
1921 isc_result_t
bind9_check_key(const cfg_obj_t * key,isc_log_t * logctx)1922 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1923 const cfg_obj_t *algobj = NULL;
1924 const cfg_obj_t *secretobj = NULL;
1925 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1926 const char *algorithm;
1927 int i;
1928 size_t len = 0;
1929 isc_result_t result;
1930 isc_buffer_t buf;
1931 unsigned char secretbuf[1024];
1932 static const algorithmtable algorithms[] = {
1933 { "hmac-md5", 128 },
1934 { "hmac-md5.sig-alg.reg.int", 0 },
1935 { "hmac-md5.sig-alg.reg.int.", 0 },
1936 { "hmac-sha1", 160 },
1937 { "hmac-sha224", 224 },
1938 { "hmac-sha256", 256 },
1939 { "hmac-sha384", 384 },
1940 { "hmac-sha512", 512 },
1941 { NULL, 0 }
1942 };
1943
1944 (void)cfg_map_get(key, "algorithm", &algobj);
1945 (void)cfg_map_get(key, "secret", &secretobj);
1946 if (secretobj == NULL || algobj == NULL) {
1947 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1948 "key '%s' must have both 'secret' and "
1949 "'algorithm' defined",
1950 keyname);
1951 return (ISC_R_FAILURE);
1952 }
1953
1954 isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
1955 result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
1956 if (result != ISC_R_SUCCESS) {
1957 cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
1958 "bad secret '%s'", isc_result_totext(result));
1959 return (result);
1960 }
1961
1962 algorithm = cfg_obj_asstring(algobj);
1963 for (i = 0; algorithms[i].name != NULL; i++) {
1964 len = strlen(algorithms[i].name);
1965 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1966 (algorithm[len] == '\0' ||
1967 (algorithms[i].size != 0 && algorithm[len] == '-')))
1968 break;
1969 }
1970 if (algorithms[i].name == NULL) {
1971 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1972 "unknown algorithm '%s'", algorithm);
1973 return (ISC_R_NOTFOUND);
1974 }
1975 if (algorithm[len] == '-') {
1976 isc_uint16_t digestbits;
1977 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1978 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1979 if (result == ISC_R_RANGE ||
1980 digestbits > algorithms[i].size) {
1981 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1982 "key '%s' digest-bits too large "
1983 "[%u..%u]", keyname,
1984 algorithms[i].size / 2,
1985 algorithms[i].size);
1986 return (ISC_R_RANGE);
1987 }
1988 if ((digestbits % 8) != 0) {
1989 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1990 "key '%s' digest-bits not multiple"
1991 " of 8", keyname);
1992 return (ISC_R_RANGE);
1993 }
1994 /*
1995 * Recommended minima for hmac algorithms.
1996 */
1997 if ((digestbits < (algorithms[i].size / 2U) ||
1998 (digestbits < 80U)))
1999 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
2000 "key '%s' digest-bits too small "
2001 "[<%u]", keyname,
2002 algorithms[i].size/2);
2003 } else {
2004 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
2005 "key '%s': unable to parse digest-bits",
2006 keyname);
2007 return (result);
2008 }
2009 }
2010 return (ISC_R_SUCCESS);
2011 }
2012
2013 static isc_result_t
fileexist(const cfg_obj_t * obj,isc_symtab_t * symtab,isc_boolean_t writeable,isc_log_t * logctx)2014 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, isc_boolean_t writeable,
2015 isc_log_t *logctx)
2016 {
2017 isc_result_t result;
2018 isc_symvalue_t symvalue;
2019 unsigned int line;
2020 const char *file;
2021
2022 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 0, &symvalue);
2023 if (result == ISC_R_SUCCESS) {
2024 if (writeable) {
2025 file = cfg_obj_file(symvalue.as_cpointer);
2026 line = cfg_obj_line(symvalue.as_cpointer);
2027 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2028 "writeable file '%s': already in use: "
2029 "%s:%u", cfg_obj_asstring(obj),
2030 file, line);
2031 return (ISC_R_EXISTS);
2032 }
2033 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 2,
2034 &symvalue);
2035 if (result == ISC_R_SUCCESS) {
2036 file = cfg_obj_file(symvalue.as_cpointer);
2037 line = cfg_obj_line(symvalue.as_cpointer);
2038 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2039 "writeable file '%s': already in use: "
2040 "%s:%u", cfg_obj_asstring(obj),
2041 file, line);
2042 return (ISC_R_EXISTS);
2043 }
2044 return (ISC_R_SUCCESS);
2045 }
2046
2047 symvalue.as_cpointer = obj;
2048 result = isc_symtab_define(symtab, cfg_obj_asstring(obj),
2049 writeable ? 2 : 1, symvalue,
2050 isc_symexists_reject);
2051 return (result);
2052 }
2053
2054 /*
2055 * Check key list for duplicates key names and that the key names
2056 * are valid domain names as these keys are used for TSIG.
2057 *
2058 * Check the key contents for validity.
2059 */
2060 static isc_result_t
check_keylist(const cfg_obj_t * keys,isc_symtab_t * symtab,isc_mem_t * mctx,isc_log_t * logctx)2061 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
2062 isc_mem_t *mctx, isc_log_t *logctx)
2063 {
2064 char namebuf[DNS_NAME_FORMATSIZE];
2065 dns_fixedname_t fname;
2066 dns_name_t *name;
2067 isc_result_t result = ISC_R_SUCCESS;
2068 isc_result_t tresult;
2069 const cfg_listelt_t *element;
2070
2071 dns_fixedname_init(&fname);
2072 name = dns_fixedname_name(&fname);
2073 for (element = cfg_list_first(keys);
2074 element != NULL;
2075 element = cfg_list_next(element))
2076 {
2077 const cfg_obj_t *key = cfg_listelt_value(element);
2078 const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
2079 isc_symvalue_t symvalue;
2080 isc_buffer_t b;
2081 char *keyname;
2082
2083 isc_buffer_constinit(&b, keyid, strlen(keyid));
2084 isc_buffer_add(&b, strlen(keyid));
2085 tresult = dns_name_fromtext(name, &b, dns_rootname,
2086 0, NULL);
2087 if (tresult != ISC_R_SUCCESS) {
2088 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2089 "key '%s': bad key name", keyid);
2090 result = tresult;
2091 continue;
2092 }
2093 tresult = bind9_check_key(key, logctx);
2094 if (tresult != ISC_R_SUCCESS)
2095 return (tresult);
2096
2097 dns_name_format(name, namebuf, sizeof(namebuf));
2098 keyname = isc_mem_strdup(mctx, namebuf);
2099 if (keyname == NULL)
2100 return (ISC_R_NOMEMORY);
2101 symvalue.as_cpointer = key;
2102 tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
2103 isc_symexists_reject);
2104 if (tresult == ISC_R_EXISTS) {
2105 const char *file;
2106 unsigned int line;
2107
2108 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
2109 1, &symvalue) == ISC_R_SUCCESS);
2110 file = cfg_obj_file(symvalue.as_cpointer);
2111 line = cfg_obj_line(symvalue.as_cpointer);
2112
2113 if (file == NULL)
2114 file = "<unknown file>";
2115 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2116 "key '%s': already exists "
2117 "previous definition: %s:%u",
2118 keyid, file, line);
2119 isc_mem_free(mctx, keyname);
2120 result = tresult;
2121 } else if (tresult != ISC_R_SUCCESS) {
2122 isc_mem_free(mctx, keyname);
2123 return (tresult);
2124 }
2125 }
2126 return (result);
2127 }
2128
2129 static struct {
2130 const char *v4;
2131 const char *v6;
2132 } sources[] = {
2133 { "transfer-source", "transfer-source-v6" },
2134 { "notify-source", "notify-source-v6" },
2135 { "query-source", "query-source-v6" },
2136 { NULL, NULL }
2137 };
2138
2139 /*
2140 * RNDC keys are not normalised unlike TSIG keys.
2141 *
2142 * "foo." is different to "foo".
2143 */
2144 static isc_boolean_t
rndckey_exists(const cfg_obj_t * keylist,const char * keyname)2145 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
2146 const cfg_listelt_t *element;
2147 const cfg_obj_t *obj;
2148 const char *str;
2149
2150 if (keylist == NULL)
2151 return (ISC_FALSE);
2152
2153 for (element = cfg_list_first(keylist);
2154 element != NULL;
2155 element = cfg_list_next(element))
2156 {
2157 obj = cfg_listelt_value(element);
2158 str = cfg_obj_asstring(cfg_map_getname(obj));
2159 if (!strcasecmp(str, keyname))
2160 return (ISC_TRUE);
2161 }
2162 return (ISC_FALSE);
2163 }
2164
2165 static isc_result_t
check_servers(const cfg_obj_t * config,const cfg_obj_t * voptions,isc_symtab_t * symtab,isc_log_t * logctx)2166 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
2167 isc_symtab_t *symtab, isc_log_t *logctx)
2168 {
2169 dns_fixedname_t fname;
2170 isc_result_t result = ISC_R_SUCCESS;
2171 isc_result_t tresult;
2172 const cfg_listelt_t *e1, *e2;
2173 const cfg_obj_t *v1, *v2, *keys;
2174 const cfg_obj_t *servers;
2175 isc_netaddr_t n1, n2;
2176 unsigned int p1, p2;
2177 const cfg_obj_t *obj;
2178 char buf[ISC_NETADDR_FORMATSIZE];
2179 char namebuf[DNS_NAME_FORMATSIZE];
2180 const char *xfr;
2181 const char *keyval;
2182 isc_buffer_t b;
2183 int source;
2184 dns_name_t *keyname;
2185
2186 servers = NULL;
2187 if (voptions != NULL)
2188 (void)cfg_map_get(voptions, "server", &servers);
2189 if (servers == NULL)
2190 (void)cfg_map_get(config, "server", &servers);
2191 if (servers == NULL)
2192 return (ISC_R_SUCCESS);
2193
2194 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
2195 v1 = cfg_listelt_value(e1);
2196 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
2197 /*
2198 * Check that unused bits are zero.
2199 */
2200 tresult = isc_netaddr_prefixok(&n1, p1);
2201 if (tresult != ISC_R_SUCCESS) {
2202 INSIST(tresult == ISC_R_FAILURE);
2203 isc_netaddr_format(&n1, buf, sizeof(buf));
2204 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
2205 "server '%s/%u': invalid prefix "
2206 "(extra bits specified)", buf, p1);
2207 result = tresult;
2208 }
2209 source = 0;
2210 do {
2211 obj = NULL;
2212 if (n1.family == AF_INET)
2213 xfr = sources[source].v6;
2214 else
2215 xfr = sources[source].v4;
2216 (void)cfg_map_get(v1, xfr, &obj);
2217 if (obj != NULL) {
2218 isc_netaddr_format(&n1, buf, sizeof(buf));
2219 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
2220 "server '%s/%u': %s not legal",
2221 buf, p1, xfr);
2222 result = ISC_R_FAILURE;
2223 }
2224 } while (sources[++source].v4 != NULL);
2225 e2 = e1;
2226 while ((e2 = cfg_list_next(e2)) != NULL) {
2227 v2 = cfg_listelt_value(e2);
2228 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
2229 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
2230 const char *file = cfg_obj_file(v1);
2231 unsigned int line = cfg_obj_line(v1);
2232
2233 if (file == NULL)
2234 file = "<unknown file>";
2235
2236 isc_netaddr_format(&n2, buf, sizeof(buf));
2237 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
2238 "server '%s/%u': already exists "
2239 "previous definition: %s:%u",
2240 buf, p2, file, line);
2241 result = ISC_R_FAILURE;
2242 }
2243 }
2244 keys = NULL;
2245 cfg_map_get(v1, "keys", &keys);
2246 if (keys != NULL) {
2247 /*
2248 * Normalize key name.
2249 */
2250 keyval = cfg_obj_asstring(keys);
2251 dns_fixedname_init(&fname);
2252 isc_buffer_constinit(&b, keyval, strlen(keyval));
2253 isc_buffer_add(&b, strlen(keyval));
2254 keyname = dns_fixedname_name(&fname);
2255 tresult = dns_name_fromtext(keyname, &b, dns_rootname,
2256 0, NULL);
2257 if (tresult != ISC_R_SUCCESS) {
2258 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
2259 "bad key name '%s'", keyval);
2260 result = ISC_R_FAILURE;
2261 continue;
2262 }
2263 dns_name_format(keyname, namebuf, sizeof(namebuf));
2264 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
2265 if (tresult != ISC_R_SUCCESS) {
2266 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
2267 "unknown key '%s'", keyval);
2268 result = ISC_R_FAILURE;
2269 }
2270 }
2271 }
2272 return (result);
2273 }
2274
2275 static isc_result_t
check_trusted_key(const cfg_obj_t * key,isc_boolean_t managed,isc_log_t * logctx)2276 check_trusted_key(const cfg_obj_t *key, isc_boolean_t managed,
2277 isc_log_t *logctx)
2278 {
2279 const char *keystr, *keynamestr;
2280 dns_fixedname_t fkeyname;
2281 dns_name_t *keyname;
2282 isc_buffer_t b;
2283 isc_region_t r;
2284 isc_result_t result = ISC_R_SUCCESS;
2285 isc_result_t tresult;
2286 isc_uint32_t flags, proto, alg;
2287 unsigned char keydata[4096];
2288
2289 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
2290 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
2291 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
2292
2293 dns_fixedname_init(&fkeyname);
2294 keyname = dns_fixedname_name(&fkeyname);
2295 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
2296
2297 isc_buffer_constinit(&b, keynamestr, strlen(keynamestr));
2298 isc_buffer_add(&b, strlen(keynamestr));
2299 result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
2300 if (result != ISC_R_SUCCESS) {
2301 cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n",
2302 isc_result_totext(result));
2303 result = ISC_R_FAILURE;
2304 }
2305
2306 if (flags > 0xffff) {
2307 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2308 "flags too big: %u\n", flags);
2309 result = ISC_R_FAILURE;
2310 }
2311 if (proto > 0xff) {
2312 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2313 "protocol too big: %u\n", proto);
2314 result = ISC_R_FAILURE;
2315 }
2316 if (alg > 0xff) {
2317 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2318 "algorithm too big: %u\n", alg);
2319 result = ISC_R_FAILURE;
2320 }
2321
2322 if (managed) {
2323 const char *initmethod;
2324 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
2325
2326 if (strcasecmp(initmethod, "initial-key") != 0) {
2327 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2328 "managed key '%s': "
2329 "invalid initialization method '%s'",
2330 keynamestr, initmethod);
2331 result = ISC_R_FAILURE;
2332 }
2333 }
2334
2335 isc_buffer_init(&b, keydata, sizeof(keydata));
2336
2337 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
2338 tresult = isc_base64_decodestring(keystr, &b);
2339
2340 if (tresult != ISC_R_SUCCESS) {
2341 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2342 "%s", isc_result_totext(tresult));
2343 result = ISC_R_FAILURE;
2344 } else {
2345 isc_buffer_usedregion(&b, &r);
2346
2347 if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
2348 r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
2349 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2350 "%s key '%s' has a weak exponent",
2351 managed ? "managed" : "trusted",
2352 keynamestr);
2353 }
2354
2355 return (result);
2356 }
2357
2358 static isc_result_t
check_viewconf(const cfg_obj_t * config,const cfg_obj_t * voptions,const char * viewname,dns_rdataclass_t vclass,isc_symtab_t * files,isc_log_t * logctx,isc_mem_t * mctx)2359 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
2360 const char *viewname, dns_rdataclass_t vclass,
2361 isc_symtab_t *files, isc_log_t *logctx, isc_mem_t *mctx)
2362 {
2363 const cfg_obj_t *zones = NULL;
2364 const cfg_obj_t *keys = NULL;
2365 const cfg_listelt_t *element, *element2;
2366 isc_symtab_t *symtab = NULL;
2367 isc_result_t result = ISC_R_SUCCESS;
2368 isc_result_t tresult = ISC_R_SUCCESS;
2369 cfg_aclconfctx_t *actx = NULL;
2370 const cfg_obj_t *obj;
2371 const cfg_obj_t *options = NULL;
2372 isc_boolean_t enablednssec, enablevalidation;
2373 const char *valstr = "no";
2374
2375 /*
2376 * Get global options block
2377 */
2378 (void)cfg_map_get(config, "options", &options);
2379
2380 /*
2381 * Check that all zone statements are syntactically correct and
2382 * there are no duplicate zones.
2383 */
2384 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
2385 ISC_FALSE, &symtab);
2386 if (tresult != ISC_R_SUCCESS)
2387 return (ISC_R_NOMEMORY);
2388
2389 cfg_aclconfctx_create(mctx, &actx);
2390
2391 if (voptions != NULL)
2392 (void)cfg_map_get(voptions, "zone", &zones);
2393 else
2394 (void)cfg_map_get(config, "zone", &zones);
2395
2396 for (element = cfg_list_first(zones);
2397 element != NULL;
2398 element = cfg_list_next(element))
2399 {
2400 const cfg_obj_t *zone = cfg_listelt_value(element);
2401
2402 tresult = check_zoneconf(zone, voptions, config, symtab,
2403 files, vclass, actx, logctx,
2404 mctx);
2405 if (tresult != ISC_R_SUCCESS)
2406 result = ISC_R_FAILURE;
2407 }
2408
2409 isc_symtab_destroy(&symtab);
2410
2411 /*
2412 * Check that forwarding is reasonable.
2413 */
2414 if (voptions == NULL) {
2415 if (options != NULL)
2416 if (check_forward(options, NULL,
2417 logctx) != ISC_R_SUCCESS)
2418 result = ISC_R_FAILURE;
2419 } else {
2420 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
2421 result = ISC_R_FAILURE;
2422 }
2423
2424 /*
2425 * Check non-zero options at the global and view levels.
2426 */
2427 if (options != NULL && check_nonzero(options, logctx) != ISC_R_SUCCESS)
2428 result = ISC_R_FAILURE;
2429 if (voptions != NULL &&check_nonzero(voptions, logctx) != ISC_R_SUCCESS)
2430 result = ISC_R_FAILURE;
2431
2432 /*
2433 * Check that dual-stack-servers is reasonable.
2434 */
2435 if (voptions == NULL) {
2436 if (options != NULL)
2437 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2438 result = ISC_R_FAILURE;
2439 } else {
2440 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
2441 result = ISC_R_FAILURE;
2442 }
2443
2444 /*
2445 * Check that rrset-order is reasonable.
2446 */
2447 if (voptions != NULL) {
2448 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
2449 result = ISC_R_FAILURE;
2450 }
2451
2452 /*
2453 * Check that all key statements are syntactically correct and
2454 * there are no duplicate keys.
2455 */
2456 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
2457 ISC_FALSE, &symtab);
2458 if (tresult != ISC_R_SUCCESS)
2459 goto cleanup;
2460
2461 (void)cfg_map_get(config, "key", &keys);
2462 tresult = check_keylist(keys, symtab, mctx, logctx);
2463 if (tresult == ISC_R_EXISTS)
2464 result = ISC_R_FAILURE;
2465 else if (tresult != ISC_R_SUCCESS) {
2466 result = tresult;
2467 goto cleanup;
2468 }
2469
2470 if (voptions != NULL) {
2471 keys = NULL;
2472 (void)cfg_map_get(voptions, "key", &keys);
2473 tresult = check_keylist(keys, symtab, mctx, logctx);
2474 if (tresult == ISC_R_EXISTS)
2475 result = ISC_R_FAILURE;
2476 else if (tresult != ISC_R_SUCCESS) {
2477 result = tresult;
2478 goto cleanup;
2479 }
2480 }
2481
2482 /*
2483 * Global servers can refer to keys in views.
2484 */
2485 if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
2486 result = ISC_R_FAILURE;
2487
2488 isc_symtab_destroy(&symtab);
2489
2490 /*
2491 * Check that dnssec-enable/dnssec-validation are sensible.
2492 */
2493 obj = NULL;
2494 if (voptions != NULL)
2495 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
2496 if (obj == NULL && options != NULL)
2497 (void)cfg_map_get(options, "dnssec-enable", &obj);
2498 if (obj == NULL)
2499 enablednssec = ISC_TRUE;
2500 else
2501 enablednssec = cfg_obj_asboolean(obj);
2502
2503 obj = NULL;
2504 if (voptions != NULL)
2505 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
2506 if (obj == NULL && options != NULL)
2507 (void)cfg_map_get(options, "dnssec-validation", &obj);
2508 if (obj == NULL) {
2509 enablevalidation = enablednssec;
2510 valstr = "yes";
2511 } else if (cfg_obj_isboolean(obj)) {
2512 enablevalidation = cfg_obj_asboolean(obj);
2513 valstr = enablevalidation ? "yes" : "no";
2514 } else {
2515 enablevalidation = ISC_TRUE;
2516 valstr = "auto";
2517 }
2518
2519 if (enablevalidation && !enablednssec)
2520 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2521 "'dnssec-validation %s;' and 'dnssec-enable no;'",
2522 valstr);
2523
2524 /*
2525 * Check trusted-keys and managed-keys.
2526 */
2527 keys = NULL;
2528 if (voptions != NULL)
2529 (void)cfg_map_get(voptions, "trusted-keys", &keys);
2530 if (keys == NULL)
2531 (void)cfg_map_get(config, "trusted-keys", &keys);
2532
2533 for (element = cfg_list_first(keys);
2534 element != NULL;
2535 element = cfg_list_next(element))
2536 {
2537 const cfg_obj_t *keylist = cfg_listelt_value(element);
2538 for (element2 = cfg_list_first(keylist);
2539 element2 != NULL;
2540 element2 = cfg_list_next(element2)) {
2541 obj = cfg_listelt_value(element2);
2542 tresult = check_trusted_key(obj, ISC_FALSE, logctx);
2543 if (tresult != ISC_R_SUCCESS)
2544 result = tresult;
2545 }
2546 }
2547
2548 keys = NULL;
2549 if (voptions != NULL)
2550 (void)cfg_map_get(voptions, "managed-keys", &keys);
2551 if (keys == NULL)
2552 (void)cfg_map_get(config, "managed-keys", &keys);
2553
2554 for (element = cfg_list_first(keys);
2555 element != NULL;
2556 element = cfg_list_next(element))
2557 {
2558 const cfg_obj_t *keylist = cfg_listelt_value(element);
2559 for (element2 = cfg_list_first(keylist);
2560 element2 != NULL;
2561 element2 = cfg_list_next(element2)) {
2562 obj = cfg_listelt_value(element2);
2563 tresult = check_trusted_key(obj, ISC_TRUE, logctx);
2564 if (tresult != ISC_R_SUCCESS)
2565 result = tresult;
2566 }
2567 }
2568
2569 /*
2570 * Check options.
2571 */
2572 if (voptions != NULL)
2573 tresult = check_options(voptions, logctx, mctx,
2574 optlevel_view);
2575 else
2576 tresult = check_options(config, logctx, mctx,
2577 optlevel_config);
2578 if (tresult != ISC_R_SUCCESS)
2579 result = tresult;
2580
2581 tresult = check_viewacls(actx, voptions, config, logctx, mctx);
2582 if (tresult != ISC_R_SUCCESS)
2583 result = tresult;
2584
2585 tresult = check_recursionacls(actx, voptions, viewname,
2586 config, logctx, mctx);
2587 if (tresult != ISC_R_SUCCESS)
2588 result = tresult;
2589
2590 tresult = check_filteraaaa(actx, voptions, viewname, config,
2591 logctx, mctx);
2592 if (tresult != ISC_R_SUCCESS)
2593 result = tresult;
2594
2595 tresult = check_dns64(actx, voptions, config, logctx, mctx);
2596 if (tresult != ISC_R_SUCCESS)
2597 result = tresult;
2598
2599 cleanup:
2600 if (symtab != NULL)
2601 isc_symtab_destroy(&symtab);
2602 if (actx != NULL)
2603 cfg_aclconfctx_detach(&actx);
2604
2605 return (result);
2606 }
2607
2608 static const char *
2609 default_channels[] = {
2610 "default_syslog",
2611 "default_stderr",
2612 "default_debug",
2613 "null",
2614 NULL
2615 };
2616
2617 static isc_result_t
bind9_check_logging(const cfg_obj_t * config,isc_log_t * logctx,isc_mem_t * mctx)2618 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
2619 isc_mem_t *mctx)
2620 {
2621 const cfg_obj_t *categories = NULL;
2622 const cfg_obj_t *category;
2623 const cfg_obj_t *channels = NULL;
2624 const cfg_obj_t *channel;
2625 const cfg_listelt_t *element;
2626 const cfg_listelt_t *delement;
2627 const char *channelname;
2628 const char *catname;
2629 const cfg_obj_t *fileobj = NULL;
2630 const cfg_obj_t *syslogobj = NULL;
2631 const cfg_obj_t *nullobj = NULL;
2632 const cfg_obj_t *stderrobj = NULL;
2633 const cfg_obj_t *logobj = NULL;
2634 isc_result_t result = ISC_R_SUCCESS;
2635 isc_result_t tresult;
2636 isc_symtab_t *symtab = NULL;
2637 isc_symvalue_t symvalue;
2638 int i;
2639
2640 (void)cfg_map_get(config, "logging", &logobj);
2641 if (logobj == NULL)
2642 return (ISC_R_SUCCESS);
2643
2644 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
2645 if (result != ISC_R_SUCCESS)
2646 return (result);
2647
2648 symvalue.as_cpointer = NULL;
2649 for (i = 0; default_channels[i] != NULL; i++) {
2650 tresult = isc_symtab_define(symtab, default_channels[i], 1,
2651 symvalue, isc_symexists_replace);
2652 if (tresult != ISC_R_SUCCESS)
2653 result = tresult;
2654 }
2655
2656 cfg_map_get(logobj, "channel", &channels);
2657
2658 for (element = cfg_list_first(channels);
2659 element != NULL;
2660 element = cfg_list_next(element))
2661 {
2662 channel = cfg_listelt_value(element);
2663 channelname = cfg_obj_asstring(cfg_map_getname(channel));
2664 fileobj = syslogobj = nullobj = stderrobj = NULL;
2665 (void)cfg_map_get(channel, "file", &fileobj);
2666 (void)cfg_map_get(channel, "syslog", &syslogobj);
2667 (void)cfg_map_get(channel, "null", &nullobj);
2668 (void)cfg_map_get(channel, "stderr", &stderrobj);
2669 i = 0;
2670 if (fileobj != NULL)
2671 i++;
2672 if (syslogobj != NULL)
2673 i++;
2674 if (nullobj != NULL)
2675 i++;
2676 if (stderrobj != NULL)
2677 i++;
2678 if (i != 1) {
2679 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2680 "channel '%s': exactly one of file, syslog, "
2681 "null, and stderr must be present",
2682 channelname);
2683 result = ISC_R_FAILURE;
2684 }
2685 tresult = isc_symtab_define(symtab, channelname, 1,
2686 symvalue, isc_symexists_replace);
2687 if (tresult != ISC_R_SUCCESS)
2688 result = tresult;
2689 }
2690
2691 cfg_map_get(logobj, "category", &categories);
2692
2693 for (element = cfg_list_first(categories);
2694 element != NULL;
2695 element = cfg_list_next(element))
2696 {
2697 category = cfg_listelt_value(element);
2698 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
2699 if (isc_log_categorybyname(logctx, catname) == NULL) {
2700 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
2701 "undefined category: '%s'", catname);
2702 result = ISC_R_FAILURE;
2703 }
2704 channels = cfg_tuple_get(category, "destinations");
2705 for (delement = cfg_list_first(channels);
2706 delement != NULL;
2707 delement = cfg_list_next(delement))
2708 {
2709 channel = cfg_listelt_value(delement);
2710 channelname = cfg_obj_asstring(channel);
2711 tresult = isc_symtab_lookup(symtab, channelname, 1,
2712 &symvalue);
2713 if (tresult != ISC_R_SUCCESS) {
2714 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2715 "undefined channel: '%s'",
2716 channelname);
2717 result = tresult;
2718 }
2719 }
2720 }
2721 isc_symtab_destroy(&symtab);
2722 return (result);
2723 }
2724
2725 static isc_result_t
bind9_check_controlskeys(const cfg_obj_t * control,const cfg_obj_t * keylist,isc_log_t * logctx)2726 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
2727 isc_log_t *logctx)
2728 {
2729 isc_result_t result = ISC_R_SUCCESS;
2730 const cfg_obj_t *control_keylist;
2731 const cfg_listelt_t *element;
2732 const cfg_obj_t *key;
2733 const char *keyval;
2734
2735 control_keylist = cfg_tuple_get(control, "keys");
2736 if (cfg_obj_isvoid(control_keylist))
2737 return (ISC_R_SUCCESS);
2738
2739 for (element = cfg_list_first(control_keylist);
2740 element != NULL;
2741 element = cfg_list_next(element))
2742 {
2743 key = cfg_listelt_value(element);
2744 keyval = cfg_obj_asstring(key);
2745
2746 if (!rndckey_exists(keylist, keyval)) {
2747 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2748 "unknown key '%s'", keyval);
2749 result = ISC_R_NOTFOUND;
2750 }
2751 }
2752 return (result);
2753 }
2754
2755 static isc_result_t
bind9_check_controls(const cfg_obj_t * config,isc_log_t * logctx,isc_mem_t * mctx)2756 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
2757 isc_mem_t *mctx)
2758 {
2759 isc_result_t result = ISC_R_SUCCESS, tresult;
2760 cfg_aclconfctx_t *actx = NULL;
2761 const cfg_listelt_t *element, *element2;
2762 const cfg_obj_t *allow;
2763 const cfg_obj_t *control;
2764 const cfg_obj_t *controls;
2765 const cfg_obj_t *controlslist = NULL;
2766 const cfg_obj_t *inetcontrols;
2767 const cfg_obj_t *unixcontrols;
2768 const cfg_obj_t *keylist = NULL;
2769 const char *path;
2770 isc_uint32_t perm, mask;
2771 dns_acl_t *acl = NULL;
2772 isc_sockaddr_t addr;
2773 int i;
2774
2775 (void)cfg_map_get(config, "controls", &controlslist);
2776 if (controlslist == NULL)
2777 return (ISC_R_SUCCESS);
2778
2779 (void)cfg_map_get(config, "key", &keylist);
2780
2781 cfg_aclconfctx_create(mctx, &actx);
2782
2783 /*
2784 * INET: Check allow clause.
2785 * UNIX: Check "perm" for sanity, check path length.
2786 */
2787 for (element = cfg_list_first(controlslist);
2788 element != NULL;
2789 element = cfg_list_next(element)) {
2790 controls = cfg_listelt_value(element);
2791 unixcontrols = NULL;
2792 inetcontrols = NULL;
2793 (void)cfg_map_get(controls, "unix", &unixcontrols);
2794 (void)cfg_map_get(controls, "inet", &inetcontrols);
2795 for (element2 = cfg_list_first(inetcontrols);
2796 element2 != NULL;
2797 element2 = cfg_list_next(element2)) {
2798 control = cfg_listelt_value(element2);
2799 allow = cfg_tuple_get(control, "allow");
2800 tresult = cfg_acl_fromconfig(allow, config, logctx,
2801 actx, mctx, 0, &acl);
2802 if (acl != NULL)
2803 dns_acl_detach(&acl);
2804 if (tresult != ISC_R_SUCCESS)
2805 result = tresult;
2806 tresult = bind9_check_controlskeys(control, keylist,
2807 logctx);
2808 if (tresult != ISC_R_SUCCESS)
2809 result = tresult;
2810 }
2811 for (element2 = cfg_list_first(unixcontrols);
2812 element2 != NULL;
2813 element2 = cfg_list_next(element2)) {
2814 control = cfg_listelt_value(element2);
2815 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
2816 tresult = isc_sockaddr_frompath(&addr, path);
2817 if (tresult == ISC_R_NOSPACE) {
2818 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
2819 "unix control '%s': path too long",
2820 path);
2821 result = ISC_R_NOSPACE;
2822 }
2823 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
2824 for (i = 0; i < 3; i++) {
2825 #ifdef NEED_SECURE_DIRECTORY
2826 mask = (0x1 << (i*3)); /* SEARCH */
2827 #else
2828 mask = (0x6 << (i*3)); /* READ + WRITE */
2829 #endif
2830 if ((perm & mask) == mask)
2831 break;
2832 }
2833 if (i == 0) {
2834 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2835 "unix control '%s' allows access "
2836 "to everyone", path);
2837 } else if (i == 3) {
2838 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2839 "unix control '%s' allows access "
2840 "to nobody", path);
2841 }
2842 tresult = bind9_check_controlskeys(control, keylist,
2843 logctx);
2844 if (tresult != ISC_R_SUCCESS)
2845 result = tresult;
2846 }
2847 }
2848 cfg_aclconfctx_detach(&actx);
2849 return (result);
2850 }
2851
2852 isc_result_t
bind9_check_namedconf(const cfg_obj_t * config,isc_log_t * logctx,isc_mem_t * mctx)2853 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
2854 isc_mem_t *mctx)
2855 {
2856 const cfg_obj_t *options = NULL;
2857 const cfg_obj_t *views = NULL;
2858 const cfg_obj_t *acls = NULL;
2859 const cfg_obj_t *kals = NULL;
2860 const cfg_obj_t *obj;
2861 const cfg_listelt_t *velement;
2862 isc_result_t result = ISC_R_SUCCESS;
2863 isc_result_t tresult;
2864 isc_symtab_t *symtab = NULL;
2865 isc_symtab_t *files = NULL;
2866
2867 static const char *builtin[] = { "localhost", "localnets",
2868 "any", "none"};
2869
2870 (void)cfg_map_get(config, "options", &options);
2871
2872 if (options != NULL &&
2873 check_options(options, logctx, mctx,
2874 optlevel_options) != ISC_R_SUCCESS)
2875 result = ISC_R_FAILURE;
2876
2877 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
2878 result = ISC_R_FAILURE;
2879
2880 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
2881 result = ISC_R_FAILURE;
2882
2883 if (options != NULL &&
2884 check_order(options, logctx) != ISC_R_SUCCESS)
2885 result = ISC_R_FAILURE;
2886
2887 (void)cfg_map_get(config, "view", &views);
2888
2889 if (views != NULL && options != NULL)
2890 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2891 result = ISC_R_FAILURE;
2892
2893 /*
2894 * Use case insensitve comparision as not all file systems are
2895 * case sensitive. This will prevent people using FOO.DB and foo.db
2896 * on case sensitive file systems but that shouldn't be a major issue.
2897 */
2898 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE,
2899 &files);
2900 if (tresult != ISC_R_SUCCESS)
2901 result = tresult;
2902
2903 if (views == NULL) {
2904 if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
2905 files, logctx, mctx) != ISC_R_SUCCESS)
2906 result = ISC_R_FAILURE;
2907 } else {
2908 const cfg_obj_t *zones = NULL;
2909
2910 (void)cfg_map_get(config, "zone", &zones);
2911 if (zones != NULL) {
2912 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
2913 "when using 'view' statements, "
2914 "all zones must be in views");
2915 result = ISC_R_FAILURE;
2916 }
2917 }
2918
2919 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
2920 if (tresult != ISC_R_SUCCESS)
2921 result = tresult;
2922 for (velement = cfg_list_first(views);
2923 velement != NULL;
2924 velement = cfg_list_next(velement))
2925 {
2926 const cfg_obj_t *view = cfg_listelt_value(velement);
2927 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
2928 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
2929 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
2930 dns_rdataclass_t vclass = dns_rdataclass_in;
2931 const char *key = cfg_obj_asstring(vname);
2932 isc_symvalue_t symvalue;
2933 unsigned int symtype;
2934
2935 tresult = ISC_R_SUCCESS;
2936 if (cfg_obj_isstring(vclassobj)) {
2937 isc_textregion_t r;
2938
2939 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
2940 r.length = strlen(r.base);
2941 tresult = dns_rdataclass_fromtext(&vclass, &r);
2942 if (tresult != ISC_R_SUCCESS)
2943 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
2944 "view '%s': invalid class %s",
2945 cfg_obj_asstring(vname), r.base);
2946 }
2947 symtype = vclass + 1;
2948 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
2949 symvalue.as_cpointer = view;
2950 tresult = isc_symtab_define(symtab, key, symtype,
2951 symvalue,
2952 isc_symexists_reject);
2953 if (tresult == ISC_R_EXISTS) {
2954 const char *file;
2955 unsigned int line;
2956 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
2957 symtype, &symvalue) == ISC_R_SUCCESS);
2958 file = cfg_obj_file(symvalue.as_cpointer);
2959 line = cfg_obj_line(symvalue.as_cpointer);
2960 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2961 "view '%s': already exists "
2962 "previous definition: %s:%u",
2963 key, file, line);
2964 result = tresult;
2965 } else if (tresult != ISC_R_SUCCESS) {
2966 result = tresult;
2967 } else if ((strcasecmp(key, "_bind") == 0 &&
2968 vclass == dns_rdataclass_ch) ||
2969 (strcasecmp(key, "_default") == 0 &&
2970 vclass == dns_rdataclass_in)) {
2971 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2972 "attempt to redefine builtin view "
2973 "'%s'", key);
2974 result = ISC_R_EXISTS;
2975 }
2976 }
2977 if (tresult == ISC_R_SUCCESS)
2978 tresult = check_viewconf(config, voptions, key, vclass,
2979 files, logctx, mctx);
2980 if (tresult != ISC_R_SUCCESS)
2981 result = ISC_R_FAILURE;
2982 }
2983 if (symtab != NULL)
2984 isc_symtab_destroy(&symtab);
2985 if (files != NULL)
2986 isc_symtab_destroy(&files);
2987
2988 if (views != NULL && options != NULL) {
2989 obj = NULL;
2990 tresult = cfg_map_get(options, "cache-file", &obj);
2991 if (tresult == ISC_R_SUCCESS) {
2992 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2993 "'cache-file' cannot be a global "
2994 "option if views are present");
2995 result = ISC_R_FAILURE;
2996 }
2997 }
2998
2999 cfg_map_get(config, "acl", &acls);
3000
3001 if (acls != NULL) {
3002 const cfg_listelt_t *elt;
3003 const cfg_listelt_t *elt2;
3004 const char *aclname;
3005
3006 for (elt = cfg_list_first(acls);
3007 elt != NULL;
3008 elt = cfg_list_next(elt)) {
3009 const cfg_obj_t *acl = cfg_listelt_value(elt);
3010 unsigned int line = cfg_obj_line(acl);
3011 unsigned int i;
3012
3013 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
3014 for (i = 0;
3015 i < sizeof(builtin) / sizeof(builtin[0]);
3016 i++)
3017 if (strcasecmp(aclname, builtin[i]) == 0) {
3018 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
3019 "attempt to redefine "
3020 "builtin acl '%s'",
3021 aclname);
3022 result = ISC_R_FAILURE;
3023 break;
3024 }
3025
3026 for (elt2 = cfg_list_next(elt);
3027 elt2 != NULL;
3028 elt2 = cfg_list_next(elt2)) {
3029 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
3030 const char *name;
3031 name = cfg_obj_asstring(cfg_tuple_get(acl2,
3032 "name"));
3033 if (strcasecmp(aclname, name) == 0) {
3034 const char *file = cfg_obj_file(acl);
3035
3036 if (file == NULL)
3037 file = "<unknown file>";
3038
3039 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
3040 "attempt to redefine "
3041 "acl '%s' previous "
3042 "definition: %s:%u",
3043 name, file, line);
3044 result = ISC_R_FAILURE;
3045 }
3046 }
3047 }
3048 }
3049
3050 tresult = cfg_map_get(config, "kal", &kals);
3051 if (tresult == ISC_R_SUCCESS) {
3052 const cfg_listelt_t *elt;
3053 const cfg_listelt_t *elt2;
3054 const char *aclname;
3055
3056 for (elt = cfg_list_first(kals);
3057 elt != NULL;
3058 elt = cfg_list_next(elt)) {
3059 const cfg_obj_t *acl = cfg_listelt_value(elt);
3060
3061 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
3062
3063 for (elt2 = cfg_list_next(elt);
3064 elt2 != NULL;
3065 elt2 = cfg_list_next(elt2)) {
3066 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
3067 const char *name;
3068 name = cfg_obj_asstring(cfg_tuple_get(acl2,
3069 "name"));
3070 if (strcasecmp(aclname, name) == 0) {
3071 const char *file = cfg_obj_file(acl);
3072 unsigned int line = cfg_obj_line(acl);
3073
3074 if (file == NULL)
3075 file = "<unknown file>";
3076
3077 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
3078 "attempt to redefine "
3079 "kal '%s' previous "
3080 "definition: %s:%u",
3081 name, file, line);
3082 result = ISC_R_FAILURE;
3083 }
3084 }
3085 }
3086 }
3087
3088 return (result);
3089 }
3090