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