1/* $NetBSD: check.c,v 1.16 2024/02/21 22:52:04 christos Exp $ */ 2 3/* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16/*! \file */ 17 18#include <ctype.h> 19#include <inttypes.h> 20#include <stdbool.h> 21#include <stdlib.h> 22 23#include <openssl/opensslv.h> 24 25#ifdef HAVE_DNSTAP 26#include <fstrm.h> 27#endif 28 29#include <isc/aes.h> 30#include <isc/base64.h> 31#include <isc/buffer.h> 32#include <isc/dir.h> 33#include <isc/file.h> 34#include <isc/hex.h> 35#include <isc/log.h> 36#include <isc/md.h> 37#include <isc/mem.h> 38#include <isc/netaddr.h> 39#include <isc/parseint.h> 40#include <isc/print.h> 41#include <isc/region.h> 42#include <isc/result.h> 43#include <isc/siphash.h> 44#include <isc/sockaddr.h> 45#include <isc/string.h> 46#include <isc/symtab.h> 47#include <isc/util.h> 48 49#include <dns/acl.h> 50#include <dns/dnstap.h> 51#include <dns/fixedname.h> 52#include <dns/kasp.h> 53#include <dns/keyvalues.h> 54#include <dns/peer.h> 55#include <dns/rbt.h> 56#include <dns/rdataclass.h> 57#include <dns/rdatatype.h> 58#include <dns/rrl.h> 59#include <dns/secalg.h> 60#include <dns/ssu.h> 61 62#include <dst/dst.h> 63 64#include <isccfg/aclconf.h> 65#include <isccfg/cfg.h> 66#include <isccfg/grammar.h> 67#include <isccfg/kaspconf.h> 68#include <isccfg/namedconf.h> 69 70#include <ns/hooks.h> 71 72#include <bind9/check.h> 73 74static in_port_t dnsport = 53; 75 76static isc_result_t 77fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, bool writeable, 78 isc_log_t *logctxlogc); 79 80static isc_result_t 81keydirexist(const cfg_obj_t *zcgf, const char *dir, const char *kaspnamestr, 82 isc_symtab_t *symtab, isc_log_t *logctx, isc_mem_t *mctx); 83static void 84freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) { 85 UNUSED(type); 86 UNUSED(value); 87 isc_mem_free(userarg, key); 88} 89 90static isc_result_t 91check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) { 92 isc_result_t result = ISC_R_SUCCESS; 93 isc_result_t tresult; 94 isc_textregion_t r; 95 dns_fixedname_t fixed; 96 const cfg_obj_t *obj; 97 dns_rdataclass_t rdclass; 98 dns_rdatatype_t rdtype; 99 isc_buffer_t b; 100 const char *str; 101 102 dns_fixedname_init(&fixed); 103 obj = cfg_tuple_get(ent, "class"); 104 if (cfg_obj_isstring(obj)) { 105 DE_CONST(cfg_obj_asstring(obj), r.base); 106 r.length = strlen(r.base); 107 tresult = dns_rdataclass_fromtext(&rdclass, &r); 108 if (tresult != ISC_R_SUCCESS) { 109 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 110 "rrset-order: invalid class '%s'", r.base); 111 if (result == ISC_R_SUCCESS) { 112 result = ISC_R_FAILURE; 113 } 114 } 115 } 116 117 obj = cfg_tuple_get(ent, "type"); 118 if (cfg_obj_isstring(obj)) { 119 DE_CONST(cfg_obj_asstring(obj), r.base); 120 r.length = strlen(r.base); 121 tresult = dns_rdatatype_fromtext(&rdtype, &r); 122 if (tresult != ISC_R_SUCCESS) { 123 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 124 "rrset-order: invalid type '%s'", r.base); 125 if (result == ISC_R_SUCCESS) { 126 result = ISC_R_FAILURE; 127 } 128 } 129 } 130 131 obj = cfg_tuple_get(ent, "name"); 132 if (cfg_obj_isstring(obj)) { 133 str = cfg_obj_asstring(obj); 134 isc_buffer_constinit(&b, str, strlen(str)); 135 isc_buffer_add(&b, strlen(str)); 136 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b, 137 dns_rootname, 0, NULL); 138 if (tresult != ISC_R_SUCCESS) { 139 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 140 "rrset-order: invalid name '%s'", str); 141 if (result == ISC_R_SUCCESS) { 142 result = ISC_R_FAILURE; 143 } 144 } 145 } 146 147 obj = cfg_tuple_get(ent, "order"); 148 if (!cfg_obj_isstring(obj) || 149 strcasecmp("order", cfg_obj_asstring(obj)) != 0) 150 { 151 cfg_obj_log(ent, logctx, ISC_LOG_ERROR, 152 "rrset-order: keyword 'order' missing"); 153 if (result == ISC_R_SUCCESS) { 154 result = ISC_R_FAILURE; 155 } 156 } 157 158 obj = cfg_tuple_get(ent, "ordering"); 159 if (!cfg_obj_isstring(obj)) { 160 cfg_obj_log(ent, logctx, ISC_LOG_ERROR, 161 "rrset-order: missing ordering"); 162 if (result == ISC_R_SUCCESS) { 163 result = ISC_R_FAILURE; 164 } 165 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) { 166#if !DNS_RDATASET_FIXED 167 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 168 "rrset-order: order 'fixed' was disabled at " 169 "compilation time"); 170#endif /* if !DNS_RDATASET_FIXED */ 171 } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 && 172 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0 && 173 strcasecmp(cfg_obj_asstring(obj), "none") != 0) 174 { 175 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 176 "rrset-order: invalid order '%s'", 177 cfg_obj_asstring(obj)); 178 if (result == ISC_R_SUCCESS) { 179 result = ISC_R_FAILURE; 180 } 181 } 182 return (result); 183} 184 185static isc_result_t 186check_order(const cfg_obj_t *options, isc_log_t *logctx) { 187 isc_result_t result = ISC_R_SUCCESS; 188 isc_result_t tresult; 189 const cfg_listelt_t *element; 190 const cfg_obj_t *obj = NULL; 191 192 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS) { 193 return (result); 194 } 195 196 for (element = cfg_list_first(obj); element != NULL; 197 element = cfg_list_next(element)) 198 { 199 tresult = check_orderent(cfg_listelt_value(element), logctx); 200 if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS) { 201 result = tresult; 202 } 203 } 204 return (result); 205} 206 207static isc_result_t 208check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) { 209 const cfg_listelt_t *element; 210 const cfg_obj_t *alternates = NULL; 211 const cfg_obj_t *value; 212 const cfg_obj_t *obj; 213 const char *str; 214 dns_fixedname_t fixed; 215 dns_name_t *name; 216 isc_buffer_t buffer; 217 isc_result_t result = ISC_R_SUCCESS; 218 isc_result_t tresult; 219 220 (void)cfg_map_get(options, "dual-stack-servers", &alternates); 221 222 if (alternates == NULL) { 223 return (ISC_R_SUCCESS); 224 } 225 226 obj = cfg_tuple_get(alternates, "port"); 227 if (cfg_obj_isuint32(obj)) { 228 uint32_t val = cfg_obj_asuint32(obj); 229 if (val > UINT16_MAX) { 230 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 231 "port '%u' out of range", val); 232 if (result == ISC_R_SUCCESS) { 233 result = ISC_R_RANGE; 234 } 235 } 236 } 237 obj = cfg_tuple_get(alternates, "addresses"); 238 for (element = cfg_list_first(obj); element != NULL; 239 element = cfg_list_next(element)) 240 { 241 value = cfg_listelt_value(element); 242 if (cfg_obj_issockaddr(value)) { 243 continue; 244 } 245 obj = cfg_tuple_get(value, "name"); 246 str = cfg_obj_asstring(obj); 247 isc_buffer_constinit(&buffer, str, strlen(str)); 248 isc_buffer_add(&buffer, strlen(str)); 249 name = dns_fixedname_initname(&fixed); 250 tresult = dns_name_fromtext(name, &buffer, dns_rootname, 0, 251 NULL); 252 if (tresult != ISC_R_SUCCESS) { 253 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad name '%s'", 254 str); 255 if (result == ISC_R_SUCCESS) { 256 result = tresult; 257 } 258 } 259 obj = cfg_tuple_get(value, "port"); 260 if (cfg_obj_isuint32(obj)) { 261 uint32_t val = cfg_obj_asuint32(obj); 262 if (val > UINT16_MAX) { 263 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 264 "port '%u' out of range", val); 265 if (result == ISC_R_SUCCESS) { 266 result = ISC_R_RANGE; 267 } 268 } 269 } 270 } 271 return (result); 272} 273 274static isc_result_t 275check_forward(const cfg_obj_t *options, const cfg_obj_t *global, 276 isc_log_t *logctx) { 277 const cfg_obj_t *forward = NULL; 278 const cfg_obj_t *forwarders = NULL; 279 280 (void)cfg_map_get(options, "forward", &forward); 281 (void)cfg_map_get(options, "forwarders", &forwarders); 282 283 if (forwarders != NULL && global != NULL) { 284 const char *file = cfg_obj_file(global); 285 unsigned int line = cfg_obj_line(global); 286 cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR, 287 "forwarders declared in root zone and " 288 "in general configuration: %s:%u", 289 file, line); 290 return (ISC_R_FAILURE); 291 } 292 if (forward != NULL && forwarders == NULL) { 293 cfg_obj_log(forward, logctx, ISC_LOG_ERROR, 294 "no matching 'forwarders' statement"); 295 return (ISC_R_FAILURE); 296 } 297 return (ISC_R_SUCCESS); 298} 299 300static isc_result_t 301disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) { 302 isc_result_t result = ISC_R_SUCCESS; 303 isc_result_t tresult; 304 const cfg_listelt_t *element; 305 const char *str; 306 isc_buffer_t b; 307 dns_fixedname_t fixed; 308 dns_name_t *name; 309 const cfg_obj_t *obj; 310 311 name = dns_fixedname_initname(&fixed); 312 obj = cfg_tuple_get(disabled, "name"); 313 str = cfg_obj_asstring(obj); 314 isc_buffer_constinit(&b, str, strlen(str)); 315 isc_buffer_add(&b, strlen(str)); 316 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); 317 if (tresult != ISC_R_SUCCESS) { 318 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad domain name '%s'", 319 str); 320 result = tresult; 321 } 322 323 obj = cfg_tuple_get(disabled, "algorithms"); 324 325 for (element = cfg_list_first(obj); element != NULL; 326 element = cfg_list_next(element)) 327 { 328 isc_textregion_t r; 329 dns_secalg_t alg; 330 331 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base); 332 r.length = strlen(r.base); 333 334 tresult = dns_secalg_fromtext(&alg, &r); 335 if (tresult != ISC_R_SUCCESS) { 336 cfg_obj_log(cfg_listelt_value(element), logctx, 337 ISC_LOG_ERROR, "invalid algorithm '%s'", 338 r.base); 339 result = tresult; 340 } 341 } 342 return (result); 343} 344 345static isc_result_t 346disabled_ds_digests(const cfg_obj_t *disabled, isc_log_t *logctx) { 347 isc_result_t result = ISC_R_SUCCESS; 348 isc_result_t tresult; 349 const cfg_listelt_t *element; 350 const char *str; 351 isc_buffer_t b; 352 dns_fixedname_t fixed; 353 dns_name_t *name; 354 const cfg_obj_t *obj; 355 356 name = dns_fixedname_initname(&fixed); 357 obj = cfg_tuple_get(disabled, "name"); 358 str = cfg_obj_asstring(obj); 359 isc_buffer_constinit(&b, str, strlen(str)); 360 isc_buffer_add(&b, strlen(str)); 361 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); 362 if (tresult != ISC_R_SUCCESS) { 363 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad domain name '%s'", 364 str); 365 result = tresult; 366 } 367 368 obj = cfg_tuple_get(disabled, "digests"); 369 370 for (element = cfg_list_first(obj); element != NULL; 371 element = cfg_list_next(element)) 372 { 373 isc_textregion_t r; 374 dns_dsdigest_t digest; 375 376 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base); 377 r.length = strlen(r.base); 378 379 /* works with a numeric argument too */ 380 tresult = dns_dsdigest_fromtext(&digest, &r); 381 if (tresult != ISC_R_SUCCESS) { 382 cfg_obj_log(cfg_listelt_value(element), logctx, 383 ISC_LOG_ERROR, "invalid digest type '%s'", 384 r.base); 385 result = tresult; 386 } 387 } 388 return (result); 389} 390 391static isc_result_t 392nameexist(const cfg_obj_t *obj, const char *name, int value, 393 isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx, 394 isc_mem_t *mctx) { 395 char *key; 396 const char *file; 397 unsigned int line; 398 isc_result_t result; 399 isc_symvalue_t symvalue; 400 401 key = isc_mem_strdup(mctx, name); 402 symvalue.as_cpointer = obj; 403 result = isc_symtab_define(symtab, key, value, symvalue, 404 isc_symexists_reject); 405 if (result == ISC_R_EXISTS) { 406 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value, 407 &symvalue) == ISC_R_SUCCESS); 408 file = cfg_obj_file(symvalue.as_cpointer); 409 line = cfg_obj_line(symvalue.as_cpointer); 410 411 if (file == NULL) { 412 file = "<unknown file>"; 413 } 414 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line); 415 isc_mem_free(mctx, key); 416 result = ISC_R_EXISTS; 417 } else if (result != ISC_R_SUCCESS) { 418 isc_mem_free(mctx, key); 419 } 420 return (result); 421} 422 423static isc_result_t 424mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx, 425 isc_mem_t *mctx) { 426 const cfg_obj_t *obj; 427 char namebuf[DNS_NAME_FORMATSIZE]; 428 const char *str; 429 dns_fixedname_t fixed; 430 dns_name_t *name; 431 isc_buffer_t b; 432 isc_result_t result = ISC_R_SUCCESS; 433 434 name = dns_fixedname_initname(&fixed); 435 obj = cfg_tuple_get(secure, "name"); 436 str = cfg_obj_asstring(obj); 437 isc_buffer_constinit(&b, str, strlen(str)); 438 isc_buffer_add(&b, strlen(str)); 439 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); 440 if (result != ISC_R_SUCCESS) { 441 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad domain name '%s'", 442 str); 443 } else { 444 dns_name_format(name, namebuf, sizeof(namebuf)); 445 result = nameexist(secure, namebuf, 1, symtab, 446 "dnssec-must-be-secure '%s': already " 447 "exists previous definition: %s:%u", 448 logctx, mctx); 449 } 450 return (result); 451} 452 453static isc_result_t 454checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig, 455 const cfg_obj_t *voptions, const cfg_obj_t *config, isc_log_t *logctx, 456 isc_mem_t *mctx) { 457 isc_result_t result; 458 const cfg_obj_t *aclobj = NULL; 459 const cfg_obj_t *options; 460 dns_acl_t *acl = NULL; 461 462 if (zconfig != NULL) { 463 options = cfg_tuple_get(zconfig, "options"); 464 cfg_map_get(options, aclname, &aclobj); 465 } 466 if (voptions != NULL && aclobj == NULL) { 467 cfg_map_get(voptions, aclname, &aclobj); 468 } 469 if (config != NULL && aclobj == NULL) { 470 options = NULL; 471 cfg_map_get(config, "options", &options); 472 if (options != NULL) { 473 cfg_map_get(options, aclname, &aclobj); 474 } 475 } 476 if (aclobj == NULL) { 477 return (ISC_R_SUCCESS); 478 } 479 result = cfg_acl_fromconfig(aclobj, config, logctx, actx, mctx, 0, 480 &acl); 481 if (acl != NULL) { 482 dns_acl_detach(&acl); 483 } 484 485 if (strcasecmp(aclname, "allow-transfer") == 0 && 486 cfg_obj_istuple(aclobj)) 487 { 488 const cfg_obj_t *obj_port = cfg_tuple_get( 489 cfg_tuple_get(aclobj, "port-transport"), "port"); 490 const cfg_obj_t *obj_proto = cfg_tuple_get( 491 cfg_tuple_get(aclobj, "port-transport"), "transport"); 492 493 if (cfg_obj_isuint32(obj_port) && 494 cfg_obj_asuint32(obj_port) >= UINT16_MAX) 495 { 496 cfg_obj_log(obj_port, logctx, ISC_LOG_ERROR, 497 "port value '%u' is out of range", 498 499 cfg_obj_asuint32(obj_port)); 500 if (result == ISC_R_SUCCESS) { 501 result = ISC_R_RANGE; 502 } 503 } 504 505 if (cfg_obj_isstring(obj_proto)) { 506 const char *allowed[] = { "tcp", "tls" }; 507 const char *transport = cfg_obj_asstring(obj_proto); 508 bool found = false; 509 for (size_t i = 0; i < ARRAY_SIZE(allowed); i++) { 510 if (strcasecmp(transport, allowed[i]) == 0) { 511 found = true; 512 } 513 } 514 515 if (!found) { 516 cfg_obj_log(obj_proto, logctx, ISC_LOG_ERROR, 517 "'%s' is not a valid transport " 518 "protocol for " 519 "zone " 520 "transfers. Please specify either " 521 "'tcp' or 'tls'", 522 transport); 523 result = ISC_R_FAILURE; 524 } 525 } 526 } 527 return (result); 528} 529 530static isc_result_t 531check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, 532 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) { 533 isc_result_t result = ISC_R_SUCCESS, tresult; 534 int i = 0; 535 536 static const char *acls[] = { 537 "allow-query", "allow-query-on", 538 "allow-query-cache", "allow-query-cache-on", 539 "blackhole", "keep-response-order", 540 "match-clients", "match-destinations", 541 "sortlist", NULL 542 }; 543 544 while (acls[i] != NULL) { 545 tresult = checkacl(acls[i++], actx, NULL, voptions, config, 546 logctx, mctx); 547 if (tresult != ISC_R_SUCCESS) { 548 result = tresult; 549 } 550 } 551 return (result); 552} 553 554static void 555dns64_error(const cfg_obj_t *obj, isc_log_t *logctx, isc_netaddr_t *netaddr, 556 unsigned int prefixlen, const char *message) { 557 char buf[ISC_NETADDR_FORMATSIZE + 1]; 558 isc_netaddr_format(netaddr, buf, sizeof(buf)); 559 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "dns64 prefix %s/%u %s", buf, 560 prefixlen, message); 561} 562 563static isc_result_t 564check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, 565 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) { 566 isc_result_t result = ISC_R_SUCCESS; 567 const cfg_obj_t *dns64 = NULL; 568 const cfg_obj_t *options; 569 const cfg_listelt_t *element; 570 const cfg_obj_t *map, *obj; 571 isc_netaddr_t na, sa; 572 unsigned int prefixlen; 573 int nbytes; 574 int i; 575 576 static const char *acls[] = { "clients", "exclude", "mapped", NULL }; 577 578 if (voptions != NULL) { 579 cfg_map_get(voptions, "dns64", &dns64); 580 } 581 if (config != NULL && dns64 == NULL) { 582 options = NULL; 583 cfg_map_get(config, "options", &options); 584 if (options != NULL) { 585 cfg_map_get(options, "dns64", &dns64); 586 } 587 } 588 if (dns64 == NULL) { 589 return (ISC_R_SUCCESS); 590 } 591 592 for (element = cfg_list_first(dns64); element != NULL; 593 element = cfg_list_next(element)) 594 { 595 map = cfg_listelt_value(element); 596 obj = cfg_map_getname(map); 597 598 cfg_obj_asnetprefix(obj, &na, &prefixlen); 599 if (na.family != AF_INET6) { 600 dns64_error(map, logctx, &na, prefixlen, 601 "must be IPv6"); 602 result = ISC_R_FAILURE; 603 continue; 604 } 605 606 if (na.type.in6.s6_addr[8] != 0) { 607 dns64_error(map, logctx, &na, prefixlen, 608 "bits [64..71] must be zero"); 609 result = ISC_R_FAILURE; 610 continue; 611 } 612 613 if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 && 614 prefixlen != 56 && prefixlen != 64 && prefixlen != 96) 615 { 616 dns64_error(map, logctx, &na, prefixlen, 617 "length is not 32/40/48/56/64/96"); 618 result = ISC_R_FAILURE; 619 continue; 620 } 621 622 for (i = 0; acls[i] != NULL; i++) { 623 obj = NULL; 624 (void)cfg_map_get(map, acls[i], &obj); 625 if (obj != NULL) { 626 dns_acl_t *acl = NULL; 627 isc_result_t tresult; 628 629 tresult = cfg_acl_fromconfig(obj, config, 630 logctx, actx, mctx, 631 0, &acl); 632 if (acl != NULL) { 633 dns_acl_detach(&acl); 634 } 635 if (tresult != ISC_R_SUCCESS) { 636 result = tresult; 637 } 638 } 639 } 640 641 obj = NULL; 642 (void)cfg_map_get(map, "suffix", &obj); 643 if (obj != NULL) { 644 static const unsigned char zeros[16]; 645 isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj)); 646 if (sa.family != AF_INET6) { 647 cfg_obj_log(map, logctx, ISC_LOG_ERROR, 648 "dns64 requires a IPv6 suffix"); 649 result = ISC_R_FAILURE; 650 continue; 651 } 652 nbytes = prefixlen / 8 + 4; 653 if (prefixlen <= 64) { 654 nbytes++; 655 } 656 if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) { 657 char netaddrbuf[ISC_NETADDR_FORMATSIZE]; 658 isc_netaddr_format(&sa, netaddrbuf, 659 sizeof(netaddrbuf)); 660 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 661 "bad suffix '%s' leading " 662 "%u octets not zeros", 663 netaddrbuf, nbytes); 664 result = ISC_R_FAILURE; 665 } 666 } 667 } 668 669 return (result); 670} 671 672#define CHECK_RRL(cond, pat, val1, val2) \ 673 do { \ 674 if (!(cond)) { \ 675 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, pat, val1, \ 676 val2); \ 677 if (result == ISC_R_SUCCESS) \ 678 result = ISC_R_RANGE; \ 679 } \ 680 } while (0) 681 682#define CHECK_RRL_RATE(rate, def, max_rate, name) \ 683 do { \ 684 obj = NULL; \ 685 mresult = cfg_map_get(map, name, &obj); \ 686 if (mresult == ISC_R_SUCCESS) { \ 687 rate = cfg_obj_asuint32(obj); \ 688 CHECK_RRL(rate <= max_rate, name " %d > %d", rate, \ 689 max_rate); \ 690 } \ 691 } while (0) 692 693static isc_result_t 694check_ratelimit(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, 695 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) { 696 isc_result_t result = ISC_R_SUCCESS; 697 isc_result_t mresult; 698 const cfg_obj_t *map = NULL; 699 const cfg_obj_t *options; 700 const cfg_obj_t *obj; 701 int min_entries, i; 702 int all_per_second; 703 int errors_per_second; 704 int nodata_per_second; 705 int nxdomains_per_second; 706 int referrals_per_second; 707 int responses_per_second; 708 int slip; 709 710 if (voptions != NULL) { 711 cfg_map_get(voptions, "rate-limit", &map); 712 } 713 if (config != NULL && map == NULL) { 714 options = NULL; 715 cfg_map_get(config, "options", &options); 716 if (options != NULL) { 717 cfg_map_get(options, "rate-limit", &map); 718 } 719 } 720 if (map == NULL) { 721 return (ISC_R_SUCCESS); 722 } 723 724 min_entries = 500; 725 obj = NULL; 726 mresult = cfg_map_get(map, "min-table-size", &obj); 727 if (mresult == ISC_R_SUCCESS) { 728 min_entries = cfg_obj_asuint32(obj); 729 if (min_entries < 1) { 730 min_entries = 1; 731 } 732 } 733 734 obj = NULL; 735 mresult = cfg_map_get(map, "max-table-size", &obj); 736 if (mresult == ISC_R_SUCCESS) { 737 i = cfg_obj_asuint32(obj); 738 CHECK_RRL(i >= min_entries, 739 "max-table-size %d < min-table-size %d", i, 740 min_entries); 741 } 742 743 CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE, 744 "responses-per-second"); 745 746 CHECK_RRL_RATE(referrals_per_second, responses_per_second, 747 DNS_RRL_MAX_RATE, "referrals-per-second"); 748 CHECK_RRL_RATE(nodata_per_second, responses_per_second, 749 DNS_RRL_MAX_RATE, "nodata-per-second"); 750 CHECK_RRL_RATE(nxdomains_per_second, responses_per_second, 751 DNS_RRL_MAX_RATE, "nxdomains-per-second"); 752 CHECK_RRL_RATE(errors_per_second, responses_per_second, 753 DNS_RRL_MAX_RATE, "errors-per-second"); 754 755 CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second"); 756 757 CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip"); 758 759 obj = NULL; 760 mresult = cfg_map_get(map, "window", &obj); 761 if (mresult == ISC_R_SUCCESS) { 762 i = cfg_obj_asuint32(obj); 763 CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW, 764 "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW); 765 } 766 767 obj = NULL; 768 mresult = cfg_map_get(map, "qps-scale", &obj); 769 if (mresult == ISC_R_SUCCESS) { 770 i = cfg_obj_asuint32(obj); 771 CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, ""); 772 } 773 774 obj = NULL; 775 mresult = cfg_map_get(map, "ipv4-prefix-length", &obj); 776 if (mresult == ISC_R_SUCCESS) { 777 i = cfg_obj_asuint32(obj); 778 CHECK_RRL(i >= 8 && i <= 32, 779 "invalid 'ipv4-prefix-length %d'%s", i, ""); 780 } 781 782 obj = NULL; 783 mresult = cfg_map_get(map, "ipv6-prefix-length", &obj); 784 if (mresult == ISC_R_SUCCESS) { 785 i = cfg_obj_asuint32(obj); 786 CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX, 787 "ipv6-prefix-length %d < 16 or > %d", i, 788 DNS_RRL_MAX_PREFIX); 789 } 790 791 obj = NULL; 792 (void)cfg_map_get(map, "exempt-clients", &obj); 793 if (obj != NULL) { 794 dns_acl_t *acl = NULL; 795 isc_result_t tresult; 796 797 tresult = cfg_acl_fromconfig(obj, config, logctx, actx, mctx, 0, 798 &acl); 799 if (acl != NULL) { 800 dns_acl_detach(&acl); 801 } 802 if (result == ISC_R_SUCCESS) { 803 result = tresult; 804 } 805 } 806 807 return (result); 808} 809 810/* 811 * Check allow-recursion and allow-recursion-on acls, and also log a 812 * warning if they're inconsistent with the "recursion" option. 813 */ 814static isc_result_t 815check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, 816 const char *viewname, const cfg_obj_t *config, 817 isc_log_t *logctx, isc_mem_t *mctx) { 818 const cfg_obj_t *options, *aclobj, *obj = NULL; 819 dns_acl_t *acl = NULL; 820 isc_result_t result = ISC_R_SUCCESS, tresult; 821 bool recursion; 822 const char *forview = " for view "; 823 int i = 0; 824 825 static const char *acls[] = { "allow-recursion", "allow-recursion-on", 826 NULL }; 827 828 if (voptions != NULL) { 829 cfg_map_get(voptions, "recursion", &obj); 830 } 831 if (obj == NULL && config != NULL) { 832 options = NULL; 833 cfg_map_get(config, "options", &options); 834 if (options != NULL) { 835 cfg_map_get(options, "recursion", &obj); 836 } 837 } 838 if (obj == NULL) { 839 recursion = true; 840 } else { 841 recursion = cfg_obj_asboolean(obj); 842 } 843 844 if (viewname == NULL) { 845 viewname = ""; 846 forview = ""; 847 } 848 849 for (i = 0; acls[i] != NULL; i++) { 850 aclobj = options = NULL; 851 acl = NULL; 852 853 if (voptions != NULL) { 854 cfg_map_get(voptions, acls[i], &aclobj); 855 } 856 if (config != NULL && aclobj == NULL) { 857 options = NULL; 858 cfg_map_get(config, "options", &options); 859 if (options != NULL) { 860 cfg_map_get(options, acls[i], &aclobj); 861 } 862 } 863 if (aclobj == NULL) { 864 continue; 865 } 866 867 tresult = cfg_acl_fromconfig(aclobj, config, logctx, actx, mctx, 868 0, &acl); 869 870 if (tresult != ISC_R_SUCCESS) { 871 result = tresult; 872 } 873 874 if (acl == NULL) { 875 continue; 876 } 877 878 if (!recursion && !dns_acl_isnone(acl)) { 879 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING, 880 "both \"recursion no;\" and " 881 "\"%s\" active%s%s", 882 acls[i], forview, viewname); 883 } 884 885 if (acl != NULL) { 886 dns_acl_detach(&acl); 887 } 888 } 889 890 return (result); 891} 892 893typedef struct { 894 const char *name; 895 unsigned int scale; 896 unsigned int max; 897} intervaltable; 898 899#ifdef HAVE_DNSTAP 900typedef struct { 901 const char *name; 902 unsigned int min; 903 unsigned int max; 904} fstrmtable; 905#endif /* ifdef HAVE_DNSTAP */ 906 907typedef enum { 908 optlevel_config, 909 optlevel_options, 910 optlevel_view, 911 optlevel_zone 912} optlevel_t; 913 914static isc_result_t 915check_name(const char *str) { 916 dns_fixedname_t fixed; 917 918 dns_fixedname_init(&fixed); 919 return (dns_name_fromstring(dns_fixedname_name(&fixed), str, 0, NULL)); 920} 921 922static bool 923kasp_name_allowed(const cfg_listelt_t *element) { 924 const char *name = cfg_obj_asstring( 925 cfg_tuple_get(cfg_listelt_value(element), "name")); 926 927 if (strcmp("none", name) == 0) { 928 return (false); 929 } 930 if (strcmp("default", name) == 0) { 931 return (false); 932 } 933 if (strcmp("insecure", name) == 0) { 934 return (false); 935 } 936 return (true); 937} 938 939static const cfg_obj_t * 940find_maplist(const cfg_obj_t *config, const char *listname, const char *name) { 941 isc_result_t result; 942 const cfg_obj_t *maplist = NULL; 943 const cfg_listelt_t *elt = NULL; 944 945 REQUIRE(config != NULL); 946 REQUIRE(name != NULL); 947 948 result = cfg_map_get(config, listname, &maplist); 949 if (result != ISC_R_SUCCESS) { 950 return (NULL); 951 } 952 953 for (elt = cfg_list_first(maplist); elt != NULL; 954 elt = cfg_list_next(elt)) 955 { 956 const cfg_obj_t *map = cfg_listelt_value(elt); 957 if (strcasecmp(cfg_obj_asstring(cfg_map_getname(map)), name) == 958 0) 959 { 960 return (map); 961 } 962 } 963 964 return (NULL); 965} 966 967static isc_result_t 968check_listener(const cfg_obj_t *listener, const cfg_obj_t *config, 969 cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx) { 970 isc_result_t tresult, result = ISC_R_SUCCESS; 971 const cfg_obj_t *ltup = NULL; 972 const cfg_obj_t *tlsobj = NULL, *httpobj = NULL; 973 const cfg_obj_t *portobj = NULL; 974 const cfg_obj_t *http_server = NULL; 975 bool do_tls = false, no_tls = false; 976 dns_acl_t *acl = NULL; 977 978 ltup = cfg_tuple_get(listener, "tuple"); 979 RUNTIME_CHECK(ltup != NULL); 980 981 tlsobj = cfg_tuple_get(ltup, "tls"); 982 if (tlsobj != NULL && cfg_obj_isstring(tlsobj)) { 983 const char *tlsname = cfg_obj_asstring(tlsobj); 984 985 if (strcasecmp(tlsname, "none") == 0) { 986 no_tls = true; 987 } else if (strcasecmp(tlsname, "ephemeral") == 0) { 988 do_tls = true; 989 } else { 990 const cfg_obj_t *tlsmap = NULL; 991 992 do_tls = true; 993 994 tlsmap = find_maplist(config, "tls", tlsname); 995 if (tlsmap == NULL) { 996 cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, 997 "tls '%s' is not defined", 998 cfg_obj_asstring(tlsobj)); 999 result = ISC_R_FAILURE; 1000 } 1001 } 1002 } 1003 1004 httpobj = cfg_tuple_get(ltup, "http"); 1005 if (httpobj != NULL && cfg_obj_isstring(httpobj)) { 1006 const char *httpname = cfg_obj_asstring(httpobj); 1007 1008 if (!do_tls && !no_tls) { 1009 cfg_obj_log(httpobj, logctx, ISC_LOG_ERROR, 1010 "http must specify a 'tls' " 1011 "statement, 'tls ephemeral', or " 1012 "'tls none'"); 1013 result = ISC_R_FAILURE; 1014 } 1015 1016 http_server = find_maplist(config, "http", httpname); 1017 if (http_server == NULL && strcasecmp(httpname, "default") != 0) 1018 { 1019 cfg_obj_log(httpobj, logctx, ISC_LOG_ERROR, 1020 "http '%s' is not defined", 1021 cfg_obj_asstring(httpobj)); 1022 result = ISC_R_FAILURE; 1023 } 1024 } 1025 1026 portobj = cfg_tuple_get(ltup, "port"); 1027 if (cfg_obj_isuint32(portobj) && 1028 cfg_obj_asuint32(portobj) >= UINT16_MAX) 1029 { 1030 cfg_obj_log(portobj, logctx, ISC_LOG_ERROR, 1031 "port value '%u' is out of range", 1032 1033 cfg_obj_asuint32(portobj)); 1034 if (result == ISC_R_SUCCESS) { 1035 result = ISC_R_RANGE; 1036 } 1037 } 1038 1039 tresult = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), config, 1040 logctx, actx, mctx, 0, &acl); 1041 if (result == ISC_R_SUCCESS) { 1042 result = tresult; 1043 } 1044 1045 if (acl != NULL) { 1046 dns_acl_detach(&acl); 1047 } 1048 1049 return (result); 1050} 1051 1052static isc_result_t 1053check_listeners(const cfg_obj_t *list, const cfg_obj_t *config, 1054 cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx) { 1055 isc_result_t tresult, result = ISC_R_SUCCESS; 1056 const cfg_listelt_t *elt = NULL; 1057 1058 for (elt = cfg_list_first(list); elt != NULL; elt = cfg_list_next(elt)) 1059 { 1060 const cfg_obj_t *obj = cfg_listelt_value(elt); 1061 tresult = check_listener(obj, config, actx, logctx, mctx); 1062 if (result == ISC_R_SUCCESS) { 1063 result = tresult; 1064 } 1065 } 1066 1067 return (result); 1068} 1069 1070static isc_result_t 1071check_port(const cfg_obj_t *options, isc_log_t *logctx, const char *type, 1072 in_port_t *portp) { 1073 const cfg_obj_t *portobj = NULL; 1074 isc_result_t result; 1075 1076 result = cfg_map_get(options, type, &portobj); 1077 if (result != ISC_R_SUCCESS) { 1078 return (ISC_R_SUCCESS); 1079 } 1080 1081 if (cfg_obj_asuint32(portobj) >= UINT16_MAX) { 1082 cfg_obj_log(portobj, logctx, ISC_LOG_ERROR, 1083 "port '%u' out of range", 1084 cfg_obj_asuint32(portobj)); 1085 return (ISC_R_RANGE); 1086 } 1087 1088 if (portp != NULL) { 1089 *portp = (in_port_t)cfg_obj_asuint32(portobj); 1090 } 1091 return (ISC_R_SUCCESS); 1092} 1093 1094static isc_result_t 1095check_options(const cfg_obj_t *options, const cfg_obj_t *config, 1096 isc_log_t *logctx, isc_mem_t *mctx, optlevel_t optlevel) { 1097 isc_result_t result = ISC_R_SUCCESS; 1098 isc_result_t tresult; 1099 unsigned int i; 1100 const cfg_obj_t *obj = NULL; 1101 const cfg_obj_t *resignobj = NULL; 1102 const cfg_listelt_t *element; 1103 isc_symtab_t *symtab = NULL; 1104 const char *str; 1105 isc_buffer_t b; 1106 uint32_t lifetime = 3600; 1107 bool has_dnssecpolicy = false; 1108 const char *ccalg = "siphash24"; 1109 cfg_aclconfctx_t *actx = NULL; 1110 static const char *sources[] = { 1111 "query-source", 1112 "query-source-v6", 1113 }; 1114 1115 /* 1116 * { "name", scale, value } 1117 * (scale * value) <= UINT32_MAX 1118 */ 1119 static intervaltable intervals[] = { 1120 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */ 1121 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */ 1122 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */ 1123 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */ 1124 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */ 1125 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */ 1126 1127 /* minimum and maximum cache and negative cache TTLs */ 1128 { "min-cache-ttl", 1, MAX_MIN_CACHE_TTL }, /* 90 secs */ 1129 { "max-cache-ttl", 1, UINT32_MAX }, /* no limit */ 1130 { "min-ncache-ttl", 1, MAX_MIN_NCACHE_TTL }, /* 90 secs */ 1131 { "max-ncache-ttl", 1, MAX_MAX_NCACHE_TTL }, /* 7 days */ 1132 }; 1133 1134 static const char *server_contact[] = { "empty-server", "empty-contact", 1135 "dns64-server", "dns64-contact", 1136 NULL }; 1137 1138#ifdef HAVE_DNSTAP 1139 static fstrmtable fstrm[] = { 1140 { "fstrm-set-buffer-hint", FSTRM_IOTHR_BUFFER_HINT_MIN, 1141 FSTRM_IOTHR_BUFFER_HINT_MAX }, 1142 { "fstrm-set-flush-timeout", FSTRM_IOTHR_FLUSH_TIMEOUT_MIN, 1143 FSTRM_IOTHR_FLUSH_TIMEOUT_MAX }, 1144 { "fstrm-set-input-queue-size", 1145 FSTRM_IOTHR_INPUT_QUEUE_SIZE_MIN, 1146 FSTRM_IOTHR_INPUT_QUEUE_SIZE_MAX }, 1147 { "fstrm-set-output-notify-threshold", 1148 FSTRM_IOTHR_QUEUE_NOTIFY_THRESHOLD_MIN, 0 }, 1149 { "fstrm-set-output-queue-size", 1150 FSTRM_IOTHR_OUTPUT_QUEUE_SIZE_MIN, 1151 FSTRM_IOTHR_OUTPUT_QUEUE_SIZE_MAX }, 1152 { "fstrm-set-reopen-interval", FSTRM_IOTHR_REOPEN_INTERVAL_MIN, 1153 FSTRM_IOTHR_REOPEN_INTERVAL_MAX } 1154 }; 1155#endif /* ifdef HAVE_DNSTAP */ 1156 1157 if (optlevel == optlevel_options) { 1158 /* 1159 * Check port values, and record "port" for later use. 1160 */ 1161 tresult = check_port(options, logctx, "port", &dnsport); 1162 if (tresult != ISC_R_SUCCESS) { 1163 result = tresult; 1164 } 1165 tresult = check_port(options, logctx, "tls-port", NULL); 1166 if (tresult != ISC_R_SUCCESS) { 1167 result = tresult; 1168 } 1169 tresult = check_port(options, logctx, "http-port", NULL); 1170 if (tresult != ISC_R_SUCCESS) { 1171 result = tresult; 1172 } 1173 tresult = check_port(options, logctx, "https-port", NULL); 1174 if (tresult != ISC_R_SUCCESS) { 1175 result = tresult; 1176 } 1177 } 1178 1179 if (optlevel == optlevel_options || optlevel == optlevel_view) { 1180 /* 1181 * Warn if query-source or query-source-v6 options specify 1182 * a port, and fail if they specify the DNS port. 1183 */ 1184 for (i = 0; i < ARRAY_SIZE(sources); i++) { 1185 obj = NULL; 1186 (void)cfg_map_get(options, sources[i], &obj); 1187 if (obj != NULL) { 1188 const isc_sockaddr_t *sa = 1189 cfg_obj_assockaddr(obj); 1190 in_port_t port = isc_sockaddr_getport(sa); 1191 if (port == dnsport) { 1192 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1193 "'%s' cannot specify the " 1194 "DNS listener port (%d)", 1195 sources[i], port); 1196 result = ISC_R_FAILURE; 1197 } else if (port != 0) { 1198 cfg_obj_log(obj, logctx, 1199 ISC_LOG_WARNING, 1200 "'%s': specifying a port " 1201 "is not recommended", 1202 sources[i]); 1203 } 1204 } 1205 } 1206 } 1207 1208 /* 1209 * Check that fields specified in units of time other than seconds 1210 * have reasonable values. 1211 */ 1212 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) { 1213 uint32_t val; 1214 obj = NULL; 1215 (void)cfg_map_get(options, intervals[i].name, &obj); 1216 if (obj == NULL) { 1217 continue; 1218 } 1219 if (cfg_obj_isduration(obj)) { 1220 val = cfg_obj_asduration(obj); 1221 } else { 1222 val = cfg_obj_asuint32(obj); 1223 } 1224 if (val > intervals[i].max) { 1225 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1226 "%s '%u' is out of range (0..%u)", 1227 intervals[i].name, val, intervals[i].max); 1228 result = ISC_R_RANGE; 1229 } else if (val > (UINT32_MAX / intervals[i].scale)) { 1230 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1231 "%s '%d' is out of range", 1232 intervals[i].name, val); 1233 result = ISC_R_RANGE; 1234 } 1235 } 1236 1237 /* 1238 * Check dnssec-policy. 1239 */ 1240 obj = NULL; 1241 (void)cfg_map_get(options, "dnssec-policy", &obj); 1242 if (obj != NULL) { 1243 bool bad_kasp = false; 1244 bool bad_name = false; 1245 1246 if (optlevel != optlevel_config && !cfg_obj_isstring(obj)) { 1247 bad_kasp = true; 1248 } else if (optlevel == optlevel_config) { 1249 dns_kasplist_t list; 1250 dns_kasp_t *kasp = NULL, *kasp_next = NULL; 1251 1252 ISC_LIST_INIT(list); 1253 1254 if (cfg_obj_islist(obj)) { 1255 for (element = cfg_list_first(obj); 1256 element != NULL; 1257 element = cfg_list_next(element)) 1258 { 1259 isc_result_t ret; 1260 cfg_obj_t *kconfig = 1261 cfg_listelt_value(element); 1262 1263 if (!cfg_obj_istuple(kconfig)) { 1264 bad_kasp = true; 1265 continue; 1266 } 1267 if (!kasp_name_allowed(element)) { 1268 bad_name = true; 1269 continue; 1270 } 1271 1272 ret = cfg_kasp_fromconfig(kconfig, NULL, 1273 mctx, logctx, 1274 &list, &kasp); 1275 if (ret != ISC_R_SUCCESS) { 1276 if (result == ISC_R_SUCCESS) { 1277 result = ret; 1278 } 1279 } 1280 1281 if (kasp != NULL) { 1282 dns_kasp_detach(&kasp); 1283 } 1284 } 1285 } 1286 1287 for (kasp = ISC_LIST_HEAD(list); kasp != NULL; 1288 kasp = kasp_next) 1289 { 1290 kasp_next = ISC_LIST_NEXT(kasp, link); 1291 ISC_LIST_UNLINK(list, kasp, link); 1292 dns_kasp_detach(&kasp); 1293 } 1294 } 1295 1296 if (bad_kasp) { 1297 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1298 "dnssec-policy may only be configured at " 1299 "the top level, please use name reference " 1300 "at the zone level"); 1301 if (result == ISC_R_SUCCESS) { 1302 result = ISC_R_FAILURE; 1303 } 1304 } else if (bad_name) { 1305 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1306 "dnssec-policy name may not be 'insecure', " 1307 "'none', or 'default' (which are built-in " 1308 "policies)"); 1309 if (result == ISC_R_SUCCESS) { 1310 result = ISC_R_FAILURE; 1311 } 1312 } else { 1313 has_dnssecpolicy = true; 1314 } 1315 } 1316 1317 obj = NULL; 1318 cfg_map_get(options, "max-rsa-exponent-size", &obj); 1319 if (obj != NULL) { 1320 uint32_t val; 1321 1322 val = cfg_obj_asuint32(obj); 1323 if (val != 0 && (val < 35 || val > 4096)) { 1324 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1325 "max-rsa-exponent-size '%u' is out of " 1326 "range (35..4096)", 1327 val); 1328 result = ISC_R_RANGE; 1329 } 1330 } 1331 1332 obj = NULL; 1333 cfg_map_get(options, "sig-validity-interval", &obj); 1334 if (obj != NULL) { 1335 uint32_t validity, resign = 0; 1336 1337 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity")); 1338 resignobj = cfg_tuple_get(obj, "re-sign"); 1339 if (!cfg_obj_isvoid(resignobj)) { 1340 resign = cfg_obj_asuint32(resignobj); 1341 } 1342 1343 if (validity > 3660 || validity == 0) { /* 10 years */ 1344 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1345 "%s '%u' is out of range (1..3660)", 1346 "sig-validity-interval", validity); 1347 result = ISC_R_RANGE; 1348 } 1349 1350 if (!cfg_obj_isvoid(resignobj)) { 1351 if (resign > 3660 || resign == 0) { /* 10 years */ 1352 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1353 "%s '%u' is out of range (1..3660)", 1354 "sig-validity-interval (re-sign)", 1355 validity); 1356 result = ISC_R_RANGE; 1357 } else if ((validity > 7 && validity < resign) || 1358 (validity <= 7 && validity * 24 < resign)) 1359 { 1360 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1361 "validity interval (%u days) " 1362 "less than re-signing interval " 1363 "(%u %s)", 1364 validity, resign, 1365 (validity > 7) ? "days" : "hours"); 1366 result = ISC_R_RANGE; 1367 } 1368 } 1369 1370 if (has_dnssecpolicy) { 1371 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1372 "sig-validity-interval: cannot be " 1373 "configured if dnssec-policy is also set"); 1374 result = ISC_R_FAILURE; 1375 } 1376 } 1377 1378 obj = NULL; 1379 cfg_map_get(options, "dnskey-sig-validity", &obj); 1380 if (obj != NULL) { 1381 uint32_t keyvalidity; 1382 1383 keyvalidity = cfg_obj_asuint32(obj); 1384 if (keyvalidity > 3660) { /* 10 years */ 1385 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1386 "%s '%u' is out of range (0..3660)", 1387 "dnskey-sig-validity", keyvalidity); 1388 result = ISC_R_RANGE; 1389 } 1390 1391 if (has_dnssecpolicy) { 1392 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1393 "dnskey-sig-validity: cannot be " 1394 "configured if dnssec-policy is also set"); 1395 result = ISC_R_FAILURE; 1396 } 1397 } 1398 1399 obj = NULL; 1400 (void)cfg_map_get(options, "preferred-glue", &obj); 1401 if (obj != NULL) { 1402 str = cfg_obj_asstring(obj); 1403 if (strcasecmp(str, "a") != 0 && strcasecmp(str, "aaaa") != 0 && 1404 strcasecmp(str, "none") != 0) 1405 { 1406 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1407 "preferred-glue unexpected value '%s'", 1408 str); 1409 } 1410 } 1411 1412 obj = NULL; 1413 (void)cfg_map_get(options, "root-delegation-only", &obj); 1414 if (obj != NULL) { 1415 if (!cfg_obj_isvoid(obj)) { 1416 for (element = cfg_list_first(obj); element != NULL; 1417 element = cfg_list_next(element)) 1418 { 1419 const cfg_obj_t *exclude; 1420 1421 exclude = cfg_listelt_value(element); 1422 str = cfg_obj_asstring(exclude); 1423 tresult = check_name(str); 1424 if (tresult != ISC_R_SUCCESS) { 1425 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1426 "bad domain name '%s'", 1427 str); 1428 result = tresult; 1429 } 1430 } 1431 } 1432 } 1433 1434 /* 1435 * Set supported DNSSEC algorithms. 1436 */ 1437 obj = NULL; 1438 (void)cfg_map_get(options, "disable-algorithms", &obj); 1439 if (obj != NULL) { 1440 for (element = cfg_list_first(obj); element != NULL; 1441 element = cfg_list_next(element)) 1442 { 1443 obj = cfg_listelt_value(element); 1444 tresult = disabled_algorithms(obj, logctx); 1445 if (tresult != ISC_R_SUCCESS) { 1446 result = tresult; 1447 } 1448 } 1449 } 1450 1451 /* 1452 * Set supported DS digest types. 1453 */ 1454 obj = NULL; 1455 (void)cfg_map_get(options, "disable-ds-digests", &obj); 1456 if (obj != NULL) { 1457 for (element = cfg_list_first(obj); element != NULL; 1458 element = cfg_list_next(element)) 1459 { 1460 obj = cfg_listelt_value(element); 1461 tresult = disabled_ds_digests(obj, logctx); 1462 if (tresult != ISC_R_SUCCESS) { 1463 result = tresult; 1464 } 1465 } 1466 } 1467 1468 /* 1469 * Check auto-dnssec at the view/options level 1470 */ 1471 obj = NULL; 1472 (void)cfg_map_get(options, "auto-dnssec", &obj); 1473 if (obj != NULL) { 1474 const char *arg = cfg_obj_asstring(obj); 1475 if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) { 1476 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1477 "auto-dnssec may only be activated at the " 1478 "zone level"); 1479 if (result == ISC_R_SUCCESS) { 1480 result = ISC_R_FAILURE; 1481 } 1482 } 1483 } 1484 1485 /* 1486 * Check dnssec-must-be-secure. 1487 */ 1488 obj = NULL; 1489 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj); 1490 if (obj != NULL) { 1491 tresult = isc_symtab_create(mctx, 100, freekey, mctx, false, 1492 &symtab); 1493 if (tresult != ISC_R_SUCCESS) { 1494 result = tresult; 1495 } else { 1496 for (element = cfg_list_first(obj); element != NULL; 1497 element = cfg_list_next(element)) 1498 { 1499 obj = cfg_listelt_value(element); 1500 tresult = mustbesecure(obj, symtab, logctx, 1501 mctx); 1502 if (result == ISC_R_SUCCESS && 1503 tresult != ISC_R_SUCCESS) 1504 { 1505 result = tresult; 1506 } 1507 } 1508 } 1509 if (symtab != NULL) { 1510 isc_symtab_destroy(&symtab); 1511 } 1512 } 1513 1514 /* 1515 * Check server/contacts for syntactic validity. 1516 */ 1517 for (i = 0; server_contact[i] != NULL; i++) { 1518 obj = NULL; 1519 (void)cfg_map_get(options, server_contact[i], &obj); 1520 if (obj != NULL) { 1521 str = cfg_obj_asstring(obj); 1522 if (check_name(str) != ISC_R_SUCCESS) { 1523 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1524 "%s: invalid name '%s'", 1525 server_contact[i], str); 1526 if (result == ISC_R_SUCCESS) { 1527 result = ISC_R_FAILURE; 1528 } 1529 } 1530 } 1531 } 1532 1533 /* 1534 * Check empty zone configuration. 1535 */ 1536 obj = NULL; 1537 (void)cfg_map_get(options, "disable-empty-zone", &obj); 1538 for (element = cfg_list_first(obj); element != NULL; 1539 element = cfg_list_next(element)) 1540 { 1541 obj = cfg_listelt_value(element); 1542 str = cfg_obj_asstring(obj); 1543 if (check_name(str) != ISC_R_SUCCESS) { 1544 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1545 "disable-empty-zone: invalid name '%s'", 1546 str); 1547 if (result == ISC_R_SUCCESS) { 1548 result = ISC_R_FAILURE; 1549 } 1550 } 1551 } 1552 1553 /* 1554 * Check that server-id is not too long. 1555 * 1024 bytes should be big enough. 1556 */ 1557 obj = NULL; 1558 (void)cfg_map_get(options, "server-id", &obj); 1559 if (obj != NULL && cfg_obj_isstring(obj) && 1560 strlen(cfg_obj_asstring(obj)) > 1024U) 1561 { 1562 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1563 "'server-id' too big (>1024 bytes)"); 1564 if (result == ISC_R_SUCCESS) { 1565 result = ISC_R_FAILURE; 1566 } 1567 } 1568 1569 obj = NULL; 1570 (void)cfg_map_get(options, "nta-lifetime", &obj); 1571 if (obj != NULL) { 1572 lifetime = cfg_obj_asduration(obj); 1573 if (lifetime > 604800) { /* 7 days */ 1574 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1575 "'nta-lifetime' cannot exceed one week"); 1576 if (result == ISC_R_SUCCESS) { 1577 result = ISC_R_RANGE; 1578 } 1579 } else if (lifetime == 0) { 1580 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1581 "'nta-lifetime' may not be zero"); 1582 if (result == ISC_R_SUCCESS) { 1583 result = ISC_R_RANGE; 1584 } 1585 } 1586 } 1587 1588 obj = NULL; 1589 (void)cfg_map_get(options, "nta-recheck", &obj); 1590 if (obj != NULL) { 1591 uint32_t recheck = cfg_obj_asduration(obj); 1592 if (recheck > 604800) { /* 7 days */ 1593 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1594 "'nta-recheck' cannot exceed one week"); 1595 if (result == ISC_R_SUCCESS) { 1596 result = ISC_R_RANGE; 1597 } 1598 } 1599 1600 if (recheck > lifetime) { 1601 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 1602 "'nta-recheck' (%d seconds) is " 1603 "greater than 'nta-lifetime' " 1604 "(%d seconds)", 1605 recheck, lifetime); 1606 } 1607 } 1608 1609 obj = NULL; 1610 (void)cfg_map_get(options, "cookie-algorithm", &obj); 1611 if (obj != NULL) { 1612 ccalg = cfg_obj_asstring(obj); 1613 if (strcasecmp(ccalg, "aes") == 0) { 1614 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 1615 "cookie-algorithm 'aes' is deprecated"); 1616 } 1617 } 1618 1619 obj = NULL; 1620 (void)cfg_map_get(options, "cookie-secret", &obj); 1621 if (obj != NULL) { 1622 unsigned char secret[32]; 1623 1624 for (element = cfg_list_first(obj); element != NULL; 1625 element = cfg_list_next(element)) 1626 { 1627 unsigned int usedlength; 1628 1629 obj = cfg_listelt_value(element); 1630 str = cfg_obj_asstring(obj); 1631 1632 memset(secret, 0, sizeof(secret)); 1633 isc_buffer_init(&b, secret, sizeof(secret)); 1634 tresult = isc_hex_decodestring(str, &b); 1635 if (tresult == ISC_R_NOSPACE) { 1636 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1637 "cookie-secret: too long"); 1638 } else if (tresult != ISC_R_SUCCESS) { 1639 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1640 "cookie-secret: invalid hex " 1641 "string"); 1642 } 1643 if (tresult != ISC_R_SUCCESS) { 1644 if (result == ISC_R_SUCCESS) { 1645 result = tresult; 1646 } 1647 continue; 1648 } 1649 1650 usedlength = isc_buffer_usedlength(&b); 1651 if (strcasecmp(ccalg, "aes") == 0 && 1652 usedlength != ISC_AES128_KEYLENGTH) 1653 { 1654 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1655 "AES cookie-secret must be 128 " 1656 "bits"); 1657 if (result == ISC_R_SUCCESS) { 1658 result = ISC_R_RANGE; 1659 } 1660 } 1661 if (strcasecmp(ccalg, "siphash24") == 0 && 1662 usedlength != ISC_SIPHASH24_KEY_LENGTH) 1663 { 1664 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1665 "SipHash-2-4 cookie-secret must be " 1666 "128 bits"); 1667 if (result == ISC_R_SUCCESS) { 1668 result = ISC_R_RANGE; 1669 } 1670 } 1671 } 1672 } 1673 1674#ifdef HAVE_DNSTAP 1675 for (i = 0; i < sizeof(fstrm) / sizeof(fstrm[0]); i++) { 1676 uint32_t value; 1677 1678 obj = NULL; 1679 (void)cfg_map_get(options, fstrm[i].name, &obj); 1680 if (obj == NULL) { 1681 continue; 1682 } 1683 1684 if (cfg_obj_isduration(obj)) { 1685 value = cfg_obj_asduration(obj); 1686 } else { 1687 value = cfg_obj_asuint32(obj); 1688 } 1689 if (value < fstrm[i].min || 1690 (fstrm[i].max != 0U && value > fstrm[i].max)) 1691 { 1692 if (fstrm[i].max != 0U) { 1693 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1694 "%s '%u' out of range (%u..%u)", 1695 fstrm[i].name, value, fstrm[i].min, 1696 fstrm[i].max); 1697 } else { 1698 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1699 "%s out of range (%u < %u)", 1700 fstrm[i].name, value, fstrm[i].min); 1701 } 1702 if (result == ISC_R_SUCCESS) { 1703 result = ISC_R_RANGE; 1704 } 1705 } 1706 1707 if (strcmp(fstrm[i].name, "fstrm-set-input-queue-size") == 0) { 1708 int bits = 0; 1709 do { 1710 bits += value & 0x1; 1711 value >>= 1; 1712 } while (value != 0U); 1713 if (bits != 1) { 1714 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1715 "%s '%u' not a power-of-2", 1716 fstrm[i].name, 1717 cfg_obj_asuint32(obj)); 1718 if (result == ISC_R_SUCCESS) { 1719 result = ISC_R_RANGE; 1720 } 1721 } 1722 } 1723 } 1724 1725 /* Check that dnstap-ouput values are consistent */ 1726 obj = NULL; 1727 (void)cfg_map_get(options, "dnstap-output", &obj); 1728 if (obj != NULL) { 1729 const cfg_obj_t *obj2; 1730 dns_dtmode_t dmode; 1731 1732 obj2 = cfg_tuple_get(obj, "mode"); 1733 if (obj2 == NULL) { 1734 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1735 "dnstap-output mode not found"); 1736 if (result == ISC_R_SUCCESS) { 1737 result = ISC_R_FAILURE; 1738 } 1739 } else { 1740 if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0) { 1741 dmode = dns_dtmode_file; 1742 } else { 1743 dmode = dns_dtmode_unix; 1744 } 1745 1746 obj2 = cfg_tuple_get(obj, "size"); 1747 if (obj2 != NULL && !cfg_obj_isvoid(obj2) && 1748 dmode == dns_dtmode_unix) 1749 { 1750 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1751 "dnstap-output size " 1752 "cannot be set with mode unix"); 1753 if (result == ISC_R_SUCCESS) { 1754 result = ISC_R_FAILURE; 1755 } 1756 } 1757 1758 obj2 = cfg_tuple_get(obj, "versions"); 1759 if (obj2 != NULL && !cfg_obj_isvoid(obj2) && 1760 dmode == dns_dtmode_unix) 1761 { 1762 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1763 "dnstap-output versions " 1764 "cannot be set with mode unix"); 1765 if (result == ISC_R_SUCCESS) { 1766 result = ISC_R_FAILURE; 1767 } 1768 } 1769 1770 obj2 = cfg_tuple_get(obj, "suffix"); 1771 if (obj2 != NULL && !cfg_obj_isvoid(obj2) && 1772 dmode == dns_dtmode_unix) 1773 { 1774 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1775 "dnstap-output suffix " 1776 "cannot be set with mode unix"); 1777 if (result == ISC_R_SUCCESS) { 1778 result = ISC_R_FAILURE; 1779 } 1780 } 1781 } 1782 } 1783#endif /* ifdef HAVE_DNSTAP */ 1784 1785 obj = NULL; 1786 (void)cfg_map_get(options, "lmdb-mapsize", &obj); 1787 if (obj != NULL) { 1788 uint64_t mapsize = cfg_obj_asuint64(obj); 1789 1790 if (mapsize < (1ULL << 20)) { /* 1 megabyte */ 1791 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1792 "'lmdb-mapsize " 1793 "%" PRId64 "' " 1794 "is too small", 1795 mapsize); 1796 if (result == ISC_R_SUCCESS) { 1797 result = ISC_R_RANGE; 1798 } 1799 } else if (mapsize > (1ULL << 40)) { /* 1 terabyte */ 1800 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1801 "'lmdb-mapsize " 1802 "%" PRId64 "' " 1803 "is too large", 1804 mapsize); 1805 if (result == ISC_R_SUCCESS) { 1806 result = ISC_R_RANGE; 1807 } 1808 } 1809 } 1810 1811 obj = NULL; 1812 (void)cfg_map_get(options, "resolver-nonbackoff-tries", &obj); 1813 if (obj != NULL && cfg_obj_asuint32(obj) == 0U) { 1814 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1815 "'resolver-nonbackoff-tries' must be >= 1"); 1816 if (result == ISC_R_SUCCESS) { 1817 result = ISC_R_RANGE; 1818 } 1819 } 1820 1821 obj = NULL; 1822 (void)cfg_map_get(options, "max-ixfr-ratio", &obj); 1823 if (obj != NULL && cfg_obj_ispercentage(obj)) { 1824 uint32_t percent = cfg_obj_aspercentage(obj); 1825 if (percent == 0) { 1826 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1827 "'ixfr-max-ratio' must be a nonzero " 1828 "percentage or 'unlimited')"); 1829 if (result == ISC_R_SUCCESS) { 1830 result = ISC_R_RANGE; 1831 } 1832 } else if (percent > 100) { 1833 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 1834 "'ixfr-max-ratio %d%%' exceeds 100%%", 1835 percent); 1836 } 1837 } 1838 1839 obj = NULL; 1840 (void)cfg_map_get(options, "check-names", &obj); 1841 if (obj != NULL && !cfg_obj_islist(obj)) { 1842 obj = NULL; 1843 } 1844 if (obj != NULL) { 1845 /* Note: SEC is defined in <sys/time.h> on some platforms. */ 1846 enum { MAS = 1, PRI = 2, SLA = 4, SCN = 8 } values = 0; 1847 for (const cfg_listelt_t *el = cfg_list_first(obj); el != NULL; 1848 el = cfg_list_next(el)) 1849 { 1850 const cfg_obj_t *tuple = cfg_listelt_value(el); 1851 const cfg_obj_t *type = cfg_tuple_get(tuple, "type"); 1852 const char *keyword = cfg_obj_asstring(type); 1853 if (strcasecmp(keyword, "primary") == 0) { 1854 if ((values & PRI) == PRI) { 1855 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1856 "'check-names primary' " 1857 "duplicated"); 1858 if (result == ISC_R_SUCCESS) { 1859 result = ISC_R_FAILURE; 1860 } 1861 } 1862 values |= PRI; 1863 } else if (strcasecmp(keyword, "master") == 0) { 1864 if ((values & MAS) == MAS) { 1865 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1866 "'check-names master' " 1867 "duplicated"); 1868 if (result == ISC_R_SUCCESS) { 1869 result = ISC_R_FAILURE; 1870 } 1871 } 1872 values |= MAS; 1873 } else if (strcasecmp(keyword, "secondary") == 0) { 1874 if ((values & SCN) == SCN) { 1875 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1876 "'check-names secondary' " 1877 "duplicated"); 1878 if (result == ISC_R_SUCCESS) { 1879 result = ISC_R_FAILURE; 1880 } 1881 } 1882 values |= SCN; 1883 } else if (strcasecmp(keyword, "slave") == 0) { 1884 if ((values & SLA) == SLA) { 1885 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1886 "'check-names slave' " 1887 "duplicated"); 1888 if (result == ISC_R_SUCCESS) { 1889 result = ISC_R_FAILURE; 1890 } 1891 } 1892 values |= SLA; 1893 } 1894 } 1895 1896 if ((values & (PRI | MAS)) == (PRI | MAS)) { 1897 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1898 "'check-names' cannot take both " 1899 "'primary' and 'master'"); 1900 if (result == ISC_R_SUCCESS) { 1901 result = ISC_R_FAILURE; 1902 } 1903 } 1904 1905 if ((values & (SCN | SLA)) == (SCN | SLA)) { 1906 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1907 "'check-names' cannot take both " 1908 "'secondary' and 'slave'"); 1909 if (result == ISC_R_SUCCESS) { 1910 result = ISC_R_FAILURE; 1911 } 1912 } 1913 } 1914 1915 obj = NULL; 1916 (void)cfg_map_get(options, "stale-refresh-time", &obj); 1917 if (obj != NULL) { 1918 uint32_t refresh_time = cfg_obj_asduration(obj); 1919 if (refresh_time > 0 && refresh_time < 30) { 1920 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 1921 "'stale-refresh-time' should either be 0 " 1922 "or otherwise 30 seconds or higher"); 1923 } 1924 } 1925 1926 cfg_aclconfctx_create(mctx, &actx); 1927 1928 obj = NULL; 1929 (void)cfg_map_get(options, "listen-on", &obj); 1930 if (obj != NULL) { 1931 INSIST(config != NULL); 1932 tresult = check_listeners(obj, config, actx, logctx, mctx); 1933 if (result == ISC_R_SUCCESS) { 1934 result = tresult; 1935 } 1936 } 1937 1938 obj = NULL; 1939 (void)cfg_map_get(options, "listen-on-v6", &obj); 1940 if (obj != NULL) { 1941 INSIST(config != NULL); 1942 tresult = check_listeners(obj, config, actx, logctx, mctx); 1943 if (result == ISC_R_SUCCESS) { 1944 result = tresult; 1945 } 1946 } 1947 1948 if (actx != NULL) { 1949 cfg_aclconfctx_detach(&actx); 1950 } 1951 1952 return (result); 1953} 1954 1955/* 1956 * Check "remote-servers" style list. 1957 */ 1958static isc_result_t 1959bind9_check_remoteserverlist(const cfg_obj_t *cctx, const char *list, 1960 isc_log_t *logctx, isc_symtab_t *symtab, 1961 isc_mem_t *mctx) { 1962 isc_symvalue_t symvalue; 1963 isc_result_t result, tresult; 1964 const cfg_obj_t *obj = NULL; 1965 const cfg_listelt_t *elt; 1966 1967 result = cfg_map_get(cctx, list, &obj); 1968 if (result != ISC_R_SUCCESS) { 1969 return (ISC_R_SUCCESS); 1970 } 1971 1972 elt = cfg_list_first(obj); 1973 while (elt != NULL) { 1974 char *tmp; 1975 const char *name; 1976 1977 obj = cfg_listelt_value(elt); 1978 name = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 1979 1980 tmp = isc_mem_strdup(mctx, name); 1981 symvalue.as_cpointer = obj; 1982 tresult = isc_symtab_define(symtab, tmp, 1, symvalue, 1983 isc_symexists_reject); 1984 if (tresult == ISC_R_EXISTS) { 1985 const char *file = NULL; 1986 unsigned int line; 1987 1988 RUNTIME_CHECK( 1989 isc_symtab_lookup(symtab, tmp, 1, &symvalue) == 1990 ISC_R_SUCCESS); 1991 file = cfg_obj_file(symvalue.as_cpointer); 1992 line = cfg_obj_line(symvalue.as_cpointer); 1993 1994 if (file == NULL) { 1995 file = "<unknown file>"; 1996 } 1997 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1998 "%s list '%s' is duplicated: " 1999 "also defined at %s:%u", 2000 list, name, file, line); 2001 isc_mem_free(mctx, tmp); 2002 result = tresult; 2003 break; 2004 } else if (tresult != ISC_R_SUCCESS) { 2005 isc_mem_free(mctx, tmp); 2006 result = tresult; 2007 break; 2008 } 2009 2010 elt = cfg_list_next(elt); 2011 } 2012 return (result); 2013} 2014 2015/* 2016 * Check primaries lists for duplicates. 2017 */ 2018static isc_result_t 2019bind9_check_primarylists(const cfg_obj_t *cctx, isc_log_t *logctx, 2020 isc_mem_t *mctx) { 2021 isc_result_t result, tresult; 2022 isc_symtab_t *symtab = NULL; 2023 2024 result = isc_symtab_create(mctx, 100, freekey, mctx, false, &symtab); 2025 if (result != ISC_R_SUCCESS) { 2026 return (result); 2027 } 2028 tresult = bind9_check_remoteserverlist(cctx, "primaries", logctx, 2029 symtab, mctx); 2030 if (tresult != ISC_R_SUCCESS) { 2031 result = tresult; 2032 } 2033 tresult = bind9_check_remoteserverlist(cctx, "masters", logctx, symtab, 2034 mctx); 2035 if (tresult != ISC_R_SUCCESS) { 2036 result = tresult; 2037 } 2038 isc_symtab_destroy(&symtab); 2039 return (result); 2040} 2041 2042/* 2043 * Check parental-agents lists for duplicates. 2044 */ 2045static isc_result_t 2046bind9_check_parentalagentlists(const cfg_obj_t *cctx, isc_log_t *logctx, 2047 isc_mem_t *mctx) { 2048 isc_result_t result, tresult; 2049 isc_symtab_t *symtab = NULL; 2050 2051 result = isc_symtab_create(mctx, 100, freekey, mctx, false, &symtab); 2052 if (result != ISC_R_SUCCESS) { 2053 return (result); 2054 } 2055 tresult = bind9_check_remoteserverlist(cctx, "parental-agents", logctx, 2056 symtab, mctx); 2057 if (tresult != ISC_R_SUCCESS) { 2058 result = tresult; 2059 } 2060 isc_symtab_destroy(&symtab); 2061 return (result); 2062} 2063 2064#if HAVE_LIBNGHTTP2 2065static isc_result_t 2066bind9_check_httpserver(const cfg_obj_t *http, isc_log_t *logctx, 2067 isc_symtab_t *symtab) { 2068 isc_result_t result, tresult; 2069 const char *name = cfg_obj_asstring(cfg_map_getname(http)); 2070 const cfg_obj_t *eps = NULL; 2071 const cfg_listelt_t *elt = NULL; 2072 isc_symvalue_t symvalue; 2073 2074 if (strcasecmp(name, "default") == 0) { 2075 cfg_obj_log(http, logctx, ISC_LOG_ERROR, 2076 "'http' name cannot be '%s' (which is a " 2077 "built-in configuration)", 2078 name); 2079 result = ISC_R_FAILURE; 2080 } else { 2081 /* Check for duplicates */ 2082 symvalue.as_cpointer = http; 2083 result = isc_symtab_define(symtab, name, 1, symvalue, 2084 isc_symexists_reject); 2085 if (result == ISC_R_EXISTS) { 2086 const char *file = NULL; 2087 unsigned int line; 2088 2089 tresult = isc_symtab_lookup(symtab, name, 1, &symvalue); 2090 RUNTIME_CHECK(tresult == ISC_R_SUCCESS); 2091 2092 line = cfg_obj_line(symvalue.as_cpointer); 2093 file = cfg_obj_file(symvalue.as_cpointer); 2094 if (file == NULL) { 2095 file = "<unknown file>"; 2096 } 2097 2098 cfg_obj_log(http, logctx, ISC_LOG_ERROR, 2099 "http '%s' is duplicated: " 2100 "also defined at %s:%u", 2101 name, file, line); 2102 } 2103 } 2104 2105 /* Check endpoints are valid */ 2106 tresult = cfg_map_get(http, "endpoints", &eps); 2107 if (tresult == ISC_R_SUCCESS) { 2108 for (elt = cfg_list_first(eps); elt != NULL; 2109 elt = cfg_list_next(elt)) 2110 { 2111 const cfg_obj_t *ep = cfg_listelt_value(elt); 2112 const char *path = cfg_obj_asstring(ep); 2113 if (!isc_nm_http_path_isvalid(path)) { 2114 cfg_obj_log(eps, logctx, ISC_LOG_ERROR, 2115 "endpoint '%s' is not a " 2116 "valid absolute HTTP path", 2117 path); 2118 if (result == ISC_R_SUCCESS) { 2119 result = ISC_R_FAILURE; 2120 } 2121 } 2122 } 2123 } 2124 2125 return (result); 2126} 2127 2128static isc_result_t 2129bind9_check_httpservers(const cfg_obj_t *config, isc_log_t *logctx, 2130 isc_mem_t *mctx) { 2131 isc_result_t result, tresult; 2132 const cfg_obj_t *obj = NULL; 2133 const cfg_listelt_t *elt = NULL; 2134 isc_symtab_t *symtab = NULL; 2135 2136 result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab); 2137 if (result != ISC_R_SUCCESS) { 2138 return (result); 2139 } 2140 2141 result = cfg_map_get(config, "http", &obj); 2142 if (result != ISC_R_SUCCESS) { 2143 result = ISC_R_SUCCESS; 2144 goto done; 2145 } 2146 2147 for (elt = cfg_list_first(obj); elt != NULL; elt = cfg_list_next(elt)) { 2148 obj = cfg_listelt_value(elt); 2149 tresult = bind9_check_httpserver(obj, logctx, symtab); 2150 if (result == ISC_R_SUCCESS) { 2151 result = tresult; 2152 } 2153 } 2154 2155done: 2156 isc_symtab_destroy(&symtab); 2157 return (result); 2158} 2159#endif /* HAVE_LIBNGHTTP2 */ 2160 2161static isc_result_t 2162bind9_check_tls_defintion(const cfg_obj_t *tlsobj, const char *name, 2163 isc_log_t *logctx, isc_symtab_t *symtab) { 2164 isc_result_t result, tresult; 2165 const cfg_obj_t *tls_proto_list = NULL, *tls_key = NULL, 2166 *tls_cert = NULL, *tls_ciphers = NULL; 2167 uint32_t tls_protos = 0; 2168 isc_symvalue_t symvalue; 2169 2170 if (strcasecmp(name, "ephemeral") == 0 || strcasecmp(name, "none") == 0) 2171 { 2172 cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, 2173 "tls clause name '%s' is reserved for internal use", 2174 name); 2175 result = ISC_R_FAILURE; 2176 } else { 2177 /* Check for duplicates */ 2178 symvalue.as_cpointer = tlsobj; 2179 result = isc_symtab_define(symtab, name, 1, symvalue, 2180 isc_symexists_reject); 2181 if (result == ISC_R_EXISTS) { 2182 const char *file = NULL; 2183 unsigned int line; 2184 2185 tresult = isc_symtab_lookup(symtab, name, 1, &symvalue); 2186 RUNTIME_CHECK(tresult == ISC_R_SUCCESS); 2187 2188 line = cfg_obj_line(symvalue.as_cpointer); 2189 file = cfg_obj_file(symvalue.as_cpointer); 2190 if (file == NULL) { 2191 file = "<unknown file>"; 2192 } 2193 2194 cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, 2195 "tls clause '%s' is duplicated: " 2196 "also defined at %s:%u", 2197 name, file, line); 2198 } 2199 } 2200 2201 (void)cfg_map_get(tlsobj, "key-file", &tls_key); 2202 (void)cfg_map_get(tlsobj, "cert-file", &tls_cert); 2203 if ((tls_key == NULL && tls_cert != NULL) || 2204 (tls_cert == NULL && tls_key != NULL)) 2205 { 2206 cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, 2207 "tls '%s': 'cert-file' and 'key-file' must " 2208 "both be specified, or both omitted", 2209 name); 2210 result = ISC_R_FAILURE; 2211 } 2212 2213 /* Check protocols are valid */ 2214 tresult = cfg_map_get(tlsobj, "protocols", &tls_proto_list); 2215 if (tresult == ISC_R_SUCCESS) { 2216 const cfg_listelt_t *proto = NULL; 2217 INSIST(tls_proto_list != NULL); 2218 for (proto = cfg_list_first(tls_proto_list); proto != 0; 2219 proto = cfg_list_next(proto)) 2220 { 2221 const cfg_obj_t *tls_proto_obj = 2222 cfg_listelt_value(proto); 2223 const char *tls_sver = cfg_obj_asstring(tls_proto_obj); 2224 const isc_tls_protocol_version_t ver = 2225 isc_tls_protocol_name_to_version(tls_sver); 2226 2227 if (ver == ISC_TLS_PROTO_VER_UNDEFINED) { 2228 cfg_obj_log(tls_proto_obj, logctx, 2229 ISC_LOG_ERROR, 2230 "'%s' is not a valid " 2231 "TLS protocol version", 2232 tls_sver); 2233 result = ISC_R_FAILURE; 2234 continue; 2235 } else if (!isc_tls_protocol_supported(ver)) { 2236 cfg_obj_log(tls_proto_obj, logctx, 2237 ISC_LOG_ERROR, 2238 "'%s' is not " 2239 "supported by the " 2240 "cryptographic library version in " 2241 "use (%s)", 2242 tls_sver, OPENSSL_VERSION_TEXT); 2243 result = ISC_R_FAILURE; 2244 } 2245 2246 if ((tls_protos & ver) != 0) { 2247 cfg_obj_log(tls_proto_obj, logctx, 2248 ISC_LOG_WARNING, 2249 "'%s' is specified more than once " 2250 "in '%s'", 2251 tls_sver, name); 2252 result = ISC_R_FAILURE; 2253 } 2254 2255 tls_protos |= ver; 2256 } 2257 2258 if (tls_protos == 0) { 2259 cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, 2260 "tls '%s' does not contain any valid " 2261 "TLS protocol versions definitions", 2262 name); 2263 result = ISC_R_FAILURE; 2264 } 2265 } 2266 2267 /* Check cipher list string is valid */ 2268 tresult = cfg_map_get(tlsobj, "ciphers", &tls_ciphers); 2269 if (tresult == ISC_R_SUCCESS) { 2270 const char *ciphers = cfg_obj_asstring(tls_ciphers); 2271 if (!isc_tls_cipherlist_valid(ciphers)) { 2272 cfg_obj_log(tls_ciphers, logctx, ISC_LOG_ERROR, 2273 "'ciphers' in the 'tls' clause '%s' is " 2274 "not a " 2275 "valid cipher list string", 2276 name); 2277 result = ISC_R_FAILURE; 2278 } 2279 } 2280 2281 return (result); 2282} 2283 2284static isc_result_t 2285bind9_check_tls_definitions(const cfg_obj_t *config, isc_log_t *logctx, 2286 isc_mem_t *mctx) { 2287 isc_result_t result, tresult; 2288 const cfg_obj_t *obj = NULL; 2289 const cfg_listelt_t *elt = NULL; 2290 isc_symtab_t *symtab = NULL; 2291 2292 result = cfg_map_get(config, "tls", &obj); 2293 if (result != ISC_R_SUCCESS) { 2294 result = ISC_R_SUCCESS; 2295 return (result); 2296 } 2297 2298 result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab); 2299 if (result != ISC_R_SUCCESS) { 2300 return (result); 2301 } 2302 2303 for (elt = cfg_list_first(obj); elt != NULL; elt = cfg_list_next(elt)) { 2304 const char *name; 2305 obj = cfg_listelt_value(elt); 2306 name = cfg_obj_asstring(cfg_map_getname(obj)); 2307 tresult = bind9_check_tls_defintion(obj, name, logctx, symtab); 2308 if (result == ISC_R_SUCCESS) { 2309 result = tresult; 2310 } 2311 } 2312 2313 isc_symtab_destroy(&symtab); 2314 2315 return (result); 2316} 2317 2318static isc_result_t 2319get_remotes(const cfg_obj_t *cctx, const char *list, const char *name, 2320 const cfg_obj_t **ret) { 2321 isc_result_t result; 2322 const cfg_obj_t *obj = NULL; 2323 const cfg_listelt_t *elt = NULL; 2324 2325 result = cfg_map_get(cctx, list, &obj); 2326 if (result != ISC_R_SUCCESS) { 2327 return (result); 2328 } 2329 2330 elt = cfg_list_first(obj); 2331 while (elt != NULL) { 2332 const char *listname; 2333 2334 obj = cfg_listelt_value(elt); 2335 listname = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 2336 2337 if (strcasecmp(listname, name) == 0) { 2338 *ret = obj; 2339 return (ISC_R_SUCCESS); 2340 } 2341 2342 elt = cfg_list_next(elt); 2343 } 2344 2345 return (ISC_R_NOTFOUND); 2346} 2347 2348static isc_result_t 2349get_remoteservers_def(const char *list, const char *name, const cfg_obj_t *cctx, 2350 const cfg_obj_t **ret) { 2351 isc_result_t result = ISC_R_NOTFOUND; 2352 2353 if (strcmp(list, "primaries") == 0) { 2354 result = get_remotes(cctx, "primaries", name, ret); 2355 if (result != ISC_R_SUCCESS) { 2356 result = get_remotes(cctx, "masters", name, ret); 2357 } 2358 } else if (strcmp(list, "parental-agents") == 0) { 2359 result = get_remotes(cctx, "parental-agents", name, ret); 2360 } 2361 return (result); 2362} 2363 2364static isc_result_t 2365validate_remotes(const char *list, const cfg_obj_t *obj, 2366 const cfg_obj_t *config, uint32_t *countp, isc_log_t *logctx, 2367 isc_mem_t *mctx) { 2368 isc_result_t result = ISC_R_SUCCESS; 2369 isc_result_t tresult; 2370 uint32_t count = 0; 2371 isc_symtab_t *symtab = NULL; 2372 isc_symvalue_t symvalue; 2373 const cfg_listelt_t *element; 2374 const cfg_listelt_t **stack = NULL; 2375 uint32_t stackcount = 0, pushed = 0; 2376 const cfg_obj_t *listobj; 2377 2378 REQUIRE(countp != NULL); 2379 result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab); 2380 if (result != ISC_R_SUCCESS) { 2381 *countp = count; 2382 return (result); 2383 } 2384 2385newlist: 2386 listobj = cfg_tuple_get(obj, "addresses"); 2387 element = cfg_list_first(listobj); 2388resume: 2389 for (; element != NULL; element = cfg_list_next(element)) { 2390 const char *listname; 2391 const cfg_obj_t *addr; 2392 const cfg_obj_t *key; 2393 const cfg_obj_t *tls; 2394 2395 addr = cfg_tuple_get(cfg_listelt_value(element), 2396 "remoteselement"); 2397 key = cfg_tuple_get(cfg_listelt_value(element), "key"); 2398 tls = cfg_tuple_get(cfg_listelt_value(element), "tls"); 2399 2400 if (cfg_obj_issockaddr(addr)) { 2401 count++; 2402 if (cfg_obj_isstring(key)) { 2403 const char *str = cfg_obj_asstring(key); 2404 dns_fixedname_t fname; 2405 dns_name_t *nm = dns_fixedname_initname(&fname); 2406 tresult = dns_name_fromstring(nm, str, 0, NULL); 2407 if (tresult != ISC_R_SUCCESS) { 2408 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 2409 "'%s' is not a valid name", 2410 str); 2411 if (result == ISC_R_SUCCESS) { 2412 result = tresult; 2413 } 2414 } 2415 } 2416 if (cfg_obj_isstring(tls)) { 2417 const char *str = cfg_obj_asstring(tls); 2418 dns_fixedname_t fname; 2419 dns_name_t *nm = dns_fixedname_initname(&fname); 2420 tresult = dns_name_fromstring(nm, str, 0, NULL); 2421 if (tresult != ISC_R_SUCCESS) { 2422 cfg_obj_log(tls, logctx, ISC_LOG_ERROR, 2423 "'%s' is not a valid name", 2424 str); 2425 if (result == ISC_R_SUCCESS) { 2426 result = tresult; 2427 } 2428 } 2429 2430 if (strcasecmp(str, "ephemeral") != 0) { 2431 const cfg_obj_t *tlsmap = NULL; 2432 2433 tlsmap = find_maplist(config, "tls", 2434 str); 2435 if (tlsmap == NULL) { 2436 cfg_obj_log( 2437 tls, logctx, 2438 ISC_LOG_ERROR, 2439 "tls '%s' is not " 2440 "defined", 2441 cfg_obj_asstring(tls)); 2442 result = ISC_R_FAILURE; 2443 } 2444 } 2445 } 2446 continue; 2447 } 2448 if (!cfg_obj_isvoid(key)) { 2449 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 2450 "unexpected token '%s'", 2451 cfg_obj_asstring(key)); 2452 if (result == ISC_R_SUCCESS) { 2453 result = ISC_R_FAILURE; 2454 } 2455 } 2456 if (!cfg_obj_isvoid(tls)) { 2457 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 2458 "unexpected token '%s'", 2459 cfg_obj_asstring(tls)); 2460 if (result == ISC_R_SUCCESS) { 2461 result = ISC_R_FAILURE; 2462 } 2463 } 2464 listname = cfg_obj_asstring(addr); 2465 symvalue.as_cpointer = addr; 2466 tresult = isc_symtab_define(symtab, listname, 1, symvalue, 2467 isc_symexists_reject); 2468 if (tresult == ISC_R_EXISTS) { 2469 continue; 2470 } 2471 tresult = get_remoteservers_def(list, listname, config, &obj); 2472 if (tresult != ISC_R_SUCCESS) { 2473 if (result == ISC_R_SUCCESS) { 2474 result = tresult; 2475 } 2476 cfg_obj_log(addr, logctx, ISC_LOG_ERROR, 2477 "unable to find %s list '%s'", list, 2478 listname); 2479 continue; 2480 } 2481 /* Grow stack? */ 2482 if (stackcount == pushed) { 2483 void *newstack; 2484 uint32_t newlen = stackcount + 16; 2485 size_t newsize, oldsize; 2486 2487 newsize = newlen * sizeof(*stack); 2488 oldsize = stackcount * sizeof(*stack); 2489 newstack = isc_mem_get(mctx, newsize); 2490 if (stackcount != 0) { 2491 void *ptr; 2492 2493 DE_CONST(stack, ptr); 2494 memmove(newstack, stack, oldsize); 2495 isc_mem_put(mctx, ptr, oldsize); 2496 } 2497 stack = newstack; 2498 stackcount = newlen; 2499 } 2500 stack[pushed++] = cfg_list_next(element); 2501 goto newlist; 2502 } 2503 if (pushed != 0) { 2504 element = stack[--pushed]; 2505 goto resume; 2506 } 2507 if (stack != NULL) { 2508 void *ptr; 2509 2510 DE_CONST(stack, ptr); 2511 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack)); 2512 } 2513 isc_symtab_destroy(&symtab); 2514 *countp = count; 2515 return (result); 2516} 2517 2518static isc_result_t 2519check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) { 2520 isc_result_t result = ISC_R_SUCCESS; 2521 isc_result_t tresult; 2522 const cfg_listelt_t *element; 2523 const cfg_listelt_t *element2; 2524 dns_fixedname_t fixed_id, fixed_name; 2525 dns_name_t *id, *name; 2526 const char *str; 2527 isc_textregion_t r; 2528 dns_rdatatype_t type; 2529 2530 /* Check for "update-policy local;" */ 2531 if (cfg_obj_isstring(policy) && 2532 strcmp("local", cfg_obj_asstring(policy)) == 0) 2533 { 2534 return (ISC_R_SUCCESS); 2535 } 2536 2537 /* Now check the grant policy */ 2538 for (element = cfg_list_first(policy); element != NULL; 2539 element = cfg_list_next(element)) 2540 { 2541 const cfg_obj_t *stmt = cfg_listelt_value(element); 2542 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity"); 2543 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype"); 2544 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name"); 2545 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types"); 2546 dns_ssumatchtype_t mtype; 2547 2548 id = dns_fixedname_initname(&fixed_id); 2549 name = dns_fixedname_initname(&fixed_name); 2550 2551 tresult = dns_ssu_mtypefromstring(cfg_obj_asstring(matchtype), 2552 &mtype); 2553 if (tresult != ISC_R_SUCCESS) { 2554 cfg_obj_log(identity, logctx, ISC_LOG_ERROR, 2555 "has a bad match-type"); 2556 } 2557 2558 str = cfg_obj_asstring(identity); 2559 tresult = dns_name_fromstring(id, str, 1, NULL); 2560 if (tresult != ISC_R_SUCCESS) { 2561 cfg_obj_log(identity, logctx, ISC_LOG_ERROR, 2562 "'%s' is not a valid name", str); 2563 result = tresult; 2564 } 2565 2566 /* 2567 * There is no name field for subzone and dname is void 2568 */ 2569 if (mtype == dns_ssumatchtype_subdomain && 2570 cfg_obj_isvoid(dname)) 2571 { 2572 str = "."; /* Use "." as a replacement. */ 2573 } else { 2574 str = cfg_obj_asstring(dname); 2575 } 2576 if (tresult == ISC_R_SUCCESS) { 2577 tresult = dns_name_fromstring(name, str, 0, NULL); 2578 if (tresult != ISC_R_SUCCESS) { 2579 cfg_obj_log(dname, logctx, ISC_LOG_ERROR, 2580 "'%s' is not a valid name", str); 2581 result = tresult; 2582 } 2583 } 2584 2585 if (tresult == ISC_R_SUCCESS && 2586 mtype == dns_ssumatchtype_wildcard && 2587 !dns_name_iswildcard(name)) 2588 { 2589 cfg_obj_log(identity, logctx, ISC_LOG_ERROR, 2590 "'%s' is not a wildcard", str); 2591 result = ISC_R_FAILURE; 2592 } 2593 2594 /* 2595 * For some match types, the name should be a placeholder 2596 * value, either "." or the same as identity. 2597 */ 2598 switch (mtype) { 2599 case dns_ssumatchtype_self: 2600 case dns_ssumatchtype_selfsub: 2601 case dns_ssumatchtype_selfwild: 2602 if (tresult == ISC_R_SUCCESS && 2603 (!dns_name_equal(id, name) && 2604 !dns_name_equal(dns_rootname, name))) 2605 { 2606 cfg_obj_log(identity, logctx, ISC_LOG_ERROR, 2607 "identity and name fields are not " 2608 "the same"); 2609 result = ISC_R_FAILURE; 2610 } 2611 break; 2612 case dns_ssumatchtype_selfkrb5: 2613 case dns_ssumatchtype_selfms: 2614 case dns_ssumatchtype_selfsubkrb5: 2615 case dns_ssumatchtype_selfsubms: 2616 case dns_ssumatchtype_tcpself: 2617 case dns_ssumatchtype_6to4self: 2618 if (tresult == ISC_R_SUCCESS && 2619 !dns_name_equal(dns_rootname, name)) 2620 { 2621 cfg_obj_log(identity, logctx, ISC_LOG_ERROR, 2622 "name field not set to " 2623 "placeholder value '.'"); 2624 result = ISC_R_FAILURE; 2625 } 2626 break; 2627 case dns_ssumatchtype_name: 2628 case dns_ssumatchtype_subdomain: /* also zonesub */ 2629 case dns_ssumatchtype_subdomainms: 2630 case dns_ssumatchtype_subdomainselfmsrhs: 2631 case dns_ssumatchtype_subdomainkrb5: 2632 case dns_ssumatchtype_subdomainselfkrb5rhs: 2633 case dns_ssumatchtype_wildcard: 2634 case dns_ssumatchtype_external: 2635 case dns_ssumatchtype_local: 2636 if (tresult == ISC_R_SUCCESS) { 2637 DE_CONST(str, r.base); 2638 r.length = strlen(str); 2639 tresult = dns_rdatatype_fromtext(&type, &r); 2640 } 2641 if (tresult == ISC_R_SUCCESS) { 2642 cfg_obj_log(identity, logctx, ISC_LOG_ERROR, 2643 "missing name field type '%s' " 2644 "found", 2645 str); 2646 result = ISC_R_FAILURE; 2647 break; 2648 } 2649 break; 2650 default: 2651 UNREACHABLE(); 2652 } 2653 2654 for (element2 = cfg_list_first(typelist); element2 != NULL; 2655 element2 = cfg_list_next(element2)) 2656 { 2657 const cfg_obj_t *typeobj; 2658 const char *bracket; 2659 2660 typeobj = cfg_listelt_value(element2); 2661 DE_CONST(cfg_obj_asstring(typeobj), r.base); 2662 2663 bracket = strchr(r.base, '(' /*)*/); 2664 if (bracket != NULL) { 2665 char *end = NULL; 2666 unsigned long max; 2667 2668 r.length = bracket - r.base; 2669 max = strtoul(bracket + 1, &end, 10); 2670 if (max > 0xffff || end[0] != /*(*/ ')' || 2671 end[1] != 0) 2672 { 2673 cfg_obj_log(typeobj, logctx, 2674 ISC_LOG_ERROR, 2675 "'%s' is not a valid count", 2676 bracket); 2677 result = DNS_R_SYNTAX; 2678 } 2679 } else { 2680 r.length = strlen(r.base); 2681 } 2682 2683 tresult = dns_rdatatype_fromtext(&type, &r); 2684 if (tresult != ISC_R_SUCCESS) { 2685 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR, 2686 "'%.*s' is not a valid type", 2687 (int)r.length, r.base); 2688 result = tresult; 2689 } 2690 } 2691 } 2692 return (result); 2693} 2694 2695typedef struct { 2696 const char *name; 2697 unsigned int allowed; 2698} optionstable; 2699 2700static isc_result_t 2701check_nonzero(const cfg_obj_t *options, isc_log_t *logctx) { 2702 isc_result_t result = ISC_R_SUCCESS; 2703 const cfg_obj_t *obj = NULL; 2704 unsigned int i; 2705 2706 static const char *nonzero[] = { "max-retry-time", "min-retry-time", 2707 "max-refresh-time", 2708 "min-refresh-time" }; 2709 /* 2710 * Check if value is zero. 2711 */ 2712 for (i = 0; i < sizeof(nonzero) / sizeof(nonzero[0]); i++) { 2713 obj = NULL; 2714 if (cfg_map_get(options, nonzero[i], &obj) == ISC_R_SUCCESS && 2715 cfg_obj_asuint32(obj) == 0) 2716 { 2717 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2718 "'%s' must not be zero", nonzero[i]); 2719 result = ISC_R_FAILURE; 2720 } 2721 } 2722 return (result); 2723} 2724 2725/*% 2726 * Check whether NOTIFY configuration at the zone level is acceptable for a 2727 * mirror zone. Return true if it is; return false otherwise. 2728 */ 2729static bool 2730check_mirror_zone_notify(const cfg_obj_t *zoptions, const char *znamestr, 2731 isc_log_t *logctx) { 2732 bool notify_configuration_ok = true; 2733 const cfg_obj_t *obj = NULL; 2734 2735 (void)cfg_map_get(zoptions, "notify", &obj); 2736 if (obj == NULL) { 2737 /* 2738 * "notify" not set at zone level. This is fine. 2739 */ 2740 return (true); 2741 } 2742 2743 if (cfg_obj_isboolean(obj)) { 2744 if (cfg_obj_asboolean(obj)) { 2745 /* 2746 * "notify yes;" set at zone level. This is an error. 2747 */ 2748 notify_configuration_ok = false; 2749 } 2750 } else { 2751 const char *notifystr = cfg_obj_asstring(obj); 2752 if (strcasecmp(notifystr, "explicit") != 0) { 2753 /* 2754 * Something else than "notify explicit;" set at zone 2755 * level. This is an error. 2756 */ 2757 notify_configuration_ok = false; 2758 } 2759 } 2760 2761 if (!notify_configuration_ok) { 2762 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR, 2763 "zone '%s': mirror zones can only be used with " 2764 "'notify no;' or 'notify explicit;'", 2765 znamestr); 2766 } 2767 2768 return (notify_configuration_ok); 2769} 2770 2771/*% 2772 * Try to determine whether recursion is available in a view without resorting 2773 * to extraordinary measures: just check the "recursion" and "allow-recursion" 2774 * settings. The point is to prevent accidental mirror zone misuse rather than 2775 * to enforce some sort of policy. Recursion is assumed to be allowed by 2776 * default if it is not explicitly disabled. 2777 */ 2778static bool 2779check_recursion(const cfg_obj_t *config, const cfg_obj_t *voptions, 2780 const cfg_obj_t *goptions, isc_log_t *logctx, 2781 cfg_aclconfctx_t *actx, isc_mem_t *mctx) { 2782 dns_acl_t *acl = NULL; 2783 const cfg_obj_t *obj; 2784 isc_result_t result; 2785 bool retval = true; 2786 2787 /* 2788 * Check the "recursion" option first. 2789 */ 2790 obj = NULL; 2791 result = ISC_R_NOTFOUND; 2792 if (voptions != NULL) { 2793 result = cfg_map_get(voptions, "recursion", &obj); 2794 } 2795 if (result != ISC_R_SUCCESS && goptions != NULL) { 2796 result = cfg_map_get(goptions, "recursion", &obj); 2797 } 2798 if (result == ISC_R_SUCCESS && !cfg_obj_asboolean(obj)) { 2799 retval = false; 2800 goto cleanup; 2801 } 2802 2803 /* 2804 * If recursion is not disabled by the "recursion" option, check 2805 * whether it is disabled by the "allow-recursion" ACL. 2806 */ 2807 obj = NULL; 2808 result = ISC_R_NOTFOUND; 2809 if (voptions != NULL) { 2810 result = cfg_map_get(voptions, "allow-recursion", &obj); 2811 } 2812 if (result != ISC_R_SUCCESS && goptions != NULL) { 2813 result = cfg_map_get(goptions, "allow-recursion", &obj); 2814 } 2815 if (result == ISC_R_SUCCESS) { 2816 result = cfg_acl_fromconfig(obj, config, logctx, actx, mctx, 0, 2817 &acl); 2818 if (result != ISC_R_SUCCESS) { 2819 goto cleanup; 2820 } 2821 retval = !dns_acl_isnone(acl); 2822 } 2823 2824cleanup: 2825 if (acl != NULL) { 2826 dns_acl_detach(&acl); 2827 } 2828 2829 return (retval); 2830} 2831 2832static isc_result_t 2833check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, 2834 const cfg_obj_t *config, isc_symtab_t *symtab, 2835 isc_symtab_t *files, isc_symtab_t *keydirs, isc_symtab_t *inview, 2836 const char *viewname, dns_rdataclass_t defclass, 2837 bool nodeprecate, cfg_aclconfctx_t *actx, isc_log_t *logctx, 2838 isc_mem_t *mctx) { 2839 const char *znamestr; 2840 const char *typestr = NULL; 2841 const char *target = NULL; 2842 unsigned int ztype; 2843 const cfg_obj_t *zoptions, *goptions = NULL; 2844 const cfg_obj_t *obj = NULL, *kasp = NULL; 2845 const cfg_obj_t *inviewobj = NULL; 2846 isc_result_t result = ISC_R_SUCCESS; 2847 isc_result_t tresult; 2848 unsigned int i; 2849 dns_rdataclass_t zclass; 2850 dns_fixedname_t fixedname; 2851 dns_name_t *zname = NULL; /* NULL if parsing of zone name fails. */ 2852 isc_buffer_t b; 2853 bool root = false; 2854 bool rfc1918 = false; 2855 bool ula = false; 2856 const cfg_listelt_t *element; 2857 bool dlz; 2858 bool ddns = false; 2859 bool has_dnssecpolicy = false; 2860 const void *clauses = NULL; 2861 const char *option = NULL; 2862 const char *kaspname = NULL; 2863 const char *dir = NULL; 2864 static const char *acls[] = { 2865 "allow-notify", 2866 "allow-transfer", 2867 "allow-update", 2868 "allow-update-forwarding", 2869 }; 2870 static optionstable dialups[] = { 2871 { "notify", CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 2872 { "notify-passive", CFG_ZONE_SECONDARY }, 2873 { "passive", CFG_ZONE_SECONDARY | CFG_ZONE_STUB }, 2874 { "refresh", CFG_ZONE_SECONDARY | CFG_ZONE_STUB }, 2875 }; 2876 static const char *sources[] = { 2877 "transfer-source", "transfer-source-v6", "notify-source", 2878 "notify-source-v6", "parental-source", "parental-source-v6", 2879 }; 2880 2881 znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); 2882 2883 zoptions = cfg_tuple_get(zconfig, "options"); 2884 2885 if (config != NULL) { 2886 cfg_map_get(config, "options", &goptions); 2887 } 2888 2889 inviewobj = NULL; 2890 (void)cfg_map_get(zoptions, "in-view", &inviewobj); 2891 if (inviewobj != NULL) { 2892 target = cfg_obj_asstring(inviewobj); 2893 ztype = CFG_ZONE_INVIEW; 2894 } else { 2895 obj = NULL; 2896 (void)cfg_map_get(zoptions, "type", &obj); 2897 if (obj == NULL) { 2898 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 2899 "zone '%s': type not present", znamestr); 2900 return (ISC_R_FAILURE); 2901 } 2902 2903 typestr = cfg_obj_asstring(obj); 2904 if (strcasecmp(typestr, "master") == 0 || 2905 strcasecmp(typestr, "primary") == 0) 2906 { 2907 ztype = CFG_ZONE_PRIMARY; 2908 } else if (strcasecmp(typestr, "slave") == 0 || 2909 strcasecmp(typestr, "secondary") == 0) 2910 { 2911 ztype = CFG_ZONE_SECONDARY; 2912 } else if (strcasecmp(typestr, "mirror") == 0) { 2913 ztype = CFG_ZONE_MIRROR; 2914 } else if (strcasecmp(typestr, "stub") == 0) { 2915 ztype = CFG_ZONE_STUB; 2916 } else if (strcasecmp(typestr, "static-stub") == 0) { 2917 ztype = CFG_ZONE_STATICSTUB; 2918 } else if (strcasecmp(typestr, "forward") == 0) { 2919 ztype = CFG_ZONE_FORWARD; 2920 } else if (strcasecmp(typestr, "hint") == 0) { 2921 ztype = CFG_ZONE_HINT; 2922 } else if (strcasecmp(typestr, "delegation-only") == 0) { 2923 ztype = CFG_ZONE_DELEGATION; 2924 if (!nodeprecate) { 2925 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 2926 "'type delegation-only' is " 2927 "deprecated"); 2928 } 2929 } else if (strcasecmp(typestr, "redirect") == 0) { 2930 ztype = CFG_ZONE_REDIRECT; 2931 } else { 2932 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2933 "zone '%s': invalid type %s", znamestr, 2934 typestr); 2935 return (ISC_R_FAILURE); 2936 } 2937 2938 if (ztype == CFG_ZONE_REDIRECT && strcmp(znamestr, ".") != 0) { 2939 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 2940 "redirect zones must be called \".\""); 2941 return (ISC_R_FAILURE); 2942 } 2943 } 2944 2945 obj = cfg_tuple_get(zconfig, "class"); 2946 if (cfg_obj_isstring(obj)) { 2947 isc_textregion_t r; 2948 2949 DE_CONST(cfg_obj_asstring(obj), r.base); 2950 r.length = strlen(r.base); 2951 result = dns_rdataclass_fromtext(&zclass, &r); 2952 if (result != ISC_R_SUCCESS) { 2953 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2954 "zone '%s': invalid class %s", znamestr, 2955 r.base); 2956 return (ISC_R_FAILURE); 2957 } 2958 if (zclass != defclass) { 2959 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2960 "zone '%s': class '%s' does not " 2961 "match view/default class", 2962 znamestr, r.base); 2963 return (ISC_R_FAILURE); 2964 } 2965 } else { 2966 zclass = defclass; 2967 } 2968 2969 /* 2970 * Look for an already existing zone. 2971 * We need to make this canonical as isc_symtab_define() 2972 * deals with strings. 2973 */ 2974 dns_fixedname_init(&fixedname); 2975 isc_buffer_constinit(&b, znamestr, strlen(znamestr)); 2976 isc_buffer_add(&b, strlen(znamestr)); 2977 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b, 2978 dns_rootname, DNS_NAME_DOWNCASE, NULL); 2979 if (tresult != ISC_R_SUCCESS) { 2980 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 2981 "zone '%s': is not a valid name", znamestr); 2982 result = ISC_R_FAILURE; 2983 } else { 2984 char namebuf[DNS_NAME_FORMATSIZE + 128]; 2985 char *tmp = namebuf; 2986 size_t len = sizeof(namebuf); 2987 2988 zname = dns_fixedname_name(&fixedname); 2989 dns_name_format(zname, namebuf, sizeof(namebuf)); 2990 tresult = nameexist(zconfig, namebuf, 2991 ztype == CFG_ZONE_HINT ? 1 2992 : ztype == CFG_ZONE_REDIRECT ? 2 2993 : 3, 2994 symtab, 2995 "zone '%s': already exists " 2996 "previous definition: %s:%u", 2997 logctx, mctx); 2998 if (tresult != ISC_R_SUCCESS) { 2999 result = tresult; 3000 } 3001 if (dns_name_equal(zname, dns_rootname)) { 3002 root = true; 3003 } else if (dns_name_isrfc1918(zname)) { 3004 rfc1918 = true; 3005 } else if (dns_name_isula(zname)) { 3006 ula = true; 3007 } 3008 len -= strlen(tmp); 3009 tmp += strlen(tmp); 3010 (void)snprintf(tmp, len, "%u/%s", zclass, 3011 (ztype == CFG_ZONE_INVIEW) ? target 3012 : (viewname != NULL) ? viewname 3013 : "_default"); 3014 switch (ztype) { 3015 case CFG_ZONE_INVIEW: 3016 tresult = isc_symtab_lookup(inview, namebuf, 0, NULL); 3017 if (tresult != ISC_R_SUCCESS) { 3018 cfg_obj_log(inviewobj, logctx, ISC_LOG_ERROR, 3019 "'in-view' zone '%s' " 3020 "does not exist in view '%s', " 3021 "or view '%s' is not yet defined", 3022 znamestr, target, target); 3023 if (result == ISC_R_SUCCESS) { 3024 result = tresult; 3025 } 3026 } 3027 break; 3028 3029 case CFG_ZONE_FORWARD: 3030 case CFG_ZONE_REDIRECT: 3031 case CFG_ZONE_DELEGATION: 3032 break; 3033 3034 case CFG_ZONE_PRIMARY: 3035 case CFG_ZONE_SECONDARY: 3036 case CFG_ZONE_MIRROR: 3037 case CFG_ZONE_HINT: 3038 case CFG_ZONE_STUB: 3039 case CFG_ZONE_STATICSTUB: 3040 tmp = isc_mem_strdup(mctx, namebuf); 3041 { 3042 isc_symvalue_t symvalue; 3043 symvalue.as_cpointer = NULL; 3044 tresult = isc_symtab_define( 3045 inview, tmp, 1, symvalue, 3046 isc_symexists_replace); 3047 if (tresult == ISC_R_NOMEMORY) { 3048 isc_mem_free(mctx, tmp); 3049 } 3050 if (result == ISC_R_SUCCESS && 3051 tresult != ISC_R_SUCCESS) 3052 { 3053 result = tresult; 3054 } 3055 } 3056 break; 3057 3058 default: 3059 UNREACHABLE(); 3060 } 3061 } 3062 3063 if (ztype == CFG_ZONE_INVIEW) { 3064 const cfg_obj_t *fwd = NULL; 3065 unsigned int maxopts = 1; 3066 3067 (void)cfg_map_get(zoptions, "forward", &fwd); 3068 if (fwd != NULL) { 3069 maxopts++; 3070 } 3071 fwd = NULL; 3072 (void)cfg_map_get(zoptions, "forwarders", &fwd); 3073 if (fwd != NULL) { 3074 maxopts++; 3075 } 3076 if (cfg_map_count(zoptions) > maxopts) { 3077 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 3078 "zone '%s': 'in-view' used " 3079 "with incompatible zone options", 3080 znamestr); 3081 if (result == ISC_R_SUCCESS) { 3082 result = ISC_R_FAILURE; 3083 } 3084 } 3085 return (result); 3086 } 3087 3088 /* 3089 * Check if value is zero. 3090 */ 3091 if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS) { 3092 result = ISC_R_FAILURE; 3093 } 3094 3095 /* 3096 * Check if a dnssec-policy is set. 3097 */ 3098 obj = NULL; 3099 (void)cfg_map_get(zoptions, "dnssec-policy", &obj); 3100 if (obj == NULL && voptions != NULL) { 3101 (void)cfg_map_get(voptions, "dnssec-policy", &obj); 3102 } 3103 if (obj == NULL && goptions != NULL) { 3104 (void)cfg_map_get(goptions, "dnssec-policy", &obj); 3105 } 3106 if (obj != NULL) { 3107 const cfg_obj_t *kasps = NULL; 3108 3109 kaspname = cfg_obj_asstring(obj); 3110 if (strcmp(kaspname, "default") == 0) { 3111 has_dnssecpolicy = true; 3112 } else if (strcmp(kaspname, "insecure") == 0) { 3113 has_dnssecpolicy = true; 3114 } else if (strcmp(kaspname, "none") == 0) { 3115 has_dnssecpolicy = false; 3116 } else { 3117 (void)cfg_map_get(config, "dnssec-policy", &kasps); 3118 for (element = cfg_list_first(kasps); element != NULL; 3119 element = cfg_list_next(element)) 3120 { 3121 const cfg_obj_t *kobj = cfg_tuple_get( 3122 cfg_listelt_value(element), "name"); 3123 if (strcmp(kaspname, cfg_obj_asstring(kobj)) == 3124 0) 3125 { 3126 has_dnssecpolicy = true; 3127 } 3128 } 3129 3130 if (!has_dnssecpolicy) { 3131 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 3132 "zone '%s': option " 3133 "'dnssec-policy %s' has no " 3134 "matching dnssec-policy config", 3135 znamestr, kaspname); 3136 if (result == ISC_R_SUCCESS) { 3137 result = ISC_R_FAILURE; 3138 } 3139 } 3140 } 3141 if (has_dnssecpolicy) { 3142 kasp = obj; 3143 } 3144 } 3145 3146 /* 3147 * Warn about zones with both dnssec-policy and max-zone-ttl 3148 */ 3149 if (has_dnssecpolicy) { 3150 obj = NULL; 3151 (void)cfg_map_get(zoptions, "max-zone-ttl", &obj); 3152 if (obj == NULL && voptions != NULL) { 3153 (void)cfg_map_get(voptions, "max-zone-ttl", &obj); 3154 } 3155 if (obj == NULL && goptions != NULL) { 3156 (void)cfg_map_get(goptions, "max-zone-ttl", &obj); 3157 } 3158 if (obj != NULL) { 3159 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 3160 "zone '%s': option 'max-zone-ttl' " 3161 "is ignored when used together with " 3162 "'dnssec-policy'", 3163 znamestr); 3164 } 3165 } 3166 3167 /* 3168 * Check validity of the zone options. 3169 */ 3170 option = cfg_map_firstclause(&cfg_type_zoneopts, &clauses, &i); 3171 while (option != NULL) { 3172 obj = NULL; 3173 if (cfg_map_get(zoptions, option, &obj) == ISC_R_SUCCESS && 3174 obj != NULL && !cfg_clause_validforzone(option, ztype)) 3175 { 3176 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 3177 "option '%s' is not allowed " 3178 "in '%s' zone '%s'", 3179 option, typestr, znamestr); 3180 result = ISC_R_FAILURE; 3181 } 3182 option = cfg_map_nextclause(&cfg_type_zoneopts, &clauses, &i); 3183 } 3184 3185 /* 3186 * Check that ACLs expand correctly. 3187 */ 3188 for (i = 0; i < ARRAY_SIZE(acls); i++) { 3189 tresult = checkacl(acls[i], actx, zconfig, voptions, config, 3190 logctx, mctx); 3191 if (tresult != ISC_R_SUCCESS) { 3192 result = tresult; 3193 } 3194 } 3195 3196 /* 3197 * Only a limited subset of all possible "notify" settings can be used 3198 * at the zone level for mirror zones. 3199 */ 3200 if (ztype == CFG_ZONE_MIRROR && 3201 !check_mirror_zone_notify(zoptions, znamestr, logctx)) 3202 { 3203 result = ISC_R_FAILURE; 3204 } 3205 3206 /* 3207 * Primary, secondary, and mirror zones may have an "also-notify" 3208 * field, but shouldn't if notify is disabled. 3209 */ 3210 if (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_SECONDARY || 3211 ztype == CFG_ZONE_MIRROR) 3212 { 3213 bool donotify = true; 3214 3215 obj = NULL; 3216 tresult = cfg_map_get(zoptions, "notify", &obj); 3217 if (tresult != ISC_R_SUCCESS && voptions != NULL) { 3218 tresult = cfg_map_get(voptions, "notify", &obj); 3219 } 3220 if (tresult != ISC_R_SUCCESS && goptions != NULL) { 3221 tresult = cfg_map_get(goptions, "notify", &obj); 3222 } 3223 if (tresult == ISC_R_SUCCESS) { 3224 if (cfg_obj_isboolean(obj)) { 3225 donotify = cfg_obj_asboolean(obj); 3226 } else { 3227 const char *str = cfg_obj_asstring(obj); 3228 if (ztype != CFG_ZONE_PRIMARY && 3229 (strcasecmp(str, "master-only") == 0 || 3230 strcasecmp(str, "primary-only") == 0)) 3231 { 3232 donotify = false; 3233 } 3234 } 3235 } 3236 3237 obj = NULL; 3238 tresult = cfg_map_get(zoptions, "also-notify", &obj); 3239 if (tresult == ISC_R_SUCCESS && !donotify) { 3240 cfg_obj_log(zoptions, logctx, ISC_LOG_WARNING, 3241 "zone '%s': 'also-notify' set but " 3242 "'notify' is disabled", 3243 znamestr); 3244 } 3245 if (tresult != ISC_R_SUCCESS && voptions != NULL) { 3246 tresult = cfg_map_get(voptions, "also-notify", &obj); 3247 } 3248 if (tresult != ISC_R_SUCCESS && goptions != NULL) { 3249 tresult = cfg_map_get(goptions, "also-notify", &obj); 3250 } 3251 if (tresult == ISC_R_SUCCESS && donotify) { 3252 uint32_t count; 3253 tresult = validate_remotes("primaries", obj, config, 3254 &count, logctx, mctx); 3255 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS) 3256 { 3257 result = tresult; 3258 } 3259 } 3260 } 3261 3262 /* 3263 * Secondary, mirror, and stub zones must have a "primaries" field, 3264 * with one exception: when mirroring the root zone, a default, 3265 * built-in primary server list is used in the absence of one 3266 * explicitly specified. 3267 */ 3268 if (ztype == CFG_ZONE_SECONDARY || ztype == CFG_ZONE_STUB || 3269 (ztype == CFG_ZONE_MIRROR && zname != NULL && 3270 !dns_name_equal(zname, dns_rootname))) 3271 { 3272 obj = NULL; 3273 (void)cfg_map_get(zoptions, "primaries", &obj); 3274 if (obj == NULL) { 3275 /* If "primaries" was unset, check for "masters" */ 3276 (void)cfg_map_get(zoptions, "masters", &obj); 3277 } else { 3278 const cfg_obj_t *obj2 = NULL; 3279 3280 /* ...bug if it was set, "masters" must not be. */ 3281 (void)cfg_map_get(zoptions, "masters", &obj2); 3282 if (obj2 != NULL) { 3283 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3284 "'primaries' and 'masters' cannot " 3285 "both be used in the same zone"); 3286 result = ISC_R_FAILURE; 3287 } 3288 } 3289 if (obj == NULL) { 3290 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR, 3291 "zone '%s': missing 'primaries' entry", 3292 znamestr); 3293 result = ISC_R_FAILURE; 3294 } else { 3295 uint32_t count; 3296 tresult = validate_remotes("primaries", obj, config, 3297 &count, logctx, mctx); 3298 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS) 3299 { 3300 result = tresult; 3301 } 3302 if (tresult == ISC_R_SUCCESS && count == 0) { 3303 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR, 3304 "zone '%s': " 3305 "empty 'primaries' entry", 3306 znamestr); 3307 result = ISC_R_FAILURE; 3308 } 3309 } 3310 } 3311 3312 /* 3313 * Warn if *-source and *-source-v6 options specify a port, 3314 * and fail if they specify the default listener port. 3315 */ 3316 for (i = 0; i < ARRAY_SIZE(sources); i++) { 3317 obj = NULL; 3318 (void)cfg_map_get(zoptions, sources[i], &obj); 3319 if (obj == NULL && goptions != NULL) { 3320 (void)cfg_map_get(goptions, sources[i], &obj); 3321 } 3322 if (obj != NULL) { 3323 in_port_t port = 3324 isc_sockaddr_getport(cfg_obj_assockaddr(obj)); 3325 if (port == dnsport) { 3326 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3327 "'%s' cannot specify the " 3328 "DNS listener port (%d)", 3329 sources[i], port); 3330 result = ISC_R_FAILURE; 3331 } else if (port != 0) { 3332 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 3333 "'%s': specifying a port is " 3334 "not recommended", 3335 sources[i]); 3336 } 3337 } 3338 } 3339 3340 /* 3341 * Primary and secondary zones that have a "parental-agents" field, 3342 * must have a corresponding "parental-agents" clause. 3343 */ 3344 if (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_SECONDARY) { 3345 obj = NULL; 3346 (void)cfg_map_get(zoptions, "parental-agents", &obj); 3347 if (obj != NULL) { 3348 uint32_t count; 3349 tresult = validate_remotes("parental-agents", obj, 3350 config, &count, logctx, 3351 mctx); 3352 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS) 3353 { 3354 result = tresult; 3355 } 3356 if (tresult == ISC_R_SUCCESS && count == 0) { 3357 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR, 3358 "zone '%s': " 3359 "empty 'parental-agents' entry", 3360 znamestr); 3361 result = ISC_R_FAILURE; 3362 } 3363 } 3364 } 3365 3366 /* 3367 * Configuring a mirror zone and disabling recursion at the same time 3368 * contradicts the purpose of the former. 3369 */ 3370 if (ztype == CFG_ZONE_MIRROR && 3371 !check_recursion(config, voptions, goptions, logctx, actx, mctx)) 3372 { 3373 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR, 3374 "zone '%s': mirror zones cannot be used if " 3375 "recursion is disabled", 3376 znamestr); 3377 result = ISC_R_FAILURE; 3378 } 3379 3380 /* 3381 * Primary zones can't have both "allow-update" and "update-policy". 3382 */ 3383 if (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_SECONDARY) { 3384 bool signing = false; 3385 isc_result_t res1, res2, res3; 3386 const cfg_obj_t *au = NULL; 3387 const char *arg; 3388 3389 obj = NULL; 3390 res1 = cfg_map_get(zoptions, "allow-update", &au); 3391 obj = NULL; 3392 res2 = cfg_map_get(zoptions, "update-policy", &obj); 3393 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) { 3394 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3395 "zone '%s': 'allow-update' is ignored " 3396 "when 'update-policy' is present", 3397 znamestr); 3398 result = ISC_R_FAILURE; 3399 } else if (res2 == ISC_R_SUCCESS) { 3400 res3 = check_update_policy(obj, logctx); 3401 if (res3 != ISC_R_SUCCESS) { 3402 result = ISC_R_FAILURE; 3403 } 3404 } 3405 3406 /* 3407 * To determine whether auto-dnssec is allowed, 3408 * we should also check for allow-update at the 3409 * view and options levels. 3410 */ 3411 if (res1 != ISC_R_SUCCESS && voptions != NULL) { 3412 res1 = cfg_map_get(voptions, "allow-update", &au); 3413 } 3414 if (res1 != ISC_R_SUCCESS && goptions != NULL) { 3415 res1 = cfg_map_get(goptions, "allow-update", &au); 3416 } 3417 3418 if (res2 == ISC_R_SUCCESS) { 3419 ddns = true; 3420 } else if (res1 == ISC_R_SUCCESS) { 3421 dns_acl_t *acl = NULL; 3422 res1 = cfg_acl_fromconfig(au, config, logctx, actx, 3423 mctx, 0, &acl); 3424 if (res1 != ISC_R_SUCCESS) { 3425 cfg_obj_log(au, logctx, ISC_LOG_ERROR, 3426 "acl expansion failed: %s", 3427 isc_result_totext(result)); 3428 result = ISC_R_FAILURE; 3429 } else if (acl != NULL) { 3430 if (!dns_acl_isnone(acl)) { 3431 ddns = true; 3432 } 3433 dns_acl_detach(&acl); 3434 } 3435 } 3436 3437 obj = NULL; 3438 res1 = cfg_map_get(zoptions, "inline-signing", &obj); 3439 if (res1 == ISC_R_SUCCESS) { 3440 signing = cfg_obj_asboolean(obj); 3441 } 3442 3443 if (has_dnssecpolicy) { 3444 if (!ddns && !signing) { 3445 cfg_obj_log(kasp, logctx, ISC_LOG_ERROR, 3446 "'inline-signing yes;' must also " 3447 "be configured explicitly for " 3448 "zones using dnssec-policy%s. See " 3449 "https://kb.isc.org/docs/" 3450 "dnssec-policy-requires-dynamic-" 3451 "dns-or-inline-signing", 3452 (ztype == CFG_ZONE_PRIMARY) 3453 ? " without a configured " 3454 "'allow-update' or " 3455 "'update-policy'" 3456 : ""); 3457 result = ISC_R_FAILURE; 3458 } 3459 } 3460 3461 obj = NULL; 3462 arg = "off"; 3463 res3 = cfg_map_get(zoptions, "auto-dnssec", &obj); 3464 if (res3 == ISC_R_SUCCESS) { 3465 arg = cfg_obj_asstring(obj); 3466 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 3467 "'auto-dnssec' option is deprecated and " 3468 "will be removed in BIND 9.19. Please " 3469 "migrate to dnssec-policy"); 3470 } 3471 if (strcasecmp(arg, "off") != 0) { 3472 if (!ddns && !signing && !has_dnssecpolicy) { 3473 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3474 "'auto-dnssec %s;' requires%s " 3475 "inline-signing to be configured " 3476 "for the zone", 3477 arg, 3478 (ztype == CFG_ZONE_PRIMARY) 3479 ? " dynamic DNS or" 3480 : ""); 3481 result = ISC_R_FAILURE; 3482 } 3483 3484 if (has_dnssecpolicy) { 3485 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3486 "'auto-dnssec %s;' cannot be " 3487 "configured if dnssec-policy is " 3488 "also set", 3489 arg); 3490 result = ISC_R_FAILURE; 3491 } 3492 } 3493 3494 obj = NULL; 3495 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj); 3496 if (res1 == ISC_R_SUCCESS) { 3497 uint32_t type = cfg_obj_asuint32(obj); 3498 if (type < 0xff00U || type > 0xffffU) { 3499 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3500 "sig-signing-type: %u out of " 3501 "range [%u..%u]", 3502 type, 0xff00U, 0xffffU); 3503 result = ISC_R_FAILURE; 3504 } 3505 } 3506 3507 obj = NULL; 3508 res1 = cfg_map_get(zoptions, "dnssec-dnskey-kskonly", &obj); 3509 if (res1 == ISC_R_SUCCESS && ztype == CFG_ZONE_SECONDARY && 3510 !signing) 3511 { 3512 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3513 "dnssec-dnskey-kskonly: requires " 3514 "inline-signing when used in secondary " 3515 "zone"); 3516 result = ISC_R_FAILURE; 3517 } 3518 if (res1 == ISC_R_SUCCESS && has_dnssecpolicy) { 3519 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3520 "dnssec-dnskey-kskonly: cannot be " 3521 "configured if dnssec-policy is also set"); 3522 result = ISC_R_FAILURE; 3523 } 3524 3525 obj = NULL; 3526 res1 = cfg_map_get(zoptions, "dnssec-secure-to-insecure", &obj); 3527 if (res1 == ISC_R_SUCCESS && has_dnssecpolicy) { 3528 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3529 "dnssec-secure-to-insecure: cannot be " 3530 "configured if dnssec-policy is also set"); 3531 result = ISC_R_FAILURE; 3532 } 3533 3534 obj = NULL; 3535 res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj); 3536 if (res1 == ISC_R_SUCCESS && ztype == CFG_ZONE_SECONDARY && 3537 !signing) 3538 { 3539 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3540 "dnssec-loadkeys-interval: requires " 3541 "inline-signing when used in secondary " 3542 "zone"); 3543 result = ISC_R_FAILURE; 3544 } 3545 3546 obj = NULL; 3547 res1 = cfg_map_get(zoptions, "update-check-ksk", &obj); 3548 if (res1 == ISC_R_SUCCESS && ztype == CFG_ZONE_SECONDARY && 3549 !signing) 3550 { 3551 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3552 "update-check-ksk: requires " 3553 "inline-signing when used in secondary " 3554 "zone"); 3555 result = ISC_R_FAILURE; 3556 } 3557 if (res1 == ISC_R_SUCCESS && has_dnssecpolicy) { 3558 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3559 "update-check-ksk: cannot be configured " 3560 "if dnssec-policy is also set"); 3561 result = ISC_R_FAILURE; 3562 } 3563 3564 obj = NULL; 3565 res1 = cfg_map_get(zoptions, "dnssec-update-mode", &obj); 3566 if (res1 == ISC_R_SUCCESS && has_dnssecpolicy) { 3567 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3568 "dnssec-update-mode: cannot be configured " 3569 "if dnssec-policy is also set"); 3570 result = ISC_R_FAILURE; 3571 } 3572 } 3573 3574 /* 3575 * Check the excessively complicated "dialup" option. 3576 */ 3577 if (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_SECONDARY || 3578 ztype == CFG_ZONE_STUB) 3579 { 3580 obj = NULL; 3581 (void)cfg_map_get(zoptions, "dialup", &obj); 3582 if (obj != NULL && cfg_obj_isstring(obj)) { 3583 const char *str = cfg_obj_asstring(obj); 3584 for (i = 0; i < sizeof(dialups) / sizeof(dialups[0]); 3585 i++) 3586 { 3587 if (strcasecmp(dialups[i].name, str) != 0) { 3588 continue; 3589 } 3590 if ((dialups[i].allowed & ztype) == 0) { 3591 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3592 "dialup type '%s' is not " 3593 "allowed in '%s' " 3594 "zone '%s'", 3595 str, typestr, znamestr); 3596 result = ISC_R_FAILURE; 3597 } 3598 break; 3599 } 3600 if (i == sizeof(dialups) / sizeof(dialups[0])) { 3601 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3602 "invalid dialup type '%s' in zone " 3603 "'%s'", 3604 str, znamestr); 3605 result = ISC_R_FAILURE; 3606 } 3607 } 3608 } 3609 3610 /* 3611 * Check that forwarding is reasonable. 3612 */ 3613 obj = NULL; 3614 if (root) { 3615 if (voptions != NULL) { 3616 (void)cfg_map_get(voptions, "forwarders", &obj); 3617 } 3618 if (obj == NULL && goptions != NULL) { 3619 (void)cfg_map_get(goptions, "forwarders", &obj); 3620 } 3621 } 3622 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS) { 3623 result = ISC_R_FAILURE; 3624 } 3625 3626 /* 3627 * Check that a RFC 1918 / ULA reverse zone is not forward first 3628 * unless explicitly configured to be so. 3629 */ 3630 if (ztype == CFG_ZONE_FORWARD && (rfc1918 || ula)) { 3631 obj = NULL; 3632 (void)cfg_map_get(zoptions, "forward", &obj); 3633 if (obj == NULL) { 3634 /* 3635 * Forward mode not explicitly configured. 3636 */ 3637 if (voptions != NULL) { 3638 cfg_map_get(voptions, "forward", &obj); 3639 } 3640 if (obj == NULL && goptions != NULL) { 3641 cfg_map_get(goptions, "forward", &obj); 3642 } 3643 if (obj == NULL || 3644 strcasecmp(cfg_obj_asstring(obj), "first") == 0) 3645 { 3646 cfg_obj_log(zconfig, logctx, ISC_LOG_WARNING, 3647 "inherited 'forward first;' for " 3648 "%s zone '%s' - did you want " 3649 "'forward only;'?", 3650 rfc1918 ? "rfc1918" : "ula", 3651 znamestr); 3652 } 3653 } 3654 } 3655 3656 /* 3657 * Check validity of static stub server addresses. 3658 */ 3659 obj = NULL; 3660 (void)cfg_map_get(zoptions, "server-addresses", &obj); 3661 if (ztype == CFG_ZONE_STATICSTUB && obj != NULL) { 3662 for (element = cfg_list_first(obj); element != NULL; 3663 element = cfg_list_next(element)) 3664 { 3665 isc_sockaddr_t sa; 3666 isc_netaddr_t na; 3667 obj = cfg_listelt_value(element); 3668 sa = *cfg_obj_assockaddr(obj); 3669 3670 isc_netaddr_fromsockaddr(&na, &sa); 3671 if (isc_netaddr_getzone(&na) != 0) { 3672 result = ISC_R_FAILURE; 3673 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3674 "scoped address is not allowed " 3675 "for static stub " 3676 "server-addresses"); 3677 } 3678 } 3679 } 3680 3681 /* 3682 * Check validity of static stub server names. 3683 */ 3684 obj = NULL; 3685 (void)cfg_map_get(zoptions, "server-names", &obj); 3686 if (zname != NULL && ztype == CFG_ZONE_STATICSTUB && obj != NULL) { 3687 for (element = cfg_list_first(obj); element != NULL; 3688 element = cfg_list_next(element)) 3689 { 3690 const char *snamestr; 3691 dns_fixedname_t fixed_sname; 3692 isc_buffer_t b2; 3693 dns_name_t *sname; 3694 3695 obj = cfg_listelt_value(element); 3696 snamestr = cfg_obj_asstring(obj); 3697 3698 isc_buffer_constinit(&b2, snamestr, strlen(snamestr)); 3699 isc_buffer_add(&b2, strlen(snamestr)); 3700 sname = dns_fixedname_initname(&fixed_sname); 3701 tresult = dns_name_fromtext(sname, &b2, dns_rootname, 0, 3702 NULL); 3703 if (tresult != ISC_R_SUCCESS) { 3704 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 3705 "server-name '%s' is not a valid " 3706 "name", 3707 snamestr); 3708 result = ISC_R_FAILURE; 3709 } else if (dns_name_issubdomain(sname, zname)) { 3710 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 3711 "server-name '%s' must not be a " 3712 "subdomain of zone name '%s'", 3713 snamestr, znamestr); 3714 result = ISC_R_FAILURE; 3715 } 3716 } 3717 } 3718 3719 /* 3720 * Warn if key-directory doesn't exist 3721 */ 3722 obj = NULL; 3723 (void)cfg_map_get(zoptions, "key-directory", &obj); 3724 if (obj == NULL && voptions != NULL) { 3725 (void)cfg_map_get(voptions, "key-directory", &obj); 3726 } 3727 if (obj == NULL && goptions != NULL) { 3728 (void)cfg_map_get(goptions, "key-directory", &obj); 3729 } 3730 if (obj != NULL) { 3731 dir = cfg_obj_asstring(obj); 3732 3733 tresult = isc_file_isdirectory(dir); 3734 switch (tresult) { 3735 case ISC_R_SUCCESS: 3736 break; 3737 case ISC_R_FILENOTFOUND: 3738 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 3739 "key-directory: '%s' does not exist", dir); 3740 break; 3741 case ISC_R_INVALIDFILE: 3742 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 3743 "key-directory: '%s' is not a directory", 3744 dir); 3745 break; 3746 default: 3747 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 3748 "key-directory: '%s' %s", dir, 3749 isc_result_totext(tresult)); 3750 result = tresult; 3751 } 3752 } 3753 3754 /* 3755 * Make sure there is no other zone with the same 3756 * key-directory and a different dnssec-policy. 3757 */ 3758 if (zname != NULL) { 3759 char keydirbuf[DNS_NAME_FORMATSIZE + 128]; 3760 char *tmp = keydirbuf; 3761 size_t len = sizeof(keydirbuf); 3762 dns_name_format(zname, keydirbuf, sizeof(keydirbuf)); 3763 len -= strlen(tmp); 3764 tmp += strlen(tmp); 3765 (void)snprintf(tmp, len, "/%s", (dir == NULL) ? "(null)" : dir); 3766 tresult = keydirexist(zconfig, (const char *)keydirbuf, 3767 kaspname, keydirs, logctx, mctx); 3768 if (tresult != ISC_R_SUCCESS) { 3769 result = tresult; 3770 } 3771 } 3772 3773 /* 3774 * Check various options. 3775 */ 3776 tresult = check_options(zoptions, config, logctx, mctx, optlevel_zone); 3777 if (tresult != ISC_R_SUCCESS) { 3778 result = tresult; 3779 } 3780 3781 /* 3782 * If the zone type is rbt/rbt64 then primary/hint zones require file 3783 * clauses. If inline-signing is used, then secondary zones require a 3784 * file clause as well. 3785 */ 3786 obj = NULL; 3787 dlz = false; 3788 tresult = cfg_map_get(zoptions, "dlz", &obj); 3789 if (tresult == ISC_R_SUCCESS) { 3790 dlz = true; 3791 } 3792 3793 obj = NULL; 3794 tresult = cfg_map_get(zoptions, "database", &obj); 3795 if (dlz && tresult == ISC_R_SUCCESS) { 3796 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 3797 "zone '%s': cannot specify both 'dlz' " 3798 "and 'database'", 3799 znamestr); 3800 result = ISC_R_FAILURE; 3801 } else if (!dlz && (tresult == ISC_R_NOTFOUND || 3802 (tresult == ISC_R_SUCCESS && 3803 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 || 3804 strcmp("rbt64", cfg_obj_asstring(obj)) == 0)))) 3805 { 3806 isc_result_t res1; 3807 const cfg_obj_t *fileobj = NULL; 3808 tresult = cfg_map_get(zoptions, "file", &fileobj); 3809 obj = NULL; 3810 res1 = cfg_map_get(zoptions, "inline-signing", &obj); 3811 if ((tresult != ISC_R_SUCCESS && 3812 (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_HINT || 3813 (ztype == CFG_ZONE_SECONDARY && res1 == ISC_R_SUCCESS && 3814 cfg_obj_asboolean(obj))))) 3815 { 3816 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 3817 "zone '%s': missing 'file' entry", 3818 znamestr); 3819 result = tresult; 3820 } else if (tresult == ISC_R_SUCCESS && 3821 (ztype == CFG_ZONE_SECONDARY || 3822 ztype == CFG_ZONE_MIRROR || ddns || 3823 has_dnssecpolicy)) 3824 { 3825 tresult = fileexist(fileobj, files, true, logctx); 3826 if (tresult != ISC_R_SUCCESS) { 3827 result = tresult; 3828 } 3829 } else if (tresult == ISC_R_SUCCESS && 3830 (ztype == CFG_ZONE_PRIMARY || 3831 ztype == CFG_ZONE_HINT)) 3832 { 3833 tresult = fileexist(fileobj, files, false, logctx); 3834 if (tresult != ISC_R_SUCCESS) { 3835 result = tresult; 3836 } 3837 } 3838 } 3839 3840 return (result); 3841} 3842 3843typedef struct keyalgorithms { 3844 const char *name; 3845 uint16_t size; 3846} algorithmtable; 3847 3848isc_result_t 3849bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) { 3850 const cfg_obj_t *algobj = NULL; 3851 const cfg_obj_t *secretobj = NULL; 3852 const char *keyname = cfg_obj_asstring(cfg_map_getname(key)); 3853 const char *algorithm; 3854 int i; 3855 size_t len = 0; 3856 isc_result_t result; 3857 isc_buffer_t buf; 3858 unsigned char secretbuf[1024]; 3859 static const algorithmtable algorithms[] = { 3860 { "hmac-md5", 128 }, 3861 { "hmac-md5.sig-alg.reg.int", 0 }, 3862 { "hmac-md5.sig-alg.reg.int.", 0 }, 3863 { "hmac-sha1", 160 }, 3864 { "hmac-sha224", 224 }, 3865 { "hmac-sha256", 256 }, 3866 { "hmac-sha384", 384 }, 3867 { "hmac-sha512", 512 }, 3868 { NULL, 0 } 3869 }; 3870 3871 (void)cfg_map_get(key, "algorithm", &algobj); 3872 (void)cfg_map_get(key, "secret", &secretobj); 3873 if (secretobj == NULL || algobj == NULL) { 3874 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 3875 "key '%s' must have both 'secret' and " 3876 "'algorithm' defined", 3877 keyname); 3878 return (ISC_R_FAILURE); 3879 } 3880 3881 isc_buffer_init(&buf, secretbuf, sizeof(secretbuf)); 3882 result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf); 3883 if (result != ISC_R_SUCCESS) { 3884 cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR, "bad secret '%s'", 3885 isc_result_totext(result)); 3886 return (result); 3887 } 3888 3889 algorithm = cfg_obj_asstring(algobj); 3890 for (i = 0; algorithms[i].name != NULL; i++) { 3891 len = strlen(algorithms[i].name); 3892 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 && 3893 (algorithm[len] == '\0' || 3894 (algorithms[i].size != 0 && algorithm[len] == '-'))) 3895 { 3896 break; 3897 } 3898 } 3899 if (algorithms[i].name == NULL) { 3900 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR, 3901 "unknown algorithm '%s'", algorithm); 3902 return (ISC_R_NOTFOUND); 3903 } 3904 if (algorithm[len] == '-') { 3905 uint16_t digestbits; 3906 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10); 3907 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) { 3908 if (result == ISC_R_RANGE || 3909 digestbits > algorithms[i].size) 3910 { 3911 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR, 3912 "key '%s' digest-bits too large " 3913 "[%u..%u]", 3914 keyname, algorithms[i].size / 2, 3915 algorithms[i].size); 3916 return (ISC_R_RANGE); 3917 } 3918 if ((digestbits % 8) != 0) { 3919 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR, 3920 "key '%s' digest-bits not multiple" 3921 " of 8", 3922 keyname); 3923 return (ISC_R_RANGE); 3924 } 3925 /* 3926 * Recommended minima for hmac algorithms. 3927 */ 3928 if ((digestbits < (algorithms[i].size / 2U) || 3929 (digestbits < 80U))) 3930 { 3931 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING, 3932 "key '%s' digest-bits too small " 3933 "[<%u]", 3934 keyname, algorithms[i].size / 2); 3935 } 3936 } else { 3937 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR, 3938 "key '%s': unable to parse digest-bits", 3939 keyname); 3940 return (result); 3941 } 3942 } 3943 return (ISC_R_SUCCESS); 3944} 3945 3946static isc_result_t 3947fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, bool writeable, 3948 isc_log_t *logctx) { 3949 isc_result_t result; 3950 isc_symvalue_t symvalue; 3951 unsigned int line; 3952 const char *file; 3953 3954 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 0, &symvalue); 3955 if (result == ISC_R_SUCCESS) { 3956 if (writeable) { 3957 file = cfg_obj_file(symvalue.as_cpointer); 3958 line = cfg_obj_line(symvalue.as_cpointer); 3959 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3960 "writeable file '%s': already in use: " 3961 "%s:%u", 3962 cfg_obj_asstring(obj), file, line); 3963 return (ISC_R_EXISTS); 3964 } 3965 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 2, 3966 &symvalue); 3967 if (result == ISC_R_SUCCESS) { 3968 file = cfg_obj_file(symvalue.as_cpointer); 3969 line = cfg_obj_line(symvalue.as_cpointer); 3970 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3971 "writeable file '%s': already in use: " 3972 "%s:%u", 3973 cfg_obj_asstring(obj), file, line); 3974 return (ISC_R_EXISTS); 3975 } 3976 return (ISC_R_SUCCESS); 3977 } 3978 3979 symvalue.as_cpointer = obj; 3980 result = isc_symtab_define(symtab, cfg_obj_asstring(obj), 3981 writeable ? 2 : 1, symvalue, 3982 isc_symexists_reject); 3983 return (result); 3984} 3985 3986static isc_result_t 3987keydirexist(const cfg_obj_t *zcfg, const char *keydir, const char *kaspnamestr, 3988 isc_symtab_t *symtab, isc_log_t *logctx, isc_mem_t *mctx) { 3989 isc_result_t result; 3990 isc_symvalue_t symvalue; 3991 char *symkey; 3992 3993 if (kaspnamestr == NULL || strcmp(kaspnamestr, "none") == 0) { 3994 return (ISC_R_SUCCESS); 3995 } 3996 3997 result = isc_symtab_lookup(symtab, keydir, 0, &symvalue); 3998 if (result == ISC_R_SUCCESS) { 3999 const cfg_obj_t *kasp = NULL; 4000 const cfg_obj_t *exist = symvalue.as_cpointer; 4001 const char *file = cfg_obj_file(exist); 4002 unsigned int line = cfg_obj_line(exist); 4003 4004 /* 4005 * Having the same key-directory for the same zone is fine 4006 * iff the zone is using the same policy, or has no policy. 4007 */ 4008 (void)cfg_map_get(cfg_tuple_get(exist, "options"), 4009 "dnssec-policy", &kasp); 4010 if (kasp == NULL || 4011 strcmp(cfg_obj_asstring(kasp), "none") == 0 || 4012 strcmp(cfg_obj_asstring(kasp), kaspnamestr) == 0) 4013 { 4014 return (ISC_R_SUCCESS); 4015 } 4016 4017 cfg_obj_log(zcfg, logctx, ISC_LOG_ERROR, 4018 "key-directory '%s' already in use by zone %s with " 4019 "policy %s: %s:%u", 4020 keydir, 4021 cfg_obj_asstring(cfg_tuple_get(exist, "name")), 4022 cfg_obj_asstring(kasp), file, line); 4023 return (ISC_R_EXISTS); 4024 } 4025 4026 /* 4027 * Add the new zone plus key-directory. 4028 */ 4029 symkey = isc_mem_strdup(mctx, keydir); 4030 symvalue.as_cpointer = zcfg; 4031 result = isc_symtab_define(symtab, symkey, 2, symvalue, 4032 isc_symexists_reject); 4033 return (result); 4034} 4035 4036/* 4037 * Check key list for duplicates key names and that the key names 4038 * are valid domain names as these keys are used for TSIG. 4039 * 4040 * Check the key contents for validity. 4041 */ 4042static isc_result_t 4043check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab, isc_mem_t *mctx, 4044 isc_log_t *logctx) { 4045 char namebuf[DNS_NAME_FORMATSIZE]; 4046 dns_fixedname_t fname; 4047 dns_name_t *name; 4048 isc_result_t result = ISC_R_SUCCESS; 4049 isc_result_t tresult; 4050 const cfg_listelt_t *element; 4051 4052 name = dns_fixedname_initname(&fname); 4053 for (element = cfg_list_first(keys); element != NULL; 4054 element = cfg_list_next(element)) 4055 { 4056 const cfg_obj_t *key = cfg_listelt_value(element); 4057 const char *keyid = cfg_obj_asstring(cfg_map_getname(key)); 4058 isc_symvalue_t symvalue; 4059 isc_buffer_t b; 4060 char *keyname; 4061 4062 isc_buffer_constinit(&b, keyid, strlen(keyid)); 4063 isc_buffer_add(&b, strlen(keyid)); 4064 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); 4065 if (tresult != ISC_R_SUCCESS) { 4066 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4067 "key '%s': bad key name", keyid); 4068 result = tresult; 4069 continue; 4070 } 4071 tresult = bind9_check_key(key, logctx); 4072 if (tresult != ISC_R_SUCCESS) { 4073 return (tresult); 4074 } 4075 4076 dns_name_format(name, namebuf, sizeof(namebuf)); 4077 keyname = isc_mem_strdup(mctx, namebuf); 4078 symvalue.as_cpointer = key; 4079 tresult = isc_symtab_define(symtab, keyname, 1, symvalue, 4080 isc_symexists_reject); 4081 if (tresult == ISC_R_EXISTS) { 4082 const char *file; 4083 unsigned int line; 4084 4085 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname, 1, 4086 &symvalue) == 4087 ISC_R_SUCCESS); 4088 file = cfg_obj_file(symvalue.as_cpointer); 4089 line = cfg_obj_line(symvalue.as_cpointer); 4090 4091 if (file == NULL) { 4092 file = "<unknown file>"; 4093 } 4094 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4095 "key '%s': already exists " 4096 "previous definition: %s:%u", 4097 keyid, file, line); 4098 isc_mem_free(mctx, keyname); 4099 result = tresult; 4100 } else if (tresult != ISC_R_SUCCESS) { 4101 isc_mem_free(mctx, keyname); 4102 return (tresult); 4103 } 4104 } 4105 return (result); 4106} 4107 4108/* 4109 * RNDC keys are not normalised unlike TSIG keys. 4110 * 4111 * "foo." is different to "foo". 4112 */ 4113static bool 4114rndckey_exists(const cfg_obj_t *keylist, const char *keyname) { 4115 const cfg_listelt_t *element; 4116 const cfg_obj_t *obj; 4117 const char *str; 4118 4119 if (keylist == NULL) { 4120 return (false); 4121 } 4122 4123 for (element = cfg_list_first(keylist); element != NULL; 4124 element = cfg_list_next(element)) 4125 { 4126 obj = cfg_listelt_value(element); 4127 str = cfg_obj_asstring(cfg_map_getname(obj)); 4128 if (!strcasecmp(str, keyname)) { 4129 return (true); 4130 } 4131 } 4132 return (false); 4133} 4134 4135static struct { 4136 const char *v4; 4137 const char *v6; 4138} sources[] = { { "transfer-source", "transfer-source-v6" }, 4139 { "notify-source", "notify-source-v6" }, 4140 { "parental-source", "parental-source-v6" }, 4141 { "query-source", "query-source-v6" }, 4142 { NULL, NULL } }; 4143 4144static struct { 4145 const char *name; 4146 isc_result_t (*set)(dns_peer_t *peer, bool newval); 4147} bools[] = { 4148 { "bogus", dns_peer_setbogus }, 4149 { "edns", dns_peer_setsupportedns }, 4150 { "provide-ixfr", dns_peer_setprovideixfr }, 4151 { "request-expire", dns_peer_setrequestexpire }, 4152 { "request-ixfr", dns_peer_setrequestixfr }, 4153 { "request-nsid", dns_peer_setrequestnsid }, 4154 { "send-cookie", dns_peer_setsendcookie }, 4155 { "tcp-keepalive", dns_peer_settcpkeepalive }, 4156 { "tcp-only", dns_peer_setforcetcp }, 4157}; 4158 4159static isc_result_t 4160check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions, 4161 isc_symtab_t *symtab, isc_mem_t *mctx, isc_log_t *logctx) { 4162 dns_fixedname_t fname; 4163 isc_result_t result = ISC_R_SUCCESS; 4164 isc_result_t tresult; 4165 const cfg_listelt_t *e1, *e2; 4166 const cfg_obj_t *v1, *v2, *keys; 4167 const cfg_obj_t *servers; 4168 isc_netaddr_t n1, n2; 4169 unsigned int p1, p2; 4170 const cfg_obj_t *obj; 4171 char buf[ISC_NETADDR_FORMATSIZE]; 4172 char namebuf[DNS_NAME_FORMATSIZE]; 4173 const char *xfr; 4174 const char *keyval; 4175 isc_buffer_t b; 4176 int source; 4177 dns_name_t *keyname; 4178 4179 servers = NULL; 4180 if (voptions != NULL) { 4181 (void)cfg_map_get(voptions, "server", &servers); 4182 } 4183 if (servers == NULL) { 4184 (void)cfg_map_get(config, "server", &servers); 4185 } 4186 if (servers == NULL) { 4187 return (ISC_R_SUCCESS); 4188 } 4189 4190 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) { 4191 dns_peer_t *peer = NULL; 4192 size_t i; 4193 v1 = cfg_listelt_value(e1); 4194 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1); 4195 /* 4196 * Check that unused bits are zero. 4197 */ 4198 tresult = isc_netaddr_prefixok(&n1, p1); 4199 if (tresult != ISC_R_SUCCESS) { 4200 INSIST(tresult == ISC_R_FAILURE); 4201 isc_netaddr_format(&n1, buf, sizeof(buf)); 4202 cfg_obj_log(v1, logctx, ISC_LOG_ERROR, 4203 "server '%s/%u': invalid prefix " 4204 "(extra bits specified)", 4205 buf, p1); 4206 result = tresult; 4207 } 4208 source = 0; 4209 do { 4210 /* 4211 * For a v6 server we can't specify a v4 source, 4212 * and vice versa. 4213 */ 4214 obj = NULL; 4215 if (n1.family == AF_INET) { 4216 xfr = sources[source].v6; 4217 } else { 4218 xfr = sources[source].v4; 4219 } 4220 (void)cfg_map_get(v1, xfr, &obj); 4221 if (obj != NULL) { 4222 isc_netaddr_format(&n1, buf, sizeof(buf)); 4223 cfg_obj_log(v1, logctx, ISC_LOG_ERROR, 4224 "server '%s/%u': %s not legal", buf, 4225 p1, xfr); 4226 result = ISC_R_FAILURE; 4227 } 4228 4229 /* 4230 * Check that we aren't using the DNS 4231 * listener port (i.e. 53, or whatever was set 4232 * as "port" in options) as a source port. 4233 */ 4234 obj = NULL; 4235 if (n1.family == AF_INET) { 4236 xfr = sources[source].v4; 4237 } else { 4238 xfr = sources[source].v6; 4239 } 4240 (void)cfg_map_get(v1, xfr, &obj); 4241 if (obj != NULL) { 4242 const isc_sockaddr_t *sa = 4243 cfg_obj_assockaddr(obj); 4244 in_port_t port = isc_sockaddr_getport(sa); 4245 if (port == dnsport) { 4246 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 4247 "'%s' cannot specify the " 4248 "DNS listener port (%d)", 4249 xfr, port); 4250 result = ISC_R_FAILURE; 4251 } 4252 } 4253 } while (sources[++source].v4 != NULL); 4254 e2 = e1; 4255 while ((e2 = cfg_list_next(e2)) != NULL) { 4256 v2 = cfg_listelt_value(e2); 4257 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2); 4258 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) { 4259 const char *file = cfg_obj_file(v1); 4260 unsigned int line = cfg_obj_line(v1); 4261 4262 if (file == NULL) { 4263 file = "<unknown file>"; 4264 } 4265 4266 isc_netaddr_format(&n2, buf, sizeof(buf)); 4267 cfg_obj_log(v2, logctx, ISC_LOG_ERROR, 4268 "server '%s/%u': already exists " 4269 "previous definition: %s:%u", 4270 buf, p2, file, line); 4271 result = ISC_R_FAILURE; 4272 } 4273 } 4274 keys = NULL; 4275 cfg_map_get(v1, "keys", &keys); 4276 if (keys != NULL) { 4277 /* 4278 * Normalize key name. 4279 */ 4280 keyval = cfg_obj_asstring(keys); 4281 isc_buffer_constinit(&b, keyval, strlen(keyval)); 4282 isc_buffer_add(&b, strlen(keyval)); 4283 keyname = dns_fixedname_initname(&fname); 4284 tresult = dns_name_fromtext(keyname, &b, dns_rootname, 4285 0, NULL); 4286 if (tresult != ISC_R_SUCCESS) { 4287 cfg_obj_log(keys, logctx, ISC_LOG_ERROR, 4288 "bad key name '%s'", keyval); 4289 result = ISC_R_FAILURE; 4290 continue; 4291 } 4292 dns_name_format(keyname, namebuf, sizeof(namebuf)); 4293 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL); 4294 if (tresult != ISC_R_SUCCESS) { 4295 cfg_obj_log(keys, logctx, ISC_LOG_ERROR, 4296 "unknown key '%s'", keyval); 4297 result = ISC_R_FAILURE; 4298 } 4299 } 4300 (void)dns_peer_newprefix(mctx, &n1, p1, &peer); 4301 for (i = 0; i < ARRAY_SIZE(bools); i++) { 4302 const cfg_obj_t *opt = NULL; 4303 cfg_map_get(v1, bools[i].name, &opt); 4304 if (opt != NULL) { 4305 tresult = (bools[i].set)( 4306 peer, cfg_obj_asboolean(opt)); 4307 if (tresult != ISC_R_SUCCESS) { 4308 cfg_obj_log(opt, logctx, ISC_LOG_ERROR, 4309 "setting server option " 4310 "'%s' failed: %s", 4311 bools[i].name, 4312 isc_result_totext(tresult)); 4313 result = ISC_R_FAILURE; 4314 } 4315 } 4316 } 4317 dns_peer_detach(&peer); 4318 } 4319 return (result); 4320} 4321 4322#define ROOT_KSK_STATIC 0x01 4323#define ROOT_KSK_MANAGED 0x02 4324#define ROOT_KSK_ANY 0x03 4325#define ROOT_KSK_2010 0x04 4326#define ROOT_KSK_2017 0x08 4327 4328static isc_result_t 4329check_trust_anchor(const cfg_obj_t *key, bool managed, unsigned int *flagsp, 4330 isc_log_t *logctx) { 4331 const char *str = NULL, *namestr = NULL; 4332 dns_fixedname_t fkeyname; 4333 dns_name_t *keyname = NULL; 4334 isc_buffer_t b; 4335 isc_region_t r; 4336 isc_result_t result = ISC_R_SUCCESS; 4337 isc_result_t tresult; 4338 uint32_t rdata1, rdata2, rdata3; 4339 unsigned char data[4096]; 4340 const char *atstr = NULL; 4341 enum { 4342 INIT_DNSKEY, 4343 STATIC_DNSKEY, 4344 INIT_DS, 4345 STATIC_DS, 4346 TRUSTED 4347 } anchortype; 4348 4349 /* 4350 * The 2010 and 2017 IANA root keys - these are used below 4351 * to check the contents of trusted, initial and 4352 * static trust anchor configurations. 4353 */ 4354 static const unsigned char root_ksk_2010[] = { 4355 0x03, 0x01, 0x00, 0x01, 0xa8, 0x00, 0x20, 0xa9, 0x55, 0x66, 4356 0xba, 0x42, 0xe8, 0x86, 0xbb, 0x80, 0x4c, 0xda, 0x84, 0xe4, 4357 0x7e, 0xf5, 0x6d, 0xbd, 0x7a, 0xec, 0x61, 0x26, 0x15, 0x55, 4358 0x2c, 0xec, 0x90, 0x6d, 0x21, 0x16, 0xd0, 0xef, 0x20, 0x70, 4359 0x28, 0xc5, 0x15, 0x54, 0x14, 0x4d, 0xfe, 0xaf, 0xe7, 0xc7, 4360 0xcb, 0x8f, 0x00, 0x5d, 0xd1, 0x82, 0x34, 0x13, 0x3a, 0xc0, 4361 0x71, 0x0a, 0x81, 0x18, 0x2c, 0xe1, 0xfd, 0x14, 0xad, 0x22, 4362 0x83, 0xbc, 0x83, 0x43, 0x5f, 0x9d, 0xf2, 0xf6, 0x31, 0x32, 4363 0x51, 0x93, 0x1a, 0x17, 0x6d, 0xf0, 0xda, 0x51, 0xe5, 0x4f, 4364 0x42, 0xe6, 0x04, 0x86, 0x0d, 0xfb, 0x35, 0x95, 0x80, 0x25, 4365 0x0f, 0x55, 0x9c, 0xc5, 0x43, 0xc4, 0xff, 0xd5, 0x1c, 0xbe, 4366 0x3d, 0xe8, 0xcf, 0xd0, 0x67, 0x19, 0x23, 0x7f, 0x9f, 0xc4, 4367 0x7e, 0xe7, 0x29, 0xda, 0x06, 0x83, 0x5f, 0xa4, 0x52, 0xe8, 4368 0x25, 0xe9, 0xa1, 0x8e, 0xbc, 0x2e, 0xcb, 0xcf, 0x56, 0x34, 4369 0x74, 0x65, 0x2c, 0x33, 0xcf, 0x56, 0xa9, 0x03, 0x3b, 0xcd, 4370 0xf5, 0xd9, 0x73, 0x12, 0x17, 0x97, 0xec, 0x80, 0x89, 0x04, 4371 0x1b, 0x6e, 0x03, 0xa1, 0xb7, 0x2d, 0x0a, 0x73, 0x5b, 0x98, 4372 0x4e, 0x03, 0x68, 0x73, 0x09, 0x33, 0x23, 0x24, 0xf2, 0x7c, 4373 0x2d, 0xba, 0x85, 0xe9, 0xdb, 0x15, 0xe8, 0x3a, 0x01, 0x43, 4374 0x38, 0x2e, 0x97, 0x4b, 0x06, 0x21, 0xc1, 0x8e, 0x62, 0x5e, 4375 0xce, 0xc9, 0x07, 0x57, 0x7d, 0x9e, 0x7b, 0xad, 0xe9, 0x52, 4376 0x41, 0xa8, 0x1e, 0xbb, 0xe8, 0xa9, 0x01, 0xd4, 0xd3, 0x27, 4377 0x6e, 0x40, 0xb1, 0x14, 0xc0, 0xa2, 0xe6, 0xfc, 0x38, 0xd1, 4378 0x9c, 0x2e, 0x6a, 0xab, 0x02, 0x64, 0x4b, 0x28, 0x13, 0xf5, 4379 0x75, 0xfc, 0x21, 0x60, 0x1e, 0x0d, 0xee, 0x49, 0xcd, 0x9e, 4380 0xe9, 0x6a, 0x43, 0x10, 0x3e, 0x52, 0x4d, 0x62, 0x87, 0x3d 4381 }; 4382 static const unsigned char root_ksk_2017[] = { 4383 0x03, 0x01, 0x00, 0x01, 0xac, 0xff, 0xb4, 0x09, 0xbc, 0xc9, 4384 0x39, 0xf8, 0x31, 0xf7, 0xa1, 0xe5, 0xec, 0x88, 0xf7, 0xa5, 4385 0x92, 0x55, 0xec, 0x53, 0x04, 0x0b, 0xe4, 0x32, 0x02, 0x73, 4386 0x90, 0xa4, 0xce, 0x89, 0x6d, 0x6f, 0x90, 0x86, 0xf3, 0xc5, 4387 0xe1, 0x77, 0xfb, 0xfe, 0x11, 0x81, 0x63, 0xaa, 0xec, 0x7a, 4388 0xf1, 0x46, 0x2c, 0x47, 0x94, 0x59, 0x44, 0xc4, 0xe2, 0xc0, 4389 0x26, 0xbe, 0x5e, 0x98, 0xbb, 0xcd, 0xed, 0x25, 0x97, 0x82, 4390 0x72, 0xe1, 0xe3, 0xe0, 0x79, 0xc5, 0x09, 0x4d, 0x57, 0x3f, 4391 0x0e, 0x83, 0xc9, 0x2f, 0x02, 0xb3, 0x2d, 0x35, 0x13, 0xb1, 4392 0x55, 0x0b, 0x82, 0x69, 0x29, 0xc8, 0x0d, 0xd0, 0xf9, 0x2c, 4393 0xac, 0x96, 0x6d, 0x17, 0x76, 0x9f, 0xd5, 0x86, 0x7b, 0x64, 4394 0x7c, 0x3f, 0x38, 0x02, 0x9a, 0xbd, 0xc4, 0x81, 0x52, 0xeb, 4395 0x8f, 0x20, 0x71, 0x59, 0xec, 0xc5, 0xd2, 0x32, 0xc7, 0xc1, 4396 0x53, 0x7c, 0x79, 0xf4, 0xb7, 0xac, 0x28, 0xff, 0x11, 0x68, 4397 0x2f, 0x21, 0x68, 0x1b, 0xf6, 0xd6, 0xab, 0xa5, 0x55, 0x03, 4398 0x2b, 0xf6, 0xf9, 0xf0, 0x36, 0xbe, 0xb2, 0xaa, 0xa5, 0xb3, 4399 0x77, 0x8d, 0x6e, 0xeb, 0xfb, 0xa6, 0xbf, 0x9e, 0xa1, 0x91, 4400 0xbe, 0x4a, 0xb0, 0xca, 0xea, 0x75, 0x9e, 0x2f, 0x77, 0x3a, 4401 0x1f, 0x90, 0x29, 0xc7, 0x3e, 0xcb, 0x8d, 0x57, 0x35, 0xb9, 4402 0x32, 0x1d, 0xb0, 0x85, 0xf1, 0xb8, 0xe2, 0xd8, 0x03, 0x8f, 4403 0xe2, 0x94, 0x19, 0x92, 0x54, 0x8c, 0xee, 0x0d, 0x67, 0xdd, 4404 0x45, 0x47, 0xe1, 0x1d, 0xd6, 0x3a, 0xf9, 0xc9, 0xfc, 0x1c, 4405 0x54, 0x66, 0xfb, 0x68, 0x4c, 0xf0, 0x09, 0xd7, 0x19, 0x7c, 4406 0x2c, 0xf7, 0x9e, 0x79, 0x2a, 0xb5, 0x01, 0xe6, 0xa8, 0xa1, 4407 0xca, 0x51, 0x9a, 0xf2, 0xcb, 0x9b, 0x5f, 0x63, 0x67, 0xe9, 4408 0x4c, 0x0d, 0x47, 0x50, 0x24, 0x51, 0x35, 0x7b, 0xe1, 0xb5 4409 }; 4410 static const unsigned char root_ds_1_2017[] = { 4411 0xae, 0x1e, 0xa5, 0xb9, 0x74, 0xd4, 0xc8, 0x58, 0xb7, 0x40, 4412 0xbd, 0x03, 0xe3, 0xce, 0xd7, 0xeb, 0xfc, 0xbd, 0x17, 0x24 4413 }; 4414 static const unsigned char root_ds_2_2017[] = { 4415 0xe0, 0x6d, 0x44, 0xb8, 0x0b, 0x8f, 0x1d, 0x39, 4416 0xa9, 0x5c, 0x0b, 0x0d, 0x7c, 0x65, 0xd0, 0x84, 4417 0x58, 0xe8, 0x80, 0x40, 0x9b, 0xbc, 0x68, 0x34, 4418 0x57, 0x10, 0x42, 0x37, 0xc7, 0xf8, 0xec, 0x8D 4419 }; 4420 4421 /* if DNSKEY, flags; if DS, key tag */ 4422 rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1")); 4423 4424 /* if DNSKEY, protocol; if DS, algorithm */ 4425 rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2")); 4426 4427 /* if DNSKEY, algorithm; if DS, digest type */ 4428 rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3")); 4429 4430 namestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); 4431 4432 keyname = dns_fixedname_initname(&fkeyname); 4433 isc_buffer_constinit(&b, namestr, strlen(namestr)); 4434 isc_buffer_add(&b, strlen(namestr)); 4435 result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL); 4436 if (result != ISC_R_SUCCESS) { 4437 cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n", 4438 isc_result_totext(result)); 4439 result = ISC_R_FAILURE; 4440 } 4441 4442 if (managed) { 4443 atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype")); 4444 4445 if (strcasecmp(atstr, "static-key") == 0) { 4446 managed = false; 4447 anchortype = STATIC_DNSKEY; 4448 } else if (strcasecmp(atstr, "static-ds") == 0) { 4449 managed = false; 4450 anchortype = STATIC_DS; 4451 } else if (strcasecmp(atstr, "initial-key") == 0) { 4452 anchortype = INIT_DNSKEY; 4453 } else if (strcasecmp(atstr, "initial-ds") == 0) { 4454 anchortype = INIT_DS; 4455 } else { 4456 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4457 "key '%s': " 4458 "invalid initialization method '%s'", 4459 namestr, atstr); 4460 result = ISC_R_FAILURE; 4461 4462 /* 4463 * We can't interpret the trust anchor, so 4464 * we skip all other checks. 4465 */ 4466 goto cleanup; 4467 } 4468 } else { 4469 atstr = "trusted-key"; 4470 anchortype = TRUSTED; 4471 } 4472 4473 switch (anchortype) { 4474 case INIT_DNSKEY: 4475 case STATIC_DNSKEY: 4476 case TRUSTED: 4477 if (rdata1 > 0xffff) { 4478 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4479 "flags too big: %u", rdata1); 4480 result = ISC_R_RANGE; 4481 } 4482 if (rdata1 & DNS_KEYFLAG_REVOKE) { 4483 cfg_obj_log(key, logctx, ISC_LOG_WARNING, 4484 "key flags revoke bit set"); 4485 } 4486 if (rdata2 > 0xff) { 4487 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4488 "protocol too big: %u", rdata2); 4489 result = ISC_R_RANGE; 4490 } 4491 if (rdata3 > 0xff) { 4492 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4493 "algorithm too big: %u\n", rdata3); 4494 result = ISC_R_RANGE; 4495 } 4496 4497 isc_buffer_init(&b, data, sizeof(data)); 4498 4499 str = cfg_obj_asstring(cfg_tuple_get(key, "data")); 4500 tresult = isc_base64_decodestring(str, &b); 4501 4502 if (tresult != ISC_R_SUCCESS) { 4503 cfg_obj_log(key, logctx, ISC_LOG_ERROR, "%s", 4504 isc_result_totext(tresult)); 4505 result = ISC_R_FAILURE; 4506 } else { 4507 isc_buffer_usedregion(&b, &r); 4508 4509 if ((rdata3 == DST_ALG_RSASHA1) && r.length > 1 && 4510 r.base[0] == 1 && r.base[1] == 3) 4511 { 4512 cfg_obj_log(key, logctx, ISC_LOG_WARNING, 4513 "%s '%s' has a weak exponent", 4514 atstr, namestr); 4515 } 4516 } 4517 4518 if (result == ISC_R_SUCCESS && 4519 dns_name_equal(keyname, dns_rootname)) 4520 { 4521 /* 4522 * Flag any use of a root key, regardless of content. 4523 */ 4524 *flagsp |= (managed ? ROOT_KSK_MANAGED 4525 : ROOT_KSK_STATIC); 4526 4527 if (rdata1 == 257 && rdata2 == 3 && rdata3 == 8 && 4528 (isc_buffer_usedlength(&b) == 4529 sizeof(root_ksk_2010)) && 4530 memcmp(data, root_ksk_2010, 4531 sizeof(root_ksk_2010)) == 0) 4532 { 4533 *flagsp |= ROOT_KSK_2010; 4534 } 4535 4536 if (rdata1 == 257 && rdata2 == 3 && rdata3 == 8 && 4537 (isc_buffer_usedlength(&b) == 4538 sizeof(root_ksk_2017)) && 4539 memcmp(data, root_ksk_2017, 4540 sizeof(root_ksk_2017)) == 0) 4541 { 4542 *flagsp |= ROOT_KSK_2017; 4543 } 4544 } 4545 break; 4546 4547 case INIT_DS: 4548 case STATIC_DS: 4549 if (rdata1 > 0xffff) { 4550 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4551 "key tag too big: %u", rdata1); 4552 result = ISC_R_RANGE; 4553 } 4554 if (rdata2 > 0xff) { 4555 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4556 "algorithm too big: %u\n", rdata2); 4557 result = ISC_R_RANGE; 4558 } 4559 if (rdata3 > 0xff) { 4560 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4561 "digest type too big: %u", rdata3); 4562 result = ISC_R_RANGE; 4563 } 4564 4565 isc_buffer_init(&b, data, sizeof(data)); 4566 4567 str = cfg_obj_asstring(cfg_tuple_get(key, "data")); 4568 tresult = isc_hex_decodestring(str, &b); 4569 4570 if (tresult != ISC_R_SUCCESS) { 4571 cfg_obj_log(key, logctx, ISC_LOG_ERROR, "%s", 4572 isc_result_totext(tresult)); 4573 result = ISC_R_FAILURE; 4574 } 4575 if (result == ISC_R_SUCCESS && 4576 dns_name_equal(keyname, dns_rootname)) 4577 { 4578 /* 4579 * Flag any use of a root key, regardless of content. 4580 */ 4581 *flagsp |= (managed ? ROOT_KSK_MANAGED 4582 : ROOT_KSK_STATIC); 4583 4584 if (rdata1 == 20326 && rdata2 == 8 && rdata3 == 1 && 4585 (isc_buffer_usedlength(&b) == 4586 sizeof(root_ds_1_2017)) && 4587 memcmp(data, root_ds_1_2017, 4588 sizeof(root_ds_1_2017)) == 0) 4589 { 4590 *flagsp |= ROOT_KSK_2017; 4591 } 4592 4593 if (rdata1 == 20326 && rdata2 == 8 && rdata3 == 2 && 4594 (isc_buffer_usedlength(&b) == 4595 sizeof(root_ds_2_2017)) && 4596 memcmp(data, root_ds_2_2017, 4597 sizeof(root_ds_2_2017)) == 0) 4598 { 4599 *flagsp |= ROOT_KSK_2017; 4600 } 4601 } 4602 break; 4603 } 4604 4605cleanup: 4606 return (result); 4607} 4608 4609static isc_result_t 4610record_static_keys(isc_symtab_t *symtab, isc_mem_t *mctx, 4611 const cfg_obj_t *keylist, isc_log_t *logctx, 4612 bool autovalidation) { 4613 isc_result_t result, ret = ISC_R_SUCCESS; 4614 const cfg_listelt_t *elt; 4615 dns_fixedname_t fixed; 4616 dns_name_t *name; 4617 char namebuf[DNS_NAME_FORMATSIZE], *p = NULL; 4618 4619 name = dns_fixedname_initname(&fixed); 4620 4621 for (elt = cfg_list_first(keylist); elt != NULL; 4622 elt = cfg_list_next(elt)) 4623 { 4624 const char *initmethod; 4625 const cfg_obj_t *init = NULL; 4626 const cfg_obj_t *obj = cfg_listelt_value(elt); 4627 const char *str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 4628 isc_symvalue_t symvalue; 4629 4630 result = dns_name_fromstring(name, str, 0, NULL); 4631 if (result != ISC_R_SUCCESS) { 4632 continue; 4633 } 4634 4635 init = cfg_tuple_get(obj, "anchortype"); 4636 if (!cfg_obj_isvoid(init)) { 4637 initmethod = cfg_obj_asstring(init); 4638 if (strcasecmp(initmethod, "initial-key") == 0) { 4639 /* initializing key, skip it */ 4640 continue; 4641 } 4642 if (strcasecmp(initmethod, "initial-ds") == 0) { 4643 /* initializing key, skip it */ 4644 continue; 4645 } 4646 } 4647 4648 dns_name_format(name, namebuf, sizeof(namebuf)); 4649 symvalue.as_cpointer = obj; 4650 p = isc_mem_strdup(mctx, namebuf); 4651 result = isc_symtab_define(symtab, p, 1, symvalue, 4652 isc_symexists_reject); 4653 if (result == ISC_R_EXISTS) { 4654 isc_mem_free(mctx, p); 4655 } else if (result != ISC_R_SUCCESS) { 4656 isc_mem_free(mctx, p); 4657 ret = result; 4658 continue; 4659 } 4660 4661 if (autovalidation && dns_name_equal(name, dns_rootname)) { 4662 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 4663 "static trust anchor for root zone " 4664 "cannot be used with " 4665 "'dnssec-validation auto'."); 4666 ret = ISC_R_FAILURE; 4667 continue; 4668 } 4669 } 4670 4671 return (ret); 4672} 4673 4674static isc_result_t 4675check_initializing_keys(isc_symtab_t *symtab, const cfg_obj_t *keylist, 4676 isc_log_t *logctx) { 4677 isc_result_t result, ret = ISC_R_SUCCESS; 4678 const cfg_listelt_t *elt; 4679 dns_fixedname_t fixed; 4680 dns_name_t *name; 4681 char namebuf[DNS_NAME_FORMATSIZE]; 4682 4683 name = dns_fixedname_initname(&fixed); 4684 4685 for (elt = cfg_list_first(keylist); elt != NULL; 4686 elt = cfg_list_next(elt)) 4687 { 4688 const cfg_obj_t *obj = cfg_listelt_value(elt); 4689 const cfg_obj_t *init = NULL; 4690 const char *str; 4691 isc_symvalue_t symvalue; 4692 4693 init = cfg_tuple_get(obj, "anchortype"); 4694 if (cfg_obj_isvoid(init) || 4695 strcasecmp(cfg_obj_asstring(init), "static-key") == 0 || 4696 strcasecmp(cfg_obj_asstring(init), "static-ds") == 0) 4697 { 4698 /* static key, skip it */ 4699 continue; 4700 } 4701 4702 str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 4703 result = dns_name_fromstring(name, str, 0, NULL); 4704 if (result != ISC_R_SUCCESS) { 4705 continue; 4706 } 4707 4708 dns_name_format(name, namebuf, sizeof(namebuf)); 4709 result = isc_symtab_lookup(symtab, namebuf, 1, &symvalue); 4710 if (result == ISC_R_SUCCESS) { 4711 const char *file = cfg_obj_file(symvalue.as_cpointer); 4712 unsigned int line = cfg_obj_line(symvalue.as_cpointer); 4713 if (file == NULL) { 4714 file = "<unknown file>"; 4715 } 4716 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 4717 "static and initializing keys " 4718 "cannot be used for the " 4719 "same domain. " 4720 "static key defined at " 4721 "%s:%u", 4722 file, line); 4723 4724 ret = ISC_R_FAILURE; 4725 } 4726 } 4727 4728 return (ret); 4729} 4730 4731static isc_result_t 4732record_ds_keys(isc_symtab_t *symtab, isc_mem_t *mctx, 4733 const cfg_obj_t *keylist) { 4734 isc_result_t result, ret = ISC_R_SUCCESS; 4735 const cfg_listelt_t *elt; 4736 dns_fixedname_t fixed; 4737 dns_name_t *name; 4738 char namebuf[DNS_NAME_FORMATSIZE], *p = NULL; 4739 4740 name = dns_fixedname_initname(&fixed); 4741 4742 for (elt = cfg_list_first(keylist); elt != NULL; 4743 elt = cfg_list_next(elt)) 4744 { 4745 const char *initmethod; 4746 const cfg_obj_t *init = NULL; 4747 const cfg_obj_t *obj = cfg_listelt_value(elt); 4748 const char *str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 4749 isc_symvalue_t symvalue; 4750 4751 result = dns_name_fromstring(name, str, 0, NULL); 4752 if (result != ISC_R_SUCCESS) { 4753 continue; 4754 } 4755 4756 init = cfg_tuple_get(obj, "anchortype"); 4757 if (!cfg_obj_isvoid(init)) { 4758 initmethod = cfg_obj_asstring(init); 4759 if (strcasecmp(initmethod, "initial-key") == 0 || 4760 strcasecmp(initmethod, "static-key") == 0) 4761 { 4762 /* Key-style key, skip it */ 4763 continue; 4764 } 4765 } 4766 4767 dns_name_format(name, namebuf, sizeof(namebuf)); 4768 symvalue.as_cpointer = obj; 4769 p = isc_mem_strdup(mctx, namebuf); 4770 result = isc_symtab_define(symtab, p, 1, symvalue, 4771 isc_symexists_reject); 4772 if (result == ISC_R_EXISTS) { 4773 isc_mem_free(mctx, p); 4774 } else if (result != ISC_R_SUCCESS) { 4775 isc_mem_free(mctx, p); 4776 ret = result; 4777 continue; 4778 } 4779 } 4780 4781 return (ret); 4782} 4783 4784/* 4785 * Check for conflicts between static and initialiizing keys. 4786 */ 4787static isc_result_t 4788check_ta_conflicts(const cfg_obj_t *global_ta, const cfg_obj_t *view_ta, 4789 const cfg_obj_t *global_tkeys, const cfg_obj_t *view_tkeys, 4790 bool autovalidation, isc_mem_t *mctx, isc_log_t *logctx) { 4791 isc_result_t result, tresult; 4792 const cfg_listelt_t *elt = NULL; 4793 const cfg_obj_t *keylist = NULL; 4794 isc_symtab_t *statictab = NULL, *dstab = NULL; 4795 4796 result = isc_symtab_create(mctx, 100, freekey, mctx, false, &statictab); 4797 if (result != ISC_R_SUCCESS) { 4798 goto cleanup; 4799 } 4800 4801 result = isc_symtab_create(mctx, 100, freekey, mctx, false, &dstab); 4802 if (result != ISC_R_SUCCESS) { 4803 goto cleanup; 4804 } 4805 4806 /* 4807 * First we record all the static keys (i.e., old-style 4808 * trusted-keys and trust-anchors configured with "static-key"), 4809 * and all the DS-style trust anchors. 4810 */ 4811 for (elt = cfg_list_first(global_ta); elt != NULL; 4812 elt = cfg_list_next(elt)) 4813 { 4814 keylist = cfg_listelt_value(elt); 4815 tresult = record_static_keys(statictab, mctx, keylist, logctx, 4816 autovalidation); 4817 if (result == ISC_R_SUCCESS) { 4818 result = tresult; 4819 } 4820 4821 tresult = record_ds_keys(dstab, mctx, keylist); 4822 if (result == ISC_R_SUCCESS) { 4823 result = tresult; 4824 } 4825 } 4826 4827 for (elt = cfg_list_first(view_ta); elt != NULL; 4828 elt = cfg_list_next(elt)) 4829 { 4830 keylist = cfg_listelt_value(elt); 4831 tresult = record_static_keys(statictab, mctx, keylist, logctx, 4832 autovalidation); 4833 if (result == ISC_R_SUCCESS) { 4834 result = tresult; 4835 } 4836 4837 tresult = record_ds_keys(dstab, mctx, keylist); 4838 if (result == ISC_R_SUCCESS) { 4839 result = tresult; 4840 } 4841 } 4842 4843 for (elt = cfg_list_first(global_tkeys); elt != NULL; 4844 elt = cfg_list_next(elt)) 4845 { 4846 keylist = cfg_listelt_value(elt); 4847 tresult = record_static_keys(statictab, mctx, keylist, logctx, 4848 autovalidation); 4849 if (result == ISC_R_SUCCESS) { 4850 result = tresult; 4851 } 4852 } 4853 4854 for (elt = cfg_list_first(view_tkeys); elt != NULL; 4855 elt = cfg_list_next(elt)) 4856 { 4857 keylist = cfg_listelt_value(elt); 4858 tresult = record_static_keys(statictab, mctx, keylist, logctx, 4859 autovalidation); 4860 if (result == ISC_R_SUCCESS) { 4861 result = tresult; 4862 } 4863 } 4864 4865 /* 4866 * Next, ensure that there's no conflict between the 4867 * static keys and the trust-anchors configured with "initial-key". 4868 */ 4869 for (elt = cfg_list_first(global_ta); elt != NULL; 4870 elt = cfg_list_next(elt)) 4871 { 4872 keylist = cfg_listelt_value(elt); 4873 tresult = check_initializing_keys(statictab, keylist, logctx); 4874 if (result == ISC_R_SUCCESS) { 4875 result = tresult; 4876 } 4877 } 4878 4879 for (elt = cfg_list_first(view_ta); elt != NULL; 4880 elt = cfg_list_next(elt)) 4881 { 4882 keylist = cfg_listelt_value(elt); 4883 tresult = check_initializing_keys(statictab, keylist, logctx); 4884 if (result == ISC_R_SUCCESS) { 4885 result = tresult; 4886 } 4887 } 4888 4889cleanup: 4890 if (statictab != NULL) { 4891 isc_symtab_destroy(&statictab); 4892 } 4893 if (dstab != NULL) { 4894 isc_symtab_destroy(&dstab); 4895 } 4896 return (result); 4897} 4898 4899typedef enum { special_zonetype_rpz, special_zonetype_catz } special_zonetype_t; 4900 4901static isc_result_t 4902check_rpz_catz(const char *rpz_catz, const cfg_obj_t *rpz_obj, 4903 const char *viewname, isc_symtab_t *symtab, isc_log_t *logctx, 4904 special_zonetype_t specialzonetype) { 4905 const cfg_listelt_t *element; 4906 const cfg_obj_t *obj, *nameobj, *zoneobj; 4907 const char *zonename, *zonetype; 4908 const char *forview = " for view "; 4909 isc_symvalue_t value; 4910 isc_result_t result, tresult; 4911 dns_fixedname_t fixed; 4912 dns_name_t *name; 4913 char namebuf[DNS_NAME_FORMATSIZE]; 4914 unsigned int num_zones = 0; 4915 4916 if (viewname == NULL) { 4917 viewname = ""; 4918 forview = ""; 4919 } 4920 result = ISC_R_SUCCESS; 4921 4922 name = dns_fixedname_initname(&fixed); 4923 obj = cfg_tuple_get(rpz_obj, "zone list"); 4924 4925 for (element = cfg_list_first(obj); element != NULL; 4926 element = cfg_list_next(element)) 4927 { 4928 obj = cfg_listelt_value(element); 4929 nameobj = cfg_tuple_get(obj, "zone name"); 4930 zonename = cfg_obj_asstring(nameobj); 4931 zonetype = ""; 4932 4933 if (specialzonetype == special_zonetype_rpz) { 4934 if (++num_zones > 64) { 4935 cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR, 4936 "more than 64 response policy " 4937 "zones in view '%s'", 4938 viewname); 4939 return (ISC_R_FAILURE); 4940 } 4941 } 4942 4943 tresult = dns_name_fromstring(name, zonename, 0, NULL); 4944 if (tresult != ISC_R_SUCCESS) { 4945 cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR, 4946 "bad domain name '%s'", zonename); 4947 if (result == ISC_R_SUCCESS) { 4948 result = tresult; 4949 } 4950 continue; 4951 } 4952 dns_name_format(name, namebuf, sizeof(namebuf)); 4953 tresult = isc_symtab_lookup(symtab, namebuf, 3, &value); 4954 if (tresult == ISC_R_SUCCESS) { 4955 obj = NULL; 4956 zoneobj = value.as_cpointer; 4957 if (zoneobj != NULL && cfg_obj_istuple(zoneobj)) { 4958 zoneobj = cfg_tuple_get(zoneobj, "options"); 4959 } 4960 if (zoneobj != NULL && cfg_obj_ismap(zoneobj)) { 4961 (void)cfg_map_get(zoneobj, "type", &obj); 4962 } 4963 if (obj != NULL) { 4964 zonetype = cfg_obj_asstring(obj); 4965 } 4966 } 4967 if (strcasecmp(zonetype, "primary") != 0 && 4968 strcasecmp(zonetype, "master") != 0 && 4969 strcasecmp(zonetype, "secondary") != 0 && 4970 strcasecmp(zonetype, "slave") != 0) 4971 { 4972 cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR, 4973 "%s '%s'%s%s is not a primary or secondary " 4974 "zone", 4975 rpz_catz, zonename, forview, viewname); 4976 if (result == ISC_R_SUCCESS) { 4977 result = ISC_R_FAILURE; 4978 } 4979 } 4980 } 4981 return (result); 4982} 4983 4984static isc_result_t 4985check_catz(const cfg_obj_t *catz_obj, const char *viewname, isc_mem_t *mctx, 4986 isc_log_t *logctx) { 4987 const cfg_listelt_t *element; 4988 const cfg_obj_t *obj, *nameobj, *primariesobj; 4989 const char *zonename; 4990 const char *forview = " for view "; 4991 isc_result_t result, tresult; 4992 isc_symtab_t *symtab = NULL; 4993 dns_fixedname_t fixed; 4994 dns_name_t *name = dns_fixedname_initname(&fixed); 4995 4996 if (viewname == NULL) { 4997 viewname = ""; 4998 forview = ""; 4999 } 5000 5001 result = isc_symtab_create(mctx, 100, freekey, mctx, false, &symtab); 5002 if (result != ISC_R_SUCCESS) { 5003 return (result); 5004 } 5005 5006 obj = cfg_tuple_get(catz_obj, "zone list"); 5007 5008 for (element = cfg_list_first(obj); element != NULL; 5009 element = cfg_list_next(element)) 5010 { 5011 char namebuf[DNS_NAME_FORMATSIZE]; 5012 5013 obj = cfg_listelt_value(element); 5014 nameobj = cfg_tuple_get(obj, "zone name"); 5015 zonename = cfg_obj_asstring(nameobj); 5016 5017 tresult = dns_name_fromstring(name, zonename, 0, NULL); 5018 if (tresult != ISC_R_SUCCESS) { 5019 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 5020 "bad domain name '%s'", zonename); 5021 if (result == ISC_R_SUCCESS) { 5022 result = tresult; 5023 continue; 5024 } 5025 } 5026 5027 dns_name_format(name, namebuf, sizeof(namebuf)); 5028 tresult = 5029 nameexist(nameobj, namebuf, 1, symtab, 5030 "catalog zone '%s': already added here %s:%u", 5031 logctx, mctx); 5032 if (tresult != ISC_R_SUCCESS) { 5033 result = tresult; 5034 continue; 5035 } 5036 5037 primariesobj = cfg_tuple_get(obj, "default-primaries"); 5038 if (primariesobj != NULL && cfg_obj_istuple(primariesobj)) { 5039 primariesobj = cfg_tuple_get(obj, "default-masters"); 5040 if (primariesobj != NULL && 5041 cfg_obj_istuple(primariesobj)) 5042 { 5043 cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR, 5044 "catalog zone '%s'%s%s: " 5045 "'default-primaries' and " 5046 "'default-masters' can not be both " 5047 "defined", 5048 zonename, forview, viewname); 5049 result = ISC_R_FAILURE; 5050 break; 5051 } 5052 } 5053 } 5054 5055 if (symtab != NULL) { 5056 isc_symtab_destroy(&symtab); 5057 } 5058 5059 return (result); 5060} 5061 5062/*% 5063 * Data structure used for the 'callback_data' argument to check_one_plugin(). 5064 */ 5065struct check_one_plugin_data { 5066 isc_mem_t *mctx; 5067 isc_log_t *lctx; 5068 cfg_aclconfctx_t *actx; 5069 isc_result_t *check_result; 5070}; 5071 5072/*% 5073 * A callback for the cfg_pluginlist_foreach() call in check_viewconf() below. 5074 * Since the point is to check configuration of all plugins even when 5075 * processing some of them fails, always return ISC_R_SUCCESS and indicate any 5076 * check failures through the 'check_result' variable passed in via the 5077 * 'callback_data' structure. 5078 */ 5079static isc_result_t 5080check_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj, 5081 const char *plugin_path, const char *parameters, 5082 void *callback_data) { 5083 struct check_one_plugin_data *data = callback_data; 5084 char full_path[PATH_MAX]; 5085 isc_result_t result; 5086 5087 result = ns_plugin_expandpath(plugin_path, full_path, 5088 sizeof(full_path)); 5089 if (result != ISC_R_SUCCESS) { 5090 cfg_obj_log(obj, data->lctx, ISC_LOG_ERROR, 5091 "%s: plugin check failed: " 5092 "unable to get full plugin path: %s", 5093 plugin_path, isc_result_totext(result)); 5094 return (result); 5095 } 5096 5097 result = ns_plugin_check(full_path, parameters, config, 5098 cfg_obj_file(obj), cfg_obj_line(obj), 5099 data->mctx, data->lctx, data->actx); 5100 if (result != ISC_R_SUCCESS) { 5101 cfg_obj_log(obj, data->lctx, ISC_LOG_ERROR, 5102 "%s: plugin check failed: %s", full_path, 5103 isc_result_totext(result)); 5104 *data->check_result = result; 5105 } 5106 5107 return (ISC_R_SUCCESS); 5108} 5109 5110static isc_result_t 5111check_dnstap(const cfg_obj_t *voptions, const cfg_obj_t *config, 5112 isc_log_t *logctx) { 5113#ifdef HAVE_DNSTAP 5114 const cfg_obj_t *options = NULL; 5115 const cfg_obj_t *obj = NULL; 5116 5117 if (config != NULL) { 5118 (void)cfg_map_get(config, "options", &options); 5119 } 5120 if (options != NULL) { 5121 (void)cfg_map_get(options, "dnstap-output", &obj); 5122 } 5123 if (obj == NULL) { 5124 if (voptions != NULL) { 5125 (void)cfg_map_get(voptions, "dnstap", &obj); 5126 } 5127 if (options != NULL && obj == NULL) { 5128 (void)cfg_map_get(options, "dnstap", &obj); 5129 } 5130 if (obj != NULL) { 5131 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 5132 "'dnstap-output' must be set if 'dnstap' " 5133 "is set"); 5134 return (ISC_R_FAILURE); 5135 } 5136 } 5137 return (ISC_R_SUCCESS); 5138#else /* ifdef HAVE_DNSTAP */ 5139 UNUSED(voptions); 5140 UNUSED(config); 5141 UNUSED(logctx); 5142 5143 return (ISC_R_SUCCESS); 5144#endif /* ifdef HAVE_DNSTAP */ 5145} 5146 5147static isc_result_t 5148check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, 5149 const char *viewname, dns_rdataclass_t vclass, 5150 isc_symtab_t *files, isc_symtab_t *keydirs, bool check_plugins, 5151 bool nodeprecate, isc_symtab_t *inview, isc_log_t *logctx, 5152 isc_mem_t *mctx) { 5153 const cfg_obj_t *zones = NULL; 5154 const cfg_obj_t *view_tkeys = NULL, *global_tkeys = NULL; 5155 const cfg_obj_t *view_mkeys = NULL, *global_mkeys = NULL; 5156 const cfg_obj_t *view_ta = NULL, *global_ta = NULL; 5157 const cfg_obj_t *check_keys[2] = { NULL, NULL }; 5158 const cfg_obj_t *keys = NULL; 5159 const cfg_listelt_t *element, *element2; 5160 isc_symtab_t *symtab = NULL; 5161 isc_result_t result = ISC_R_SUCCESS; 5162 isc_result_t tresult = ISC_R_SUCCESS; 5163 cfg_aclconfctx_t *actx = NULL; 5164 const cfg_obj_t *obj; 5165 const cfg_obj_t *options = NULL; 5166 const cfg_obj_t *opts = NULL; 5167 const cfg_obj_t *plugin_list = NULL; 5168 bool autovalidation = false; 5169 unsigned int tflags = 0, dflags = 0; 5170 int i; 5171 5172 /* 5173 * Get global options block 5174 */ 5175 (void)cfg_map_get(config, "options", &options); 5176 5177 /* 5178 * The most relevant options for this view 5179 */ 5180 if (voptions != NULL) { 5181 opts = voptions; 5182 } else { 5183 opts = options; 5184 } 5185 5186 /* 5187 * Check that all zone statements are syntactically correct and 5188 * there are no duplicate zones. 5189 */ 5190 tresult = isc_symtab_create(mctx, 1000, freekey, mctx, false, &symtab); 5191 if (tresult != ISC_R_SUCCESS) { 5192 return (ISC_R_NOMEMORY); 5193 } 5194 5195 cfg_aclconfctx_create(mctx, &actx); 5196 5197 if (voptions != NULL) { 5198 (void)cfg_map_get(voptions, "zone", &zones); 5199 } else { 5200 (void)cfg_map_get(config, "zone", &zones); 5201 } 5202 5203 for (element = cfg_list_first(zones); element != NULL; 5204 element = cfg_list_next(element)) 5205 { 5206 const cfg_obj_t *zone = cfg_listelt_value(element); 5207 5208 tresult = check_zoneconf(zone, voptions, config, symtab, files, 5209 keydirs, inview, viewname, vclass, 5210 nodeprecate, actx, logctx, mctx); 5211 if (tresult != ISC_R_SUCCESS) { 5212 result = ISC_R_FAILURE; 5213 } 5214 } 5215 5216 /* 5217 * Check that the response-policy and catalog-zones options 5218 * refer to zones that exist. 5219 */ 5220 if (opts != NULL) { 5221 obj = NULL; 5222 if ((cfg_map_get(opts, "response-policy", &obj) == 5223 ISC_R_SUCCESS) && 5224 (check_rpz_catz("response-policy zone", obj, viewname, 5225 symtab, logctx, 5226 special_zonetype_rpz) != ISC_R_SUCCESS)) 5227 { 5228 result = ISC_R_FAILURE; 5229 } 5230 5231 obj = NULL; 5232 if ((cfg_map_get(opts, "catalog-zones", &obj) == 5233 ISC_R_SUCCESS) && 5234 (check_rpz_catz("catalog zone", obj, viewname, symtab, 5235 logctx, 5236 special_zonetype_catz) != ISC_R_SUCCESS)) 5237 { 5238 result = ISC_R_FAILURE; 5239 } 5240 } 5241 5242 /* 5243 * Check catalog-zones configuration. 5244 */ 5245 if (opts != NULL) { 5246 obj = NULL; 5247 if ((cfg_map_get(opts, "catalog-zones", &obj) == 5248 ISC_R_SUCCESS) && 5249 (check_catz(obj, viewname, mctx, logctx) != ISC_R_SUCCESS)) 5250 { 5251 result = ISC_R_FAILURE; 5252 } 5253 } 5254 5255 isc_symtab_destroy(&symtab); 5256 5257 /* 5258 * Check that forwarding is reasonable. 5259 */ 5260 if (opts != NULL && check_forward(opts, NULL, logctx) != ISC_R_SUCCESS) 5261 { 5262 result = ISC_R_FAILURE; 5263 } 5264 5265 /* 5266 * Check non-zero options at the global and view levels. 5267 */ 5268 if (options != NULL && check_nonzero(options, logctx) != ISC_R_SUCCESS) 5269 { 5270 result = ISC_R_FAILURE; 5271 } 5272 if (voptions != NULL && 5273 check_nonzero(voptions, logctx) != ISC_R_SUCCESS) 5274 { 5275 result = ISC_R_FAILURE; 5276 } 5277 5278 /* 5279 * Check that dual-stack-servers is reasonable. 5280 */ 5281 if (opts != NULL && check_dual_stack(opts, logctx) != ISC_R_SUCCESS) { 5282 result = ISC_R_FAILURE; 5283 } 5284 5285 /* 5286 * Check that rrset-order is reasonable. 5287 */ 5288 if (opts != NULL && check_order(opts, logctx) != ISC_R_SUCCESS) { 5289 result = ISC_R_FAILURE; 5290 } 5291 5292 /* 5293 * Check that all key statements are syntactically correct and 5294 * there are no duplicate keys. 5295 */ 5296 tresult = isc_symtab_create(mctx, 1000, freekey, mctx, false, &symtab); 5297 if (tresult != ISC_R_SUCCESS) { 5298 goto cleanup; 5299 } 5300 5301 (void)cfg_map_get(config, "key", &keys); 5302 tresult = check_keylist(keys, symtab, mctx, logctx); 5303 if (tresult == ISC_R_EXISTS) { 5304 result = ISC_R_FAILURE; 5305 } else if (tresult != ISC_R_SUCCESS) { 5306 result = tresult; 5307 goto cleanup; 5308 } 5309 5310 if (voptions != NULL) { 5311 keys = NULL; 5312 (void)cfg_map_get(voptions, "key", &keys); 5313 tresult = check_keylist(keys, symtab, mctx, logctx); 5314 if (tresult == ISC_R_EXISTS) { 5315 result = ISC_R_FAILURE; 5316 } else if (tresult != ISC_R_SUCCESS) { 5317 result = tresult; 5318 goto cleanup; 5319 } 5320 } 5321 5322 /* 5323 * Global servers can refer to keys in views. 5324 */ 5325 if (check_servers(config, voptions, symtab, mctx, logctx) != 5326 ISC_R_SUCCESS) 5327 { 5328 result = ISC_R_FAILURE; 5329 } 5330 5331 isc_symtab_destroy(&symtab); 5332 5333 /* 5334 * Load all DNSSEC keys. 5335 */ 5336 if (voptions != NULL) { 5337 (void)cfg_map_get(voptions, "trusted-keys", &view_tkeys); 5338 (void)cfg_map_get(voptions, "trust-anchors", &view_ta); 5339 (void)cfg_map_get(voptions, "managed-keys", &view_mkeys); 5340 } 5341 (void)cfg_map_get(config, "trusted-keys", &global_tkeys); 5342 (void)cfg_map_get(config, "trust-anchors", &global_ta); 5343 (void)cfg_map_get(config, "managed-keys", &global_mkeys); 5344 5345 /* 5346 * Check trusted-keys. 5347 */ 5348 check_keys[0] = view_tkeys; 5349 check_keys[1] = global_tkeys; 5350 for (i = 0; i < 2; i++) { 5351 if (check_keys[i] != NULL) { 5352 unsigned int flags = 0; 5353 5354 for (element = cfg_list_first(check_keys[i]); 5355 element != NULL; element = cfg_list_next(element)) 5356 { 5357 const cfg_obj_t *keylist = 5358 cfg_listelt_value(element); 5359 for (element2 = cfg_list_first(keylist); 5360 element2 != NULL; 5361 element2 = cfg_list_next(element2)) 5362 { 5363 obj = cfg_listelt_value(element2); 5364 tresult = check_trust_anchor( 5365 obj, false, &flags, logctx); 5366 if (tresult != ISC_R_SUCCESS) { 5367 result = tresult; 5368 } 5369 } 5370 } 5371 5372 if ((flags & ROOT_KSK_STATIC) != 0) { 5373 cfg_obj_log(check_keys[i], logctx, 5374 ISC_LOG_WARNING, 5375 "trusted-keys entry for the root " 5376 "zone WILL FAIL after key " 5377 "rollover - use trust-anchors " 5378 "with initial-key " 5379 "or initial-ds instead."); 5380 } 5381 5382 tflags |= flags; 5383 } 5384 } 5385 5386 /* 5387 * Check dnssec/managed-keys. (Only one or the other can be used.) 5388 */ 5389 if ((view_mkeys != NULL || global_mkeys != NULL) && 5390 (view_ta != NULL || global_ta != NULL)) 5391 { 5392 keys = (view_mkeys != NULL) ? view_mkeys : global_mkeys; 5393 5394 cfg_obj_log(keys, logctx, ISC_LOG_ERROR, 5395 "use of managed-keys is not allowed when " 5396 "trust-anchors is also in use"); 5397 result = ISC_R_FAILURE; 5398 } 5399 5400 if (view_ta == NULL && global_ta == NULL) { 5401 view_ta = view_mkeys; 5402 global_ta = global_mkeys; 5403 } 5404 5405 check_keys[0] = view_ta; 5406 check_keys[1] = global_ta; 5407 for (i = 0; i < 2; i++) { 5408 if (check_keys[i] != NULL) { 5409 unsigned int flags = 0; 5410 5411 for (element = cfg_list_first(check_keys[i]); 5412 element != NULL; element = cfg_list_next(element)) 5413 { 5414 const cfg_obj_t *keylist = 5415 cfg_listelt_value(element); 5416 for (element2 = cfg_list_first(keylist); 5417 element2 != NULL; 5418 element2 = cfg_list_next(element2)) 5419 { 5420 obj = cfg_listelt_value(element2); 5421 tresult = check_trust_anchor( 5422 obj, true, &flags, logctx); 5423 if (tresult != ISC_R_SUCCESS) { 5424 result = tresult; 5425 } 5426 } 5427 } 5428 5429 if ((flags & ROOT_KSK_STATIC) != 0) { 5430 cfg_obj_log(check_keys[i], logctx, 5431 ISC_LOG_WARNING, 5432 "static entry for the root " 5433 "zone WILL FAIL after key " 5434 "rollover - use trust-anchors " 5435 "with initial-key " 5436 "or initial-ds instead."); 5437 } 5438 5439 if ((flags & ROOT_KSK_2010) != 0 && 5440 (flags & ROOT_KSK_2017) == 0) 5441 { 5442 cfg_obj_log(check_keys[i], logctx, 5443 ISC_LOG_WARNING, 5444 "initial-key entry for the root " 5445 "zone uses the 2010 key without " 5446 "the updated 2017 key"); 5447 } 5448 5449 dflags |= flags; 5450 } 5451 } 5452 5453 if ((tflags & ROOT_KSK_ANY) != 0 && (dflags & ROOT_KSK_ANY) != 0) { 5454 keys = (view_ta != NULL) ? view_ta : global_ta; 5455 cfg_obj_log(keys, logctx, ISC_LOG_WARNING, 5456 "both trusted-keys and trust-anchors " 5457 "for the root zone are present"); 5458 } 5459 5460 if ((dflags & ROOT_KSK_ANY) == ROOT_KSK_ANY) { 5461 keys = (view_ta != NULL) ? view_ta : global_ta; 5462 cfg_obj_log(keys, logctx, ISC_LOG_WARNING, 5463 "both initial and static entries for the " 5464 "root zone are present"); 5465 } 5466 5467 obj = NULL; 5468 if (voptions != NULL) { 5469 (void)cfg_map_get(voptions, "dnssec-validation", &obj); 5470 } 5471 if (obj == NULL && options != NULL) { 5472 (void)cfg_map_get(options, "dnssec-validation", &obj); 5473 } 5474 if (obj != NULL && !cfg_obj_isboolean(obj)) { 5475 autovalidation = true; 5476 } 5477 5478 tresult = check_ta_conflicts(global_ta, view_ta, global_tkeys, 5479 view_tkeys, autovalidation, mctx, logctx); 5480 if (tresult != ISC_R_SUCCESS) { 5481 result = tresult; 5482 } 5483 5484 /* 5485 * Check options. 5486 */ 5487 if (voptions != NULL) { 5488 tresult = check_options(voptions, NULL, logctx, mctx, 5489 optlevel_view); 5490 } else { 5491 tresult = check_options(config, config, logctx, mctx, 5492 optlevel_config); 5493 } 5494 if (tresult != ISC_R_SUCCESS) { 5495 result = tresult; 5496 } 5497 5498 tresult = check_dnstap(voptions, config, logctx); 5499 if (tresult != ISC_R_SUCCESS) { 5500 result = tresult; 5501 } 5502 5503 tresult = check_viewacls(actx, voptions, config, logctx, mctx); 5504 if (tresult != ISC_R_SUCCESS) { 5505 result = tresult; 5506 } 5507 5508 tresult = check_recursionacls(actx, voptions, viewname, config, logctx, 5509 mctx); 5510 if (tresult != ISC_R_SUCCESS) { 5511 result = tresult; 5512 } 5513 5514 tresult = check_dns64(actx, voptions, config, logctx, mctx); 5515 if (tresult != ISC_R_SUCCESS) { 5516 result = tresult; 5517 } 5518 5519 tresult = check_ratelimit(actx, voptions, config, logctx, mctx); 5520 if (tresult != ISC_R_SUCCESS) { 5521 result = tresult; 5522 } 5523 5524 /* 5525 * Load plugins. 5526 */ 5527 if (check_plugins) { 5528 if (voptions != NULL) { 5529 (void)cfg_map_get(voptions, "plugin", &plugin_list); 5530 } else { 5531 (void)cfg_map_get(config, "plugin", &plugin_list); 5532 } 5533 } 5534 5535 { 5536 struct check_one_plugin_data check_one_plugin_data = { 5537 .mctx = mctx, 5538 .lctx = logctx, 5539 .actx = actx, 5540 .check_result = &tresult, 5541 }; 5542 5543 (void)cfg_pluginlist_foreach(config, plugin_list, logctx, 5544 check_one_plugin, 5545 &check_one_plugin_data); 5546 if (tresult != ISC_R_SUCCESS) { 5547 result = tresult; 5548 } 5549 } 5550 5551cleanup: 5552 if (symtab != NULL) { 5553 isc_symtab_destroy(&symtab); 5554 } 5555 if (actx != NULL) { 5556 cfg_aclconfctx_detach(&actx); 5557 } 5558 5559 return (result); 5560} 5561 5562static const char *default_channels[] = { "default_syslog", "default_stderr", 5563 "default_debug", "null", NULL }; 5564 5565static isc_result_t 5566bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx, 5567 isc_mem_t *mctx) { 5568 const cfg_obj_t *categories = NULL; 5569 const cfg_obj_t *category; 5570 const cfg_obj_t *channels = NULL; 5571 const cfg_obj_t *channel; 5572 const cfg_listelt_t *element; 5573 const cfg_listelt_t *delement; 5574 const char *channelname; 5575 const char *catname; 5576 const cfg_obj_t *fileobj = NULL; 5577 const cfg_obj_t *syslogobj = NULL; 5578 const cfg_obj_t *nullobj = NULL; 5579 const cfg_obj_t *stderrobj = NULL; 5580 const cfg_obj_t *logobj = NULL; 5581 isc_result_t result = ISC_R_SUCCESS; 5582 isc_result_t tresult; 5583 isc_symtab_t *symtab = NULL; 5584 isc_symvalue_t symvalue; 5585 int i; 5586 5587 (void)cfg_map_get(config, "logging", &logobj); 5588 if (logobj == NULL) { 5589 return (ISC_R_SUCCESS); 5590 } 5591 5592 result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab); 5593 if (result != ISC_R_SUCCESS) { 5594 return (result); 5595 } 5596 5597 symvalue.as_cpointer = NULL; 5598 for (i = 0; default_channels[i] != NULL; i++) { 5599 tresult = isc_symtab_define(symtab, default_channels[i], 1, 5600 symvalue, isc_symexists_replace); 5601 if (tresult != ISC_R_SUCCESS) { 5602 result = tresult; 5603 } 5604 } 5605 5606 cfg_map_get(logobj, "channel", &channels); 5607 5608 for (element = cfg_list_first(channels); element != NULL; 5609 element = cfg_list_next(element)) 5610 { 5611 channel = cfg_listelt_value(element); 5612 channelname = cfg_obj_asstring(cfg_map_getname(channel)); 5613 fileobj = syslogobj = nullobj = stderrobj = NULL; 5614 (void)cfg_map_get(channel, "file", &fileobj); 5615 (void)cfg_map_get(channel, "syslog", &syslogobj); 5616 (void)cfg_map_get(channel, "null", &nullobj); 5617 (void)cfg_map_get(channel, "stderr", &stderrobj); 5618 i = 0; 5619 if (fileobj != NULL) { 5620 i++; 5621 } 5622 if (syslogobj != NULL) { 5623 i++; 5624 } 5625 if (nullobj != NULL) { 5626 i++; 5627 } 5628 if (stderrobj != NULL) { 5629 i++; 5630 } 5631 if (i != 1) { 5632 cfg_obj_log(channel, logctx, ISC_LOG_ERROR, 5633 "channel '%s': exactly one of file, " 5634 "syslog, " 5635 "null, and stderr must be present", 5636 channelname); 5637 result = ISC_R_FAILURE; 5638 } 5639 tresult = isc_symtab_define(symtab, channelname, 1, symvalue, 5640 isc_symexists_replace); 5641 if (tresult != ISC_R_SUCCESS) { 5642 result = tresult; 5643 } 5644 } 5645 5646 cfg_map_get(logobj, "category", &categories); 5647 5648 for (element = cfg_list_first(categories); element != NULL; 5649 element = cfg_list_next(element)) 5650 { 5651 category = cfg_listelt_value(element); 5652 catname = cfg_obj_asstring(cfg_tuple_get(category, "name")); 5653 if (isc_log_categorybyname(logctx, catname) == NULL) { 5654 cfg_obj_log(category, logctx, ISC_LOG_ERROR, 5655 "undefined category: '%s'", catname); 5656 result = ISC_R_FAILURE; 5657 } 5658 channels = cfg_tuple_get(category, "destinations"); 5659 for (delement = cfg_list_first(channels); delement != NULL; 5660 delement = cfg_list_next(delement)) 5661 { 5662 channel = cfg_listelt_value(delement); 5663 channelname = cfg_obj_asstring(channel); 5664 tresult = isc_symtab_lookup(symtab, channelname, 1, 5665 &symvalue); 5666 if (tresult != ISC_R_SUCCESS) { 5667 cfg_obj_log(channel, logctx, ISC_LOG_ERROR, 5668 "undefined channel: '%s'", 5669 channelname); 5670 result = tresult; 5671 } 5672 } 5673 } 5674 isc_symtab_destroy(&symtab); 5675 return (result); 5676} 5677 5678static isc_result_t 5679bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist, 5680 isc_log_t *logctx) { 5681 isc_result_t result = ISC_R_SUCCESS; 5682 const cfg_obj_t *control_keylist; 5683 const cfg_listelt_t *element; 5684 const cfg_obj_t *key; 5685 const char *keyval; 5686 5687 control_keylist = cfg_tuple_get(control, "keys"); 5688 if (cfg_obj_isvoid(control_keylist)) { 5689 return (ISC_R_SUCCESS); 5690 } 5691 5692 for (element = cfg_list_first(control_keylist); element != NULL; 5693 element = cfg_list_next(element)) 5694 { 5695 key = cfg_listelt_value(element); 5696 keyval = cfg_obj_asstring(key); 5697 5698 if (!rndckey_exists(keylist, keyval)) { 5699 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 5700 "unknown key '%s'", keyval); 5701 result = ISC_R_NOTFOUND; 5702 } 5703 } 5704 return (result); 5705} 5706 5707static isc_result_t 5708bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx, 5709 isc_mem_t *mctx) { 5710 isc_result_t result = ISC_R_SUCCESS, tresult; 5711 cfg_aclconfctx_t *actx = NULL; 5712 const cfg_listelt_t *element, *element2; 5713 const cfg_obj_t *allow; 5714 const cfg_obj_t *control; 5715 const cfg_obj_t *controls; 5716 const cfg_obj_t *controlslist = NULL; 5717 const cfg_obj_t *inetcontrols; 5718 const cfg_obj_t *unixcontrols; 5719 const cfg_obj_t *keylist = NULL; 5720 const char *path; 5721 uint32_t perm, mask; 5722 dns_acl_t *acl = NULL; 5723 isc_sockaddr_t addr; 5724 int i; 5725 5726 (void)cfg_map_get(config, "controls", &controlslist); 5727 if (controlslist == NULL) { 5728 return (ISC_R_SUCCESS); 5729 } 5730 5731 (void)cfg_map_get(config, "key", &keylist); 5732 5733 cfg_aclconfctx_create(mctx, &actx); 5734 5735 /* 5736 * INET: Check allow clause. 5737 * UNIX: Check "perm" for sanity, check path length. 5738 */ 5739 for (element = cfg_list_first(controlslist); element != NULL; 5740 element = cfg_list_next(element)) 5741 { 5742 controls = cfg_listelt_value(element); 5743 unixcontrols = NULL; 5744 inetcontrols = NULL; 5745 (void)cfg_map_get(controls, "unix", &unixcontrols); 5746 (void)cfg_map_get(controls, "inet", &inetcontrols); 5747 for (element2 = cfg_list_first(inetcontrols); element2 != NULL; 5748 element2 = cfg_list_next(element2)) 5749 { 5750 control = cfg_listelt_value(element2); 5751 allow = cfg_tuple_get(control, "allow"); 5752 tresult = cfg_acl_fromconfig(allow, config, logctx, 5753 actx, mctx, 0, &acl); 5754 if (acl != NULL) { 5755 dns_acl_detach(&acl); 5756 } 5757 if (tresult != ISC_R_SUCCESS) { 5758 result = tresult; 5759 } 5760 tresult = bind9_check_controlskeys(control, keylist, 5761 logctx); 5762 if (tresult != ISC_R_SUCCESS) { 5763 result = tresult; 5764 } 5765 } 5766 for (element2 = cfg_list_first(unixcontrols); element2 != NULL; 5767 element2 = cfg_list_next(element2)) 5768 { 5769 control = cfg_listelt_value(element2); 5770 path = cfg_obj_asstring(cfg_tuple_get(control, "path")); 5771 tresult = isc_sockaddr_frompath(&addr, path); 5772 if (tresult == ISC_R_NOSPACE) { 5773 cfg_obj_log(control, logctx, ISC_LOG_ERROR, 5774 "unix control '%s': path too long", 5775 path); 5776 result = ISC_R_NOSPACE; 5777 } 5778 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); 5779 for (i = 0; i < 3; i++) { 5780#ifdef NEED_SECURE_DIRECTORY 5781 mask = (0x1 << (i * 3)); /* SEARCH */ 5782#else /* ifdef NEED_SECURE_DIRECTORY */ 5783 mask = (0x6 << (i * 3)); /* READ + WRITE */ 5784#endif /* ifdef NEED_SECURE_DIRECTORY */ 5785 if ((perm & mask) == mask) { 5786 break; 5787 } 5788 } 5789 if (i == 0) { 5790 cfg_obj_log(control, logctx, ISC_LOG_WARNING, 5791 "unix control '%s' allows access " 5792 "to everyone", 5793 path); 5794 } else if (i == 3) { 5795 cfg_obj_log(control, logctx, ISC_LOG_WARNING, 5796 "unix control '%s' allows access " 5797 "to nobody", 5798 path); 5799 } 5800 tresult = bind9_check_controlskeys(control, keylist, 5801 logctx); 5802 if (tresult != ISC_R_SUCCESS) { 5803 result = tresult; 5804 } 5805 } 5806 } 5807 cfg_aclconfctx_detach(&actx); 5808 return (result); 5809} 5810 5811isc_result_t 5812bind9_check_namedconf(const cfg_obj_t *config, bool check_plugins, 5813 bool nodeprecate, isc_log_t *logctx, isc_mem_t *mctx) { 5814 const cfg_obj_t *options = NULL; 5815 const cfg_obj_t *views = NULL; 5816 const cfg_obj_t *acls = NULL; 5817 const cfg_listelt_t *velement; 5818 isc_result_t result = ISC_R_SUCCESS; 5819 isc_result_t tresult; 5820 isc_symtab_t *symtab = NULL; 5821 isc_symtab_t *files = NULL; 5822 isc_symtab_t *keydirs = NULL; 5823 isc_symtab_t *inview = NULL; 5824 5825 static const char *builtin[] = { "localhost", "localnets", "any", 5826 "none" }; 5827 5828 (void)cfg_map_get(config, "options", &options); 5829 5830 if (options != NULL && check_options(options, config, logctx, mctx, 5831 optlevel_options) != ISC_R_SUCCESS) 5832 { 5833 result = ISC_R_FAILURE; 5834 } 5835 5836 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS) { 5837 result = ISC_R_FAILURE; 5838 } 5839 5840 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS) { 5841 result = ISC_R_FAILURE; 5842 } 5843 5844 if (bind9_check_primarylists(config, logctx, mctx) != ISC_R_SUCCESS) { 5845 result = ISC_R_FAILURE; 5846 } 5847 5848 if (bind9_check_parentalagentlists(config, logctx, mctx) != 5849 ISC_R_SUCCESS) 5850 { 5851 result = ISC_R_FAILURE; 5852 } 5853 5854#if HAVE_LIBNGHTTP2 5855 if (bind9_check_httpservers(config, logctx, mctx) != ISC_R_SUCCESS) { 5856 result = ISC_R_FAILURE; 5857 } 5858#endif /* HAVE_LIBNGHTTP2 */ 5859 5860 if (bind9_check_tls_definitions(config, logctx, mctx) != ISC_R_SUCCESS) 5861 { 5862 result = ISC_R_FAILURE; 5863 } 5864 5865 (void)cfg_map_get(config, "view", &views); 5866 5867 if (views != NULL && options != NULL) { 5868 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS) { 5869 result = ISC_R_FAILURE; 5870 5871 /* 5872 * Use case insensitive comparison as not all file 5873 * systems are case sensitive. This will prevent people 5874 * using FOO.DB and foo.db on case sensitive file 5875 * systems but that shouldn't be a major issue. 5876 */ 5877 } 5878 } 5879 5880 /* 5881 * Use case insensitive comparison as not all file systems are 5882 * case sensitive. This will prevent people using FOO.DB and foo.db 5883 * on case sensitive file systems but that shouldn't be a major issue. 5884 */ 5885 tresult = isc_symtab_create(mctx, 100, NULL, NULL, false, &files); 5886 if (tresult != ISC_R_SUCCESS) { 5887 result = tresult; 5888 goto cleanup; 5889 } 5890 5891 tresult = isc_symtab_create(mctx, 100, freekey, mctx, false, &keydirs); 5892 if (tresult != ISC_R_SUCCESS) { 5893 result = tresult; 5894 goto cleanup; 5895 } 5896 5897 tresult = isc_symtab_create(mctx, 100, freekey, mctx, true, &inview); 5898 if (tresult != ISC_R_SUCCESS) { 5899 result = tresult; 5900 goto cleanup; 5901 } 5902 5903 if (views == NULL) { 5904 tresult = check_viewconf(config, NULL, NULL, dns_rdataclass_in, 5905 files, keydirs, check_plugins, 5906 nodeprecate, inview, logctx, mctx); 5907 if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS) { 5908 result = ISC_R_FAILURE; 5909 } 5910 } else { 5911 const cfg_obj_t *zones = NULL; 5912 const cfg_obj_t *plugins = NULL; 5913 5914 (void)cfg_map_get(config, "zone", &zones); 5915 if (zones != NULL) { 5916 cfg_obj_log(zones, logctx, ISC_LOG_ERROR, 5917 "when using 'view' statements, " 5918 "all zones must be in views"); 5919 result = ISC_R_FAILURE; 5920 } 5921 5922 (void)cfg_map_get(config, "plugin", &plugins); 5923 if (plugins != NULL) { 5924 cfg_obj_log(plugins, logctx, ISC_LOG_ERROR, 5925 "when using 'view' statements, " 5926 "all plugins must be defined in views"); 5927 result = ISC_R_FAILURE; 5928 } 5929 } 5930 5931 tresult = isc_symtab_create(mctx, 100, NULL, NULL, true, &symtab); 5932 if (tresult != ISC_R_SUCCESS) { 5933 result = tresult; 5934 goto cleanup; 5935 } 5936 for (velement = cfg_list_first(views); velement != NULL; 5937 velement = cfg_list_next(velement)) 5938 { 5939 const cfg_obj_t *view = cfg_listelt_value(velement); 5940 const cfg_obj_t *vname = cfg_tuple_get(view, "name"); 5941 const cfg_obj_t *voptions = cfg_tuple_get(view, "options"); 5942 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class"); 5943 dns_rdataclass_t vclass = dns_rdataclass_in; 5944 const char *key = cfg_obj_asstring(vname); 5945 isc_symvalue_t symvalue; 5946 unsigned int symtype; 5947 5948 tresult = ISC_R_SUCCESS; 5949 if (cfg_obj_isstring(vclassobj)) { 5950 isc_textregion_t r; 5951 5952 DE_CONST(cfg_obj_asstring(vclassobj), r.base); 5953 r.length = strlen(r.base); 5954 tresult = dns_rdataclass_fromtext(&vclass, &r); 5955 if (tresult != ISC_R_SUCCESS) { 5956 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR, 5957 "view '%s': invalid class %s", 5958 cfg_obj_asstring(vname), r.base); 5959 } 5960 } 5961 symtype = vclass + 1; 5962 if (tresult == ISC_R_SUCCESS && symtab != NULL) { 5963 symvalue.as_cpointer = view; 5964 tresult = isc_symtab_define(symtab, key, symtype, 5965 symvalue, 5966 isc_symexists_reject); 5967 if (tresult == ISC_R_EXISTS) { 5968 const char *file; 5969 unsigned int line; 5970 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, 5971 symtype, 5972 &symvalue) == 5973 ISC_R_SUCCESS); 5974 file = cfg_obj_file(symvalue.as_cpointer); 5975 line = cfg_obj_line(symvalue.as_cpointer); 5976 cfg_obj_log(view, logctx, ISC_LOG_ERROR, 5977 "view '%s': already exists " 5978 "previous definition: %s:%u", 5979 key, file, line); 5980 result = tresult; 5981 } else if (tresult != ISC_R_SUCCESS) { 5982 result = tresult; 5983 } else if ((strcasecmp(key, "_bind") == 0 && 5984 vclass == dns_rdataclass_ch) || 5985 (strcasecmp(key, "_default") == 0 && 5986 vclass == dns_rdataclass_in)) 5987 { 5988 cfg_obj_log(view, logctx, ISC_LOG_ERROR, 5989 "attempt to redefine builtin view " 5990 "'%s'", 5991 key); 5992 result = ISC_R_EXISTS; 5993 } 5994 } 5995 if (tresult == ISC_R_SUCCESS) { 5996 tresult = check_viewconf(config, voptions, key, vclass, 5997 files, keydirs, check_plugins, 5998 nodeprecate, inview, logctx, 5999 mctx); 6000 } 6001 if (tresult != ISC_R_SUCCESS) { 6002 result = ISC_R_FAILURE; 6003 } 6004 } 6005 6006 cfg_map_get(config, "acl", &acls); 6007 6008 if (acls != NULL) { 6009 const cfg_listelt_t *elt; 6010 const cfg_listelt_t *elt2; 6011 const char *aclname; 6012 6013 for (elt = cfg_list_first(acls); elt != NULL; 6014 elt = cfg_list_next(elt)) 6015 { 6016 const cfg_obj_t *acl = cfg_listelt_value(elt); 6017 unsigned int line = cfg_obj_line(acl); 6018 unsigned int i; 6019 6020 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name")); 6021 for (i = 0; i < sizeof(builtin) / sizeof(builtin[0]); 6022 i++) 6023 { 6024 if (strcasecmp(aclname, builtin[i]) == 0) { 6025 { 6026 cfg_obj_log(acl, logctx, 6027 ISC_LOG_ERROR, 6028 "attempt to " 6029 "redefine " 6030 "builtin acl '%s'", 6031 aclname); 6032 result = ISC_R_FAILURE; 6033 break; 6034 } 6035 } 6036 } 6037 6038 for (elt2 = cfg_list_next(elt); elt2 != NULL; 6039 elt2 = cfg_list_next(elt2)) 6040 { 6041 const cfg_obj_t *acl2 = cfg_listelt_value(elt2); 6042 const char *name; 6043 name = cfg_obj_asstring( 6044 cfg_tuple_get(acl2, "name")); 6045 if (strcasecmp(aclname, name) == 0) { 6046 const char *file = cfg_obj_file(acl); 6047 6048 if (file == NULL) { 6049 file = "<unknown file>"; 6050 } 6051 6052 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR, 6053 "attempt to redefine " 6054 "acl '%s' previous " 6055 "definition: %s:%u", 6056 name, file, line); 6057 result = ISC_R_FAILURE; 6058 } 6059 } 6060 } 6061 } 6062 6063cleanup: 6064 if (symtab != NULL) { 6065 isc_symtab_destroy(&symtab); 6066 } 6067 if (inview != NULL) { 6068 isc_symtab_destroy(&inview); 6069 } 6070 if (files != NULL) { 6071 isc_symtab_destroy(&files); 6072 } 6073 if (keydirs != NULL) { 6074 isc_symtab_destroy(&keydirs); 6075 } 6076 6077 return (result); 6078} 6079