00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021
00022 #include <stdlib.h>
00023
00024 #include <isc/base64.h>
00025 #include <isc/buffer.h>
00026 #include <isc/file.h>
00027 #include <isc/hex.h>
00028 #include <isc/log.h>
00029 #include <isc/mem.h>
00030 #include <isc/netaddr.h>
00031 #include <isc/parseint.h>
00032 #include <isc/platform.h>
00033 #include <isc/region.h>
00034 #include <isc/result.h>
00035 #include <isc/sockaddr.h>
00036 #include <isc/string.h>
00037 #include <isc/symtab.h>
00038 #include <isc/util.h>
00039
00040 #ifdef ISC_PLATFORM_USESIT
00041 #ifdef AES_SIT
00042 #include <isc/aes.h>
00043 #endif
00044 #ifdef HMAC_SHA1_SIT
00045 #include <isc/sha1.h>
00046 #endif
00047 #ifdef HMAC_SHA256_SIT
00048 #include <isc/sha2.h>
00049 #endif
00050 #endif
00051
00052 #include <dns/acl.h>
00053 #include <dns/fixedname.h>
00054 #include <dns/rdataclass.h>
00055 #include <dns/rdatatype.h>
00056 #include <dns/secalg.h>
00057
00058 #include <dst/dst.h>
00059
00060 #include <isccfg/aclconf.h>
00061 #include <isccfg/cfg.h>
00062
00063 #include <bind9/check.h>
00064
00065 static isc_result_t
00066 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, isc_boolean_t writeable,
00067 isc_log_t *logctxlogc);
00068
00069 static void
00070 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
00071 UNUSED(type);
00072 UNUSED(value);
00073 isc_mem_free(userarg, key);
00074 }
00075
00076 static isc_result_t
00077 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
00078 isc_result_t result = ISC_R_SUCCESS;
00079 isc_result_t tresult;
00080 isc_textregion_t r;
00081 dns_fixedname_t fixed;
00082 const cfg_obj_t *obj;
00083 dns_rdataclass_t rdclass;
00084 dns_rdatatype_t rdtype;
00085 isc_buffer_t b;
00086 const char *str;
00087
00088 dns_fixedname_init(&fixed);
00089 obj = cfg_tuple_get(ent, "class");
00090 if (cfg_obj_isstring(obj)) {
00091
00092 DE_CONST(cfg_obj_asstring(obj), r.base);
00093 r.length = strlen(r.base);
00094 tresult = dns_rdataclass_fromtext(&rdclass, &r);
00095 if (tresult != ISC_R_SUCCESS) {
00096 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00097 "rrset-order: invalid class '%s'",
00098 r.base);
00099 result = ISC_R_FAILURE;
00100 }
00101 }
00102
00103 obj = cfg_tuple_get(ent, "type");
00104 if (cfg_obj_isstring(obj)) {
00105 DE_CONST(cfg_obj_asstring(obj), r.base);
00106 r.length = strlen(r.base);
00107 tresult = dns_rdatatype_fromtext(&rdtype, &r);
00108 if (tresult != ISC_R_SUCCESS) {
00109 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00110 "rrset-order: invalid type '%s'",
00111 r.base);
00112 result = ISC_R_FAILURE;
00113 }
00114 }
00115
00116 obj = cfg_tuple_get(ent, "name");
00117 if (cfg_obj_isstring(obj)) {
00118 str = cfg_obj_asstring(obj);
00119 isc_buffer_constinit(&b, str, strlen(str));
00120 isc_buffer_add(&b, strlen(str));
00121 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
00122 dns_rootname, 0, NULL);
00123 if (tresult != ISC_R_SUCCESS) {
00124 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00125 "rrset-order: invalid name '%s'", str);
00126 result = ISC_R_FAILURE;
00127 }
00128 }
00129
00130 obj = cfg_tuple_get(ent, "order");
00131 if (!cfg_obj_isstring(obj) ||
00132 strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
00133 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
00134 "rrset-order: keyword 'order' missing");
00135 result = ISC_R_FAILURE;
00136 }
00137
00138 obj = cfg_tuple_get(ent, "ordering");
00139 if (!cfg_obj_isstring(obj)) {
00140 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
00141 "rrset-order: missing ordering");
00142 result = ISC_R_FAILURE;
00143 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
00144 #if !DNS_RDATASET_FIXED
00145 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
00146 "rrset-order: order 'fixed' was disabled at "
00147 "compilation time");
00148 #endif
00149 } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
00150 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
00151 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00152 "rrset-order: invalid order '%s'",
00153 cfg_obj_asstring(obj));
00154 result = ISC_R_FAILURE;
00155 }
00156 return (result);
00157 }
00158
00159 static isc_result_t
00160 check_order(const cfg_obj_t *options, isc_log_t *logctx) {
00161 isc_result_t result = ISC_R_SUCCESS;
00162 isc_result_t tresult;
00163 const cfg_listelt_t *element;
00164 const cfg_obj_t *obj = NULL;
00165
00166 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
00167 return (result);
00168
00169 for (element = cfg_list_first(obj);
00170 element != NULL;
00171 element = cfg_list_next(element))
00172 {
00173 tresult = check_orderent(cfg_listelt_value(element), logctx);
00174 if (tresult != ISC_R_SUCCESS)
00175 result = tresult;
00176 }
00177 return (result);
00178 }
00179
00180 static isc_result_t
00181 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
00182 const cfg_listelt_t *element;
00183 const cfg_obj_t *alternates = NULL;
00184 const cfg_obj_t *value;
00185 const cfg_obj_t *obj;
00186 const char *str;
00187 dns_fixedname_t fixed;
00188 dns_name_t *name;
00189 isc_buffer_t buffer;
00190 isc_result_t result = ISC_R_SUCCESS;
00191 isc_result_t tresult;
00192
00193 (void)cfg_map_get(options, "dual-stack-servers", &alternates);
00194
00195 if (alternates == NULL)
00196 return (ISC_R_SUCCESS);
00197
00198 obj = cfg_tuple_get(alternates, "port");
00199 if (cfg_obj_isuint32(obj)) {
00200 isc_uint32_t val = cfg_obj_asuint32(obj);
00201 if (val > ISC_UINT16_MAX) {
00202 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00203 "port '%u' out of range", val);
00204 result = ISC_R_FAILURE;
00205 }
00206 }
00207 obj = cfg_tuple_get(alternates, "addresses");
00208 for (element = cfg_list_first(obj);
00209 element != NULL;
00210 element = cfg_list_next(element)) {
00211 value = cfg_listelt_value(element);
00212 if (cfg_obj_issockaddr(value))
00213 continue;
00214 obj = cfg_tuple_get(value, "name");
00215 str = cfg_obj_asstring(obj);
00216 isc_buffer_constinit(&buffer, str, strlen(str));
00217 isc_buffer_add(&buffer, strlen(str));
00218 dns_fixedname_init(&fixed);
00219 name = dns_fixedname_name(&fixed);
00220 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
00221 0, NULL);
00222 if (tresult != ISC_R_SUCCESS) {
00223 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00224 "bad name '%s'", str);
00225 result = ISC_R_FAILURE;
00226 }
00227 obj = cfg_tuple_get(value, "port");
00228 if (cfg_obj_isuint32(obj)) {
00229 isc_uint32_t val = cfg_obj_asuint32(obj);
00230 if (val > ISC_UINT16_MAX) {
00231 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00232 "port '%u' out of range", val);
00233 result = ISC_R_FAILURE;
00234 }
00235 }
00236 }
00237 return (result);
00238 }
00239
00240 static isc_result_t
00241 check_forward(const cfg_obj_t *options, const cfg_obj_t *global,
00242 isc_log_t *logctx)
00243 {
00244 const cfg_obj_t *forward = NULL;
00245 const cfg_obj_t *forwarders = NULL;
00246
00247 (void)cfg_map_get(options, "forward", &forward);
00248 (void)cfg_map_get(options, "forwarders", &forwarders);
00249
00250 if (forwarders != NULL && global != NULL) {
00251 const char *file = cfg_obj_file(global);
00252 unsigned int line = cfg_obj_line(global);
00253 cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
00254 "forwarders declared in root zone and "
00255 "in general configuration: %s:%u",
00256 file, line);
00257 return (ISC_R_FAILURE);
00258 }
00259 if (forward != NULL && forwarders == NULL) {
00260 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
00261 "no matching 'forwarders' statement");
00262 return (ISC_R_FAILURE);
00263 }
00264 return (ISC_R_SUCCESS);
00265 }
00266
00267 static isc_result_t
00268 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
00269 isc_result_t result = ISC_R_SUCCESS;
00270 isc_result_t tresult;
00271 const cfg_listelt_t *element;
00272 const char *str;
00273 isc_buffer_t b;
00274 dns_fixedname_t fixed;
00275 dns_name_t *name;
00276 const cfg_obj_t *obj;
00277
00278 dns_fixedname_init(&fixed);
00279 name = dns_fixedname_name(&fixed);
00280 obj = cfg_tuple_get(disabled, "name");
00281 str = cfg_obj_asstring(obj);
00282 isc_buffer_constinit(&b, str, strlen(str));
00283 isc_buffer_add(&b, strlen(str));
00284 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
00285 if (tresult != ISC_R_SUCCESS) {
00286 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00287 "bad domain name '%s'", str);
00288 result = tresult;
00289 }
00290
00291 obj = cfg_tuple_get(disabled, "algorithms");
00292
00293 for (element = cfg_list_first(obj);
00294 element != NULL;
00295 element = cfg_list_next(element))
00296 {
00297 isc_textregion_t r;
00298 dns_secalg_t alg;
00299
00300 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
00301 r.length = strlen(r.base);
00302
00303 tresult = dns_secalg_fromtext(&alg, &r);
00304 if (tresult != ISC_R_SUCCESS) {
00305 cfg_obj_log(cfg_listelt_value(element), logctx,
00306 ISC_LOG_ERROR, "invalid algorithm '%s'",
00307 r.base);
00308 result = tresult;
00309 }
00310 }
00311 return (result);
00312 }
00313
00314 static isc_result_t
00315 disabled_ds_digests(const cfg_obj_t *disabled, isc_log_t *logctx) {
00316 isc_result_t result = ISC_R_SUCCESS;
00317 isc_result_t tresult;
00318 const cfg_listelt_t *element;
00319 const char *str;
00320 isc_buffer_t b;
00321 dns_fixedname_t fixed;
00322 dns_name_t *name;
00323 const cfg_obj_t *obj;
00324
00325 dns_fixedname_init(&fixed);
00326 name = dns_fixedname_name(&fixed);
00327 obj = cfg_tuple_get(disabled, "name");
00328 str = cfg_obj_asstring(obj);
00329 isc_buffer_constinit(&b, str, strlen(str));
00330 isc_buffer_add(&b, strlen(str));
00331 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
00332 if (tresult != ISC_R_SUCCESS) {
00333 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00334 "bad domain name '%s'", str);
00335 result = tresult;
00336 }
00337
00338 obj = cfg_tuple_get(disabled, "digests");
00339
00340 for (element = cfg_list_first(obj);
00341 element != NULL;
00342 element = cfg_list_next(element))
00343 {
00344 isc_textregion_t r;
00345 dns_dsdigest_t digest;
00346
00347 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
00348 r.length = strlen(r.base);
00349
00350
00351 tresult = dns_dsdigest_fromtext(&digest, &r);
00352 if (tresult != ISC_R_SUCCESS) {
00353 cfg_obj_log(cfg_listelt_value(element), logctx,
00354 ISC_LOG_ERROR, "invalid digest type '%s'",
00355 r.base);
00356 result = tresult;
00357 }
00358 }
00359 return (result);
00360 }
00361
00362 static isc_result_t
00363 nameexist(const cfg_obj_t *obj, const char *name, int value,
00364 isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
00365 isc_mem_t *mctx)
00366 {
00367 char *key;
00368 const char *file;
00369 unsigned int line;
00370 isc_result_t result;
00371 isc_symvalue_t symvalue;
00372
00373 key = isc_mem_strdup(mctx, name);
00374 if (key == NULL)
00375 return (ISC_R_NOMEMORY);
00376 symvalue.as_cpointer = obj;
00377 result = isc_symtab_define(symtab, key, value, symvalue,
00378 isc_symexists_reject);
00379 if (result == ISC_R_EXISTS) {
00380 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
00381 &symvalue) == ISC_R_SUCCESS);
00382 file = cfg_obj_file(symvalue.as_cpointer);
00383 line = cfg_obj_line(symvalue.as_cpointer);
00384
00385 if (file == NULL)
00386 file = "<unknown file>";
00387 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
00388 isc_mem_free(mctx, key);
00389 result = ISC_R_EXISTS;
00390 } else if (result != ISC_R_SUCCESS) {
00391 isc_mem_free(mctx, key);
00392 }
00393 return (result);
00394 }
00395
00396 static isc_result_t
00397 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
00398 isc_mem_t *mctx)
00399 {
00400 const cfg_obj_t *obj;
00401 char namebuf[DNS_NAME_FORMATSIZE];
00402 const char *str;
00403 dns_fixedname_t fixed;
00404 dns_name_t *name;
00405 isc_buffer_t b;
00406 isc_result_t result = ISC_R_SUCCESS;
00407
00408 dns_fixedname_init(&fixed);
00409 name = dns_fixedname_name(&fixed);
00410 obj = cfg_tuple_get(secure, "name");
00411 str = cfg_obj_asstring(obj);
00412 isc_buffer_constinit(&b, str, strlen(str));
00413 isc_buffer_add(&b, strlen(str));
00414 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
00415 if (result != ISC_R_SUCCESS) {
00416 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00417 "bad domain name '%s'", str);
00418 } else {
00419 dns_name_format(name, namebuf, sizeof(namebuf));
00420 result = nameexist(secure, namebuf, 1, symtab,
00421 "dnssec-must-be-secure '%s': already "
00422 "exists previous definition: %s:%u",
00423 logctx, mctx);
00424 }
00425 return (result);
00426 }
00427
00428 static isc_result_t
00429 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
00430 const cfg_obj_t *voptions, const cfg_obj_t *config,
00431 isc_log_t *logctx, isc_mem_t *mctx)
00432 {
00433 isc_result_t result;
00434 const cfg_obj_t *aclobj = NULL;
00435 const cfg_obj_t *options;
00436 dns_acl_t *acl = NULL;
00437
00438 if (zconfig != NULL) {
00439 options = cfg_tuple_get(zconfig, "options");
00440 cfg_map_get(options, aclname, &aclobj);
00441 }
00442 if (voptions != NULL && aclobj == NULL)
00443 cfg_map_get(voptions, aclname, &aclobj);
00444 if (config != NULL && aclobj == NULL) {
00445 options = NULL;
00446 cfg_map_get(config, "options", &options);
00447 if (options != NULL)
00448 cfg_map_get(options, aclname, &aclobj);
00449 }
00450 if (aclobj == NULL)
00451 return (ISC_R_SUCCESS);
00452 result = cfg_acl_fromconfig(aclobj, config, logctx,
00453 actx, mctx, 0, &acl);
00454 if (acl != NULL)
00455 dns_acl_detach(&acl);
00456 return (result);
00457 }
00458
00459 static isc_result_t
00460 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
00461 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
00462 {
00463 isc_result_t result = ISC_R_SUCCESS, tresult;
00464 int i = 0;
00465
00466 static const char *acls[] = { "allow-query", "allow-query-on",
00467 "allow-query-cache", "allow-query-cache-on",
00468 "blackhole", "keep-response-order", "match-clients",
00469 "match-destinations", "sortlist", "filter-aaaa", NULL };
00470
00471 while (acls[i] != NULL) {
00472 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
00473 logctx, mctx);
00474 if (tresult != ISC_R_SUCCESS)
00475 result = tresult;
00476 }
00477 return (result);
00478 }
00479
00480 static const unsigned char zeros[16];
00481
00482 static isc_result_t
00483 check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
00484 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
00485 {
00486 isc_result_t result = ISC_R_SUCCESS;
00487 const cfg_obj_t *dns64 = NULL;
00488 const cfg_obj_t *options;
00489 const cfg_listelt_t *element;
00490 const cfg_obj_t *map, *obj;
00491 isc_netaddr_t na, sa;
00492 unsigned int prefixlen;
00493 int nbytes;
00494 int i;
00495
00496 static const char *acls[] = { "clients", "exclude", "mapped", NULL};
00497
00498 if (voptions != NULL)
00499 cfg_map_get(voptions, "dns64", &dns64);
00500 if (config != NULL && dns64 == NULL) {
00501 options = NULL;
00502 cfg_map_get(config, "options", &options);
00503 if (options != NULL)
00504 cfg_map_get(options, "dns64", &dns64);
00505 }
00506 if (dns64 == NULL)
00507 return (ISC_R_SUCCESS);
00508
00509 for (element = cfg_list_first(dns64);
00510 element != NULL;
00511 element = cfg_list_next(element))
00512 {
00513 map = cfg_listelt_value(element);
00514 obj = cfg_map_getname(map);
00515
00516 cfg_obj_asnetprefix(obj, &na, &prefixlen);
00517 if (na.family != AF_INET6) {
00518 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
00519 "dns64 requires a IPv6 prefix");
00520 result = ISC_R_FAILURE;
00521 continue;
00522 }
00523
00524 if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 &&
00525 prefixlen != 56 && prefixlen != 64 && prefixlen != 96) {
00526 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
00527 "bad prefix length %u [32/40/48/56/64/96]",
00528 prefixlen);
00529 result = ISC_R_FAILURE;
00530 continue;
00531 }
00532
00533 for (i = 0; acls[i] != NULL; i++) {
00534 obj = NULL;
00535 (void)cfg_map_get(map, acls[i], &obj);
00536 if (obj != NULL) {
00537 dns_acl_t *acl = NULL;
00538 isc_result_t tresult;
00539
00540 tresult = cfg_acl_fromconfig(obj, config,
00541 logctx, actx,
00542 mctx, 0, &acl);
00543 if (acl != NULL)
00544 dns_acl_detach(&acl);
00545 if (tresult != ISC_R_SUCCESS)
00546 result = tresult;
00547 }
00548 }
00549
00550 obj = NULL;
00551 (void)cfg_map_get(map, "suffix", &obj);
00552 if (obj != NULL) {
00553 isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj));
00554 if (sa.family != AF_INET6) {
00555 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
00556 "dns64 requires a IPv6 suffix");
00557 result = ISC_R_FAILURE;
00558 continue;
00559 }
00560 nbytes = prefixlen / 8 + 4;
00561 if (prefixlen >= 32 && prefixlen <= 64)
00562 nbytes++;
00563 if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) {
00564 char netaddrbuf[ISC_NETADDR_FORMATSIZE];
00565 isc_netaddr_format(&sa, netaddrbuf,
00566 sizeof(netaddrbuf));
00567 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00568 "bad suffix '%s' leading "
00569 "%u octets not zeros",
00570 netaddrbuf, nbytes);
00571 result = ISC_R_FAILURE;
00572 }
00573 }
00574 }
00575
00576 return (result);
00577 }
00578
00579
00580
00581
00582
00583
00584 static isc_result_t
00585 check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
00586 const char *viewname, const cfg_obj_t *config,
00587 isc_log_t *logctx, isc_mem_t *mctx)
00588 {
00589 const cfg_obj_t *options, *aclobj, *obj = NULL;
00590 dns_acl_t *acl = NULL;
00591 isc_result_t result = ISC_R_SUCCESS, tresult;
00592 isc_boolean_t recursion;
00593 const char *forview = " for view ";
00594 int i = 0;
00595
00596 static const char *acls[] = { "allow-recursion", "allow-recursion-on",
00597 NULL };
00598
00599 if (voptions != NULL)
00600 cfg_map_get(voptions, "recursion", &obj);
00601 if (obj == NULL && config != NULL) {
00602 options = NULL;
00603 cfg_map_get(config, "options", &options);
00604 if (options != NULL)
00605 cfg_map_get(options, "recursion", &obj);
00606 }
00607 if (obj == NULL)
00608 recursion = ISC_TRUE;
00609 else
00610 recursion = cfg_obj_asboolean(obj);
00611
00612 if (viewname == NULL) {
00613 viewname = "";
00614 forview = "";
00615 }
00616
00617 for (i = 0; acls[i] != NULL; i++) {
00618 aclobj = options = NULL;
00619 acl = NULL;
00620
00621 if (voptions != NULL)
00622 cfg_map_get(voptions, acls[i], &aclobj);
00623 if (config != NULL && aclobj == NULL) {
00624 options = NULL;
00625 cfg_map_get(config, "options", &options);
00626 if (options != NULL)
00627 cfg_map_get(options, acls[i], &aclobj);
00628 }
00629 if (aclobj == NULL)
00630 continue;
00631
00632 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
00633 actx, mctx, 0, &acl);
00634
00635 if (tresult != ISC_R_SUCCESS)
00636 result = tresult;
00637
00638 if (acl == NULL)
00639 continue;
00640
00641 if (recursion == ISC_FALSE && !dns_acl_isnone(acl)) {
00642 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
00643 "both \"recursion no;\" and "
00644 "\"%s\" active%s%s",
00645 acls[i], forview, viewname);
00646 }
00647
00648 if (acl != NULL)
00649 dns_acl_detach(&acl);
00650 }
00651
00652 return (result);
00653 }
00654
00655 static isc_result_t
00656 check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
00657 const char *viewname, const cfg_obj_t *config,
00658 isc_log_t *logctx, isc_mem_t *mctx)
00659 {
00660 const cfg_obj_t *options, *aclobj, *obj;
00661 dns_acl_t *acl = NULL;
00662 isc_result_t result = ISC_R_SUCCESS;
00663 dns_aaaa_t filter4, filter6;
00664 const char *forview = " for view ";
00665
00666 if (viewname == NULL) {
00667 viewname = "";
00668 forview = "";
00669 }
00670
00671 aclobj = options = NULL;
00672 acl = NULL;
00673
00674 if (voptions != NULL)
00675 cfg_map_get(voptions, "filter-aaaa", &aclobj);
00676 if (config != NULL && aclobj == NULL) {
00677 options = NULL;
00678 cfg_map_get(config, "options", &options);
00679 if (options != NULL)
00680 cfg_map_get(options, "filter-aaaa", &aclobj);
00681 }
00682 if (aclobj == NULL)
00683 return (result);
00684
00685 result = cfg_acl_fromconfig(aclobj, config, logctx,
00686 actx, mctx, 0, &acl);
00687 if (result != ISC_R_SUCCESS)
00688 goto failure;
00689
00690 obj = NULL;
00691 if (voptions != NULL)
00692 cfg_map_get(voptions, "filter-aaaa-on-v4", &obj);
00693 if (obj == NULL && config != NULL) {
00694 options = NULL;
00695 cfg_map_get(config, "options", &options);
00696 if (options != NULL)
00697 cfg_map_get(options, "filter-aaaa-on-v4", &obj);
00698 }
00699
00700 if (obj == NULL)
00701 filter4 = dns_aaaa_ok;
00702 else if (cfg_obj_isboolean(obj))
00703 filter4 = cfg_obj_asboolean(obj) ? dns_aaaa_filter :
00704 dns_aaaa_ok;
00705 else
00706 filter4 = dns_aaaa_break_dnssec;
00707
00708 obj = NULL;
00709 if (voptions != NULL)
00710 cfg_map_get(voptions, "filter-aaaa-on-v6", &obj);
00711 if (obj == NULL && config != NULL) {
00712 options = NULL;
00713 cfg_map_get(config, "options", &options);
00714 if (options != NULL)
00715 cfg_map_get(options, "filter-aaaa-on-v6", &obj);
00716 }
00717
00718 if (obj == NULL)
00719 filter6 = dns_aaaa_ok;
00720 else if (cfg_obj_isboolean(obj))
00721 filter6 = cfg_obj_asboolean(obj) ? dns_aaaa_filter :
00722 dns_aaaa_ok;
00723 else
00724 filter6 = dns_aaaa_break_dnssec;
00725
00726 if ((filter4 != dns_aaaa_ok || filter6 != dns_aaaa_ok) &&
00727 dns_acl_isnone(acl))
00728 {
00729 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
00730 "\"filter-aaaa\" is 'none;' but "
00731 "either filter-aaaa-on-v4 or filter-aaaa-on-v6 "
00732 "is enabled%s%s", forview, viewname);
00733 result = ISC_R_FAILURE;
00734 } else if (filter4 == dns_aaaa_ok && filter6 == dns_aaaa_ok &&
00735 !dns_acl_isnone(acl))
00736 {
00737 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
00738 "\"filter-aaaa\" is set but "
00739 "neither filter-aaaa-on-v4 or filter-aaaa-on-v6 "
00740 "is enabled%s%s", forview, viewname);
00741 result = ISC_R_FAILURE;
00742 }
00743
00744 failure:
00745 if (acl != NULL)
00746 dns_acl_detach(&acl);
00747
00748 return (result);
00749 }
00750
00751 typedef struct {
00752 const char *name;
00753 unsigned int scale;
00754 unsigned int max;
00755 } intervaltable;
00756
00757 typedef enum {
00758 optlevel_config,
00759 optlevel_options,
00760 optlevel_view,
00761 optlevel_zone
00762 } optlevel_t;
00763
00764 static isc_result_t
00765 check_dscp(const cfg_obj_t *options, isc_log_t *logctx) {
00766 isc_result_t result = ISC_R_SUCCESS;
00767 const cfg_obj_t *obj = NULL;
00768
00769
00770
00771
00772 obj = NULL;
00773 (void)cfg_map_get(options, "dscp", &obj);
00774 if (obj != NULL) {
00775 isc_uint32_t dscp = cfg_obj_asuint32(obj);
00776 if (dscp >= 64) {
00777 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00778 "'dscp' out of range (0-63)");
00779 result = ISC_R_FAILURE;
00780 }
00781 }
00782
00783 return (result);
00784 }
00785
00786 static isc_result_t
00787 check_name(const char *str) {
00788 dns_fixedname_t fixed;
00789
00790 dns_fixedname_init(&fixed);
00791 return (dns_name_fromstring(dns_fixedname_name(&fixed), str, 0, NULL));
00792 }
00793
00794 static isc_result_t
00795 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
00796 optlevel_t optlevel)
00797 {
00798 isc_result_t result = ISC_R_SUCCESS;
00799 isc_result_t tresult;
00800 unsigned int i;
00801 const cfg_obj_t *obj = NULL;
00802 const cfg_obj_t *resignobj = NULL;
00803 const cfg_listelt_t *element;
00804 isc_symtab_t *symtab = NULL;
00805 dns_fixedname_t fixed;
00806 const char *str;
00807 dns_name_t *name;
00808 #ifdef ISC_PLATFORM_USESIT
00809 isc_buffer_t b;
00810 #endif
00811 isc_uint32_t lifetime = 3600;
00812
00813 static intervaltable intervals[] = {
00814 { "cleaning-interval", 60, 28 * 24 * 60 },
00815 { "heartbeat-interval", 60, 28 * 24 * 60 },
00816 { "interface-interval", 60, 28 * 24 * 60 },
00817 { "max-transfer-idle-in", 60, 28 * 24 * 60 },
00818 { "max-transfer-idle-out", 60, 28 * 24 * 60 },
00819 { "max-transfer-time-in", 60, 28 * 24 * 60 },
00820 { "max-transfer-time-out", 60, 28 * 24 * 60 },
00821 { "statistics-interval", 60, 28 * 24 * 60 },
00822 };
00823
00824 static const char *server_contact[] = {
00825 "empty-server", "empty-contact",
00826 "dns64-server", "dns64-contact",
00827 NULL
00828 };
00829
00830
00831
00832
00833
00834 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
00835 isc_uint32_t val;
00836 obj = NULL;
00837 (void)cfg_map_get(options, intervals[i].name, &obj);
00838 if (obj == NULL)
00839 continue;
00840 val = cfg_obj_asuint32(obj);
00841 if (val > intervals[i].max) {
00842 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00843 "%s '%u' is out of range (0..%u)",
00844 intervals[i].name, val,
00845 intervals[i].max);
00846 result = ISC_R_RANGE;
00847 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
00848 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00849 "%s '%d' is out of range",
00850 intervals[i].name, val);
00851 result = ISC_R_RANGE;
00852 }
00853 }
00854
00855 obj = NULL;
00856 cfg_map_get(options, "max-rsa-exponent-size", &obj);
00857 if (obj != NULL) {
00858 isc_uint32_t val;
00859
00860 val = cfg_obj_asuint32(obj);
00861 if (val != 0 && (val < 35 || val > 4096)) {
00862 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00863 "max-rsa-exponent-size '%u' is out of "
00864 "range (35..4096)", val);
00865 result = ISC_R_RANGE;
00866 }
00867 }
00868
00869 obj = NULL;
00870 cfg_map_get(options, "sig-validity-interval", &obj);
00871 if (obj != NULL) {
00872 isc_uint32_t validity, resign = 0;
00873
00874 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
00875 resignobj = cfg_tuple_get(obj, "re-sign");
00876 if (!cfg_obj_isvoid(resignobj))
00877 resign = cfg_obj_asuint32(resignobj);
00878
00879 if (validity > 3660 || validity == 0) {
00880 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00881 "%s '%u' is out of range (1..3660)",
00882 "sig-validity-interval", validity);
00883 result = ISC_R_RANGE;
00884 }
00885
00886 if (!cfg_obj_isvoid(resignobj)) {
00887 if (resign > 3660 || resign == 0) {
00888 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00889 "%s '%u' is out of range (1..3660)",
00890 "sig-validity-interval (re-sign)",
00891 validity);
00892 result = ISC_R_RANGE;
00893 } else if ((validity > 7 && validity < resign) ||
00894 (validity <= 7 && validity * 24 < resign)) {
00895 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00896 "validity interval (%u days) "
00897 "less than re-signing interval "
00898 "(%u %s)", validity, resign,
00899 (validity > 7) ? "days" : "hours");
00900 result = ISC_R_RANGE;
00901 }
00902 }
00903 }
00904
00905 obj = NULL;
00906 (void)cfg_map_get(options, "preferred-glue", &obj);
00907 if (obj != NULL) {
00908 str = cfg_obj_asstring(obj);
00909 if (strcasecmp(str, "a") != 0 &&
00910 strcasecmp(str, "aaaa") != 0 &&
00911 strcasecmp(str, "none") != 0)
00912 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00913 "preferred-glue unexpected value '%s'",
00914 str);
00915 }
00916
00917 obj = NULL;
00918 (void)cfg_map_get(options, "root-delegation-only", &obj);
00919 if (obj != NULL) {
00920 if (!cfg_obj_isvoid(obj)) {
00921 for (element = cfg_list_first(obj);
00922 element != NULL;
00923 element = cfg_list_next(element)) {
00924 const cfg_obj_t *exclude;
00925
00926 exclude = cfg_listelt_value(element);
00927 str = cfg_obj_asstring(exclude);
00928 tresult = check_name(str);
00929 if (tresult != ISC_R_SUCCESS) {
00930 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00931 "bad domain name '%s'",
00932 str);
00933 result = tresult;
00934 }
00935 }
00936 }
00937 }
00938
00939
00940
00941
00942 obj = NULL;
00943 (void)cfg_map_get(options, "disable-algorithms", &obj);
00944 if (obj != NULL) {
00945 for (element = cfg_list_first(obj);
00946 element != NULL;
00947 element = cfg_list_next(element))
00948 {
00949 obj = cfg_listelt_value(element);
00950 tresult = disabled_algorithms(obj, logctx);
00951 if (tresult != ISC_R_SUCCESS)
00952 result = tresult;
00953 }
00954 }
00955
00956
00957
00958
00959 obj = NULL;
00960 (void)cfg_map_get(options, "disable-ds-digests", &obj);
00961 if (obj != NULL) {
00962 for (element = cfg_list_first(obj);
00963 element != NULL;
00964 element = cfg_list_next(element))
00965 {
00966 obj = cfg_listelt_value(element);
00967 tresult = disabled_ds_digests(obj, logctx);
00968 if (tresult != ISC_R_SUCCESS)
00969 result = tresult;
00970 }
00971 }
00972
00973 dns_fixedname_init(&fixed);
00974 name = dns_fixedname_name(&fixed);
00975
00976
00977
00978
00979 obj = NULL;
00980 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
00981 if (obj != NULL) {
00982 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
00983 ISC_FALSE, &symtab);
00984 if (tresult != ISC_R_SUCCESS)
00985 result = tresult;
00986 for (element = cfg_list_first(obj);
00987 element != NULL;
00988 element = cfg_list_next(element))
00989 {
00990 const char *dlv;
00991 const cfg_obj_t *dlvobj, *anchor;
00992
00993 obj = cfg_listelt_value(element);
00994
00995 anchor = cfg_tuple_get(obj, "trust-anchor");
00996 dlvobj = cfg_tuple_get(obj, "domain");
00997 dlv = cfg_obj_asstring(dlvobj);
00998
00999
01000
01001
01002
01003 if (cfg_obj_isvoid(anchor)) {
01004 if (!strcasecmp(dlv, "no") ||
01005 !strcasecmp(dlv, "auto"))
01006 continue;
01007 }
01008
01009 tresult = dns_name_fromstring(name, dlv, 0, NULL);
01010 if (tresult != ISC_R_SUCCESS) {
01011 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01012 "bad domain name '%s'", dlv);
01013 result = tresult;
01014 continue;
01015 }
01016 if (symtab != NULL) {
01017 tresult = nameexist(obj, dlv, 1, symtab,
01018 "dnssec-lookaside '%s': "
01019 "already exists previous "
01020 "definition: %s:%u",
01021 logctx, mctx);
01022 if (tresult != ISC_R_SUCCESS &&
01023 result == ISC_R_SUCCESS)
01024 result = tresult;
01025 }
01026
01027
01028
01029
01030
01031 if (!dns_name_equal(dns_rootname, name)) {
01032 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01033 "dnssec-lookaside '%s': "
01034 "non-root not yet supported", dlv);
01035 if (result == ISC_R_SUCCESS)
01036 result = ISC_R_FAILURE;
01037 }
01038
01039 if (!cfg_obj_isvoid(anchor)) {
01040 dlv = cfg_obj_asstring(anchor);
01041 tresult = check_name(dlv);
01042 if (tresult != ISC_R_SUCCESS) {
01043 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01044 "bad domain name '%s'",
01045 dlv);
01046 if (result == ISC_R_SUCCESS)
01047 result = tresult;
01048 }
01049 } else {
01050 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01051 "dnssec-lookaside requires "
01052 "either 'auto' or 'no', or a "
01053 "domain and trust anchor");
01054 if (result == ISC_R_SUCCESS)
01055 result = ISC_R_FAILURE;
01056 }
01057 }
01058
01059 if (symtab != NULL)
01060 isc_symtab_destroy(&symtab);
01061 }
01062
01063
01064
01065
01066 obj = NULL;
01067 (void)cfg_map_get(options, "auto-dnssec", &obj);
01068 if (obj != NULL) {
01069 const char *arg = cfg_obj_asstring(obj);
01070 if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) {
01071 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01072 "auto-dnssec may only be activated at the "
01073 "zone level");
01074 result = ISC_R_FAILURE;
01075 }
01076 }
01077
01078
01079
01080
01081 obj = NULL;
01082 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
01083 if (obj != NULL) {
01084 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
01085 ISC_FALSE, &symtab);
01086 if (tresult != ISC_R_SUCCESS)
01087 result = tresult;
01088 for (element = cfg_list_first(obj);
01089 element != NULL;
01090 element = cfg_list_next(element))
01091 {
01092 obj = cfg_listelt_value(element);
01093 tresult = mustbesecure(obj, symtab, logctx, mctx);
01094 if (tresult != ISC_R_SUCCESS)
01095 result = tresult;
01096 }
01097 if (symtab != NULL)
01098 isc_symtab_destroy(&symtab);
01099 }
01100
01101
01102
01103
01104 for (i= 0; server_contact[i] != NULL; i++) {
01105 obj = NULL;
01106 (void)cfg_map_get(options, server_contact[i], &obj);
01107 if (obj != NULL) {
01108 str = cfg_obj_asstring(obj);
01109 if (check_name(str) != ISC_R_SUCCESS) {
01110 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01111 "%s: invalid name '%s'",
01112 server_contact[i], str);
01113 result = ISC_R_FAILURE;
01114 }
01115 }
01116 }
01117
01118
01119
01120
01121 obj = NULL;
01122 (void)cfg_map_get(options, "disable-empty-zone", &obj);
01123 for (element = cfg_list_first(obj);
01124 element != NULL;
01125 element = cfg_list_next(element))
01126 {
01127 obj = cfg_listelt_value(element);
01128 str = cfg_obj_asstring(obj);
01129 if (check_name(str) != ISC_R_SUCCESS) {
01130 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01131 "disable-empty-zone: invalid name '%s'",
01132 str);
01133 result = ISC_R_FAILURE;
01134 }
01135 }
01136
01137
01138
01139
01140
01141 obj = NULL;
01142 (void)cfg_map_get(options, "server-id", &obj);
01143 if (obj != NULL && cfg_obj_isstring(obj) &&
01144 strlen(cfg_obj_asstring(obj)) > 1024U) {
01145 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01146 "'server-id' too big (>1024 bytes)");
01147 result = ISC_R_FAILURE;
01148 }
01149
01150 tresult = check_dscp(options, logctx);
01151 if (tresult != ISC_R_SUCCESS)
01152 result = tresult;
01153
01154 obj = NULL;
01155 (void)cfg_map_get(options, "nta-lifetime", &obj);
01156 if (obj != NULL) {
01157 lifetime = cfg_obj_asuint32(obj);
01158 if (lifetime > 604800) {
01159 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01160 "'nta-lifetime' cannot exceed one week");
01161 result = ISC_R_RANGE;
01162 } else if (lifetime == 0) {
01163 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01164 "'nta-lifetime' may not be zero");
01165 result = ISC_R_RANGE;
01166 }
01167 }
01168
01169 obj = NULL;
01170 (void)cfg_map_get(options, "nta-recheck", &obj);
01171 if (obj != NULL) {
01172 isc_uint32_t recheck = cfg_obj_asuint32(obj);
01173 if (recheck > 604800) {
01174 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01175 "'nta-recheck' cannot exceed one week");
01176 result = ISC_R_RANGE;
01177 }
01178
01179 if (recheck > lifetime)
01180 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
01181 "'nta-recheck' (%d seconds) is "
01182 "greater than 'nta-lifetime' "
01183 "(%d seconds)", recheck, lifetime);
01184 }
01185
01186 #ifdef ISC_PLATFORM_USESIT
01187 obj = NULL;
01188 (void) cfg_map_get(options, "sit-secret", &obj);
01189 if (obj != NULL) {
01190 unsigned char secret[32];
01191
01192 memset(secret, 0, sizeof(secret));
01193 isc_buffer_init(&b, secret, sizeof(secret));
01194 tresult = isc_hex_decodestring(cfg_obj_asstring(obj), &b);
01195 if (tresult == ISC_R_NOSPACE) {
01196 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01197 "sit-secret: too long");
01198 } else if (tresult != ISC_R_SUCCESS) {
01199 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01200 "sit-secret: invalid hex string");
01201 }
01202 if (tresult != ISC_R_SUCCESS)
01203 result = tresult;
01204 #ifdef AES_SIT
01205 if (tresult == ISC_R_SUCCESS &&
01206 isc_buffer_usedlength(&b) != ISC_AES128_KEYLENGTH) {
01207 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01208 "AES sit-secret must be on 128 bits");
01209 result = ISC_R_RANGE;
01210 }
01211 #endif
01212 #ifdef HMAC_SHA1_SIT
01213 if (tresult == ISC_R_SUCCESS &&
01214 isc_buffer_usedlength(&b) != ISC_SHA1_DIGESTLENGTH) {
01215 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01216 "SHA1 sit-secret must be on 160 bits");
01217 result = ISC_R_RANGE;
01218 }
01219 #endif
01220 #ifdef HMAC_SHA256_SIT
01221 if (tresult == ISC_R_SUCCESS &&
01222 isc_buffer_usedlength(&b) != ISC_SHA256_DIGESTLENGTH) {
01223 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01224 "SHA256 sit-secret must be on 256 bits");
01225 result = ISC_R_RANGE;
01226 }
01227 #endif
01228 }
01229 #endif
01230
01231 return (result);
01232 }
01233
01234 static isc_result_t
01235 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
01236 isc_result_t result;
01237 const cfg_obj_t *masters = NULL;
01238 const cfg_listelt_t *elt;
01239
01240 result = cfg_map_get(cctx, "masters", &masters);
01241 if (result != ISC_R_SUCCESS)
01242 return (result);
01243 for (elt = cfg_list_first(masters);
01244 elt != NULL;
01245 elt = cfg_list_next(elt)) {
01246 const cfg_obj_t *list;
01247 const char *listname;
01248
01249 list = cfg_listelt_value(elt);
01250 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
01251
01252 if (strcasecmp(listname, name) == 0) {
01253 *ret = list;
01254 return (ISC_R_SUCCESS);
01255 }
01256 }
01257 return (ISC_R_NOTFOUND);
01258 }
01259
01260 static isc_result_t
01261 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
01262 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
01263 {
01264 isc_result_t result = ISC_R_SUCCESS;
01265 isc_result_t tresult;
01266 isc_uint32_t count = 0;
01267 isc_symtab_t *symtab = NULL;
01268 isc_symvalue_t symvalue;
01269 const cfg_listelt_t *element;
01270 const cfg_listelt_t **stack = NULL;
01271 isc_uint32_t stackcount = 0, pushed = 0;
01272 const cfg_obj_t *list;
01273
01274 REQUIRE(countp != NULL);
01275 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
01276 if (result != ISC_R_SUCCESS) {
01277 *countp = count;
01278 return (result);
01279 }
01280
01281 newlist:
01282 list = cfg_tuple_get(obj, "addresses");
01283 element = cfg_list_first(list);
01284 resume:
01285 for ( ;
01286 element != NULL;
01287 element = cfg_list_next(element))
01288 {
01289 const char *listname;
01290 const cfg_obj_t *addr;
01291 const cfg_obj_t *key;
01292
01293 addr = cfg_tuple_get(cfg_listelt_value(element),
01294 "masterselement");
01295 key = cfg_tuple_get(cfg_listelt_value(element), "key");
01296
01297 if (cfg_obj_issockaddr(addr)) {
01298 count++;
01299 continue;
01300 }
01301 if (!cfg_obj_isvoid(key)) {
01302 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
01303 "unexpected token '%s'",
01304 cfg_obj_asstring(key));
01305 if (result == ISC_R_SUCCESS)
01306 result = ISC_R_FAILURE;
01307 }
01308 listname = cfg_obj_asstring(addr);
01309 symvalue.as_cpointer = addr;
01310 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
01311 isc_symexists_reject);
01312 if (tresult == ISC_R_EXISTS)
01313 continue;
01314 tresult = get_masters_def(config, listname, &obj);
01315 if (tresult != ISC_R_SUCCESS) {
01316 if (result == ISC_R_SUCCESS)
01317 result = tresult;
01318 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
01319 "unable to find masters list '%s'",
01320 listname);
01321 continue;
01322 }
01323
01324 if (stackcount == pushed) {
01325 void * new;
01326 isc_uint32_t newlen = stackcount + 16;
01327 size_t newsize, oldsize;
01328
01329 newsize = newlen * sizeof(*stack);
01330 oldsize = stackcount * sizeof(*stack);
01331 new = isc_mem_get(mctx, newsize);
01332 if (new == NULL)
01333 goto cleanup;
01334 if (stackcount != 0) {
01335 void *ptr;
01336
01337 DE_CONST(stack, ptr);
01338 memmove(new, stack, oldsize);
01339 isc_mem_put(mctx, ptr, oldsize);
01340 }
01341 stack = new;
01342 stackcount = newlen;
01343 }
01344 stack[pushed++] = cfg_list_next(element);
01345 goto newlist;
01346 }
01347 if (pushed != 0) {
01348 element = stack[--pushed];
01349 goto resume;
01350 }
01351 cleanup:
01352 if (stack != NULL) {
01353 void *ptr;
01354
01355 DE_CONST(stack, ptr);
01356 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
01357 }
01358 isc_symtab_destroy(&symtab);
01359 *countp = count;
01360 return (result);
01361 }
01362
01363 static isc_result_t
01364 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
01365 isc_result_t result = ISC_R_SUCCESS;
01366 isc_result_t tresult;
01367 const cfg_listelt_t *element;
01368 const cfg_listelt_t *element2;
01369 dns_fixedname_t fixed;
01370 const char *str;
01371 isc_buffer_t b;
01372
01373
01374 if (cfg_obj_isstring(policy) &&
01375 strcmp("local", cfg_obj_asstring(policy)) == 0)
01376 return (ISC_R_SUCCESS);
01377
01378
01379 for (element = cfg_list_first(policy);
01380 element != NULL;
01381 element = cfg_list_next(element))
01382 {
01383 const cfg_obj_t *stmt = cfg_listelt_value(element);
01384 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
01385 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
01386 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
01387 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
01388
01389 dns_fixedname_init(&fixed);
01390 str = cfg_obj_asstring(identity);
01391 isc_buffer_constinit(&b, str, strlen(str));
01392 isc_buffer_add(&b, strlen(str));
01393 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
01394 dns_rootname, 0, NULL);
01395 if (tresult != ISC_R_SUCCESS) {
01396 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
01397 "'%s' is not a valid name", str);
01398 result = tresult;
01399 }
01400
01401 if (tresult == ISC_R_SUCCESS &&
01402 strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) {
01403 dns_fixedname_init(&fixed);
01404 str = cfg_obj_asstring(dname);
01405 isc_buffer_constinit(&b, str, strlen(str));
01406 isc_buffer_add(&b, strlen(str));
01407 tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
01408 &b, dns_rootname, 0, NULL);
01409 if (tresult != ISC_R_SUCCESS) {
01410 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
01411 "'%s' is not a valid name", str);
01412 result = tresult;
01413 }
01414 }
01415
01416 if (tresult == ISC_R_SUCCESS &&
01417 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
01418 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
01419 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
01420 "'%s' is not a wildcard", str);
01421 result = ISC_R_FAILURE;
01422 }
01423
01424 for (element2 = cfg_list_first(typelist);
01425 element2 != NULL;
01426 element2 = cfg_list_next(element2))
01427 {
01428 const cfg_obj_t *typeobj;
01429 isc_textregion_t r;
01430 dns_rdatatype_t type;
01431
01432 typeobj = cfg_listelt_value(element2);
01433 DE_CONST(cfg_obj_asstring(typeobj), r.base);
01434 r.length = strlen(r.base);
01435
01436 tresult = dns_rdatatype_fromtext(&type, &r);
01437 if (tresult != ISC_R_SUCCESS) {
01438 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
01439 "'%s' is not a valid type", r.base);
01440 result = tresult;
01441 }
01442 }
01443 }
01444 return (result);
01445 }
01446
01447 #define MASTERZONE 1
01448 #define SLAVEZONE 2
01449 #define STUBZONE 4
01450 #define HINTZONE 8
01451 #define FORWARDZONE 16
01452 #define DELEGATIONZONE 32
01453 #define STATICSTUBZONE 64
01454 #define REDIRECTZONE 128
01455 #define STREDIRECTZONE 0
01456 #define CHECKACL 512
01457
01458 typedef struct {
01459 const char *name;
01460 int allowed;
01461 } optionstable;
01462
01463 static isc_result_t
01464 check_nonzero(const cfg_obj_t *options, isc_log_t *logctx) {
01465 isc_result_t result = ISC_R_SUCCESS;
01466 const cfg_obj_t *obj = NULL;
01467 unsigned int i;
01468
01469 static const char *nonzero[] = { "max-retry-time", "min-retry-time",
01470 "max-refresh-time", "min-refresh-time" };
01471
01472
01473
01474 for (i = 0; i < sizeof(nonzero) / sizeof(nonzero[0]); i++) {
01475 obj = NULL;
01476 if (cfg_map_get(options, nonzero[i], &obj) == ISC_R_SUCCESS &&
01477 cfg_obj_asuint32(obj) == 0) {
01478 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01479 "'%s' must not be zero", nonzero[i]);
01480 result = ISC_R_FAILURE;
01481 }
01482 }
01483 return (result);
01484 }
01485
01486 static isc_result_t
01487 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
01488 const cfg_obj_t *config, isc_symtab_t *symtab,
01489 isc_symtab_t *files, dns_rdataclass_t defclass,
01490 cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx)
01491 {
01492 const char *znamestr;
01493 const char *typestr;
01494 unsigned int ztype;
01495 const cfg_obj_t *zoptions, *goptions = NULL;
01496 const cfg_obj_t *obj = NULL;
01497 isc_result_t result = ISC_R_SUCCESS;
01498 isc_result_t tresult;
01499 unsigned int i;
01500 dns_rdataclass_t zclass;
01501 dns_fixedname_t fixedname;
01502 dns_name_t *zname = NULL;
01503 isc_buffer_t b;
01504 isc_boolean_t root = ISC_FALSE;
01505 const cfg_listelt_t *element;
01506 isc_boolean_t dlz;
01507 dns_masterformat_t masterformat;
01508 isc_boolean_t ddns = ISC_FALSE;
01509
01510 static optionstable options[] = {
01511 { "allow-notify", SLAVEZONE | CHECKACL },
01512 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE |
01513 CHECKACL | STATICSTUBZONE },
01514 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
01515 { "allow-update", MASTERZONE | CHECKACL },
01516 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
01517 { "also-notify", MASTERZONE | SLAVEZONE },
01518 { "auto-dnssec", MASTERZONE | SLAVEZONE },
01519 { "check-dup-records", MASTERZONE },
01520 { "check-mx", MASTERZONE },
01521 { "check-mx-cname", MASTERZONE },
01522 { "check-srv-cname", MASTERZONE },
01523 { "check-wildcard", MASTERZONE },
01524 { "database", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE },
01525 { "delegation-only", HINTZONE | STUBZONE | FORWARDZONE |
01526 DELEGATIONZONE },
01527 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE | STREDIRECTZONE },
01528 { "dnssec-dnskey-kskonly", MASTERZONE | SLAVEZONE },
01529 { "dnssec-loadkeys-interval", MASTERZONE | SLAVEZONE },
01530 { "dnssec-secure-to-insecure", MASTERZONE },
01531 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE | REDIRECTZONE },
01532 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | STATICSTUBZONE |
01533 FORWARDZONE },
01534 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | STATICSTUBZONE |
01535 FORWARDZONE },
01536 { "integrity-check", MASTERZONE },
01537 { "ixfr-base", MASTERZONE | SLAVEZONE },
01538 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
01539 { "journal", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
01540 { "key-directory", MASTERZONE | SLAVEZONE },
01541 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
01542 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE |
01543 REDIRECTZONE },
01544 { "masters", SLAVEZONE | STUBZONE | REDIRECTZONE },
01545 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
01546 { "max-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01547 { "max-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01548 { "max-transfer-idle-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01549 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
01550 { "max-transfer-time-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01551 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
01552 { "max-zone-ttl", MASTERZONE | REDIRECTZONE },
01553 { "min-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01554 { "min-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01555 { "notify", MASTERZONE | SLAVEZONE },
01556 { "notify-source", MASTERZONE | SLAVEZONE },
01557 { "notify-source-v6", MASTERZONE | SLAVEZONE },
01558 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
01559 { "request-expire", SLAVEZONE | REDIRECTZONE },
01560 { "request-ixfr", SLAVEZONE | REDIRECTZONE },
01561 { "server-addresses", STATICSTUBZONE },
01562 { "server-names", STATICSTUBZONE },
01563 { "sig-re-signing-interval", MASTERZONE | SLAVEZONE },
01564 { "sig-signing-nodes", MASTERZONE | SLAVEZONE },
01565 { "sig-signing-signatures", MASTERZONE | SLAVEZONE },
01566 { "sig-signing-type", MASTERZONE | SLAVEZONE },
01567 { "sig-validity-interval", MASTERZONE | SLAVEZONE },
01568 { "signing", MASTERZONE | SLAVEZONE },
01569 { "transfer-source", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01570 { "transfer-source-v6", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01571 { "try-tcp-refresh", SLAVEZONE | STREDIRECTZONE },
01572 { "update-check-ksk", MASTERZONE | SLAVEZONE },
01573 { "update-policy", MASTERZONE },
01574 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE |
01575 STATICSTUBZONE | REDIRECTZONE },
01576 };
01577
01578 static optionstable dialups[] = {
01579 { "notify", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
01580 { "notify-passive", SLAVEZONE | STREDIRECTZONE },
01581 { "passive", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01582 { "refresh", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01583 };
01584
01585 znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
01586
01587 zoptions = cfg_tuple_get(zconfig, "options");
01588
01589 if (config != NULL)
01590 cfg_map_get(config, "options", &goptions);
01591
01592 obj = NULL;
01593 (void)cfg_map_get(zoptions, "in-view", &obj);
01594 if (obj != NULL) {
01595 const cfg_obj_t *fwd = NULL;
01596 unsigned int maxopts = 1;
01597 (void)cfg_map_get(zoptions, "forward", &fwd);
01598 if (fwd != NULL)
01599 maxopts++;
01600 fwd = NULL;
01601 (void)cfg_map_get(zoptions, "forwarders", &fwd);
01602 if (fwd != NULL)
01603 maxopts++;
01604 if (cfg_map_count(zoptions) > maxopts) {
01605 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
01606 "zone '%s': 'in-view' used "
01607 "with incompatible zone options",
01608 znamestr);
01609 return (ISC_R_FAILURE);
01610 }
01611 return (ISC_R_SUCCESS);
01612 }
01613
01614 obj = NULL;
01615 (void)cfg_map_get(zoptions, "type", &obj);
01616 if (obj == NULL) {
01617 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
01618 "zone '%s': type not present", znamestr);
01619 return (ISC_R_FAILURE);
01620 }
01621
01622 typestr = cfg_obj_asstring(obj);
01623 if (strcasecmp(typestr, "master") == 0)
01624 ztype = MASTERZONE;
01625 else if (strcasecmp(typestr, "slave") == 0)
01626 ztype = SLAVEZONE;
01627 else if (strcasecmp(typestr, "stub") == 0)
01628 ztype = STUBZONE;
01629 else if (strcasecmp(typestr, "static-stub") == 0)
01630 ztype = STATICSTUBZONE;
01631 else if (strcasecmp(typestr, "forward") == 0)
01632 ztype = FORWARDZONE;
01633 else if (strcasecmp(typestr, "hint") == 0)
01634 ztype = HINTZONE;
01635 else if (strcasecmp(typestr, "delegation-only") == 0)
01636 ztype = DELEGATIONZONE;
01637 else if (strcasecmp(typestr, "redirect") == 0)
01638 ztype = REDIRECTZONE;
01639 else {
01640 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01641 "zone '%s': invalid type %s",
01642 znamestr, typestr);
01643 return (ISC_R_FAILURE);
01644 }
01645
01646 if (ztype == REDIRECTZONE && strcmp(znamestr, ".") != 0) {
01647 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
01648 "redirect zones must be called \".\"");
01649 return (ISC_R_FAILURE);
01650 }
01651 obj = cfg_tuple_get(zconfig, "class");
01652 if (cfg_obj_isstring(obj)) {
01653 isc_textregion_t r;
01654
01655 DE_CONST(cfg_obj_asstring(obj), r.base);
01656 r.length = strlen(r.base);
01657 result = dns_rdataclass_fromtext(&zclass, &r);
01658 if (result != ISC_R_SUCCESS) {
01659 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01660 "zone '%s': invalid class %s",
01661 znamestr, r.base);
01662 return (ISC_R_FAILURE);
01663 }
01664 if (zclass != defclass) {
01665 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01666 "zone '%s': class '%s' does not "
01667 "match view/default class",
01668 znamestr, r.base);
01669 return (ISC_R_FAILURE);
01670 }
01671 }
01672
01673
01674
01675
01676
01677
01678 dns_fixedname_init(&fixedname);
01679 isc_buffer_constinit(&b, znamestr, strlen(znamestr));
01680 isc_buffer_add(&b, strlen(znamestr));
01681 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
01682 dns_rootname, DNS_NAME_DOWNCASE, NULL);
01683 if (tresult != ISC_R_SUCCESS) {
01684 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
01685 "zone '%s': is not a valid name", znamestr);
01686 result = ISC_R_FAILURE;
01687 } else {
01688 char namebuf[DNS_NAME_FORMATSIZE];
01689
01690 zname = dns_fixedname_name(&fixedname);
01691 dns_name_format(zname, namebuf, sizeof(namebuf));
01692 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 :
01693 ztype == REDIRECTZONE ? 2 : 3,
01694 symtab, "zone '%s': already exists "
01695 "previous definition: %s:%u", logctx, mctx);
01696 if (tresult != ISC_R_SUCCESS)
01697 result = tresult;
01698 if (dns_name_equal(zname, dns_rootname))
01699 root = ISC_TRUE;
01700 }
01701
01702
01703
01704
01705 if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS)
01706 result = ISC_R_FAILURE;
01707
01708
01709
01710
01711
01712 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
01713 obj = NULL;
01714 if ((options[i].allowed & ztype) == 0 &&
01715 cfg_map_get(zoptions, options[i].name, &obj) ==
01716 ISC_R_SUCCESS)
01717 {
01718 if (strcmp(options[i].name, "allow-update") != 0 ||
01719 ztype != SLAVEZONE) {
01720 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01721 "option '%s' is not allowed "
01722 "in '%s' zone '%s'",
01723 options[i].name, typestr,
01724 znamestr);
01725 result = ISC_R_FAILURE;
01726 } else
01727 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
01728 "option '%s' is not allowed "
01729 "in '%s' zone '%s'",
01730 options[i].name, typestr,
01731 znamestr);
01732 }
01733 obj = NULL;
01734 if ((options[i].allowed & ztype) != 0 &&
01735 (options[i].allowed & CHECKACL) != 0) {
01736
01737 tresult = checkacl(options[i].name, actx, zconfig,
01738 voptions, config, logctx, mctx);
01739 if (tresult != ISC_R_SUCCESS)
01740 result = tresult;
01741 }
01742
01743 }
01744
01745
01746
01747
01748
01749 if (ztype == MASTERZONE || ztype == SLAVEZONE ) {
01750 isc_boolean_t donotify = ISC_TRUE;
01751
01752 obj = NULL;
01753 tresult = cfg_map_get(zoptions, "notify", &obj);
01754 if (tresult != ISC_R_SUCCESS && voptions != NULL)
01755 tresult = cfg_map_get(voptions, "notify", &obj);
01756 if (tresult != ISC_R_SUCCESS && goptions != NULL)
01757 tresult = cfg_map_get(goptions, "notify", &obj);
01758 if (tresult == ISC_R_SUCCESS) {
01759 if (cfg_obj_isboolean(obj))
01760 donotify = cfg_obj_asboolean(obj);
01761 else {
01762 const char *notifystr = cfg_obj_asstring(obj);
01763 if (ztype != MASTERZONE &&
01764 strcasecmp(notifystr, "master-only") == 0)
01765 donotify = ISC_FALSE;
01766 }
01767 }
01768
01769 obj = NULL;
01770 tresult = cfg_map_get(zoptions, "also-notify", &obj);
01771 if (tresult == ISC_R_SUCCESS && !donotify) {
01772 cfg_obj_log(zoptions, logctx, ISC_LOG_WARNING,
01773 "zone '%s': 'also-notify' set but "
01774 "'notify' is disabled", znamestr);
01775 } else if (tresult == ISC_R_SUCCESS) {
01776 isc_uint32_t count;
01777 tresult = validate_masters(obj, config, &count,
01778 logctx, mctx);
01779 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
01780 result = tresult;
01781 }
01782 }
01783
01784
01785
01786
01787 if (ztype == SLAVEZONE || ztype == STUBZONE) {
01788 obj = NULL;
01789 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
01790 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
01791 "zone '%s': missing 'masters' entry",
01792 znamestr);
01793 result = ISC_R_FAILURE;
01794 } else {
01795 isc_uint32_t count;
01796 tresult = validate_masters(obj, config, &count,
01797 logctx, mctx);
01798 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
01799 result = tresult;
01800 if (tresult == ISC_R_SUCCESS && count == 0) {
01801 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
01802 "zone '%s': empty 'masters' entry",
01803 znamestr);
01804 result = ISC_R_FAILURE;
01805 }
01806 }
01807 }
01808
01809
01810
01811
01812 if (ztype == MASTERZONE || ztype == SLAVEZONE) {
01813 isc_boolean_t signing = ISC_FALSE;
01814 isc_result_t res1, res2, res3;
01815 const cfg_obj_t *au = NULL;
01816 const char *arg;
01817
01818 obj = NULL;
01819 res1 = cfg_map_get(zoptions, "allow-update", &au);
01820 obj = NULL;
01821 res2 = cfg_map_get(zoptions, "update-policy", &obj);
01822 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
01823 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01824 "zone '%s': 'allow-update' is ignored "
01825 "when 'update-policy' is present",
01826 znamestr);
01827 result = ISC_R_FAILURE;
01828 } else if (res2 == ISC_R_SUCCESS) {
01829 res3 = check_update_policy(obj, logctx);
01830 if (res3 != ISC_R_SUCCESS)
01831 result = ISC_R_FAILURE;
01832 }
01833
01834
01835
01836
01837
01838
01839 if (res1 != ISC_R_SUCCESS && voptions != NULL)
01840 res1 = cfg_map_get(voptions, "allow-update", &au);
01841 if (res1 != ISC_R_SUCCESS && goptions != NULL)
01842 res1 = cfg_map_get(goptions, "allow-update", &au);
01843
01844 if (res2 == ISC_R_SUCCESS)
01845 ddns = ISC_TRUE;
01846 else if (res1 == ISC_R_SUCCESS) {
01847 dns_acl_t *acl = NULL;
01848 res1 = cfg_acl_fromconfig(au, config, logctx,
01849 actx, mctx, 0, &acl);
01850 if (res1 != ISC_R_SUCCESS) {
01851 cfg_obj_log(au, logctx, ISC_LOG_ERROR,
01852 "acl expansion failed: %s",
01853 isc_result_totext(result));
01854 result = ISC_R_FAILURE;
01855 } else if (acl != NULL) {
01856 if (!dns_acl_isnone(acl))
01857 ddns = ISC_TRUE;
01858 dns_acl_detach(&acl);
01859 }
01860 }
01861
01862 obj = NULL;
01863 res1 = cfg_map_get(zoptions, "inline-signing", &obj);
01864 if (res1 == ISC_R_SUCCESS)
01865 signing = cfg_obj_asboolean(obj);
01866
01867 obj = NULL;
01868 arg = "off";
01869 res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
01870 if (res3 == ISC_R_SUCCESS)
01871 arg = cfg_obj_asstring(obj);
01872 if (strcasecmp(arg, "off") != 0 && !ddns && !signing) {
01873 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01874 "'auto-dnssec %s;' requires%s "
01875 "inline-signing to be configured for "
01876 "the zone", arg,
01877 (ztype == MASTERZONE) ?
01878 " dynamic DNS or" : "");
01879 result = ISC_R_FAILURE;
01880 }
01881
01882 obj = NULL;
01883 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
01884 if (res1 == ISC_R_SUCCESS) {
01885 isc_uint32_t type = cfg_obj_asuint32(obj);
01886 if (type < 0xff00U || type > 0xffffU)
01887 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01888 "sig-signing-type: %u out of "
01889 "range [%u..%u]", type,
01890 0xff00U, 0xffffU);
01891 result = ISC_R_FAILURE;
01892 }
01893
01894 obj = NULL;
01895 res1 = cfg_map_get(zoptions, "dnssec-dnskey-kskonly", &obj);
01896 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
01897 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01898 "dnssec-dnskey-kskonly: requires "
01899 "inline-signing when used in slave zone");
01900 result = ISC_R_FAILURE;
01901 }
01902
01903 obj = NULL;
01904 res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj);
01905 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
01906 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01907 "dnssec-loadkeys-interval: requires "
01908 "inline-signing when used in slave zone");
01909 result = ISC_R_FAILURE;
01910 }
01911
01912 obj = NULL;
01913 res1 = cfg_map_get(zoptions, "update-check-ksk", &obj);
01914 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
01915 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01916 "update-check-ksk: requires "
01917 "inline-signing when used in slave zone");
01918 result = ISC_R_FAILURE;
01919 }
01920 }
01921
01922
01923
01924
01925 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
01926 const cfg_obj_t *dialup = NULL;
01927 (void)cfg_map_get(zoptions, "dialup", &dialup);
01928 if (dialup != NULL && cfg_obj_isstring(dialup)) {
01929 const char *str = cfg_obj_asstring(dialup);
01930 for (i = 0;
01931 i < sizeof(dialups) / sizeof(dialups[0]);
01932 i++)
01933 {
01934 if (strcasecmp(dialups[i].name, str) != 0)
01935 continue;
01936 if ((dialups[i].allowed & ztype) == 0) {
01937 cfg_obj_log(obj, logctx,
01938 ISC_LOG_ERROR,
01939 "dialup type '%s' is not "
01940 "allowed in '%s' "
01941 "zone '%s'",
01942 str, typestr, znamestr);
01943 result = ISC_R_FAILURE;
01944 }
01945 break;
01946 }
01947 if (i == sizeof(dialups) / sizeof(dialups[0])) {
01948 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01949 "invalid dialup type '%s' in zone "
01950 "'%s'", str, znamestr);
01951 result = ISC_R_FAILURE;
01952 }
01953 }
01954 }
01955
01956
01957
01958
01959 obj = NULL;
01960 if (root) {
01961 if (voptions != NULL)
01962 (void)cfg_map_get(voptions, "forwarders", &obj);
01963 if (obj == NULL && goptions != NULL)
01964 (void)cfg_map_get(goptions, "forwarders", &obj);
01965 }
01966 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
01967 result = ISC_R_FAILURE;
01968
01969
01970
01971
01972 obj = NULL;
01973 (void)cfg_map_get(zoptions, "server-addresses", &obj);
01974 if (ztype == STATICSTUBZONE && obj != NULL) {
01975 for (element = cfg_list_first(obj);
01976 element != NULL;
01977 element = cfg_list_next(element))
01978 {
01979 isc_sockaddr_t sa;
01980 isc_netaddr_t na;
01981 obj = cfg_listelt_value(element);
01982 sa = *cfg_obj_assockaddr(obj);
01983
01984 if (isc_sockaddr_getport(&sa) != 0) {
01985 result = ISC_R_FAILURE;
01986 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01987 "port is not configurable for "
01988 "static stub server-addresses");
01989 }
01990
01991 isc_netaddr_fromsockaddr(&na, &sa);
01992 if (isc_netaddr_getzone(&na) != 0) {
01993 result = ISC_R_FAILURE;
01994 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01995 "scoped address is not allowed "
01996 "for static stub "
01997 "server-addresses");
01998 }
01999 }
02000 }
02001
02002
02003
02004
02005 obj = NULL;
02006 (void)cfg_map_get(zoptions, "server-names", &obj);
02007 if (zname != NULL && ztype == STATICSTUBZONE && obj != NULL) {
02008 for (element = cfg_list_first(obj);
02009 element != NULL;
02010 element = cfg_list_next(element))
02011 {
02012 const char *snamestr;
02013 dns_fixedname_t fixed_sname;
02014 isc_buffer_t b2;
02015 dns_name_t *sname;
02016
02017 obj = cfg_listelt_value(element);
02018 snamestr = cfg_obj_asstring(obj);
02019
02020 dns_fixedname_init(&fixed_sname);
02021 isc_buffer_constinit(&b2, snamestr, strlen(snamestr));
02022 isc_buffer_add(&b2, strlen(snamestr));
02023 sname = dns_fixedname_name(&fixed_sname);
02024 tresult = dns_name_fromtext(sname, &b2, dns_rootname,
02025 0, NULL);
02026 if (tresult != ISC_R_SUCCESS) {
02027 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
02028 "server-name '%s' is not a valid "
02029 "name", snamestr);
02030 result = ISC_R_FAILURE;
02031 } else if (dns_name_issubdomain(sname, zname)) {
02032 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
02033 "server-name '%s' must not be a "
02034 "subdomain of zone name '%s'",
02035 snamestr, znamestr);
02036 result = ISC_R_FAILURE;
02037 }
02038 }
02039 }
02040
02041
02042
02043
02044
02045 masterformat = dns_masterformat_text;
02046 obj = NULL;
02047 (void)cfg_map_get(zoptions, "masterfile-format", &obj);
02048 if (obj != NULL) {
02049 const char *masterformatstr = cfg_obj_asstring(obj);
02050 if (strcasecmp(masterformatstr, "text") == 0)
02051 masterformat = dns_masterformat_text;
02052 else if (strcasecmp(masterformatstr, "raw") == 0)
02053 masterformat = dns_masterformat_raw;
02054 else if (strcasecmp(masterformatstr, "map") == 0)
02055 masterformat = dns_masterformat_map;
02056 else
02057 INSIST(0);
02058 }
02059
02060 if (masterformat == dns_masterformat_map) {
02061 obj = NULL;
02062 (void)cfg_map_get(zoptions, "max-zone-ttl", &obj);
02063 if (obj == NULL && voptions != NULL)
02064 (void)cfg_map_get(voptions, "max-zone-ttl", &obj);
02065 if (obj == NULL && goptions !=NULL)
02066 (void)cfg_map_get(goptions, "max-zone-ttl", &obj);
02067 if (obj != NULL) {
02068 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
02069 "zone '%s': 'max-zone-ttl' is not "
02070 "compatible with 'masterfile-format map'",
02071 znamestr);
02072 result = ISC_R_FAILURE;
02073 }
02074 }
02075
02076
02077
02078
02079 obj = NULL;
02080 tresult = cfg_map_get(zoptions, "key-directory", &obj);
02081 if (tresult == ISC_R_SUCCESS) {
02082 const char *dir = cfg_obj_asstring(obj);
02083 tresult = isc_file_isdirectory(dir);
02084 switch (tresult) {
02085 case ISC_R_SUCCESS:
02086 break;
02087 case ISC_R_FILENOTFOUND:
02088 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
02089 "key-directory: '%s' does not exist",
02090 dir);
02091 break;
02092 case ISC_R_INVALIDFILE:
02093 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
02094 "key-directory: '%s' is not a directory",
02095 dir);
02096 break;
02097 default:
02098 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
02099 "key-directory: '%s' %s",
02100 dir, isc_result_totext(tresult));
02101 result = tresult;
02102 }
02103 }
02104
02105
02106
02107
02108 tresult = check_options(zoptions, logctx, mctx, optlevel_zone);
02109 if (tresult != ISC_R_SUCCESS)
02110 result = tresult;
02111
02112
02113
02114
02115
02116
02117
02118 obj = NULL;
02119 dlz = ISC_FALSE;
02120 tresult = cfg_map_get(zoptions, "dlz", &obj);
02121 if (tresult == ISC_R_SUCCESS)
02122 dlz = ISC_TRUE;
02123
02124 obj = NULL;
02125 tresult = cfg_map_get(zoptions, "database", &obj);
02126 if (dlz && tresult == ISC_R_SUCCESS) {
02127 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
02128 "zone '%s': cannot specify both 'dlz' "
02129 "and 'database'", znamestr);
02130 result = ISC_R_FAILURE;
02131 } else if (!dlz &&
02132 (tresult == ISC_R_NOTFOUND ||
02133 (tresult == ISC_R_SUCCESS &&
02134 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
02135 strcmp("rbt64", cfg_obj_asstring(obj)) == 0))))
02136 {
02137 isc_result_t res1;
02138 const cfg_obj_t *fileobj = NULL;
02139 tresult = cfg_map_get(zoptions, "file", &fileobj);
02140 obj = NULL;
02141 res1 = cfg_map_get(zoptions, "inline-signing", &obj);
02142 if ((tresult != ISC_R_SUCCESS &&
02143 (ztype == MASTERZONE || ztype == HINTZONE ||
02144 (ztype == SLAVEZONE && res1 == ISC_R_SUCCESS &&
02145 cfg_obj_asboolean(obj))))) {
02146 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
02147 "zone '%s': missing 'file' entry",
02148 znamestr);
02149 result = tresult;
02150 } else if (tresult == ISC_R_SUCCESS &&
02151 (ztype == SLAVEZONE || ddns)) {
02152 tresult = fileexist(fileobj, files, ISC_TRUE, logctx);
02153 if (tresult != ISC_R_SUCCESS)
02154 result = tresult;
02155 } else if (tresult == ISC_R_SUCCESS &&
02156 (ztype == MASTERZONE || ztype == HINTZONE)) {
02157 tresult = fileexist(fileobj, files, ISC_FALSE, logctx);
02158 if (tresult != ISC_R_SUCCESS)
02159 result = tresult;
02160 }
02161 }
02162
02163 return (result);
02164 }
02165
02166
02167 typedef struct keyalgorithms {
02168 const char *name;
02169 isc_uint16_t size;
02170 } algorithmtable;
02171
02172 isc_result_t
02173 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
02174 const cfg_obj_t *algobj = NULL;
02175 const cfg_obj_t *secretobj = NULL;
02176 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
02177 const char *algorithm;
02178 int i;
02179 size_t len = 0;
02180 isc_result_t result;
02181 isc_buffer_t buf;
02182 unsigned char secretbuf[1024];
02183 static const algorithmtable algorithms[] = {
02184 { "hmac-md5", 128 },
02185 { "hmac-md5.sig-alg.reg.int", 0 },
02186 { "hmac-md5.sig-alg.reg.int.", 0 },
02187 { "hmac-sha1", 160 },
02188 { "hmac-sha224", 224 },
02189 { "hmac-sha256", 256 },
02190 { "hmac-sha384", 384 },
02191 { "hmac-sha512", 512 },
02192 { NULL, 0 }
02193 };
02194
02195 (void)cfg_map_get(key, "algorithm", &algobj);
02196 (void)cfg_map_get(key, "secret", &secretobj);
02197 if (secretobj == NULL || algobj == NULL) {
02198 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
02199 "key '%s' must have both 'secret' and "
02200 "'algorithm' defined",
02201 keyname);
02202 return (ISC_R_FAILURE);
02203 }
02204
02205 isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
02206 result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
02207 if (result != ISC_R_SUCCESS) {
02208 cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
02209 "bad secret '%s'", isc_result_totext(result));
02210 return (result);
02211 }
02212
02213 algorithm = cfg_obj_asstring(algobj);
02214 for (i = 0; algorithms[i].name != NULL; i++) {
02215 len = strlen(algorithms[i].name);
02216 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
02217 (algorithm[len] == '\0' ||
02218 (algorithms[i].size != 0 && algorithm[len] == '-')))
02219 break;
02220 }
02221 if (algorithms[i].name == NULL) {
02222 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
02223 "unknown algorithm '%s'", algorithm);
02224 return (ISC_R_NOTFOUND);
02225 }
02226 if (algorithm[len] == '-') {
02227 isc_uint16_t digestbits;
02228 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
02229 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
02230 if (result == ISC_R_RANGE ||
02231 digestbits > algorithms[i].size) {
02232 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
02233 "key '%s' digest-bits too large "
02234 "[%u..%u]", keyname,
02235 algorithms[i].size / 2,
02236 algorithms[i].size);
02237 return (ISC_R_RANGE);
02238 }
02239 if ((digestbits % 8) != 0) {
02240 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
02241 "key '%s' digest-bits not multiple"
02242 " of 8", keyname);
02243 return (ISC_R_RANGE);
02244 }
02245
02246
02247
02248 if ((digestbits < (algorithms[i].size / 2U) ||
02249 (digestbits < 80U)))
02250 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
02251 "key '%s' digest-bits too small "
02252 "[<%u]", keyname,
02253 algorithms[i].size/2);
02254 } else {
02255 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
02256 "key '%s': unable to parse digest-bits",
02257 keyname);
02258 return (result);
02259 }
02260 }
02261 return (ISC_R_SUCCESS);
02262 }
02263
02264 static isc_result_t
02265 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, isc_boolean_t writeable,
02266 isc_log_t *logctx)
02267 {
02268 isc_result_t result;
02269 isc_symvalue_t symvalue;
02270 unsigned int line;
02271 const char *file;
02272
02273 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 0, &symvalue);
02274 if (result == ISC_R_SUCCESS) {
02275 if (writeable) {
02276 file = cfg_obj_file(symvalue.as_cpointer);
02277 line = cfg_obj_line(symvalue.as_cpointer);
02278 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
02279 "writeable file '%s': already in use: "
02280 "%s:%u", cfg_obj_asstring(obj),
02281 file, line);
02282 return (ISC_R_EXISTS);
02283 }
02284 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 2,
02285 &symvalue);
02286 if (result == ISC_R_SUCCESS) {
02287 file = cfg_obj_file(symvalue.as_cpointer);
02288 line = cfg_obj_line(symvalue.as_cpointer);
02289 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
02290 "writeable file '%s': already in use: "
02291 "%s:%u", cfg_obj_asstring(obj),
02292 file, line);
02293 return (ISC_R_EXISTS);
02294 }
02295 return (ISC_R_SUCCESS);
02296 }
02297
02298 symvalue.as_cpointer = obj;
02299 result = isc_symtab_define(symtab, cfg_obj_asstring(obj),
02300 writeable ? 2 : 1, symvalue,
02301 isc_symexists_reject);
02302 return (result);
02303 }
02304
02305
02306
02307
02308
02309
02310
02311 static isc_result_t
02312 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
02313 isc_mem_t *mctx, isc_log_t *logctx)
02314 {
02315 char namebuf[DNS_NAME_FORMATSIZE];
02316 dns_fixedname_t fname;
02317 dns_name_t *name;
02318 isc_result_t result = ISC_R_SUCCESS;
02319 isc_result_t tresult;
02320 const cfg_listelt_t *element;
02321
02322 dns_fixedname_init(&fname);
02323 name = dns_fixedname_name(&fname);
02324 for (element = cfg_list_first(keys);
02325 element != NULL;
02326 element = cfg_list_next(element))
02327 {
02328 const cfg_obj_t *key = cfg_listelt_value(element);
02329 const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
02330 isc_symvalue_t symvalue;
02331 isc_buffer_t b;
02332 char *keyname;
02333
02334 isc_buffer_constinit(&b, keyid, strlen(keyid));
02335 isc_buffer_add(&b, strlen(keyid));
02336 tresult = dns_name_fromtext(name, &b, dns_rootname,
02337 0, NULL);
02338 if (tresult != ISC_R_SUCCESS) {
02339 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
02340 "key '%s': bad key name", keyid);
02341 result = tresult;
02342 continue;
02343 }
02344 tresult = bind9_check_key(key, logctx);
02345 if (tresult != ISC_R_SUCCESS)
02346 return (tresult);
02347
02348 dns_name_format(name, namebuf, sizeof(namebuf));
02349 keyname = isc_mem_strdup(mctx, namebuf);
02350 if (keyname == NULL)
02351 return (ISC_R_NOMEMORY);
02352 symvalue.as_cpointer = key;
02353 tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
02354 isc_symexists_reject);
02355 if (tresult == ISC_R_EXISTS) {
02356 const char *file;
02357 unsigned int line;
02358
02359 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
02360 1, &symvalue) == ISC_R_SUCCESS);
02361 file = cfg_obj_file(symvalue.as_cpointer);
02362 line = cfg_obj_line(symvalue.as_cpointer);
02363
02364 if (file == NULL)
02365 file = "<unknown file>";
02366 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
02367 "key '%s': already exists "
02368 "previous definition: %s:%u",
02369 keyid, file, line);
02370 isc_mem_free(mctx, keyname);
02371 result = tresult;
02372 } else if (tresult != ISC_R_SUCCESS) {
02373 isc_mem_free(mctx, keyname);
02374 return (tresult);
02375 }
02376 }
02377 return (result);
02378 }
02379
02380 static struct {
02381 const char *v4;
02382 const char *v6;
02383 } sources[] = {
02384 { "transfer-source", "transfer-source-v6" },
02385 { "notify-source", "notify-source-v6" },
02386 { "query-source", "query-source-v6" },
02387 { NULL, NULL }
02388 };
02389
02390
02391
02392
02393
02394
02395 static isc_boolean_t
02396 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
02397 const cfg_listelt_t *element;
02398 const cfg_obj_t *obj;
02399 const char *str;
02400
02401 if (keylist == NULL)
02402 return (ISC_FALSE);
02403
02404 for (element = cfg_list_first(keylist);
02405 element != NULL;
02406 element = cfg_list_next(element))
02407 {
02408 obj = cfg_listelt_value(element);
02409 str = cfg_obj_asstring(cfg_map_getname(obj));
02410 if (!strcasecmp(str, keyname))
02411 return (ISC_TRUE);
02412 }
02413 return (ISC_FALSE);
02414 }
02415
02416 static isc_result_t
02417 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
02418 isc_symtab_t *symtab, isc_log_t *logctx)
02419 {
02420 dns_fixedname_t fname;
02421 isc_result_t result = ISC_R_SUCCESS;
02422 isc_result_t tresult;
02423 const cfg_listelt_t *e1, *e2;
02424 const cfg_obj_t *v1, *v2, *keys;
02425 const cfg_obj_t *servers;
02426 isc_netaddr_t n1, n2;
02427 unsigned int p1, p2;
02428 const cfg_obj_t *obj;
02429 char buf[ISC_NETADDR_FORMATSIZE];
02430 char namebuf[DNS_NAME_FORMATSIZE];
02431 const char *xfr;
02432 const char *keyval;
02433 isc_buffer_t b;
02434 int source;
02435 dns_name_t *keyname;
02436
02437 servers = NULL;
02438 if (voptions != NULL)
02439 (void)cfg_map_get(voptions, "server", &servers);
02440 if (servers == NULL)
02441 (void)cfg_map_get(config, "server", &servers);
02442 if (servers == NULL)
02443 return (ISC_R_SUCCESS);
02444
02445 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
02446 v1 = cfg_listelt_value(e1);
02447 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
02448
02449
02450
02451 tresult = isc_netaddr_prefixok(&n1, p1);
02452 if (tresult != ISC_R_SUCCESS) {
02453 INSIST(tresult == ISC_R_FAILURE);
02454 isc_netaddr_format(&n1, buf, sizeof(buf));
02455 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
02456 "server '%s/%u': invalid prefix "
02457 "(extra bits specified)", buf, p1);
02458 result = tresult;
02459 }
02460 source = 0;
02461 do {
02462 obj = NULL;
02463 if (n1.family == AF_INET)
02464 xfr = sources[source].v6;
02465 else
02466 xfr = sources[source].v4;
02467 (void)cfg_map_get(v1, xfr, &obj);
02468 if (obj != NULL) {
02469 isc_netaddr_format(&n1, buf, sizeof(buf));
02470 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
02471 "server '%s/%u': %s not legal",
02472 buf, p1, xfr);
02473 result = ISC_R_FAILURE;
02474 }
02475 } while (sources[++source].v4 != NULL);
02476 e2 = e1;
02477 while ((e2 = cfg_list_next(e2)) != NULL) {
02478 v2 = cfg_listelt_value(e2);
02479 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
02480 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
02481 const char *file = cfg_obj_file(v1);
02482 unsigned int line = cfg_obj_line(v1);
02483
02484 if (file == NULL)
02485 file = "<unknown file>";
02486
02487 isc_netaddr_format(&n2, buf, sizeof(buf));
02488 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
02489 "server '%s/%u': already exists "
02490 "previous definition: %s:%u",
02491 buf, p2, file, line);
02492 result = ISC_R_FAILURE;
02493 }
02494 }
02495 keys = NULL;
02496 cfg_map_get(v1, "keys", &keys);
02497 if (keys != NULL) {
02498
02499
02500
02501 keyval = cfg_obj_asstring(keys);
02502 dns_fixedname_init(&fname);
02503 isc_buffer_constinit(&b, keyval, strlen(keyval));
02504 isc_buffer_add(&b, strlen(keyval));
02505 keyname = dns_fixedname_name(&fname);
02506 tresult = dns_name_fromtext(keyname, &b, dns_rootname,
02507 0, NULL);
02508 if (tresult != ISC_R_SUCCESS) {
02509 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
02510 "bad key name '%s'", keyval);
02511 result = ISC_R_FAILURE;
02512 continue;
02513 }
02514 dns_name_format(keyname, namebuf, sizeof(namebuf));
02515 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
02516 if (tresult != ISC_R_SUCCESS) {
02517 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
02518 "unknown key '%s'", keyval);
02519 result = ISC_R_FAILURE;
02520 }
02521 }
02522 }
02523 return (result);
02524 }
02525
02526 static isc_result_t
02527 check_trusted_key(const cfg_obj_t *key, isc_boolean_t managed,
02528 isc_log_t *logctx)
02529 {
02530 const char *keystr, *keynamestr;
02531 dns_fixedname_t fkeyname;
02532 dns_name_t *keyname;
02533 isc_buffer_t b;
02534 isc_region_t r;
02535 isc_result_t result = ISC_R_SUCCESS;
02536 isc_result_t tresult;
02537 isc_uint32_t flags, proto, alg;
02538 unsigned char keydata[4096];
02539
02540 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
02541 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
02542 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
02543
02544 dns_fixedname_init(&fkeyname);
02545 keyname = dns_fixedname_name(&fkeyname);
02546 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
02547
02548 isc_buffer_constinit(&b, keynamestr, strlen(keynamestr));
02549 isc_buffer_add(&b, strlen(keynamestr));
02550 result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
02551 if (result != ISC_R_SUCCESS) {
02552 cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n",
02553 isc_result_totext(result));
02554 result = ISC_R_FAILURE;
02555 }
02556
02557 if (flags > 0xffff) {
02558 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
02559 "flags too big: %u\n", flags);
02560 result = ISC_R_FAILURE;
02561 }
02562 if (proto > 0xff) {
02563 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
02564 "protocol too big: %u\n", proto);
02565 result = ISC_R_FAILURE;
02566 }
02567 if (alg > 0xff) {
02568 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
02569 "algorithm too big: %u\n", alg);
02570 result = ISC_R_FAILURE;
02571 }
02572
02573 if (managed) {
02574 const char *initmethod;
02575 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
02576
02577 if (strcasecmp(initmethod, "initial-key") != 0) {
02578 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
02579 "managed key '%s': "
02580 "invalid initialization method '%s'",
02581 keynamestr, initmethod);
02582 result = ISC_R_FAILURE;
02583 }
02584 }
02585
02586 isc_buffer_init(&b, keydata, sizeof(keydata));
02587
02588 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
02589 tresult = isc_base64_decodestring(keystr, &b);
02590
02591 if (tresult != ISC_R_SUCCESS) {
02592 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
02593 "%s", isc_result_totext(tresult));
02594 result = ISC_R_FAILURE;
02595 } else {
02596 isc_buffer_usedregion(&b, &r);
02597
02598 if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
02599 r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
02600 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
02601 "%s key '%s' has a weak exponent",
02602 managed ? "managed" : "trusted",
02603 keynamestr);
02604 }
02605
02606 return (result);
02607 }
02608
02609 static isc_result_t
02610 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
02611 const char *viewname, dns_rdataclass_t vclass,
02612 isc_symtab_t *files, isc_log_t *logctx, isc_mem_t *mctx)
02613 {
02614 const cfg_obj_t *zones = NULL;
02615 const cfg_obj_t *keys = NULL;
02616 const cfg_listelt_t *element, *element2;
02617 isc_symtab_t *symtab = NULL;
02618 isc_result_t result = ISC_R_SUCCESS;
02619 isc_result_t tresult = ISC_R_SUCCESS;
02620 cfg_aclconfctx_t *actx = NULL;
02621 const cfg_obj_t *obj;
02622 const cfg_obj_t *options = NULL;
02623 isc_boolean_t enablednssec, enablevalidation;
02624 const char *valstr = "no";
02625
02626
02627
02628
02629 (void)cfg_map_get(config, "options", &options);
02630
02631
02632
02633
02634
02635 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
02636 ISC_FALSE, &symtab);
02637 if (tresult != ISC_R_SUCCESS)
02638 return (ISC_R_NOMEMORY);
02639
02640 cfg_aclconfctx_create(mctx, &actx);
02641
02642 if (voptions != NULL)
02643 (void)cfg_map_get(voptions, "zone", &zones);
02644 else
02645 (void)cfg_map_get(config, "zone", &zones);
02646
02647 for (element = cfg_list_first(zones);
02648 element != NULL;
02649 element = cfg_list_next(element))
02650 {
02651 const cfg_obj_t *zone = cfg_listelt_value(element);
02652
02653 tresult = check_zoneconf(zone, voptions, config, symtab,
02654 files, vclass, actx, logctx,
02655 mctx);
02656 if (tresult != ISC_R_SUCCESS)
02657 result = ISC_R_FAILURE;
02658 }
02659
02660 isc_symtab_destroy(&symtab);
02661
02662
02663
02664
02665 if (voptions == NULL) {
02666 if (options != NULL)
02667 if (check_forward(options, NULL,
02668 logctx) != ISC_R_SUCCESS)
02669 result = ISC_R_FAILURE;
02670 } else {
02671 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
02672 result = ISC_R_FAILURE;
02673 }
02674
02675
02676
02677
02678 if (options != NULL && check_nonzero(options, logctx) != ISC_R_SUCCESS)
02679 result = ISC_R_FAILURE;
02680 if (voptions != NULL &&check_nonzero(voptions, logctx) != ISC_R_SUCCESS)
02681 result = ISC_R_FAILURE;
02682
02683
02684
02685
02686 if (voptions == NULL) {
02687 if (options != NULL)
02688 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
02689 result = ISC_R_FAILURE;
02690 } else {
02691 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
02692 result = ISC_R_FAILURE;
02693 }
02694
02695
02696
02697
02698 if (voptions != NULL) {
02699 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
02700 result = ISC_R_FAILURE;
02701 }
02702
02703
02704
02705
02706
02707 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
02708 ISC_FALSE, &symtab);
02709 if (tresult != ISC_R_SUCCESS)
02710 goto cleanup;
02711
02712 (void)cfg_map_get(config, "key", &keys);
02713 tresult = check_keylist(keys, symtab, mctx, logctx);
02714 if (tresult == ISC_R_EXISTS)
02715 result = ISC_R_FAILURE;
02716 else if (tresult != ISC_R_SUCCESS) {
02717 result = tresult;
02718 goto cleanup;
02719 }
02720
02721 if (voptions != NULL) {
02722 keys = NULL;
02723 (void)cfg_map_get(voptions, "key", &keys);
02724 tresult = check_keylist(keys, symtab, mctx, logctx);
02725 if (tresult == ISC_R_EXISTS)
02726 result = ISC_R_FAILURE;
02727 else if (tresult != ISC_R_SUCCESS) {
02728 result = tresult;
02729 goto cleanup;
02730 }
02731 }
02732
02733
02734
02735
02736 if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
02737 result = ISC_R_FAILURE;
02738
02739 isc_symtab_destroy(&symtab);
02740
02741
02742
02743
02744 obj = NULL;
02745 if (voptions != NULL)
02746 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
02747 if (obj == NULL && options != NULL)
02748 (void)cfg_map_get(options, "dnssec-enable", &obj);
02749 if (obj == NULL)
02750 enablednssec = ISC_TRUE;
02751 else
02752 enablednssec = cfg_obj_asboolean(obj);
02753
02754 obj = NULL;
02755 if (voptions != NULL)
02756 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
02757 if (obj == NULL && options != NULL)
02758 (void)cfg_map_get(options, "dnssec-validation", &obj);
02759 if (obj == NULL) {
02760 enablevalidation = enablednssec;
02761 valstr = "yes";
02762 } else if (cfg_obj_isboolean(obj)) {
02763 enablevalidation = cfg_obj_asboolean(obj);
02764 valstr = enablevalidation ? "yes" : "no";
02765 } else {
02766 enablevalidation = ISC_TRUE;
02767 valstr = "auto";
02768 }
02769
02770 if (enablevalidation && !enablednssec)
02771 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
02772 "'dnssec-validation %s;' and 'dnssec-enable no;'",
02773 valstr);
02774
02775
02776
02777
02778 keys = NULL;
02779 if (voptions != NULL)
02780 (void)cfg_map_get(voptions, "trusted-keys", &keys);
02781 if (keys == NULL)
02782 (void)cfg_map_get(config, "trusted-keys", &keys);
02783
02784 for (element = cfg_list_first(keys);
02785 element != NULL;
02786 element = cfg_list_next(element))
02787 {
02788 const cfg_obj_t *keylist = cfg_listelt_value(element);
02789 for (element2 = cfg_list_first(keylist);
02790 element2 != NULL;
02791 element2 = cfg_list_next(element2)) {
02792 obj = cfg_listelt_value(element2);
02793 tresult = check_trusted_key(obj, ISC_FALSE, logctx);
02794 if (tresult != ISC_R_SUCCESS)
02795 result = tresult;
02796 }
02797 }
02798
02799 keys = NULL;
02800 if (voptions != NULL)
02801 (void)cfg_map_get(voptions, "managed-keys", &keys);
02802 if (keys == NULL)
02803 (void)cfg_map_get(config, "managed-keys", &keys);
02804
02805 for (element = cfg_list_first(keys);
02806 element != NULL;
02807 element = cfg_list_next(element))
02808 {
02809 const cfg_obj_t *keylist = cfg_listelt_value(element);
02810 for (element2 = cfg_list_first(keylist);
02811 element2 != NULL;
02812 element2 = cfg_list_next(element2)) {
02813 obj = cfg_listelt_value(element2);
02814 tresult = check_trusted_key(obj, ISC_TRUE, logctx);
02815 if (tresult != ISC_R_SUCCESS)
02816 result = tresult;
02817 }
02818 }
02819
02820
02821
02822
02823 if (voptions != NULL)
02824 tresult = check_options(voptions, logctx, mctx,
02825 optlevel_view);
02826 else
02827 tresult = check_options(config, logctx, mctx,
02828 optlevel_config);
02829 if (tresult != ISC_R_SUCCESS)
02830 result = tresult;
02831
02832 tresult = check_viewacls(actx, voptions, config, logctx, mctx);
02833 if (tresult != ISC_R_SUCCESS)
02834 result = tresult;
02835
02836 tresult = check_recursionacls(actx, voptions, viewname,
02837 config, logctx, mctx);
02838 if (tresult != ISC_R_SUCCESS)
02839 result = tresult;
02840
02841 tresult = check_filteraaaa(actx, voptions, viewname, config,
02842 logctx, mctx);
02843 if (tresult != ISC_R_SUCCESS)
02844 result = tresult;
02845
02846 tresult = check_dns64(actx, voptions, config, logctx, mctx);
02847 if (tresult != ISC_R_SUCCESS)
02848 result = tresult;
02849
02850 cleanup:
02851 if (symtab != NULL)
02852 isc_symtab_destroy(&symtab);
02853 if (actx != NULL)
02854 cfg_aclconfctx_detach(&actx);
02855
02856 return (result);
02857 }
02858
02859 static const char *
02860 default_channels[] = {
02861 "default_syslog",
02862 "default_stderr",
02863 "default_debug",
02864 "null",
02865 NULL
02866 };
02867
02868 static isc_result_t
02869 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
02870 isc_mem_t *mctx)
02871 {
02872 const cfg_obj_t *categories = NULL;
02873 const cfg_obj_t *category;
02874 const cfg_obj_t *channels = NULL;
02875 const cfg_obj_t *channel;
02876 const cfg_listelt_t *element;
02877 const cfg_listelt_t *delement;
02878 const char *channelname;
02879 const char *catname;
02880 const cfg_obj_t *fileobj = NULL;
02881 const cfg_obj_t *syslogobj = NULL;
02882 const cfg_obj_t *nullobj = NULL;
02883 const cfg_obj_t *stderrobj = NULL;
02884 const cfg_obj_t *logobj = NULL;
02885 isc_result_t result = ISC_R_SUCCESS;
02886 isc_result_t tresult;
02887 isc_symtab_t *symtab = NULL;
02888 isc_symvalue_t symvalue;
02889 int i;
02890
02891 (void)cfg_map_get(config, "logging", &logobj);
02892 if (logobj == NULL)
02893 return (ISC_R_SUCCESS);
02894
02895 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
02896 if (result != ISC_R_SUCCESS)
02897 return (result);
02898
02899 symvalue.as_cpointer = NULL;
02900 for (i = 0; default_channels[i] != NULL; i++) {
02901 tresult = isc_symtab_define(symtab, default_channels[i], 1,
02902 symvalue, isc_symexists_replace);
02903 if (tresult != ISC_R_SUCCESS)
02904 result = tresult;
02905 }
02906
02907 cfg_map_get(logobj, "channel", &channels);
02908
02909 for (element = cfg_list_first(channels);
02910 element != NULL;
02911 element = cfg_list_next(element))
02912 {
02913 channel = cfg_listelt_value(element);
02914 channelname = cfg_obj_asstring(cfg_map_getname(channel));
02915 fileobj = syslogobj = nullobj = stderrobj = NULL;
02916 (void)cfg_map_get(channel, "file", &fileobj);
02917 (void)cfg_map_get(channel, "syslog", &syslogobj);
02918 (void)cfg_map_get(channel, "null", &nullobj);
02919 (void)cfg_map_get(channel, "stderr", &stderrobj);
02920 i = 0;
02921 if (fileobj != NULL)
02922 i++;
02923 if (syslogobj != NULL)
02924 i++;
02925 if (nullobj != NULL)
02926 i++;
02927 if (stderrobj != NULL)
02928 i++;
02929 if (i != 1) {
02930 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
02931 "channel '%s': exactly one of file, syslog, "
02932 "null, and stderr must be present",
02933 channelname);
02934 result = ISC_R_FAILURE;
02935 }
02936 tresult = isc_symtab_define(symtab, channelname, 1,
02937 symvalue, isc_symexists_replace);
02938 if (tresult != ISC_R_SUCCESS)
02939 result = tresult;
02940 }
02941
02942 cfg_map_get(logobj, "category", &categories);
02943
02944 for (element = cfg_list_first(categories);
02945 element != NULL;
02946 element = cfg_list_next(element))
02947 {
02948 category = cfg_listelt_value(element);
02949 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
02950 if (isc_log_categorybyname(logctx, catname) == NULL) {
02951 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
02952 "undefined category: '%s'", catname);
02953 result = ISC_R_FAILURE;
02954 }
02955 channels = cfg_tuple_get(category, "destinations");
02956 for (delement = cfg_list_first(channels);
02957 delement != NULL;
02958 delement = cfg_list_next(delement))
02959 {
02960 channel = cfg_listelt_value(delement);
02961 channelname = cfg_obj_asstring(channel);
02962 tresult = isc_symtab_lookup(symtab, channelname, 1,
02963 &symvalue);
02964 if (tresult != ISC_R_SUCCESS) {
02965 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
02966 "undefined channel: '%s'",
02967 channelname);
02968 result = tresult;
02969 }
02970 }
02971 }
02972 isc_symtab_destroy(&symtab);
02973 return (result);
02974 }
02975
02976 static isc_result_t
02977 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
02978 isc_log_t *logctx)
02979 {
02980 isc_result_t result = ISC_R_SUCCESS;
02981 const cfg_obj_t *control_keylist;
02982 const cfg_listelt_t *element;
02983 const cfg_obj_t *key;
02984 const char *keyval;
02985
02986 control_keylist = cfg_tuple_get(control, "keys");
02987 if (cfg_obj_isvoid(control_keylist))
02988 return (ISC_R_SUCCESS);
02989
02990 for (element = cfg_list_first(control_keylist);
02991 element != NULL;
02992 element = cfg_list_next(element))
02993 {
02994 key = cfg_listelt_value(element);
02995 keyval = cfg_obj_asstring(key);
02996
02997 if (!rndckey_exists(keylist, keyval)) {
02998 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
02999 "unknown key '%s'", keyval);
03000 result = ISC_R_NOTFOUND;
03001 }
03002 }
03003 return (result);
03004 }
03005
03006 static isc_result_t
03007 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
03008 isc_mem_t *mctx)
03009 {
03010 isc_result_t result = ISC_R_SUCCESS, tresult;
03011 cfg_aclconfctx_t *actx = NULL;
03012 const cfg_listelt_t *element, *element2;
03013 const cfg_obj_t *allow;
03014 const cfg_obj_t *control;
03015 const cfg_obj_t *controls;
03016 const cfg_obj_t *controlslist = NULL;
03017 const cfg_obj_t *inetcontrols;
03018 const cfg_obj_t *unixcontrols;
03019 const cfg_obj_t *keylist = NULL;
03020 const char *path;
03021 isc_uint32_t perm, mask;
03022 dns_acl_t *acl = NULL;
03023 isc_sockaddr_t addr;
03024 int i;
03025
03026 (void)cfg_map_get(config, "controls", &controlslist);
03027 if (controlslist == NULL)
03028 return (ISC_R_SUCCESS);
03029
03030 (void)cfg_map_get(config, "key", &keylist);
03031
03032 cfg_aclconfctx_create(mctx, &actx);
03033
03034
03035
03036
03037
03038 for (element = cfg_list_first(controlslist);
03039 element != NULL;
03040 element = cfg_list_next(element)) {
03041 controls = cfg_listelt_value(element);
03042 unixcontrols = NULL;
03043 inetcontrols = NULL;
03044 (void)cfg_map_get(controls, "unix", &unixcontrols);
03045 (void)cfg_map_get(controls, "inet", &inetcontrols);
03046 for (element2 = cfg_list_first(inetcontrols);
03047 element2 != NULL;
03048 element2 = cfg_list_next(element2)) {
03049 control = cfg_listelt_value(element2);
03050 allow = cfg_tuple_get(control, "allow");
03051 tresult = cfg_acl_fromconfig(allow, config, logctx,
03052 actx, mctx, 0, &acl);
03053 if (acl != NULL)
03054 dns_acl_detach(&acl);
03055 if (tresult != ISC_R_SUCCESS)
03056 result = tresult;
03057 tresult = bind9_check_controlskeys(control, keylist,
03058 logctx);
03059 if (tresult != ISC_R_SUCCESS)
03060 result = tresult;
03061 }
03062 for (element2 = cfg_list_first(unixcontrols);
03063 element2 != NULL;
03064 element2 = cfg_list_next(element2)) {
03065 control = cfg_listelt_value(element2);
03066 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
03067 tresult = isc_sockaddr_frompath(&addr, path);
03068 if (tresult == ISC_R_NOSPACE) {
03069 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
03070 "unix control '%s': path too long",
03071 path);
03072 result = ISC_R_NOSPACE;
03073 }
03074 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
03075 for (i = 0; i < 3; i++) {
03076 #ifdef NEED_SECURE_DIRECTORY
03077 mask = (0x1 << (i*3));
03078 #else
03079 mask = (0x6 << (i*3));
03080 #endif
03081 if ((perm & mask) == mask)
03082 break;
03083 }
03084 if (i == 0) {
03085 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
03086 "unix control '%s' allows access "
03087 "to everyone", path);
03088 } else if (i == 3) {
03089 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
03090 "unix control '%s' allows access "
03091 "to nobody", path);
03092 }
03093 tresult = bind9_check_controlskeys(control, keylist,
03094 logctx);
03095 if (tresult != ISC_R_SUCCESS)
03096 result = tresult;
03097 }
03098 }
03099 cfg_aclconfctx_detach(&actx);
03100 return (result);
03101 }
03102
03103 isc_result_t
03104 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
03105 isc_mem_t *mctx)
03106 {
03107 const cfg_obj_t *options = NULL;
03108 const cfg_obj_t *views = NULL;
03109 const cfg_obj_t *acls = NULL;
03110 const cfg_obj_t *kals = NULL;
03111 const cfg_obj_t *obj;
03112 const cfg_listelt_t *velement;
03113 isc_result_t result = ISC_R_SUCCESS;
03114 isc_result_t tresult;
03115 isc_symtab_t *symtab = NULL;
03116 isc_symtab_t *files = NULL;
03117
03118 static const char *builtin[] = { "localhost", "localnets",
03119 "any", "none"};
03120
03121 (void)cfg_map_get(config, "options", &options);
03122
03123 if (options != NULL &&
03124 check_options(options, logctx, mctx,
03125 optlevel_options) != ISC_R_SUCCESS)
03126 result = ISC_R_FAILURE;
03127
03128 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
03129 result = ISC_R_FAILURE;
03130
03131 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
03132 result = ISC_R_FAILURE;
03133
03134 if (options != NULL &&
03135 check_order(options, logctx) != ISC_R_SUCCESS)
03136 result = ISC_R_FAILURE;
03137
03138 (void)cfg_map_get(config, "view", &views);
03139
03140 if (views != NULL && options != NULL)
03141 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
03142 result = ISC_R_FAILURE;
03143
03144
03145
03146
03147
03148
03149 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE,
03150 &files);
03151 if (tresult != ISC_R_SUCCESS)
03152 result = tresult;
03153
03154 if (views == NULL) {
03155 if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
03156 files, logctx, mctx) != ISC_R_SUCCESS)
03157 result = ISC_R_FAILURE;
03158 } else {
03159 const cfg_obj_t *zones = NULL;
03160
03161 (void)cfg_map_get(config, "zone", &zones);
03162 if (zones != NULL) {
03163 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
03164 "when using 'view' statements, "
03165 "all zones must be in views");
03166 result = ISC_R_FAILURE;
03167 }
03168 }
03169
03170 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
03171 if (tresult != ISC_R_SUCCESS)
03172 result = tresult;
03173 for (velement = cfg_list_first(views);
03174 velement != NULL;
03175 velement = cfg_list_next(velement))
03176 {
03177 const cfg_obj_t *view = cfg_listelt_value(velement);
03178 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
03179 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
03180 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
03181 dns_rdataclass_t vclass = dns_rdataclass_in;
03182 const char *key = cfg_obj_asstring(vname);
03183 isc_symvalue_t symvalue;
03184
03185 tresult = ISC_R_SUCCESS;
03186 if (cfg_obj_isstring(vclassobj)) {
03187 isc_textregion_t r;
03188
03189 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
03190 r.length = strlen(r.base);
03191 tresult = dns_rdataclass_fromtext(&vclass, &r);
03192 if (tresult != ISC_R_SUCCESS)
03193 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
03194 "view '%s': invalid class %s",
03195 cfg_obj_asstring(vname), r.base);
03196 }
03197 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
03198 symvalue.as_cpointer = view;
03199 tresult = isc_symtab_define(symtab, key, vclass,
03200 symvalue,
03201 isc_symexists_reject);
03202 if (tresult == ISC_R_EXISTS) {
03203 const char *file;
03204 unsigned int line;
03205 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
03206 vclass, &symvalue) == ISC_R_SUCCESS);
03207 file = cfg_obj_file(symvalue.as_cpointer);
03208 line = cfg_obj_line(symvalue.as_cpointer);
03209 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
03210 "view '%s': already exists "
03211 "previous definition: %s:%u",
03212 key, file, line);
03213 result = tresult;
03214 } else if (tresult != ISC_R_SUCCESS) {
03215 result = tresult;
03216 } else if ((strcasecmp(key, "_bind") == 0 &&
03217 vclass == dns_rdataclass_ch) ||
03218 (strcasecmp(key, "_default") == 0 &&
03219 vclass == dns_rdataclass_in)) {
03220 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
03221 "attempt to redefine builtin view "
03222 "'%s'", key);
03223 result = ISC_R_EXISTS;
03224 }
03225 }
03226 if (tresult == ISC_R_SUCCESS)
03227 tresult = check_viewconf(config, voptions, key, vclass,
03228 files, logctx, mctx);
03229 if (tresult != ISC_R_SUCCESS)
03230 result = ISC_R_FAILURE;
03231 }
03232 if (symtab != NULL)
03233 isc_symtab_destroy(&symtab);
03234 if (files != NULL)
03235 isc_symtab_destroy(&files);
03236
03237 if (views != NULL && options != NULL) {
03238 obj = NULL;
03239 tresult = cfg_map_get(options, "cache-file", &obj);
03240 if (tresult == ISC_R_SUCCESS) {
03241 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
03242 "'cache-file' cannot be a global "
03243 "option if views are present");
03244 result = ISC_R_FAILURE;
03245 }
03246 }
03247
03248 cfg_map_get(config, "acl", &acls);
03249
03250 if (acls != NULL) {
03251 const cfg_listelt_t *elt;
03252 const cfg_listelt_t *elt2;
03253 const char *aclname;
03254
03255 for (elt = cfg_list_first(acls);
03256 elt != NULL;
03257 elt = cfg_list_next(elt)) {
03258 const cfg_obj_t *acl = cfg_listelt_value(elt);
03259 unsigned int line = cfg_obj_line(acl);
03260 unsigned int i;
03261
03262 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
03263 for (i = 0;
03264 i < sizeof(builtin) / sizeof(builtin[0]);
03265 i++)
03266 if (strcasecmp(aclname, builtin[i]) == 0) {
03267 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
03268 "attempt to redefine "
03269 "builtin acl '%s'",
03270 aclname);
03271 result = ISC_R_FAILURE;
03272 break;
03273 }
03274
03275 for (elt2 = cfg_list_next(elt);
03276 elt2 != NULL;
03277 elt2 = cfg_list_next(elt2)) {
03278 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
03279 const char *name;
03280 name = cfg_obj_asstring(cfg_tuple_get(acl2,
03281 "name"));
03282 if (strcasecmp(aclname, name) == 0) {
03283 const char *file = cfg_obj_file(acl);
03284
03285 if (file == NULL)
03286 file = "<unknown file>";
03287
03288 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
03289 "attempt to redefine "
03290 "acl '%s' previous "
03291 "definition: %s:%u",
03292 name, file, line);
03293 result = ISC_R_FAILURE;
03294 }
03295 }
03296 }
03297 }
03298
03299 tresult = cfg_map_get(config, "kal", &kals);
03300 if (tresult == ISC_R_SUCCESS) {
03301 const cfg_listelt_t *elt;
03302 const cfg_listelt_t *elt2;
03303 const char *aclname;
03304
03305 for (elt = cfg_list_first(kals);
03306 elt != NULL;
03307 elt = cfg_list_next(elt)) {
03308 const cfg_obj_t *acl = cfg_listelt_value(elt);
03309
03310 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
03311
03312 for (elt2 = cfg_list_next(elt);
03313 elt2 != NULL;
03314 elt2 = cfg_list_next(elt2)) {
03315 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
03316 const char *name;
03317 name = cfg_obj_asstring(cfg_tuple_get(acl2,
03318 "name"));
03319 if (strcasecmp(aclname, name) == 0) {
03320 const char *file = cfg_obj_file(acl);
03321 unsigned int line = cfg_obj_line(acl);
03322
03323 if (file == NULL)
03324 file = "<unknown file>";
03325
03326 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
03327 "attempt to redefine "
03328 "kal '%s' previous "
03329 "definition: %s:%u",
03330 name, file, line);
03331 result = ISC_R_FAILURE;
03332 }
03333 }
03334 }
03335 }
03336
03337 return (result);
03338 }