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