PageRenderTime 133ms CodeModel.GetById 34ms app.highlight 85ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/bind9/lib/bind9/check.c

https://bitbucket.org/freebsd/freebsd-head/
C | 2810 lines | 2392 code | 269 blank | 149 comment | 823 complexity | 403e0d46707d40b5f2209939c560fcaf MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
   3 * Copyright (C) 2001-2003  Internet Software Consortium.
   4 *
   5 * Permission to use, copy, modify, and/or distribute this software for any
   6 * purpose with or without fee is hereby granted, provided that the above
   7 * copyright notice and this permission notice appear in all copies.
   8 *
   9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  15 * PERFORMANCE OF THIS SOFTWARE.
  16 */
  17
  18/* $Id$ */
  19
  20/*! \file */
  21
  22#include <config.h>
  23
  24#include <stdlib.h>
  25
  26#include <isc/base64.h>
  27#include <isc/buffer.h>
  28#include <isc/log.h>
  29#include <isc/mem.h>
  30#include <isc/netaddr.h>
  31#include <isc/parseint.h>
  32#include <isc/region.h>
  33#include <isc/result.h>
  34#include <isc/sockaddr.h>
  35#include <isc/string.h>
  36#include <isc/symtab.h>
  37#include <isc/util.h>
  38
  39#include <dns/acl.h>
  40#include <dns/fixedname.h>
  41#include <dns/rdataclass.h>
  42#include <dns/rdatatype.h>
  43#include <dns/secalg.h>
  44
  45#include <dst/dst.h>
  46
  47#include <isccfg/aclconf.h>
  48#include <isccfg/cfg.h>
  49
  50#include <bind9/check.h>
  51
  52static void
  53freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
  54	UNUSED(type);
  55	UNUSED(value);
  56	isc_mem_free(userarg, key);
  57}
  58
  59static isc_result_t
  60check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
  61	isc_result_t result = ISC_R_SUCCESS;
  62	isc_result_t tresult;
  63	isc_textregion_t r;
  64	dns_fixedname_t fixed;
  65	const cfg_obj_t *obj;
  66	dns_rdataclass_t rdclass;
  67	dns_rdatatype_t rdtype;
  68	isc_buffer_t b;
  69	const char *str;
  70
  71	dns_fixedname_init(&fixed);
  72	obj = cfg_tuple_get(ent, "class");
  73	if (cfg_obj_isstring(obj)) {
  74
  75		DE_CONST(cfg_obj_asstring(obj), r.base);
  76		r.length = strlen(r.base);
  77		tresult = dns_rdataclass_fromtext(&rdclass, &r);
  78		if (tresult != ISC_R_SUCCESS) {
  79			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  80				    "rrset-order: invalid class '%s'",
  81				    r.base);
  82			result = ISC_R_FAILURE;
  83		}
  84	}
  85
  86	obj = cfg_tuple_get(ent, "type");
  87	if (cfg_obj_isstring(obj)) {
  88
  89		DE_CONST(cfg_obj_asstring(obj), r.base);
  90		r.length = strlen(r.base);
  91		tresult = dns_rdatatype_fromtext(&rdtype, &r);
  92		if (tresult != ISC_R_SUCCESS) {
  93			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  94				    "rrset-order: invalid type '%s'",
  95				    r.base);
  96			result = ISC_R_FAILURE;
  97		}
  98	}
  99
 100	obj = cfg_tuple_get(ent, "name");
 101	if (cfg_obj_isstring(obj)) {
 102		str = cfg_obj_asstring(obj);
 103		isc_buffer_init(&b, str, strlen(str));
 104		isc_buffer_add(&b, strlen(str));
 105		tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
 106					    dns_rootname, 0, NULL);
 107		if (tresult != ISC_R_SUCCESS) {
 108			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 109				    "rrset-order: invalid name '%s'", str);
 110			result = ISC_R_FAILURE;
 111		}
 112	}
 113
 114	obj = cfg_tuple_get(ent, "order");
 115	if (!cfg_obj_isstring(obj) ||
 116	    strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
 117		cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
 118			    "rrset-order: keyword 'order' missing");
 119		result = ISC_R_FAILURE;
 120	}
 121
 122	obj = cfg_tuple_get(ent, "ordering");
 123	if (!cfg_obj_isstring(obj)) {
 124	    cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
 125			"rrset-order: missing ordering");
 126		result = ISC_R_FAILURE;
 127	} else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
 128#if !DNS_RDATASET_FIXED
 129		cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
 130			    "rrset-order: order 'fixed' was disabled at "
 131			    "compilation time");
 132#endif
 133	} else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
 134		   strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
 135		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 136			    "rrset-order: invalid order '%s'",
 137			    cfg_obj_asstring(obj));
 138		result = ISC_R_FAILURE;
 139	}
 140	return (result);
 141}
 142
 143static isc_result_t
 144check_order(const cfg_obj_t *options, isc_log_t *logctx) {
 145	isc_result_t result = ISC_R_SUCCESS;
 146	isc_result_t tresult;
 147	const cfg_listelt_t *element;
 148	const cfg_obj_t *obj = NULL;
 149
 150	if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
 151		return (result);
 152
 153	for (element = cfg_list_first(obj);
 154	     element != NULL;
 155	     element = cfg_list_next(element))
 156	{
 157		tresult = check_orderent(cfg_listelt_value(element), logctx);
 158		if (tresult != ISC_R_SUCCESS)
 159			result = tresult;
 160	}
 161	return (result);
 162}
 163
 164static isc_result_t
 165check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
 166	const cfg_listelt_t *element;
 167	const cfg_obj_t *alternates = NULL;
 168	const cfg_obj_t *value;
 169	const cfg_obj_t *obj;
 170	const char *str;
 171	dns_fixedname_t fixed;
 172	dns_name_t *name;
 173	isc_buffer_t buffer;
 174	isc_result_t result = ISC_R_SUCCESS;
 175	isc_result_t tresult;
 176
 177	(void)cfg_map_get(options, "dual-stack-servers", &alternates);
 178
 179	if (alternates == NULL)
 180		return (ISC_R_SUCCESS);
 181
 182	obj = cfg_tuple_get(alternates, "port");
 183	if (cfg_obj_isuint32(obj)) {
 184		isc_uint32_t val = cfg_obj_asuint32(obj);
 185		if (val > ISC_UINT16_MAX) {
 186			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 187				    "port '%u' out of range", val);
 188			result = ISC_R_FAILURE;
 189		}
 190	}
 191	obj = cfg_tuple_get(alternates, "addresses");
 192	for (element = cfg_list_first(obj);
 193	     element != NULL;
 194	     element = cfg_list_next(element)) {
 195		value = cfg_listelt_value(element);
 196		if (cfg_obj_issockaddr(value))
 197			continue;
 198		obj = cfg_tuple_get(value, "name");
 199		str = cfg_obj_asstring(obj);
 200		isc_buffer_init(&buffer, str, strlen(str));
 201		isc_buffer_add(&buffer, strlen(str));
 202		dns_fixedname_init(&fixed);
 203		name = dns_fixedname_name(&fixed);
 204		tresult = dns_name_fromtext(name, &buffer, dns_rootname,
 205					    0, NULL);
 206		if (tresult != ISC_R_SUCCESS) {
 207			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 208				    "bad name '%s'", str);
 209			result = ISC_R_FAILURE;
 210		}
 211		obj = cfg_tuple_get(value, "port");
 212		if (cfg_obj_isuint32(obj)) {
 213			isc_uint32_t val = cfg_obj_asuint32(obj);
 214			if (val > ISC_UINT16_MAX) {
 215				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 216					    "port '%u' out of range", val);
 217				result = ISC_R_FAILURE;
 218			}
 219		}
 220	}
 221	return (result);
 222}
 223
 224static isc_result_t
 225check_forward(const cfg_obj_t *options,  const cfg_obj_t *global,
 226	      isc_log_t *logctx)
 227{
 228	const cfg_obj_t *forward = NULL;
 229	const cfg_obj_t *forwarders = NULL;
 230
 231	(void)cfg_map_get(options, "forward", &forward);
 232	(void)cfg_map_get(options, "forwarders", &forwarders);
 233
 234	if (forwarders != NULL && global != NULL) {
 235		const char *file = cfg_obj_file(global);
 236		unsigned int line = cfg_obj_line(global);
 237		cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
 238			    "forwarders declared in root zone and "
 239			    "in general configuration: %s:%u",
 240			    file, line);
 241		return (ISC_R_FAILURE);
 242	}
 243	if (forward != NULL && forwarders == NULL) {
 244		cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
 245			    "no matching 'forwarders' statement");
 246		return (ISC_R_FAILURE);
 247	}
 248	return (ISC_R_SUCCESS);
 249}
 250
 251static isc_result_t
 252disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
 253	isc_result_t result = ISC_R_SUCCESS;
 254	isc_result_t tresult;
 255	const cfg_listelt_t *element;
 256	const char *str;
 257	isc_buffer_t b;
 258	dns_fixedname_t fixed;
 259	dns_name_t *name;
 260	const cfg_obj_t *obj;
 261
 262	dns_fixedname_init(&fixed);
 263	name = dns_fixedname_name(&fixed);
 264	obj = cfg_tuple_get(disabled, "name");
 265	str = cfg_obj_asstring(obj);
 266	isc_buffer_init(&b, str, strlen(str));
 267	isc_buffer_add(&b, strlen(str));
 268	tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
 269	if (tresult != ISC_R_SUCCESS) {
 270		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 271			    "bad domain name '%s'", str);
 272		result = tresult;
 273	}
 274
 275	obj = cfg_tuple_get(disabled, "algorithms");
 276
 277	for (element = cfg_list_first(obj);
 278	     element != NULL;
 279	     element = cfg_list_next(element))
 280	{
 281		isc_textregion_t r;
 282		dns_secalg_t alg;
 283		isc_result_t tresult;
 284
 285		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
 286		r.length = strlen(r.base);
 287
 288		tresult = dns_secalg_fromtext(&alg, &r);
 289		if (tresult != ISC_R_SUCCESS) {
 290			isc_uint8_t ui;
 291			result = isc_parse_uint8(&ui, r.base, 10);
 292		}
 293		if (tresult != ISC_R_SUCCESS) {
 294			cfg_obj_log(cfg_listelt_value(element), logctx,
 295				    ISC_LOG_ERROR, "invalid algorithm '%s'",
 296				    r.base);
 297			result = tresult;
 298		}
 299	}
 300	return (result);
 301}
 302
 303static isc_result_t
 304nameexist(const cfg_obj_t *obj, const char *name, int value,
 305	  isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
 306	  isc_mem_t *mctx)
 307{
 308	char *key;
 309	const char *file;
 310	unsigned int line;
 311	isc_result_t result;
 312	isc_symvalue_t symvalue;
 313
 314	key = isc_mem_strdup(mctx, name);
 315	if (key == NULL)
 316		return (ISC_R_NOMEMORY);
 317	symvalue.as_cpointer = obj;
 318	result = isc_symtab_define(symtab, key, value, symvalue,
 319				   isc_symexists_reject);
 320	if (result == ISC_R_EXISTS) {
 321		RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
 322						&symvalue) == ISC_R_SUCCESS);
 323		file = cfg_obj_file(symvalue.as_cpointer);
 324		line = cfg_obj_line(symvalue.as_cpointer);
 325
 326		if (file == NULL)
 327			file = "<unknown file>";
 328		cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
 329		isc_mem_free(mctx, key);
 330		result = ISC_R_EXISTS;
 331	} else if (result != ISC_R_SUCCESS) {
 332		isc_mem_free(mctx, key);
 333	}
 334	return (result);
 335}
 336
 337static isc_result_t
 338mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
 339	     isc_mem_t *mctx)
 340{
 341	const cfg_obj_t *obj;
 342	char namebuf[DNS_NAME_FORMATSIZE];
 343	const char *str;
 344	dns_fixedname_t fixed;
 345	dns_name_t *name;
 346	isc_buffer_t b;
 347	isc_result_t result = ISC_R_SUCCESS;
 348
 349	dns_fixedname_init(&fixed);
 350	name = dns_fixedname_name(&fixed);
 351	obj = cfg_tuple_get(secure, "name");
 352	str = cfg_obj_asstring(obj);
 353	isc_buffer_init(&b, str, strlen(str));
 354	isc_buffer_add(&b, strlen(str));
 355	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
 356	if (result != ISC_R_SUCCESS) {
 357		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 358			    "bad domain name '%s'", str);
 359	} else {
 360		dns_name_format(name, namebuf, sizeof(namebuf));
 361		result = nameexist(secure, namebuf, 1, symtab,
 362				   "dnssec-must-be-secure '%s': already "
 363				   "exists previous definition: %s:%u",
 364				   logctx, mctx);
 365	}
 366	return (result);
 367}
 368
 369static isc_result_t
 370checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
 371	 const cfg_obj_t *voptions, const cfg_obj_t *config,
 372	 isc_log_t *logctx, isc_mem_t *mctx)
 373{
 374	isc_result_t result;
 375	const cfg_obj_t *aclobj = NULL;
 376	const cfg_obj_t *options;
 377	dns_acl_t *acl = NULL;
 378
 379	if (zconfig != NULL) {
 380		options = cfg_tuple_get(zconfig, "options");
 381		cfg_map_get(options, aclname, &aclobj);
 382	}
 383	if (voptions != NULL && aclobj == NULL)
 384		cfg_map_get(voptions, aclname, &aclobj);
 385	if (config != NULL && aclobj == NULL) {
 386		options = NULL;
 387		cfg_map_get(config, "options", &options);
 388		if (options != NULL)
 389			cfg_map_get(options, aclname, &aclobj);
 390	}
 391	if (aclobj == NULL)
 392		return (ISC_R_SUCCESS);
 393	result = cfg_acl_fromconfig(aclobj, config, logctx,
 394				    actx, mctx, 0, &acl);
 395	if (acl != NULL)
 396		dns_acl_detach(&acl);
 397	return (result);
 398}
 399
 400static isc_result_t
 401check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
 402	       const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
 403{
 404	isc_result_t result = ISC_R_SUCCESS, tresult;
 405	int i = 0;
 406
 407	static const char *acls[] = { "allow-query", "allow-query-on",
 408		"allow-query-cache", "allow-query-cache-on",
 409		"blackhole", "match-clients", "match-destinations",
 410		"sortlist", "filter-aaaa", NULL };
 411
 412	while (acls[i] != NULL) {
 413		tresult = checkacl(acls[i++], actx, NULL, voptions, config,
 414				   logctx, mctx);
 415		if (tresult != ISC_R_SUCCESS)
 416			result = tresult;
 417	}
 418	return (result);
 419}
 420
 421static const unsigned char zeros[16];
 422
 423static isc_result_t
 424check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
 425	    const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
 426{
 427	isc_result_t result = ISC_R_SUCCESS;
 428	const cfg_obj_t *dns64 = NULL;
 429	const cfg_obj_t *options;
 430	const cfg_listelt_t *element;
 431	const cfg_obj_t *map, *obj;
 432	isc_netaddr_t na, sa;
 433	unsigned int prefixlen;
 434	int nbytes;
 435	int i;
 436
 437	static const char *acls[] = { "clients", "exclude", "mapped", NULL};
 438
 439	if (voptions != NULL)
 440		cfg_map_get(voptions, "dns64", &dns64);
 441	if (config != NULL && dns64 == NULL) {
 442		options = NULL;
 443		cfg_map_get(config, "options", &options);
 444		if (options != NULL)
 445			cfg_map_get(options, "dns64", &dns64);
 446	}
 447	if (dns64 == NULL)
 448		return (ISC_R_SUCCESS);
 449
 450	for (element = cfg_list_first(dns64);
 451	     element != NULL;
 452	     element = cfg_list_next(element))
 453	{
 454		map = cfg_listelt_value(element);
 455		obj = cfg_map_getname(map);
 456
 457		cfg_obj_asnetprefix(obj, &na, &prefixlen);
 458		if (na.family != AF_INET6) {
 459			cfg_obj_log(map, logctx, ISC_LOG_ERROR,
 460				    "dns64 requires a IPv6 prefix");
 461			result = ISC_R_FAILURE;
 462			continue;
 463		}
 464
 465		if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 &&
 466		    prefixlen != 56 && prefixlen != 64 && prefixlen != 96) {
 467			cfg_obj_log(map, logctx, ISC_LOG_ERROR,
 468				    "bad prefix length %u [32/40/48/56/64/96]",
 469				    prefixlen);
 470			result = ISC_R_FAILURE;
 471			continue;
 472		}
 473
 474		for (i = 0; acls[i] != NULL; i++) {
 475			obj = NULL;
 476			(void)cfg_map_get(map, acls[i], &obj);
 477			if (obj != NULL) {
 478				dns_acl_t *acl = NULL;
 479				isc_result_t tresult;
 480
 481				tresult = cfg_acl_fromconfig(obj, config,
 482							     logctx, actx,
 483							     mctx, 0, &acl);
 484				if (acl != NULL)
 485					dns_acl_detach(&acl);
 486				if (tresult != ISC_R_SUCCESS)
 487					result = tresult;
 488			}
 489		}
 490
 491		obj = NULL;
 492		(void)cfg_map_get(map, "suffix", &obj);
 493		if (obj != NULL) {
 494			isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj));
 495			if (sa.family != AF_INET6) {
 496				cfg_obj_log(map, logctx, ISC_LOG_ERROR,
 497					    "dns64 requires a IPv6 suffix");
 498				result = ISC_R_FAILURE;
 499				continue;
 500			}
 501			nbytes = prefixlen / 8 + 4;
 502			if (prefixlen >= 32 && prefixlen <= 64)
 503				nbytes++;
 504			if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) {
 505				char netaddrbuf[ISC_NETADDR_FORMATSIZE];
 506				isc_netaddr_format(&sa, netaddrbuf,
 507						   sizeof(netaddrbuf));
 508				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 509					    "bad suffix '%s' leading "
 510					    "%u octets not zeros",
 511					    netaddrbuf, nbytes);
 512				result = ISC_R_FAILURE;
 513			}
 514		}
 515	}
 516
 517	return (result);
 518}
 519
 520
 521/*
 522 * Check allow-recursion and allow-recursion-on acls, and also log a
 523 * warning if they're inconsistent with the "recursion" option.
 524 */
 525static isc_result_t
 526check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
 527		    const char *viewname, const cfg_obj_t *config,
 528		    isc_log_t *logctx, isc_mem_t *mctx)
 529{
 530	const cfg_obj_t *options, *aclobj, *obj = NULL;
 531	dns_acl_t *acl = NULL;
 532	isc_result_t result = ISC_R_SUCCESS, tresult;
 533	isc_boolean_t recursion;
 534	const char *forview = " for view ";
 535	int i = 0;
 536
 537	static const char *acls[] = { "allow-recursion", "allow-recursion-on",
 538				      NULL };
 539
 540	if (voptions != NULL)
 541		cfg_map_get(voptions, "recursion", &obj);
 542	if (obj == NULL && config != NULL) {
 543		options = NULL;
 544		cfg_map_get(config, "options", &options);
 545		if (options != NULL)
 546			cfg_map_get(options, "recursion", &obj);
 547	}
 548	if (obj == NULL)
 549		recursion = ISC_TRUE;
 550	else
 551		recursion = cfg_obj_asboolean(obj);
 552
 553	if (viewname == NULL) {
 554		viewname = "";
 555		forview = "";
 556	}
 557
 558	for (i = 0; acls[i] != NULL; i++) {
 559		aclobj = options = NULL;
 560		acl = NULL;
 561
 562		if (voptions != NULL)
 563			cfg_map_get(voptions, acls[i], &aclobj);
 564		if (config != NULL && aclobj == NULL) {
 565			options = NULL;
 566			cfg_map_get(config, "options", &options);
 567			if (options != NULL)
 568				cfg_map_get(options, acls[i], &aclobj);
 569		}
 570		if (aclobj == NULL)
 571			continue;
 572
 573		tresult = cfg_acl_fromconfig(aclobj, config, logctx,
 574					    actx, mctx, 0, &acl);
 575
 576		if (tresult != ISC_R_SUCCESS)
 577			result = tresult;
 578
 579		if (acl == NULL)
 580			continue;
 581
 582		if (recursion == ISC_FALSE && !dns_acl_isnone(acl)) {
 583			cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
 584				    "both \"recursion no;\" and "
 585				    "\"%s\" active%s%s",
 586				    acls[i], forview, viewname);
 587		}
 588
 589		if (acl != NULL)
 590			dns_acl_detach(&acl);
 591	}
 592
 593	return (result);
 594}
 595
 596static isc_result_t
 597check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
 598		 const char *viewname, const cfg_obj_t *config,
 599		 isc_log_t *logctx, isc_mem_t *mctx)
 600{
 601	const cfg_obj_t *options, *aclobj, *obj = NULL;
 602	dns_acl_t *acl = NULL;
 603	isc_result_t result = ISC_R_SUCCESS, tresult;
 604	dns_v4_aaaa_t filter;
 605	const char *forview = " for view ";
 606
 607	if (voptions != NULL)
 608		cfg_map_get(voptions, "filter-aaaa-on-v4", &obj);
 609	if (obj == NULL && config != NULL) {
 610		options = NULL;
 611		cfg_map_get(config, "options", &options);
 612		if (options != NULL)
 613			cfg_map_get(options, "filter-aaaa-on-v4", &obj);
 614	}
 615
 616	if (obj == NULL)
 617		filter = dns_v4_aaaa_ok;		/* default */
 618	else if (cfg_obj_isboolean(obj))
 619		filter = cfg_obj_asboolean(obj) ? dns_v4_aaaa_filter :
 620						  dns_v4_aaaa_ok;
 621	else
 622		filter = dns_v4_aaaa_break_dnssec; 	/* break-dnssec */
 623
 624	if (viewname == NULL) {
 625		viewname = "";
 626		forview = "";
 627	}
 628
 629	aclobj = options = NULL;
 630	acl = NULL;
 631
 632	if (voptions != NULL)
 633		cfg_map_get(voptions, "filter-aaaa", &aclobj);
 634	if (config != NULL && aclobj == NULL) {
 635		options = NULL;
 636		cfg_map_get(config, "options", &options);
 637		if (options != NULL)
 638			cfg_map_get(options, "filter-aaaa", &aclobj);
 639	}
 640	if (aclobj == NULL)
 641		return (result);
 642
 643	tresult = cfg_acl_fromconfig(aclobj, config, logctx,
 644				    actx, mctx, 0, &acl);
 645
 646	if (tresult != ISC_R_SUCCESS) {
 647		result = tresult;
 648	} else if (filter != dns_v4_aaaa_ok && dns_acl_isnone(acl)) {
 649		cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
 650			    "both \"filter-aaaa-on-v4 %s;\" and "
 651			    "\"filter-aaaa\" is 'none;'%s%s",
 652			    filter == dns_v4_aaaa_break_dnssec ?
 653			    "break-dnssec" : "yes", forview, viewname);
 654		result = ISC_R_FAILURE;
 655	} else if (filter == dns_v4_aaaa_ok && !dns_acl_isnone(acl)) {
 656		cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
 657			    "both \"filter-aaaa-on-v4 no;\" and "
 658			    "\"filter-aaaa\" is set%s%s", forview, viewname);
 659		result = ISC_R_FAILURE;
 660	}
 661
 662	if (acl != NULL)
 663		dns_acl_detach(&acl);
 664
 665	return (result);
 666}
 667
 668typedef struct {
 669	const char *name;
 670	unsigned int scale;
 671	unsigned int max;
 672} intervaltable;
 673
 674typedef enum {
 675	optlevel_config,
 676	optlevel_options,
 677	optlevel_view,
 678	optlevel_zone
 679} optlevel_t;
 680
 681static isc_result_t
 682check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
 683	      optlevel_t optlevel)
 684{
 685	isc_result_t result = ISC_R_SUCCESS;
 686	isc_result_t tresult;
 687	unsigned int i;
 688	const cfg_obj_t *obj = NULL;
 689	const cfg_obj_t *resignobj = NULL;
 690	const cfg_listelt_t *element;
 691	isc_symtab_t *symtab = NULL;
 692	dns_fixedname_t fixed;
 693	const char *str;
 694	dns_name_t *name;
 695	isc_buffer_t b;
 696
 697	static intervaltable intervals[] = {
 698	{ "cleaning-interval", 60, 28 * 24 * 60 },	/* 28 days */
 699	{ "heartbeat-interval", 60, 28 * 24 * 60 },	/* 28 days */
 700	{ "interface-interval", 60, 28 * 24 * 60 },	/* 28 days */
 701	{ "max-transfer-idle-in", 60, 28 * 24 * 60 },	/* 28 days */
 702	{ "max-transfer-idle-out", 60, 28 * 24 * 60 },	/* 28 days */
 703	{ "max-transfer-time-in", 60, 28 * 24 * 60 },	/* 28 days */
 704	{ "max-transfer-time-out", 60, 28 * 24 * 60 },	/* 28 days */
 705	{ "statistics-interval", 60, 28 * 24 * 60 },	/* 28 days */
 706	};
 707
 708	static const char *server_contact[] = {
 709		"empty-server", "empty-contact",
 710		"dns64-server", "dns64-contact",
 711		NULL
 712	};
 713
 714	/*
 715	 * Check that fields specified in units of time other than seconds
 716	 * have reasonable values.
 717	 */
 718	for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
 719		isc_uint32_t val;
 720		obj = NULL;
 721		(void)cfg_map_get(options, intervals[i].name, &obj);
 722		if (obj == NULL)
 723			continue;
 724		val = cfg_obj_asuint32(obj);
 725		if (val > intervals[i].max) {
 726			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 727				    "%s '%u' is out of range (0..%u)",
 728				    intervals[i].name, val,
 729				    intervals[i].max);
 730			result = ISC_R_RANGE;
 731		} else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
 732			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 733				    "%s '%d' is out of range",
 734				    intervals[i].name, val);
 735			result = ISC_R_RANGE;
 736		}
 737	}
 738
 739	obj = NULL;
 740	cfg_map_get(options, "sig-validity-interval", &obj);
 741	if (obj != NULL) {
 742		isc_uint32_t validity, resign = 0;
 743
 744		validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
 745		resignobj = cfg_tuple_get(obj, "re-sign");
 746		if (!cfg_obj_isvoid(resignobj))
 747			resign = cfg_obj_asuint32(resignobj);
 748
 749		if (validity > 3660 || validity == 0) { /* 10 years */
 750			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 751				    "%s '%u' is out of range (1..3660)",
 752				    "sig-validity-interval", validity);
 753			result = ISC_R_RANGE;
 754		}
 755
 756		if (!cfg_obj_isvoid(resignobj)) {
 757			if (resign > 3660 || resign == 0) { /* 10 years */
 758				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 759					    "%s '%u' is out of range (1..3660)",
 760					    "sig-validity-interval (re-sign)",
 761					    validity);
 762				result = ISC_R_RANGE;
 763			} else if ((validity > 7 && validity < resign) ||
 764				   (validity <= 7 && validity * 24 < resign)) {
 765				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 766					    "validity interval (%u days) "
 767					    "less than re-signing interval "
 768					    "(%u %s)", validity, resign,
 769					    (validity > 7) ? "days" : "hours");
 770				result = ISC_R_RANGE;
 771			}
 772		}
 773	}
 774
 775	obj = NULL;
 776	(void)cfg_map_get(options, "preferred-glue", &obj);
 777	if (obj != NULL) {
 778		const char *str;
 779		str = cfg_obj_asstring(obj);
 780		if (strcasecmp(str, "a") != 0 &&
 781		    strcasecmp(str, "aaaa") != 0 &&
 782		    strcasecmp(str, "none") != 0)
 783			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 784				    "preferred-glue unexpected value '%s'",
 785				    str);
 786	}
 787
 788	obj = NULL;
 789	(void)cfg_map_get(options, "root-delegation-only", &obj);
 790	if (obj != NULL) {
 791		if (!cfg_obj_isvoid(obj)) {
 792			const cfg_listelt_t *element;
 793			const cfg_obj_t *exclude;
 794			const char *str;
 795			dns_fixedname_t fixed;
 796			dns_name_t *name;
 797			isc_buffer_t b;
 798
 799			dns_fixedname_init(&fixed);
 800			name = dns_fixedname_name(&fixed);
 801			for (element = cfg_list_first(obj);
 802			     element != NULL;
 803			     element = cfg_list_next(element)) {
 804				exclude = cfg_listelt_value(element);
 805				str = cfg_obj_asstring(exclude);
 806				isc_buffer_init(&b, str, strlen(str));
 807				isc_buffer_add(&b, strlen(str));
 808				tresult = dns_name_fromtext(name, &b,
 809							   dns_rootname,
 810							   0, NULL);
 811				if (tresult != ISC_R_SUCCESS) {
 812					cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 813						    "bad domain name '%s'",
 814						    str);
 815					result = tresult;
 816				}
 817			}
 818		}
 819	}
 820
 821	/*
 822	 * Set supported DNSSEC algorithms.
 823	 */
 824	obj = NULL;
 825	(void)cfg_map_get(options, "disable-algorithms", &obj);
 826	if (obj != NULL) {
 827		for (element = cfg_list_first(obj);
 828		     element != NULL;
 829		     element = cfg_list_next(element))
 830		{
 831			obj = cfg_listelt_value(element);
 832			tresult = disabled_algorithms(obj, logctx);
 833			if (tresult != ISC_R_SUCCESS)
 834				result = tresult;
 835		}
 836	}
 837
 838	dns_fixedname_init(&fixed);
 839	name = dns_fixedname_name(&fixed);
 840
 841	/*
 842	 * Check the DLV zone name.
 843	 */
 844	obj = NULL;
 845	(void)cfg_map_get(options, "dnssec-lookaside", &obj);
 846	if (obj != NULL) {
 847		tresult = isc_symtab_create(mctx, 100, freekey, mctx,
 848					    ISC_FALSE, &symtab);
 849		if (tresult != ISC_R_SUCCESS)
 850			result = tresult;
 851		for (element = cfg_list_first(obj);
 852		     element != NULL;
 853		     element = cfg_list_next(element))
 854		{
 855			const char *dlv;
 856			const cfg_obj_t *dlvobj, *anchor;
 857
 858			obj = cfg_listelt_value(element);
 859
 860			anchor = cfg_tuple_get(obj, "trust-anchor");
 861			dlvobj = cfg_tuple_get(obj, "domain");
 862			dlv = cfg_obj_asstring(dlvobj);
 863
 864			/*
 865			 * If domain is "auto" or "no" and trust anchor
 866			 * is missing, skip remaining tests
 867			 */
 868			if (cfg_obj_isvoid(anchor)) {
 869				if (!strcasecmp(dlv, "no") ||
 870				    !strcasecmp(dlv, "auto"))
 871					continue;
 872			}
 873
 874			isc_buffer_init(&b, dlv, strlen(dlv));
 875			isc_buffer_add(&b, strlen(dlv));
 876			tresult = dns_name_fromtext(name, &b, dns_rootname,
 877						    0, NULL);
 878			if (tresult != ISC_R_SUCCESS) {
 879				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 880					    "bad domain name '%s'", dlv);
 881				result = tresult;
 882				continue;
 883			}
 884			if (symtab != NULL) {
 885				tresult = nameexist(obj, dlv, 1, symtab,
 886						    "dnssec-lookaside '%s': "
 887						    "already exists previous "
 888						    "definition: %s:%u",
 889						    logctx, mctx);
 890				if (tresult != ISC_R_SUCCESS &&
 891				    result == ISC_R_SUCCESS)
 892					result = tresult;
 893			}
 894			/*
 895			 * XXXMPA to be removed when multiple lookaside
 896			 * namespaces are supported.
 897			 */
 898			if (!dns_name_equal(dns_rootname, name)) {
 899				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 900					    "dnssec-lookaside '%s': "
 901					    "non-root not yet supported", dlv);
 902				if (result == ISC_R_SUCCESS)
 903					result = ISC_R_FAILURE;
 904			}
 905
 906			if (!cfg_obj_isvoid(anchor)) {
 907				dlv = cfg_obj_asstring(anchor);
 908				isc_buffer_init(&b, dlv, strlen(dlv));
 909				isc_buffer_add(&b, strlen(dlv));
 910				tresult = dns_name_fromtext(name, &b,
 911							    dns_rootname,
 912							    DNS_NAME_DOWNCASE,
 913							    NULL);
 914				if (tresult != ISC_R_SUCCESS) {
 915					cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 916						    "bad domain name '%s'",
 917						    dlv);
 918					if (result == ISC_R_SUCCESS)
 919						result = tresult;
 920				}
 921			} else {
 922				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 923					"dnssec-lookaside requires "
 924					"either 'auto' or 'no', or a "
 925					"domain and trust anchor");
 926				if (result == ISC_R_SUCCESS)
 927					result = ISC_R_FAILURE;
 928			}
 929		}
 930
 931		if (symtab != NULL)
 932			isc_symtab_destroy(&symtab);
 933	}
 934
 935	/*
 936	 * Check auto-dnssec at the view/options level
 937	 */
 938	obj = NULL;
 939	(void)cfg_map_get(options, "auto-dnssec", &obj);
 940	if (obj != NULL) {
 941		const char *arg = cfg_obj_asstring(obj);
 942		if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) {
 943			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 944				    "auto-dnssec may only be activated at the "
 945				    "zone level");
 946			result = ISC_R_FAILURE;
 947		}
 948	}
 949
 950	/*
 951	 * Check dnssec-must-be-secure.
 952	 */
 953	obj = NULL;
 954	(void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
 955	if (obj != NULL) {
 956		isc_symtab_t *symtab = NULL;
 957		tresult = isc_symtab_create(mctx, 100, freekey, mctx,
 958					    ISC_FALSE, &symtab);
 959		if (tresult != ISC_R_SUCCESS)
 960			result = tresult;
 961		for (element = cfg_list_first(obj);
 962		     element != NULL;
 963		     element = cfg_list_next(element))
 964		{
 965			obj = cfg_listelt_value(element);
 966			tresult = mustbesecure(obj, symtab, logctx, mctx);
 967			if (tresult != ISC_R_SUCCESS)
 968				result = tresult;
 969		}
 970		if (symtab != NULL)
 971			isc_symtab_destroy(&symtab);
 972	}
 973
 974	/*
 975	 * Check server/contacts for syntactic validity.
 976	 */
 977	for (i= 0; server_contact[i] != NULL; i++) {
 978		obj = NULL;
 979		(void)cfg_map_get(options, server_contact[i], &obj);
 980		if (obj != NULL) {
 981			str = cfg_obj_asstring(obj);
 982			isc_buffer_init(&b, str, strlen(str));
 983			isc_buffer_add(&b, strlen(str));
 984			tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
 985						    &b, dns_rootname, 0, NULL);
 986			if (tresult != ISC_R_SUCCESS) {
 987				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 988					    "%s: invalid name '%s'",
 989					    server_contact[i], str);
 990				result = ISC_R_FAILURE;
 991			}
 992		}
 993	}
 994
 995	/*
 996	 * Check empty zone configuration.
 997	 */
 998	obj = NULL;
 999	(void)cfg_map_get(options, "disable-empty-zone", &obj);
1000	for (element = cfg_list_first(obj);
1001	     element != NULL;
1002	     element = cfg_list_next(element))
1003	{
1004		obj = cfg_listelt_value(element);
1005		str = cfg_obj_asstring(obj);
1006		isc_buffer_init(&b, str, strlen(str));
1007		isc_buffer_add(&b, strlen(str));
1008		tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1009					    dns_rootname, 0, NULL);
1010		if (tresult != ISC_R_SUCCESS) {
1011			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1012				    "disable-empty-zone: invalid name '%s'",
1013				    str);
1014			result = ISC_R_FAILURE;
1015		}
1016	}
1017
1018	/*
1019	 * Check that server-id is not too long.
1020	 * 1024 bytes should be big enough.
1021	 */
1022	obj = NULL;
1023	(void)cfg_map_get(options, "server-id", &obj);
1024	if (obj != NULL && cfg_obj_isstring(obj) &&
1025	    strlen(cfg_obj_asstring(obj)) > 1024U) {
1026		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1027			    "'server-id' too big (>1024 bytes)");
1028		result = ISC_R_FAILURE;
1029	}
1030
1031	return (result);
1032}
1033
1034static isc_result_t
1035get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
1036	isc_result_t result;
1037	const cfg_obj_t *masters = NULL;
1038	const cfg_listelt_t *elt;
1039
1040	result = cfg_map_get(cctx, "masters", &masters);
1041	if (result != ISC_R_SUCCESS)
1042		return (result);
1043	for (elt = cfg_list_first(masters);
1044	     elt != NULL;
1045	     elt = cfg_list_next(elt)) {
1046		const cfg_obj_t *list;
1047		const char *listname;
1048
1049		list = cfg_listelt_value(elt);
1050		listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
1051
1052		if (strcasecmp(listname, name) == 0) {
1053			*ret = list;
1054			return (ISC_R_SUCCESS);
1055		}
1056	}
1057	return (ISC_R_NOTFOUND);
1058}
1059
1060static isc_result_t
1061validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
1062		 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
1063{
1064	isc_result_t result = ISC_R_SUCCESS;
1065	isc_result_t tresult;
1066	isc_uint32_t count = 0;
1067	isc_symtab_t *symtab = NULL;
1068	isc_symvalue_t symvalue;
1069	const cfg_listelt_t *element;
1070	const cfg_listelt_t **stack = NULL;
1071	isc_uint32_t stackcount = 0, pushed = 0;
1072	const cfg_obj_t *list;
1073
1074	REQUIRE(countp != NULL);
1075	result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1076	if (result != ISC_R_SUCCESS) {
1077		*countp = count;
1078		return (result);
1079	}
1080
1081 newlist:
1082	list = cfg_tuple_get(obj, "addresses");
1083	element = cfg_list_first(list);
1084 resume:
1085	for ( ;
1086	     element != NULL;
1087	     element = cfg_list_next(element))
1088	{
1089		const char *listname;
1090		const cfg_obj_t *addr;
1091		const cfg_obj_t *key;
1092
1093		addr = cfg_tuple_get(cfg_listelt_value(element),
1094				     "masterselement");
1095		key = cfg_tuple_get(cfg_listelt_value(element), "key");
1096
1097		if (cfg_obj_issockaddr(addr)) {
1098			count++;
1099			continue;
1100		}
1101		if (!cfg_obj_isvoid(key)) {
1102			cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1103				    "unexpected token '%s'",
1104				    cfg_obj_asstring(key));
1105			if (result == ISC_R_SUCCESS)
1106				result = ISC_R_FAILURE;
1107		}
1108		listname = cfg_obj_asstring(addr);
1109		symvalue.as_cpointer = addr;
1110		tresult = isc_symtab_define(symtab, listname, 1, symvalue,
1111					    isc_symexists_reject);
1112		if (tresult == ISC_R_EXISTS)
1113			continue;
1114		tresult = get_masters_def(config, listname, &obj);
1115		if (tresult != ISC_R_SUCCESS) {
1116			if (result == ISC_R_SUCCESS)
1117				result = tresult;
1118			cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
1119				    "unable to find masters list '%s'",
1120				    listname);
1121			continue;
1122		}
1123		/* Grow stack? */
1124		if (stackcount == pushed) {
1125			void * new;
1126			isc_uint32_t newlen = stackcount + 16;
1127			size_t newsize, oldsize;
1128
1129			newsize = newlen * sizeof(*stack);
1130			oldsize = stackcount * sizeof(*stack);
1131			new = isc_mem_get(mctx, newsize);
1132			if (new == NULL)
1133				goto cleanup;
1134			if (stackcount != 0) {
1135				void *ptr;
1136
1137				DE_CONST(stack, ptr);
1138				memcpy(new, stack, oldsize);
1139				isc_mem_put(mctx, ptr, oldsize);
1140			}
1141			stack = new;
1142			stackcount = newlen;
1143		}
1144		stack[pushed++] = cfg_list_next(element);
1145		goto newlist;
1146	}
1147	if (pushed != 0) {
1148		element = stack[--pushed];
1149		goto resume;
1150	}
1151 cleanup:
1152	if (stack != NULL) {
1153		void *ptr;
1154
1155		DE_CONST(stack, ptr);
1156		isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
1157	}
1158	isc_symtab_destroy(&symtab);
1159	*countp = count;
1160	return (result);
1161}
1162
1163static isc_result_t
1164check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
1165	isc_result_t result = ISC_R_SUCCESS;
1166	isc_result_t tresult;
1167	const cfg_listelt_t *element;
1168	const cfg_listelt_t *element2;
1169	dns_fixedname_t fixed;
1170	const char *str;
1171	isc_buffer_t b;
1172
1173	/* Check for "update-policy local;" */
1174	if (cfg_obj_isstring(policy) &&
1175	    strcmp("local", cfg_obj_asstring(policy)) == 0)
1176		return (ISC_R_SUCCESS);
1177
1178	/* Now check the grant policy */
1179	for (element = cfg_list_first(policy);
1180	     element != NULL;
1181	     element = cfg_list_next(element))
1182	{
1183		const cfg_obj_t *stmt = cfg_listelt_value(element);
1184		const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
1185		const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
1186		const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
1187		const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
1188
1189		dns_fixedname_init(&fixed);
1190		str = cfg_obj_asstring(identity);
1191		isc_buffer_init(&b, str, strlen(str));
1192		isc_buffer_add(&b, strlen(str));
1193		tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1194					    dns_rootname, 0, NULL);
1195		if (tresult != ISC_R_SUCCESS) {
1196			cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1197				    "'%s' is not a valid name", str);
1198			result = tresult;
1199		}
1200
1201		if (tresult == ISC_R_SUCCESS &&
1202		    strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) {
1203			dns_fixedname_init(&fixed);
1204			str = cfg_obj_asstring(dname);
1205			isc_buffer_init(&b, str, strlen(str));
1206			isc_buffer_add(&b, strlen(str));
1207			tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
1208						    &b, dns_rootname, 0, NULL);
1209			if (tresult != ISC_R_SUCCESS) {
1210				cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
1211					    "'%s' is not a valid name", str);
1212				result = tresult;
1213			}
1214		}
1215
1216		if (tresult == ISC_R_SUCCESS &&
1217		    strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
1218		    !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
1219			cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1220				    "'%s' is not a wildcard", str);
1221			result = ISC_R_FAILURE;
1222		}
1223
1224		for (element2 = cfg_list_first(typelist);
1225		     element2 != NULL;
1226		     element2 = cfg_list_next(element2))
1227		{
1228			const cfg_obj_t *typeobj;
1229			isc_textregion_t r;
1230			dns_rdatatype_t type;
1231
1232			typeobj = cfg_listelt_value(element2);
1233			DE_CONST(cfg_obj_asstring(typeobj), r.base);
1234			r.length = strlen(r.base);
1235
1236			tresult = dns_rdatatype_fromtext(&type, &r);
1237			if (tresult != ISC_R_SUCCESS) {
1238				cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
1239					    "'%s' is not a valid type", r.base);
1240				result = tresult;
1241			}
1242		}
1243	}
1244	return (result);
1245}
1246
1247#define MASTERZONE	1
1248#define SLAVEZONE	2
1249#define STUBZONE	4
1250#define HINTZONE	8
1251#define FORWARDZONE	16
1252#define DELEGATIONZONE	32
1253#define STATICSTUBZONE	64
1254#define CHECKACL	128
1255
1256typedef struct {
1257	const char *name;
1258	int allowed;
1259} optionstable;
1260
1261static isc_result_t
1262check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
1263	       const cfg_obj_t *config, isc_symtab_t *symtab,
1264	       dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
1265	       isc_log_t *logctx, isc_mem_t *mctx)
1266{
1267	const char *znamestr;
1268	const char *typestr;
1269	unsigned int ztype;
1270	const cfg_obj_t *zoptions;
1271	const cfg_obj_t *obj = NULL;
1272	isc_result_t result = ISC_R_SUCCESS;
1273	isc_result_t tresult;
1274	unsigned int i;
1275	dns_rdataclass_t zclass;
1276	dns_fixedname_t fixedname;
1277	dns_name_t *zname = NULL;
1278	isc_buffer_t b;
1279	isc_boolean_t root = ISC_FALSE;
1280	const cfg_listelt_t *element;
1281
1282	static optionstable options[] = {
1283	{ "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL |
1284	  STATICSTUBZONE },
1285	{ "allow-notify", SLAVEZONE | CHECKACL },
1286	{ "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
1287	{ "notify", MASTERZONE | SLAVEZONE },
1288	{ "also-notify", MASTERZONE | SLAVEZONE },
1289	{ "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
1290	{ "delegation-only", HINTZONE | STUBZONE | DELEGATIONZONE },
1291	{ "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
1292	{ "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
1293	{ "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
1294	{ "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
1295	{ "notify-source", MASTERZONE | SLAVEZONE },
1296	{ "notify-source-v6", MASTERZONE | SLAVEZONE },
1297	{ "transfer-source", SLAVEZONE | STUBZONE },
1298	{ "transfer-source-v6", SLAVEZONE | STUBZONE },
1299	{ "max-transfer-time-in", SLAVEZONE | STUBZONE },
1300	{ "max-transfer-time-out", MASTERZONE | SLAVEZONE },
1301	{ "max-transfer-idle-in", SLAVEZONE | STUBZONE },
1302	{ "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
1303	{ "max-retry-time", SLAVEZONE | STUBZONE },
1304	{ "min-retry-time", SLAVEZONE | STUBZONE },
1305	{ "max-refresh-time", SLAVEZONE | STUBZONE },
1306	{ "min-refresh-time", SLAVEZONE | STUBZONE },
1307	{ "dnssec-secure-to-insecure", MASTERZONE },
1308	{ "sig-validity-interval", MASTERZONE },
1309	{ "sig-re-signing-interval", MASTERZONE },
1310	{ "sig-signing-nodes", MASTERZONE },
1311	{ "sig-signing-type", MASTERZONE },
1312	{ "sig-signing-signatures", MASTERZONE },
1313	{ "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE |
1314	  STATICSTUBZONE},
1315	{ "allow-update", MASTERZONE | CHECKACL },
1316	{ "allow-update-forwarding", SLAVEZONE | CHECKACL },
1317	{ "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1318	{ "journal", MASTERZONE | SLAVEZONE },
1319	{ "ixfr-base", MASTERZONE | SLAVEZONE },
1320	{ "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
1321	{ "masters", SLAVEZONE | STUBZONE },
1322	{ "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
1323	{ "update-policy", MASTERZONE },
1324	{ "database", MASTERZONE | SLAVEZONE | STUBZONE },
1325	{ "key-directory", MASTERZONE },
1326	{ "check-wildcard", MASTERZONE },
1327	{ "check-mx", MASTERZONE },
1328	{ "check-dup-records", MASTERZONE },
1329	{ "integrity-check", MASTERZONE },
1330	{ "check-mx-cname", MASTERZONE },
1331	{ "check-srv-cname", MASTERZONE },
1332	{ "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1333	{ "update-check-ksk", MASTERZONE },
1334	{ "dnssec-dnskey-kskonly", MASTERZONE },
1335	{ "auto-dnssec", MASTERZONE },
1336	{ "try-tcp-refresh", SLAVEZONE },
1337	{ "server-addresses", STATICSTUBZONE },
1338	{ "server-names", STATICSTUBZONE },
1339	};
1340
1341	static optionstable dialups[] = {
1342	{ "notify", MASTERZONE | SLAVEZONE },
1343	{ "notify-passive", SLAVEZONE },
1344	{ "refresh", SLAVEZONE | STUBZONE },
1345	{ "passive", SLAVEZONE | STUBZONE },
1346	};
1347
1348	znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1349
1350	zoptions = cfg_tuple_get(zconfig, "options");
1351
1352	obj = NULL;
1353	(void)cfg_map_get(zoptions, "type", &obj);
1354	if (obj == NULL) {
1355		cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1356			    "zone '%s': type not present", znamestr);
1357		return (ISC_R_FAILURE);
1358	}
1359
1360	typestr = cfg_obj_asstring(obj);
1361	if (strcasecmp(typestr, "master") == 0)
1362		ztype = MASTERZONE;
1363	else if (strcasecmp(typestr, "slave") == 0)
1364		ztype = SLAVEZONE;
1365	else if (strcasecmp(typestr, "stub") == 0)
1366		ztype = STUBZONE;
1367	else if (strcasecmp(typestr, "static-stub") == 0)
1368		ztype = STATICSTUBZONE;
1369	else if (strcasecmp(typestr, "forward") == 0)
1370		ztype = FORWARDZONE;
1371	else if (strcasecmp(typestr, "hint") == 0)
1372		ztype = HINTZONE;
1373	else if (strcasecmp(typestr, "delegation-only") == 0)
1374		ztype = DELEGATIONZONE;
1375	else {
1376		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1377			    "zone '%s': invalid type %s",
1378			    znamestr, typestr);
1379		return (ISC_R_FAILURE);
1380	}
1381
1382	obj = cfg_tuple_get(zconfig, "class");
1383	if (cfg_obj_isstring(obj)) {
1384		isc_textregion_t r;
1385
1386		DE_CONST(cfg_obj_asstring(obj), r.base);
1387		r.length = strlen(r.base);
1388		result = dns_rdataclass_fromtext(&zclass, &r);
1389		if (result != ISC_R_SUCCESS) {
1390			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1391				    "zone '%s': invalid class %s",
1392				    znamestr, r.base);
1393			return (ISC_R_FAILURE);
1394		}
1395		if (zclass != defclass) {
1396			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1397				    "zone '%s': class '%s' does not "
1398				    "match view/default class",
1399				    znamestr, r.base);
1400			return (ISC_R_FAILURE);
1401		}
1402	}
1403
1404	/*
1405	 * Look for an already existing zone.
1406	 * We need to make this canonical as isc_symtab_define()
1407	 * deals with strings.
1408	 */
1409	dns_fixedname_init(&fixedname);
1410	isc_buffer_init(&b, znamestr, strlen(znamestr));
1411	isc_buffer_add(&b, strlen(znamestr));
1412	tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1413				    dns_rootname, DNS_NAME_DOWNCASE, NULL);
1414	if (tresult != ISC_R_SUCCESS) {
1415		cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1416			    "zone '%s': is not a valid name", znamestr);
1417		result = ISC_R_FAILURE;
1418	} else {
1419		char namebuf[DNS_NAME_FORMATSIZE];
1420
1421		zname = dns_fixedname_name(&fixedname);
1422		dns_name_format(zname, namebuf, sizeof(namebuf));
1423		tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
1424				    symtab, "zone '%s': already exists "
1425				    "previous definition: %s:%u", logctx, mctx);
1426		if (tresult != ISC_R_SUCCESS)
1427			result = tresult;
1428		if (dns_name_equal(zname, dns_rootname))
1429			root = ISC_TRUE;
1430	}
1431
1432	/*
1433	 * Look for inappropriate options for the given zone type.
1434	 * Check that ACLs expand correctly.
1435	 */
1436	for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1437		obj = NULL;
1438		if ((options[i].allowed & ztype) == 0 &&
1439		    cfg_map_get(zoptions, options[i].name, &obj) ==
1440		    ISC_R_SUCCESS)
1441		{
1442			if (strcmp(options[i].name, "allow-update") != 0 ||
1443			    ztype != SLAVEZONE) {
1444				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1445					    "option '%s' is not allowed "
1446					    "in '%s' zone '%s'",
1447					    options[i].name, typestr,
1448					    znamestr);
1449					result = ISC_R_FAILURE;
1450			} else
1451				cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1452					    "option '%s' is not allowed "
1453					    "in '%s' zone '%s'",
1454					    options[i].name, typestr,
1455					    znamestr);
1456		}
1457		obj = NULL;
1458		if ((options[i].allowed & ztype) != 0 &&
1459		    (options[i].allowed & CHECKACL) != 0) {
1460
1461			tresult = checkacl(options[i].name, actx, zconfig,
1462					   voptions, config, logctx, mctx);
1463			if (tresult != ISC_R_SUCCESS)
1464				result = tresult;
1465		}
1466
1467	}
1468
1469	/*
1470	 * Slave & stub zones must have a "masters" field.
1471	 */
1472	if (ztype == SLAVEZONE || ztype == STUBZONE) {
1473		obj = NULL;
1474		if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1475			cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1476				    "zone '%s': missing 'masters' entry",
1477				    znamestr);
1478			result = ISC_R_FAILURE;
1479		} else {
1480			isc_uint32_t count;
1481			tresult = validate_masters(obj, config, &count,
1482						   logctx, mctx);
1483			if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1484				result = tresult;
1485			if (tresult == ISC_R_SUCCESS && count == 0) {
1486				cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1487					    "zone '%s': empty 'masters' entry",
1488					    znamestr);
1489				result = ISC_R_FAILURE;
1490			}
1491		}
1492	}
1493
1494	/*
1495	 * Master zones can't have both "allow-update" and "update-policy".
1496	 */
1497	if (ztype == MASTERZONE) {
1498		isc_result_t res1, res2, res3;
1499		const char *arg;
1500		isc_boolean_t ddns;
1501
1502		obj = NULL;
1503		res1 = cfg_map_get(zoptions, "allow-update", &obj);
1504		obj = NULL;
1505		res2 = cfg_map_get(zoptions, "update-policy", &obj);
1506		if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1507			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1508				    "zone '%s': 'allow-update' is ignored "
1509				    "when 'update-policy' is present",
1510				    znamestr);
1511			result = ISC_R_FAILURE;
1512		} else if (res2 == ISC_R_SUCCESS &&
1513			   check_update_policy(obj, logctx) != ISC_R_SUCCESS)
1514			result = ISC_R_FAILURE;
1515		ddns = ISC_TF(res1 == ISC_R_SUCCESS || res2 == ISC_R_SUCCESS);
1516
1517		obj = NULL;
1518		arg = "off";
1519		res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
1520		if (res3 == ISC_R_SUCCESS)
1521			arg = cfg_obj_asstring(obj);
1522		if (strcasecmp(arg, "off") != 0 && !ddns) {
1523			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1524				    "'auto-dnssec %s;' requires "
1525				    "dynamic DNS to be configured in the zone",
1526				    arg);
1527			result = ISC_R_FAILURE;
1528		}
1529		if (strcasecmp(arg, "create") == 0) {
1530			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1531				    "'auto-dnssec create;' is not "
1532				    "yet implemented");
1533			result = ISC_R_FAILURE;
1534		}
1535
1536		obj = NULL;
1537		res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
1538		if (res1 == ISC_R_SUCCESS) {
1539			isc_uint32_t type = cfg_obj_asuint32(obj);
1540			if (type < 0xff00U || type > 0xffffU)
1541				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1542					    "sig-signing-type: %u out of "
1543					    "range [%u..%u]", type,
1544					    0xff00U, 0xffffU);
1545			result = ISC_R_FAILURE;
1546		}
1547	}
1548
1549	/*
1550	 * Check the excessively complicated "dialup" option.
1551	 */
1552	if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1553		const cfg_obj_t *dialup = NULL;
1554		(void)cfg_map_get(zoptions, "dialup", &dialup);
1555		if (dialup != NULL && cfg_obj_isstring(dialup)) {
1556			const char *str = cfg_obj_asstring(dialup);
1557			for (i = 0;
1558			     i < sizeof(dialups) / sizeof(dialups[0]);
1559			     i++)
1560			{
1561				if (strcasecmp(dialups[i].name, str) != 0)
1562					continue;
1563				if ((dialups[i].allowed & ztype) == 0) {
1564					cfg_obj_log(obj, logctx,
1565						    ISC_LOG_ERROR,
1566						    "dialup type '%s' is not "
1567						    "allowed in '%s' "
1568						    "zone '%s'",
1569						    str, typestr, znamestr);
1570					result = ISC_R_FAILURE;
1571				}
1572				break;
1573			}
1574			if (i == sizeof(dialups) / sizeof(dialups[0])) {
1575				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1576					    "invalid dialup type '%s' in zone "
1577					    "'%s'", str, znamestr);
1578				result = ISC_R_FAILURE;
1579			}
1580		}
1581	}
1582
1583	/*
1584	 * Check that forwarding is reasonable.
1585	 */
1586	obj = NULL;
1587	if (root) {
1588		if (voptions != NULL)
1589			(void)cfg_map_get(voptions, "forwarders", &obj);
1590		if (obj == NULL) {
1591			const cfg_obj_t *options = NULL;
1592			(void)cfg_map_get(config, "options", &options);
1593			if (options != NULL)
1594				(void)cfg_map_get(options, "forwarders", &obj);
1595		}
1596	}
1597	if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
1598		result = ISC_R_FAILURE;
1599
1600	/*
1601	 * Check validity of static stub server addresses.
1602	 */
1603	obj = NULL;
1604	(void)cfg_map_get(zoptions, "server-addresses", &obj);
1605	if (ztype == STATICSTUBZONE && obj != NULL) {
1606		for (element = cfg_list_first(obj);
1607		     element != NULL;
1608		     element = cfg_list_next(element))
1609		{
1610			isc_sockaddr_t sa;
1611			isc_netaddr_t na;
1612			obj = cfg_listelt_value(element);
1613			sa = *cfg_obj_assockaddr(obj);
1614
1615			if (isc_sockaddr_getport(&sa) != 0) {
1616				result = ISC_R_FAILURE;
1617				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1618					    "port is not configurable for "
1619					    "static stub server-addresses");
1620			}
1621
1622			isc_netaddr_fromsockaddr(&na, &sa);
1623			if (isc_netaddr_getzone(&na) != 0) {
1624				result = ISC_R_FAILURE;
1625				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1626					    "scoped address is not allowed "
1627					    "for static stub "
1628					    "server-addresses");
1629			}
1630		}
1631	}
1632
1633	/*
1634	 * Check validity of static stub server names.
1635	 */
1636	obj = NULL;
1637	(void)cfg_map_get(zoptions, "server-names", &obj);
1638	if (zname != NULL && ztype == STATICSTUBZONE && obj != NULL) {
1639		for (element = cfg_list_first(obj);
1640		     element != NULL;
1641		     element = cfg_list_next(element))
1642		{
1643			const char *snamestr;
1644			dns_fixedname_t fixed_sname;
1645			isc_buffer_t b2;
1646			dns_name_t *sname;
1647
1648			obj = cfg_listelt_value(element);
1649			snamestr = cfg_obj_asstring(obj);
1650
1651			dns_fixedname_init(&fixed_sname);
1652			isc_buffer_init(&b2, snamestr, strlen(snamestr));
1653			isc_buffer_add(&b2, strlen(snamestr));
1654			sname = dns_fixedname_name(&fixed_sname);
1655			tresult = dns_name_fromtext(sname, &b2, dns_rootname,
1656						    0, NULL);
1657			if (tresult != ISC_R_SUCCESS) {
1658				cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1659					    "server-name '%s' is not a valid "
1660					    "name", snamestr);
1661				result = ISC_R_FAILURE;
1662			} else if (dns_name_issubdomain(sname, zname)) {
1663				cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1664					    "server-name '%s' must not be a "
1665					    "subdomain of zone name '%s'",
1666					    snamestr, znamestr);
1667				result = ISC_R_FAILURE;
1668			}
1669		}
1670	}
1671
1672	/*
1673	 * Check various options.
1674	 */
1675	tresult = check_options(zoptions, logctx, mctx, optlevel_zone);
1676	if (tresult != ISC_R_SUCCESS)
1677		result = tresult;
1678
1679	/*
1680	 * If the zone type is rbt/rbt64 then master/hint zones
1681	 * require file clauses.
1682	 */
1683	obj = NULL;
1684	tresult = cfg_map_get(zoptions, "database", &obj);
1685	if (tresult == ISC_R_NOTFOUND ||
1686	    (tresult == ISC_R_SUCCESS &&
1687	     (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1688	      strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
1689		obj = NULL;
1690		tresult = cfg_map_get(zoptions, "file", &obj);
1691		if (tresult != ISC_R_SUCCESS &&
1692		    (ztype == MASTERZONE || ztype == HINTZONE)) {
1693			cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1694				    "zone '%s': missing 'file' entry",
1695				    znamestr);
1696			result = tresult;
1697		}
1698	}
1699
1700	return (result);
1701}
1702
1703
1704typedef struct keyalgorithms {
1705	const char *name;
1706	isc_uint16_t size;
1707} algorithmtable;
1708
1709isc_result_t
1710bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1711	const cfg_obj_t *algobj = NULL;
1712	const cfg_obj_t *secretobj = NULL;
1713	const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1714	const char *algorithm;
1715	int i;
1716	size_t len = 0;
1717	isc_result_t result;
1718	isc_buffer_t buf;
1719	unsigned char secretbuf[1024];
1720	static const algorithmtable algorithms[] = {
1721		{ "hmac-md5", 128 },
1722		{ "hmac-md5.sig-alg.reg.int", 0 },
1723		{ "hmac-md5.sig-alg.reg.int.", 0 },
1724		{ "hmac-sha1", 160 },
1725		{ "hmac-sha224", 224 },
1726		{ "hmac-sha256", 256 },
1727		{ "hmac-sha384", 384 },
1728		{ "hmac-sha512", 512 },
1729		{  NULL, 0 }
1730	};
1731
1732	(void)cfg_map_get(key, "algorithm", &algobj);
1733	(void)cfg_map_get(key, "secret", &secretobj);
1734	if (secretobj == NULL || algobj == NULL) {
1735		cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1736			    "key '%s' must have both 'secret' and "
1737			    "'algorithm' defined",
1738			    keyname);
1739		return (ISC_R_FAILURE);
1740	}
1741
1742	isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
1743	result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
1744	if (result != ISC_R_SUCCESS) {
1745		cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
1746			    "bad secret '%s'", isc_result_totext(result));
1747		return (result);
1748	}
1749
1750	algorithm = cfg_obj_asstring(algobj);
1751	for (i = 0; algorithms[i].name != NULL; i++) {
1752		len = strlen(algorithms[i].name);
1753		if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1754		    (algorithm[len] == '\0' ||
1755		     (algorithms[i].size != 0 && algorithm[len] == '-')))
1756			break;
1757	}
1758	if (algorithms[i].name == NULL) {
1759		cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1760			    "unknown algorithm '%s'", algorithm);
1761		return (ISC_R_NOTFOUND);
1762	}
1763	if (algorithm[len] == '-') {
1764		isc_uint16_t digestbits;
1765		isc_result_t result;
1766		result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1767		if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1768			if (result == ISC_R_RANGE ||
1769			    digestbits > algorithms[i].size) {
1770				cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1771					    "key '%s' digest-bits too large "
1772					    "[%u..%u]", keyname,
1773					    algorithms[i].size / 2,
1774					    algorithms[i].size);
1775				return (ISC_R_RANGE);
1776			}
1777			if ((digestbits % 8) != 0) {
1778				cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1779					    "key '%s' digest-bits not multiple"
1780					    " of 8", keyname);
1781				return (ISC_R_RANGE);
1782			}
1783			/*
1784			 * Recommended minima for hmac algorithms.
1785			 */
1786			if ((di

Large files files are truncated, but you can click here to view the full file