PageRenderTime 108ms CodeModel.GetById 22ms app.highlight 75ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/bind9/bin/named/zoneconf.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1500 lines | 1200 code | 165 blank | 135 comment | 500 complexity | 6995061632f144c357c2e2c9d3946a7a MD5 | raw file
   1/*
   2 * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
   3 * Copyright (C) 1999-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: zoneconf.c,v 1.170.14.7 2012/01/31 23:46:39 tbox Exp $ */
  19
  20/*% */
  21
  22#include <config.h>
  23
  24#include <isc/buffer.h>
  25#include <isc/file.h>
  26#include <isc/mem.h>
  27#include <isc/print.h>
  28#include <isc/stats.h>
  29#include <isc/string.h>		/* Required for HP/UX (and others?) */
  30#include <isc/util.h>
  31
  32#include <dns/acl.h>
  33#include <dns/db.h>
  34#include <dns/fixedname.h>
  35#include <dns/log.h>
  36#include <dns/name.h>
  37#include <dns/rdata.h>
  38#include <dns/rdatatype.h>
  39#include <dns/rdataset.h>
  40#include <dns/rdatalist.h>
  41#include <dns/result.h>
  42#include <dns/sdlz.h>
  43#include <dns/ssu.h>
  44#include <dns/stats.h>
  45#include <dns/view.h>
  46#include <dns/zone.h>
  47
  48#include <named/client.h>
  49#include <named/config.h>
  50#include <named/globals.h>
  51#include <named/log.h>
  52#include <named/server.h>
  53#include <named/zoneconf.h>
  54
  55/* ACLs associated with zone */
  56typedef enum {
  57	allow_notify,
  58	allow_query,
  59	allow_transfer,
  60	allow_update,
  61	allow_update_forwarding
  62} acl_type_t;
  63
  64#define RETERR(x) do { \
  65	isc_result_t _r = (x); \
  66	if (_r != ISC_R_SUCCESS) \
  67		return (_r); \
  68	} while (0)
  69
  70#define CHECK(x) do { \
  71	result = (x); \
  72	if (result != ISC_R_SUCCESS) \
  73		goto cleanup; \
  74	} while (0)
  75
  76/*%
  77 * Convenience function for configuring a single zone ACL.
  78 */
  79static isc_result_t
  80configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
  81		   const cfg_obj_t *config, acl_type_t acltype,
  82		   cfg_aclconfctx_t *actx, dns_zone_t *zone,
  83		   void (*setzacl)(dns_zone_t *, dns_acl_t *),
  84		   void (*clearzacl)(dns_zone_t *))
  85{
  86	isc_result_t result;
  87	const cfg_obj_t *maps[5] = {NULL, NULL, NULL, NULL, NULL};
  88	const cfg_obj_t *aclobj = NULL;
  89	int i = 0;
  90	dns_acl_t **aclp = NULL, *acl = NULL;
  91	const char *aclname;
  92	dns_view_t *view;
  93
  94	view = dns_zone_getview(zone);
  95
  96	switch (acltype) {
  97	    case allow_notify:
  98		if (view != NULL)
  99			aclp = &view->notifyacl;
 100		aclname = "allow-notify";
 101		break;
 102	    case allow_query:
 103		if (view != NULL)
 104			aclp = &view->queryacl;
 105		aclname = "allow-query";
 106		break;
 107	    case allow_transfer:
 108		if (view != NULL)
 109			aclp = &view->transferacl;
 110		aclname = "allow-transfer";
 111		break;
 112	    case allow_update:
 113		if (view != NULL)
 114			aclp = &view->updateacl;
 115		aclname = "allow-update";
 116		break;
 117	    case allow_update_forwarding:
 118		if (view != NULL)
 119			aclp = &view->upfwdacl;
 120		aclname = "allow-update-forwarding";
 121		break;
 122	    default:
 123		INSIST(0);
 124		return (ISC_R_FAILURE);
 125	}
 126
 127	/* First check to see if ACL is defined within the zone */
 128	if (zconfig != NULL) {
 129		maps[0] = cfg_tuple_get(zconfig, "options");
 130		(void)ns_config_get(maps, aclname, &aclobj);
 131		if (aclobj != NULL) {
 132			aclp = NULL;
 133			goto parse_acl;
 134		}
 135	}
 136
 137	/* Failing that, see if there's a default ACL already in the view */
 138	if (aclp != NULL && *aclp != NULL) {
 139		(*setzacl)(zone, *aclp);
 140		return (ISC_R_SUCCESS);
 141	}
 142
 143	/* Check for default ACLs that haven't been parsed yet */
 144	if (vconfig != NULL) {
 145		const cfg_obj_t *options = cfg_tuple_get(vconfig, "options");
 146		if (options != NULL)
 147			maps[i++] = options;
 148	}
 149	if (config != NULL) {
 150		const cfg_obj_t *options = NULL;
 151		(void)cfg_map_get(config, "options", &options);
 152		if (options != NULL)
 153			maps[i++] = options;
 154	}
 155	maps[i++] = ns_g_defaults;
 156	maps[i] = NULL;
 157
 158	(void)ns_config_get(maps, aclname, &aclobj);
 159	if (aclobj == NULL) {
 160		(*clearzacl)(zone);
 161		return (ISC_R_SUCCESS);
 162	}
 163
 164parse_acl:
 165	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, actx,
 166				    dns_zone_getmctx(zone), 0, &acl);
 167	if (result != ISC_R_SUCCESS)
 168		return (result);
 169	(*setzacl)(zone, acl);
 170
 171	/* Set the view default now */
 172	if (aclp != NULL)
 173		dns_acl_attach(acl, aclp);
 174
 175	dns_acl_detach(&acl);
 176	return (ISC_R_SUCCESS);
 177}
 178
 179/*%
 180 * Parse the zone update-policy statement.
 181 */
 182static isc_result_t
 183configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
 184			const char *zname)
 185{
 186	const cfg_obj_t *updatepolicy = NULL;
 187	const cfg_listelt_t *element, *element2;
 188	dns_ssutable_t *table = NULL;
 189	isc_mem_t *mctx = dns_zone_getmctx(zone);
 190	isc_boolean_t autoddns = ISC_FALSE;
 191	isc_result_t result;
 192
 193	(void)cfg_map_get(zconfig, "update-policy", &updatepolicy);
 194
 195	if (updatepolicy == NULL) {
 196		dns_zone_setssutable(zone, NULL);
 197		return (ISC_R_SUCCESS);
 198	}
 199
 200	if (cfg_obj_isstring(updatepolicy) &&
 201	    strcmp("local", cfg_obj_asstring(updatepolicy)) == 0) {
 202		autoddns = ISC_TRUE;
 203		updatepolicy = NULL;
 204	}
 205
 206	result = dns_ssutable_create(mctx, &table);
 207	if (result != ISC_R_SUCCESS)
 208		return (result);
 209
 210	for (element = cfg_list_first(updatepolicy);
 211	     element != NULL;
 212	     element = cfg_list_next(element))
 213	{
 214		const cfg_obj_t *stmt = cfg_listelt_value(element);
 215		const cfg_obj_t *mode = cfg_tuple_get(stmt, "mode");
 216		const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
 217		const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
 218		const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
 219		const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
 220		const char *str;
 221		isc_boolean_t grant = ISC_FALSE;
 222		isc_boolean_t usezone = ISC_FALSE;
 223		unsigned int mtype = DNS_SSUMATCHTYPE_NAME;
 224		dns_fixedname_t fname, fident;
 225		isc_buffer_t b;
 226		dns_rdatatype_t *types;
 227		unsigned int i, n;
 228
 229		str = cfg_obj_asstring(mode);
 230		if (strcasecmp(str, "grant") == 0)
 231			grant = ISC_TRUE;
 232		else if (strcasecmp(str, "deny") == 0)
 233			grant = ISC_FALSE;
 234		else
 235			INSIST(0);
 236
 237		str = cfg_obj_asstring(matchtype);
 238		if (strcasecmp(str, "name") == 0)
 239			mtype = DNS_SSUMATCHTYPE_NAME;
 240		else if (strcasecmp(str, "subdomain") == 0)
 241			mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
 242		else if (strcasecmp(str, "wildcard") == 0)
 243			mtype = DNS_SSUMATCHTYPE_WILDCARD;
 244		else if (strcasecmp(str, "self") == 0)
 245			mtype = DNS_SSUMATCHTYPE_SELF;
 246		else if (strcasecmp(str, "selfsub") == 0)
 247			mtype = DNS_SSUMATCHTYPE_SELFSUB;
 248		else if (strcasecmp(str, "selfwild") == 0)
 249			mtype = DNS_SSUMATCHTYPE_SELFWILD;
 250		else if (strcasecmp(str, "ms-self") == 0)
 251			mtype = DNS_SSUMATCHTYPE_SELFMS;
 252		else if (strcasecmp(str, "krb5-self") == 0)
 253			mtype = DNS_SSUMATCHTYPE_SELFKRB5;
 254		else if (strcasecmp(str, "ms-subdomain") == 0)
 255			mtype = DNS_SSUMATCHTYPE_SUBDOMAINMS;
 256		else if (strcasecmp(str, "krb5-subdomain") == 0)
 257			mtype = DNS_SSUMATCHTYPE_SUBDOMAINKRB5;
 258		else if (strcasecmp(str, "tcp-self") == 0)
 259			mtype = DNS_SSUMATCHTYPE_TCPSELF;
 260		else if (strcasecmp(str, "6to4-self") == 0)
 261			mtype = DNS_SSUMATCHTYPE_6TO4SELF;
 262		else if (strcasecmp(str, "zonesub") == 0) {
 263			mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
 264			usezone = ISC_TRUE;
 265		} else if (strcasecmp(str, "external") == 0)
 266			mtype = DNS_SSUMATCHTYPE_EXTERNAL;
 267		else
 268			INSIST(0);
 269
 270		dns_fixedname_init(&fident);
 271		str = cfg_obj_asstring(identity);
 272		isc_buffer_init(&b, str, strlen(str));
 273		isc_buffer_add(&b, strlen(str));
 274		result = dns_name_fromtext(dns_fixedname_name(&fident), &b,
 275					   dns_rootname, 0, NULL);
 276		if (result != ISC_R_SUCCESS) {
 277			cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
 278				    "'%s' is not a valid name", str);
 279			goto cleanup;
 280		}
 281
 282		dns_fixedname_init(&fname);
 283		if (usezone) {
 284			result = dns_name_copy(dns_zone_getorigin(zone),
 285					       dns_fixedname_name(&fname),
 286					       NULL);
 287			if (result != ISC_R_SUCCESS) {
 288				cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
 289					    "error copying origin: %s",
 290					    isc_result_totext(result));
 291				goto cleanup;
 292			}
 293		} else {
 294			str = cfg_obj_asstring(dname);
 295			isc_buffer_init(&b, str, strlen(str));
 296			isc_buffer_add(&b, strlen(str));
 297			result = dns_name_fromtext(dns_fixedname_name(&fname),
 298						   &b, dns_rootname, 0, NULL);
 299			if (result != ISC_R_SUCCESS) {
 300				cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
 301					    "'%s' is not a valid name", str);
 302				goto cleanup;
 303			}
 304		}
 305
 306		n = ns_config_listcount(typelist);
 307		if (n == 0)
 308			types = NULL;
 309		else {
 310			types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t));
 311			if (types == NULL) {
 312				result = ISC_R_NOMEMORY;
 313				goto cleanup;
 314			}
 315		}
 316
 317		i = 0;
 318		for (element2 = cfg_list_first(typelist);
 319		     element2 != NULL;
 320		     element2 = cfg_list_next(element2))
 321		{
 322			const cfg_obj_t *typeobj;
 323			isc_textregion_t r;
 324
 325			INSIST(i < n);
 326
 327			typeobj = cfg_listelt_value(element2);
 328			str = cfg_obj_asstring(typeobj);
 329			DE_CONST(str, r.base);
 330			r.length = strlen(str);
 331
 332			result = dns_rdatatype_fromtext(&types[i++], &r);
 333			if (result != ISC_R_SUCCESS) {
 334				cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
 335					    "'%s' is not a valid type", str);
 336				isc_mem_put(mctx, types,
 337					    n * sizeof(dns_rdatatype_t));
 338				goto cleanup;
 339			}
 340		}
 341		INSIST(i == n);
 342
 343		result = dns_ssutable_addrule(table, grant,
 344					      dns_fixedname_name(&fident),
 345					      mtype,
 346					      dns_fixedname_name(&fname),
 347					      n, types);
 348		if (types != NULL)
 349			isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t));
 350		if (result != ISC_R_SUCCESS) {
 351			goto cleanup;
 352		}
 353	}
 354
 355	/*
 356	 * If "update-policy local;" and a session key exists,
 357	 * then use the default policy, which is equivalent to:
 358	 * update-policy { grant <session-keyname> zonesub any; };
 359	 */
 360	if (autoddns) {
 361		dns_rdatatype_t any = dns_rdatatype_any;
 362
 363		if (ns_g_server->session_keyname == NULL) {
 364			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 365				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
 366				      "failed to enable auto DDNS policy "
 367				      "for zone %s: session key not found",
 368				      zname);
 369			result = ISC_R_NOTFOUND;
 370			goto cleanup;
 371		}
 372
 373		result = dns_ssutable_addrule(table, ISC_TRUE,
 374					      ns_g_server->session_keyname,
 375					      DNS_SSUMATCHTYPE_SUBDOMAIN,
 376					      dns_zone_getorigin(zone),
 377					      1, &any);
 378
 379		if (result != ISC_R_SUCCESS)
 380			goto cleanup;
 381	}
 382
 383	result = ISC_R_SUCCESS;
 384	dns_zone_setssutable(zone, table);
 385
 386 cleanup:
 387	dns_ssutable_detach(&table);
 388	return (result);
 389}
 390
 391/*
 392 * This is the TTL used for internally generated RRsets for static-stub zones.
 393 * The value doesn't matter because the mapping is static, but needs to be
 394 * defined for the sake of implementation.
 395 */
 396#define STATICSTUB_SERVER_TTL 86400
 397
 398/*%
 399 * Configure an apex NS with glues for a static-stub zone.
 400 * For example, for the zone named "example.com", the following RRs will be
 401 * added to the zone DB:
 402 * example.com. NS example.com.
 403 * example.com. A 192.0.2.1
 404 * example.com. AAAA 2001:db8::1
 405 */
 406static isc_result_t
 407configure_staticstub_serveraddrs(const cfg_obj_t *zconfig, dns_zone_t *zone,
 408				 dns_rdatalist_t *rdatalist_ns,
 409				 dns_rdatalist_t *rdatalist_a,
 410				 dns_rdatalist_t *rdatalist_aaaa)
 411{
 412	const cfg_listelt_t *element;
 413	isc_mem_t *mctx = dns_zone_getmctx(zone);
 414	isc_region_t region, sregion;
 415	dns_rdata_t *rdata;
 416	isc_result_t result = ISC_R_SUCCESS;
 417
 418	for (element = cfg_list_first(zconfig);
 419	     element != NULL;
 420	     element = cfg_list_next(element))
 421	{
 422		const isc_sockaddr_t* sa;
 423		isc_netaddr_t na;
 424		const cfg_obj_t *address = cfg_listelt_value(element);
 425		dns_rdatalist_t *rdatalist;
 426
 427		sa = cfg_obj_assockaddr(address);
 428		if (isc_sockaddr_getport(sa) != 0) {
 429			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
 430				    "port is not configurable for "
 431				    "static stub server-addresses");
 432			return (ISC_R_FAILURE);
 433		}
 434		isc_netaddr_fromsockaddr(&na, sa);
 435		if (isc_netaddr_getzone(&na) != 0) {
 436			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
 437					    "scoped address is not allowed "
 438					    "for static stub "
 439					    "server-addresses");
 440			return (ISC_R_FAILURE);
 441		}
 442
 443		switch (na.family) {
 444		case AF_INET:
 445			region.length = sizeof(na.type.in);
 446			rdatalist = rdatalist_a;
 447			break;
 448		default:
 449			INSIST(na.family == AF_INET6);
 450			region.length = sizeof(na.type.in6);
 451			rdatalist = rdatalist_aaaa;
 452			break;
 453		}
 454
 455		rdata = isc_mem_get(mctx, sizeof(*rdata) + region.length);
 456		if (rdata == NULL)
 457			return (ISC_R_NOMEMORY);
 458		region.base = (unsigned char *)(rdata + 1);
 459		memcpy(region.base, &na.type, region.length);
 460		dns_rdata_init(rdata);
 461		dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
 462				     rdatalist->type, &region);
 463		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
 464	}
 465
 466	/*
 467	 * If no address is specified (unlikely in this context, but possible),
 468	 * there's nothing to do anymore.
 469	 */
 470	if (ISC_LIST_EMPTY(rdatalist_a->rdata) &&
 471	    ISC_LIST_EMPTY(rdatalist_aaaa->rdata)) {
 472		return (ISC_R_SUCCESS);
 473	}
 474
 475	/* Add to the list an apex NS with the ns name being the origin name */
 476	dns_name_toregion(dns_zone_getorigin(zone), &sregion);
 477	rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length);
 478	if (rdata == NULL) {
 479		/*
 480		 * Already allocated data will be freed in the caller, so
 481		 * we can simply return here.
 482		 */
 483		return (ISC_R_NOMEMORY);
 484	}
 485	region.length = sregion.length;
 486	region.base = (unsigned char *)(rdata + 1);
 487	memcpy(region.base, sregion.base, region.length);
 488	dns_rdata_init(rdata);
 489	dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
 490			     dns_rdatatype_ns, &region);
 491	ISC_LIST_APPEND(rdatalist_ns->rdata, rdata, link);
 492
 493	return (result);
 494}
 495
 496/*%
 497 * Configure an apex NS with an out-of-zone NS names for a static-stub zone.
 498 * For example, for the zone named "example.com", something like the following
 499 * RRs will be added to the zone DB:
 500 * example.com. NS ns.example.net.
 501 */
 502static isc_result_t
 503configure_staticstub_servernames(const cfg_obj_t *zconfig, dns_zone_t *zone,
 504				 dns_rdatalist_t *rdatalist, const char *zname)
 505{
 506	const cfg_listelt_t *element;
 507	isc_mem_t *mctx = dns_zone_getmctx(zone);
 508	dns_rdata_t *rdata;
 509	isc_region_t sregion, region;
 510	isc_result_t result = ISC_R_SUCCESS;
 511
 512	for (element = cfg_list_first(zconfig);
 513	     element != NULL;
 514	     element = cfg_list_next(element))
 515	{
 516		const cfg_obj_t *obj;
 517		const char *str;
 518		dns_fixedname_t fixed_name;
 519		dns_name_t *nsname;
 520		isc_buffer_t b;
 521
 522		obj = cfg_listelt_value(element);
 523		str = cfg_obj_asstring(obj);
 524
 525		dns_fixedname_init(&fixed_name);
 526		nsname = dns_fixedname_name(&fixed_name);
 527
 528		isc_buffer_init(&b, str, strlen(str));
 529		isc_buffer_add(&b, strlen(str));
 530		result = dns_name_fromtext(nsname, &b, dns_rootname, 0, NULL);
 531		if (result != ISC_R_SUCCESS) {
 532			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
 533					    "server-name '%s' is not a valid "
 534					    "name", str);
 535			return (result);
 536		}
 537		if (dns_name_issubdomain(nsname, dns_zone_getorigin(zone))) {
 538			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
 539				    "server-name '%s' must not be a "
 540				    "subdomain of zone name '%s'",
 541				    str, zname);
 542			return (ISC_R_FAILURE);
 543		}
 544
 545		dns_name_toregion(nsname, &sregion);
 546		rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length);
 547		if (rdata == NULL)
 548			return (ISC_R_NOMEMORY);
 549		region.length = sregion.length;
 550		region.base = (unsigned char *)(rdata + 1);
 551		memcpy(region.base, sregion.base, region.length);
 552		dns_rdata_init(rdata);
 553		dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
 554				     dns_rdatatype_ns, &region);
 555		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
 556	}
 557
 558	return (result);
 559}
 560
 561/*%
 562 * Configure static-stub zone.
 563 */
 564static isc_result_t
 565configure_staticstub(const cfg_obj_t *zconfig, dns_zone_t *zone,
 566		     const char *zname, const char *dbtype)
 567{
 568	int i = 0;
 569	const cfg_obj_t *obj;
 570	isc_mem_t *mctx = dns_zone_getmctx(zone);
 571	dns_db_t *db = NULL;
 572	dns_dbversion_t *dbversion = NULL;
 573	dns_dbnode_t *apexnode = NULL;
 574	dns_name_t apexname;
 575	isc_result_t result;
 576	dns_rdataset_t rdataset;
 577	dns_rdatalist_t rdatalist_ns, rdatalist_a, rdatalist_aaaa;
 578	dns_rdatalist_t* rdatalists[] = {
 579		&rdatalist_ns, &rdatalist_a, &rdatalist_aaaa, NULL
 580	};
 581	dns_rdata_t *rdata;
 582	isc_region_t region;
 583
 584	/* Create the DB beforehand */
 585	RETERR(dns_db_create(mctx, dbtype, dns_zone_getorigin(zone),
 586			     dns_dbtype_stub, dns_zone_getclass(zone),
 587			     0, NULL, &db));
 588	dns_zone_setdb(zone, db);
 589
 590	dns_rdatalist_init(&rdatalist_ns);
 591	rdatalist_ns.rdclass = dns_zone_getclass(zone);
 592	rdatalist_ns.type = dns_rdatatype_ns;
 593	rdatalist_ns.ttl = STATICSTUB_SERVER_TTL;
 594
 595	dns_rdatalist_init(&rdatalist_a);
 596	rdatalist_a.rdclass = dns_zone_getclass(zone);
 597	rdatalist_a.type = dns_rdatatype_a;
 598	rdatalist_a.ttl = STATICSTUB_SERVER_TTL;
 599
 600	dns_rdatalist_init(&rdatalist_aaaa);
 601	rdatalist_aaaa.rdclass = dns_zone_getclass(zone);
 602	rdatalist_aaaa.type = dns_rdatatype_aaaa;
 603	rdatalist_aaaa.ttl = STATICSTUB_SERVER_TTL;
 604
 605	/* Prepare zone RRs from the configuration */
 606	obj = NULL;
 607	result = cfg_map_get(zconfig, "server-addresses", &obj);
 608	if (result == ISC_R_SUCCESS) {
 609		INSIST(obj != NULL);
 610		result = configure_staticstub_serveraddrs(obj, zone,
 611							  &rdatalist_ns,
 612							  &rdatalist_a,
 613							  &rdatalist_aaaa);
 614		if (result != ISC_R_SUCCESS)
 615			goto cleanup;
 616	}
 617
 618	obj = NULL;
 619	result = cfg_map_get(zconfig, "server-names", &obj);
 620	if (result == ISC_R_SUCCESS) {
 621		INSIST(obj != NULL);
 622		result = configure_staticstub_servernames(obj, zone,
 623							  &rdatalist_ns,
 624							  zname);
 625		if (result != ISC_R_SUCCESS)
 626			goto cleanup;
 627	}
 628
 629	/*
 630	 * Sanity check: there should be at least one NS RR at the zone apex
 631	 * to trigger delegation.
 632	 */
 633	if (ISC_LIST_EMPTY(rdatalist_ns.rdata)) {
 634		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 635			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
 636			      "No NS record is configured for a "
 637			      "static-stub zone '%s'", zname);
 638		result = ISC_R_FAILURE;
 639		goto cleanup;
 640	}
 641
 642	/*
 643	 * Now add NS and glue A/AAAA RRsets to the zone DB.
 644	 * First open a new version for the add operation and get a pointer
 645	 * to the apex node (all RRs are of the apex name).
 646	 */
 647	result = dns_db_newversion(db, &dbversion);
 648	if (result != ISC_R_SUCCESS)
 649		goto cleanup;
 650	dns_name_init(&apexname, NULL);
 651	dns_name_clone(dns_zone_getorigin(zone), &apexname);
 652	result = dns_db_findnode(db, &apexname, ISC_FALSE, &apexnode);
 653	if (result != ISC_R_SUCCESS)
 654		goto cleanup;
 655
 656	/* Add NS RRset */
 657	dns_rdataset_init(&rdataset);
 658	RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_ns, &rdataset)
 659		      == ISC_R_SUCCESS);
 660	result = dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset,
 661				    0, NULL);
 662	dns_rdataset_disassociate(&rdataset);
 663	if (result != ISC_R_SUCCESS)
 664		goto cleanup;
 665
 666	/* Add glue A RRset, if any */
 667	if (!ISC_LIST_EMPTY(rdatalist_a.rdata)) {
 668		RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_a, &rdataset)
 669			      == ISC_R_SUCCESS);
 670		result = dns_db_addrdataset(db, apexnode, dbversion, 0,
 671					    &rdataset, 0, NULL);
 672		dns_rdataset_disassociate(&rdataset);
 673		if (result != ISC_R_SUCCESS)
 674			goto cleanup;
 675	}
 676
 677	/* Add glue AAAA RRset, if any */
 678	if (!ISC_LIST_EMPTY(rdatalist_aaaa.rdata)) {
 679		RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_aaaa,
 680						       &rdataset)
 681			      == ISC_R_SUCCESS);
 682		result = dns_db_addrdataset(db, apexnode, dbversion, 0,
 683					    &rdataset, 0, NULL);
 684		dns_rdataset_disassociate(&rdataset);
 685		if (result != ISC_R_SUCCESS)
 686			goto cleanup;
 687	}
 688
 689	result = ISC_R_SUCCESS;
 690
 691  cleanup:
 692	if (apexnode != NULL)
 693		dns_db_detachnode(db, &apexnode);
 694	if (dbversion != NULL)
 695		dns_db_closeversion(db, &dbversion, ISC_TRUE);
 696	if (db != NULL)
 697		dns_db_detach(&db);
 698	for (i = 0; rdatalists[i] != NULL; i++) {
 699		while ((rdata = ISC_LIST_HEAD(rdatalists[i]->rdata)) != NULL) {
 700			ISC_LIST_UNLINK(rdatalists[i]->rdata, rdata, link);
 701			dns_rdata_toregion(rdata, &region);
 702			isc_mem_put(mctx, rdata,
 703				    sizeof(*rdata) + region.length);
 704		}
 705	}
 706
 707	return (result);
 708}
 709
 710/*%
 711 * Convert a config file zone type into a server zone type.
 712 */
 713static inline dns_zonetype_t
 714zonetype_fromconfig(const cfg_obj_t *map) {
 715	const cfg_obj_t *obj = NULL;
 716	isc_result_t result;
 717
 718	result = cfg_map_get(map, "type", &obj);
 719	INSIST(result == ISC_R_SUCCESS && obj != NULL);
 720	return (ns_config_getzonetype(obj));
 721}
 722
 723/*%
 724 * Helper function for strtoargv().  Pardon the gratuitous recursion.
 725 */
 726static isc_result_t
 727strtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp,
 728	     char ***argvp, unsigned int n)
 729{
 730	isc_result_t result;
 731
 732	/* Discard leading whitespace. */
 733	while (*s == ' ' || *s == '\t')
 734		s++;
 735
 736	if (*s == '\0') {
 737		/* We have reached the end of the string. */
 738		*argcp = n;
 739		*argvp = isc_mem_get(mctx, n * sizeof(char *));
 740		if (*argvp == NULL)
 741			return (ISC_R_NOMEMORY);
 742	} else {
 743		char *p = s;
 744		while (*p != ' ' && *p != '\t' && *p != '\0')
 745			p++;
 746		if (*p != '\0')
 747			*p++ = '\0';
 748
 749		result = strtoargvsub(mctx, p, argcp, argvp, n + 1);
 750		if (result != ISC_R_SUCCESS)
 751			return (result);
 752		(*argvp)[n] = s;
 753	}
 754	return (ISC_R_SUCCESS);
 755}
 756
 757/*%
 758 * Tokenize the string "s" into whitespace-separated words,
 759 * return the number of words in '*argcp' and an array
 760 * of pointers to the words in '*argvp'.  The caller
 761 * must free the array using isc_mem_put().  The string
 762 * is modified in-place.
 763 */
 764static isc_result_t
 765strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) {
 766	return (strtoargvsub(mctx, s, argcp, argvp, 0));
 767}
 768
 769static void
 770checknames(dns_zonetype_t ztype, const cfg_obj_t **maps,
 771	   const cfg_obj_t **objp)
 772{
 773	const char *zone = NULL;
 774	isc_result_t result;
 775
 776	switch (ztype) {
 777	case dns_zone_slave: zone = "slave"; break;
 778	case dns_zone_master: zone = "master"; break;
 779	default:
 780		INSIST(0);
 781	}
 782	result = ns_checknames_get(maps, zone, objp);
 783	INSIST(result == ISC_R_SUCCESS && objp != NULL && *objp != NULL);
 784}
 785
 786isc_result_t
 787ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
 788		  const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac,
 789		  dns_zone_t *zone)
 790{
 791	isc_result_t result;
 792	const char *zname;
 793	dns_rdataclass_t zclass;
 794	dns_rdataclass_t vclass;
 795	const cfg_obj_t *maps[5];
 796	const cfg_obj_t *zoptions = NULL;
 797	const cfg_obj_t *options = NULL;
 798	const cfg_obj_t *obj;
 799	const char *filename = NULL;
 800	dns_notifytype_t notifytype = dns_notifytype_yes;
 801	isc_sockaddr_t *addrs;
 802	dns_name_t **keynames;
 803	isc_uint32_t count;
 804	char *cpval;
 805	unsigned int dbargc;
 806	char **dbargv;
 807	static char default_dbtype[] = "rbt";
 808	isc_mem_t *mctx = dns_zone_getmctx(zone);
 809	dns_dialuptype_t dialup = dns_dialuptype_no;
 810	dns_zonetype_t ztype;
 811	int i;
 812	isc_int32_t journal_size;
 813	isc_boolean_t multi;
 814	isc_boolean_t alt;
 815	dns_view_t *view;
 816	isc_boolean_t check = ISC_FALSE, fail = ISC_FALSE;
 817	isc_boolean_t warn = ISC_FALSE, ignore = ISC_FALSE;
 818	isc_boolean_t ixfrdiff;
 819	dns_masterformat_t masterformat;
 820	isc_stats_t *zoneqrystats;
 821	isc_boolean_t zonestats_on;
 822	int seconds;
 823
 824	i = 0;
 825	if (zconfig != NULL) {
 826		zoptions = cfg_tuple_get(zconfig, "options");
 827		maps[i++] = zoptions;
 828	}
 829	if (vconfig != NULL)
 830		maps[i++] = cfg_tuple_get(vconfig, "options");
 831	if (config != NULL) {
 832		(void)cfg_map_get(config, "options", &options);
 833		if (options != NULL)
 834			maps[i++] = options;
 835	}
 836	maps[i++] = ns_g_defaults;
 837	maps[i] = NULL;
 838
 839	if (vconfig != NULL)
 840		RETERR(ns_config_getclass(cfg_tuple_get(vconfig, "class"),
 841					  dns_rdataclass_in, &vclass));
 842	else
 843		vclass = dns_rdataclass_in;
 844
 845	/*
 846	 * Configure values common to all zone types.
 847	 */
 848
 849	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
 850
 851	RETERR(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
 852				  vclass, &zclass));
 853	dns_zone_setclass(zone, zclass);
 854
 855	ztype = zonetype_fromconfig(zoptions);
 856	dns_zone_settype(zone, ztype);
 857
 858	obj = NULL;
 859	result = cfg_map_get(zoptions, "database", &obj);
 860	if (result == ISC_R_SUCCESS)
 861		cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
 862	else
 863		cpval = default_dbtype;
 864
 865	if (cpval == NULL)
 866		return(ISC_R_NOMEMORY);
 867
 868	result = strtoargv(mctx, cpval, &dbargc, &dbargv);
 869	if (result != ISC_R_SUCCESS && cpval != default_dbtype) {
 870		isc_mem_free(mctx, cpval);
 871		return (result);
 872	}
 873
 874	/*
 875	 * ANSI C is strange here.  There is no logical reason why (char **)
 876	 * cannot be promoted automatically to (const char * const *) by the
 877	 * compiler w/o generating a warning.
 878	 */
 879	result = dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv);
 880	isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv));
 881	if (cpval != default_dbtype)
 882		isc_mem_free(mctx, cpval);
 883	if (result != ISC_R_SUCCESS)
 884		return (result);
 885
 886	obj = NULL;
 887	result = cfg_map_get(zoptions, "file", &obj);
 888	if (result == ISC_R_SUCCESS)
 889		filename = cfg_obj_asstring(obj);
 890
 891	/*
 892	 * Unless we're using some alternative database, a master zone
 893	 * will be needing a master file.
 894	 */
 895	if (ztype == dns_zone_master && cpval == default_dbtype &&
 896	    filename == NULL) {
 897		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 898			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
 899			      "zone '%s': 'file' not specified",
 900			      zname);
 901		return (ISC_R_FAILURE);
 902	}
 903
 904	masterformat = dns_masterformat_text;
 905	obj = NULL;
 906	result= ns_config_get(maps, "masterfile-format", &obj);
 907	if (result == ISC_R_SUCCESS) {
 908		const char *masterformatstr = cfg_obj_asstring(obj);
 909
 910		if (strcasecmp(masterformatstr, "text") == 0)
 911			masterformat = dns_masterformat_text;
 912		else if (strcasecmp(masterformatstr, "raw") == 0)
 913			masterformat = dns_masterformat_raw;
 914		else
 915			INSIST(0);
 916	}
 917	RETERR(dns_zone_setfile2(zone, filename, masterformat));
 918
 919	obj = NULL;
 920	result = cfg_map_get(zoptions, "journal", &obj);
 921	if (result == ISC_R_SUCCESS)
 922		RETERR(dns_zone_setjournal(zone, cfg_obj_asstring(obj)));
 923
 924	if (ztype == dns_zone_slave)
 925		RETERR(configure_zone_acl(zconfig, vconfig, config,
 926					  allow_notify, ac, zone,
 927					  dns_zone_setnotifyacl,
 928					  dns_zone_clearnotifyacl));
 929	/*
 930	 * XXXAG This probably does not make sense for stubs.
 931	 */
 932	RETERR(configure_zone_acl(zconfig, vconfig, config,
 933				  allow_query, ac, zone,
 934				  dns_zone_setqueryacl,
 935				  dns_zone_clearqueryacl));
 936
 937	obj = NULL;
 938	result = ns_config_get(maps, "dialup", &obj);
 939	INSIST(result == ISC_R_SUCCESS && obj != NULL);
 940	if (cfg_obj_isboolean(obj)) {
 941		if (cfg_obj_asboolean(obj))
 942			dialup = dns_dialuptype_yes;
 943		else
 944			dialup = dns_dialuptype_no;
 945	} else {
 946		const char *dialupstr = cfg_obj_asstring(obj);
 947		if (strcasecmp(dialupstr, "notify") == 0)
 948			dialup = dns_dialuptype_notify;
 949		else if (strcasecmp(dialupstr, "notify-passive") == 0)
 950			dialup = dns_dialuptype_notifypassive;
 951		else if (strcasecmp(dialupstr, "refresh") == 0)
 952			dialup = dns_dialuptype_refresh;
 953		else if (strcasecmp(dialupstr, "passive") == 0)
 954			dialup = dns_dialuptype_passive;
 955		else
 956			INSIST(0);
 957	}
 958	dns_zone_setdialup(zone, dialup);
 959
 960	obj = NULL;
 961	result = ns_config_get(maps, "zone-statistics", &obj);
 962	INSIST(result == ISC_R_SUCCESS && obj != NULL);
 963	zonestats_on = cfg_obj_asboolean(obj);
 964	zoneqrystats = NULL;
 965	if (zonestats_on) {
 966		RETERR(isc_stats_create(mctx, &zoneqrystats,
 967					dns_nsstatscounter_max));
 968	}
 969	dns_zone_setrequeststats(zone, zoneqrystats);
 970	if (zoneqrystats != NULL)
 971		isc_stats_detach(&zoneqrystats);
 972
 973	/*
 974	 * Configure master functionality.  This applies
 975	 * to primary masters (type "master") and slaves
 976	 * acting as masters (type "slave"), but not to stubs.
 977	 */
 978	if (ztype != dns_zone_stub && ztype != dns_zone_staticstub) {
 979		obj = NULL;
 980		result = ns_config_get(maps, "notify", &obj);
 981		INSIST(result == ISC_R_SUCCESS && obj != NULL);
 982		if (cfg_obj_isboolean(obj)) {
 983			if (cfg_obj_asboolean(obj))
 984				notifytype = dns_notifytype_yes;
 985			else
 986				notifytype = dns_notifytype_no;
 987		} else {
 988			const char *notifystr = cfg_obj_asstring(obj);
 989			if (strcasecmp(notifystr, "explicit") == 0)
 990				notifytype = dns_notifytype_explicit;
 991			else if (strcasecmp(notifystr, "master-only") == 0)
 992				notifytype = dns_notifytype_masteronly;
 993			else
 994				INSIST(0);
 995		}
 996		dns_zone_setnotifytype(zone, notifytype);
 997
 998		obj = NULL;
 999		result = ns_config_get(maps, "also-notify", &obj);
1000		if (result == ISC_R_SUCCESS) {
1001			isc_sockaddr_t *addrs = NULL;
1002			isc_uint32_t addrcount;
1003			result = ns_config_getiplist(config, obj, 0, mctx,
1004						     &addrs, &addrcount);
1005			if (result != ISC_R_SUCCESS)
1006				return (result);
1007			result = dns_zone_setalsonotify(zone, addrs,
1008							addrcount);
1009			ns_config_putiplist(mctx, &addrs, addrcount);
1010			if (result != ISC_R_SUCCESS)
1011				return (result);
1012		} else
1013			RETERR(dns_zone_setalsonotify(zone, NULL, 0));
1014
1015		obj = NULL;
1016		result = ns_config_get(maps, "notify-source", &obj);
1017		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1018		RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj)));
1019		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1020
1021		obj = NULL;
1022		result = ns_config_get(maps, "notify-source-v6", &obj);
1023		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1024		RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj)));
1025		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1026
1027		obj = NULL;
1028		result = ns_config_get(maps, "notify-to-soa", &obj);
1029		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1030		dns_zone_setoption(zone, DNS_ZONEOPT_NOTIFYTOSOA,
1031				   cfg_obj_asboolean(obj));
1032
1033		dns_zone_setisself(zone, ns_client_isself, NULL);
1034
1035		RETERR(configure_zone_acl(zconfig, vconfig, config,
1036					  allow_transfer, ac, zone,
1037					  dns_zone_setxfracl,
1038					  dns_zone_clearxfracl));
1039
1040		obj = NULL;
1041		result = ns_config_get(maps, "max-transfer-time-out", &obj);
1042		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1043		dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60);
1044
1045		obj = NULL;
1046		result = ns_config_get(maps, "max-transfer-idle-out", &obj);
1047		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1048		dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60);
1049
1050		obj = NULL;
1051		result =  ns_config_get(maps, "max-journal-size", &obj);
1052		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1053		dns_zone_setjournalsize(zone, -1);
1054		if (cfg_obj_isstring(obj)) {
1055			const char *str = cfg_obj_asstring(obj);
1056			INSIST(strcasecmp(str, "unlimited") == 0);
1057			journal_size = ISC_UINT32_MAX / 2;
1058		} else {
1059			isc_resourcevalue_t value;
1060			value = cfg_obj_asuint64(obj);
1061			if (value > ISC_UINT32_MAX / 2) {
1062				cfg_obj_log(obj, ns_g_lctx,
1063					    ISC_LOG_ERROR,
1064					    "'max-journal-size "
1065					    "%" ISC_PRINT_QUADFORMAT "d' "
1066					    "is too large",
1067					    value);
1068				RETERR(ISC_R_RANGE);
1069			}
1070			journal_size = (isc_uint32_t)value;
1071		}
1072		dns_zone_setjournalsize(zone, journal_size);
1073
1074		obj = NULL;
1075		result = ns_config_get(maps, "ixfr-from-differences", &obj);
1076		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1077		if (cfg_obj_isboolean(obj))
1078			ixfrdiff = cfg_obj_asboolean(obj);
1079		else if (!strcasecmp(cfg_obj_asstring(obj), "master") &&
1080			 ztype == dns_zone_master)
1081			ixfrdiff = ISC_TRUE;
1082		else if (!strcasecmp(cfg_obj_asstring(obj), "slave") &&
1083			ztype == dns_zone_slave)
1084			ixfrdiff = ISC_TRUE;
1085		else
1086			ixfrdiff = ISC_FALSE;
1087		dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS, ixfrdiff);
1088
1089		checknames(ztype, maps, &obj);
1090		INSIST(obj != NULL);
1091		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1092			fail = ISC_FALSE;
1093			check = ISC_TRUE;
1094		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1095			fail = check = ISC_TRUE;
1096		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1097			fail = check = ISC_FALSE;
1098		} else
1099			INSIST(0);
1100		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, check);
1101		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL, fail);
1102
1103		obj = NULL;
1104		result = ns_config_get(maps, "notify-delay", &obj);
1105		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1106		dns_zone_setnotifydelay(zone, cfg_obj_asuint32(obj));
1107
1108		obj = NULL;
1109		result = ns_config_get(maps, "check-sibling", &obj);
1110		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1111		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSIBLING,
1112				   cfg_obj_asboolean(obj));
1113
1114		obj = NULL;
1115		result = ns_config_get(maps, "zero-no-soa-ttl", &obj);
1116		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1117		dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj));
1118
1119		obj = NULL;
1120		result = ns_config_get(maps, "nsec3-test-zone", &obj);
1121		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1122		dns_zone_setoption(zone, DNS_ZONEOPT_NSEC3TESTZONE,
1123				   cfg_obj_asboolean(obj));
1124	}
1125
1126	/*
1127	 * Configure update-related options.  These apply to
1128	 * primary masters only.
1129	 */
1130	if (ztype == dns_zone_master) {
1131		dns_acl_t *updateacl;
1132
1133		RETERR(configure_zone_acl(zconfig, vconfig, config,
1134					  allow_update, ac, zone,
1135					  dns_zone_setupdateacl,
1136					  dns_zone_clearupdateacl));
1137
1138		updateacl = dns_zone_getupdateacl(zone);
1139		if (updateacl != NULL  && dns_acl_isinsecure(updateacl))
1140			isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
1141				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1142				      "zone '%s' allows updates by IP "
1143				      "address, which is insecure",
1144				      zname);
1145
1146		RETERR(configure_zone_ssutable(zoptions, zone, zname));
1147
1148		obj = NULL;
1149		result = ns_config_get(maps, "sig-validity-interval", &obj);
1150		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1151		{
1152			const cfg_obj_t *validity, *resign;
1153
1154			validity = cfg_tuple_get(obj, "validity");
1155			seconds = cfg_obj_asuint32(validity) * 86400;
1156			dns_zone_setsigvalidityinterval(zone, seconds);
1157
1158			resign = cfg_tuple_get(obj, "re-sign");
1159			if (cfg_obj_isvoid(resign)) {
1160				seconds /= 4;
1161			} else {
1162				if (seconds > 7 * 86400)
1163					seconds = cfg_obj_asuint32(resign) *
1164							86400;
1165				else
1166					seconds = cfg_obj_asuint32(resign) *
1167							3600;
1168			}
1169			dns_zone_setsigresigninginterval(zone, seconds);
1170		}
1171
1172		obj = NULL;
1173		result = ns_config_get(maps, "key-directory", &obj);
1174		if (result == ISC_R_SUCCESS) {
1175			filename = cfg_obj_asstring(obj);
1176			RETERR(dns_zone_setkeydirectory(zone, filename));
1177		}
1178
1179		obj = NULL;
1180		result = ns_config_get(maps, "sig-signing-signatures", &obj);
1181		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1182		dns_zone_setsignatures(zone, cfg_obj_asuint32(obj));
1183
1184		obj = NULL;
1185		result = ns_config_get(maps, "sig-signing-nodes", &obj);
1186		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1187		dns_zone_setnodes(zone, cfg_obj_asuint32(obj));
1188
1189		obj = NULL;
1190		result = ns_config_get(maps, "sig-signing-type", &obj);
1191		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1192		dns_zone_setprivatetype(zone, cfg_obj_asuint32(obj));
1193
1194		obj = NULL;
1195		result = ns_config_get(maps, "update-check-ksk", &obj);
1196		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1197		dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK,
1198				   cfg_obj_asboolean(obj));
1199
1200		obj = NULL;
1201		result = ns_config_get(maps, "dnssec-dnskey-kskonly", &obj);
1202		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1203		dns_zone_setoption(zone, DNS_ZONEOPT_DNSKEYKSKONLY,
1204				   cfg_obj_asboolean(obj));
1205	} else if (ztype == dns_zone_slave) {
1206		RETERR(configure_zone_acl(zconfig, vconfig, config,
1207					  allow_update_forwarding, ac, zone,
1208					  dns_zone_setforwardacl,
1209					  dns_zone_clearforwardacl));
1210	}
1211
1212	/*%
1213	 * Primary master functionality.
1214	 */
1215	if (ztype == dns_zone_master) {
1216		isc_boolean_t allow = ISC_FALSE, maint = ISC_FALSE;
1217
1218		obj = NULL;
1219		result = ns_config_get(maps, "check-wildcard", &obj);
1220		if (result == ISC_R_SUCCESS)
1221			check = cfg_obj_asboolean(obj);
1222		else
1223			check = ISC_FALSE;
1224		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKWILDCARD, check);
1225
1226		obj = NULL;
1227		result = ns_config_get(maps, "check-dup-records", &obj);
1228		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1229		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1230			fail = ISC_FALSE;
1231			check = ISC_TRUE;
1232		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1233			fail = check = ISC_TRUE;
1234		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1235			fail = check = ISC_FALSE;
1236		} else
1237			INSIST(0);
1238		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKDUPRR, check);
1239		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKDUPRRFAIL, fail);
1240
1241		obj = NULL;
1242		result = ns_config_get(maps, "check-mx", &obj);
1243		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1244		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1245			fail = ISC_FALSE;
1246			check = ISC_TRUE;
1247		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1248			fail = check = ISC_TRUE;
1249		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1250			fail = check = ISC_FALSE;
1251		} else
1252			INSIST(0);
1253		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMX, check);
1254		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMXFAIL, fail);
1255
1256		obj = NULL;
1257		result = ns_config_get(maps, "check-integrity", &obj);
1258		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1259		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKINTEGRITY,
1260				   cfg_obj_asboolean(obj));
1261
1262		obj = NULL;
1263		result = ns_config_get(maps, "check-mx-cname", &obj);
1264		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1265		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1266			warn = ISC_TRUE;
1267			ignore = ISC_FALSE;
1268		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1269			warn = ignore = ISC_FALSE;
1270		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1271			warn = ignore = ISC_TRUE;
1272		} else
1273			INSIST(0);
1274		dns_zone_setoption(zone, DNS_ZONEOPT_WARNMXCNAME, warn);
1275		dns_zone_setoption(zone, DNS_ZONEOPT_IGNOREMXCNAME, ignore);
1276
1277		obj = NULL;
1278		result = ns_config_get(maps, "check-srv-cname", &obj);
1279		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1280		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1281			warn = ISC_TRUE;
1282			ignore = ISC_FALSE;
1283		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1284			warn = ignore = ISC_FALSE;
1285		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1286			warn = ignore = ISC_TRUE;
1287		} else
1288			INSIST(0);
1289		dns_zone_setoption(zone, DNS_ZONEOPT_WARNSRVCNAME, warn);
1290		dns_zone_setoption(zone, DNS_ZONEOPT_IGNORESRVCNAME, ignore);
1291
1292		obj = NULL;
1293		result = ns_config_get(maps, "dnssec-secure-to-insecure", &obj);
1294		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1295		dns_zone_setoption(zone, DNS_ZONEOPT_SECURETOINSECURE,
1296				   cfg_obj_asboolean(obj));
1297
1298		obj = NULL;
1299		result = cfg_map_get(zoptions, "auto-dnssec", &obj);
1300		if (result == ISC_R_SUCCESS) {
1301			const char *arg = cfg_obj_asstring(obj);
1302			if (strcasecmp(arg, "allow") == 0)
1303				allow = ISC_TRUE;
1304			else if (strcasecmp(arg, "maintain") == 0)
1305				allow = maint = ISC_TRUE;
1306			else if (strcasecmp(arg, "off") == 0)
1307				;
1308			else
1309				INSIST(0);
1310			dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow);
1311			dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint);
1312		}
1313	}
1314
1315	/*
1316	 * Configure slave functionality.
1317	 */
1318	switch (ztype) {
1319	case dns_zone_slave:
1320	case dns_zone_stub:
1321		count = 0;
1322		obj = NULL;
1323		(void)cfg_map_get(zoptions, "masters", &obj);
1324		if (obj != NULL) {
1325			addrs = NULL;
1326			keynames = NULL;
1327			RETERR(ns_config_getipandkeylist(config, obj, mctx,
1328							 &addrs, &keynames,
1329							 &count));
1330			result = dns_zone_setmasterswithkeys(zone, addrs,
1331							     keynames, count);
1332			if (count != 0)
1333				ns_config_putipandkeylist(mctx, &addrs,
1334							  &keynames, count);
1335			else
1336				INSIST(addrs == NULL && keynames == NULL);
1337		} else
1338			result = dns_zone_setmasters(zone, NULL, 0);
1339		RETERR(result);
1340
1341		multi = ISC_FALSE;
1342		if (count > 1) {
1343			obj = NULL;
1344			result = ns_config_get(maps, "multi-master", &obj);
1345			INSIST(result == ISC_R_SUCCESS && obj != NULL);
1346			multi = cfg_obj_asboolean(obj);
1347		}
1348		dns_zone_setoption(zone, DNS_ZONEOPT_MULTIMASTER, multi);
1349
1350		obj = NULL;
1351		result = ns_config_get(maps, "max-transfer-time-in", &obj);
1352		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1353		dns_zone_setmaxxfrin(zone, cfg_obj_asuint32(obj) * 60);
1354
1355		obj = NULL;
1356		result = ns_config_get(maps, "max-transfer-idle-in", &obj);
1357		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1358		dns_zone_setidlein(zone, cfg_obj_asuint32(obj) * 60);
1359
1360		obj = NULL;
1361		result = ns_config_get(maps, "max-refresh-time", &obj);
1362		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1363		dns_zone_setmaxrefreshtime(zone, cfg_obj_asuint32(obj));
1364
1365		obj = NULL;
1366		result = ns_config_get(maps, "min-refresh-time", &obj);
1367		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1368		dns_zone_setminrefreshtime(zone, cfg_obj_asuint32(obj));
1369
1370		obj = NULL;
1371		result = ns_config_get(maps, "max-retry-time", &obj);
1372		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1373		dns_zone_setmaxretrytime(zone, cfg_obj_asuint32(obj));
1374
1375		obj = NULL;
1376		result = ns_config_get(maps, "min-retry-time", &obj);
1377		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1378		dns_zone_setminretrytime(zone, cfg_obj_asuint32(obj));
1379
1380		obj = NULL;
1381		result = ns_config_get(maps, "transfer-source", &obj);
1382		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1383		RETERR(dns_zone_setxfrsource4(zone, cfg_obj_assockaddr(obj)));
1384		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1385
1386		obj = NULL;
1387		result = ns_config_get(maps, "transfer-source-v6", &obj);
1388		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1389		RETERR(dns_zone_setxfrsource6(zone, cfg_obj_assockaddr(obj)));
1390		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1391
1392		obj = NULL;
1393		result = ns_config_get(maps, "alt-transfer-source", &obj);
1394		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1395		RETERR(dns_zone_setaltxfrsource4(zone, cfg_obj_assockaddr(obj)));
1396
1397		obj = NULL;
1398		result = ns_config_get(maps, "alt-transfer-source-v6", &obj);
1399		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1400		RETERR(dns_zone_setaltxfrsource6(zone, cfg_obj_assockaddr(obj)));
1401
1402		obj = NULL;
1403		(void)ns_config_get(maps, "use-alt-transfer-source", &obj);
1404		if (obj == NULL) {
1405			/*
1406			 * Default off when views are in use otherwise
1407			 * on for BIND 8 compatibility.
1408			 */
1409			view = dns_zone_getview(zone);
1410			if (view != NULL && strcmp(view->name, "_default") == 0)
1411				alt = ISC_TRUE;
1412			else
1413				alt = ISC_FALSE;
1414		} else
1415			alt = cfg_obj_asboolean(obj);
1416		dns_zone_setoption(zone, DNS_ZONEOPT_USEALTXFRSRC, alt);
1417
1418		obj = NULL;
1419		(void)ns_config_get(maps, "try-tcp-refresh", &obj);
1420		dns_zone_setoption(zone, DNS_ZONEOPT_TRYTCPREFRESH,
1421				   cfg_obj_asboolean(obj));
1422		break;
1423
1424	case dns_zone_staticstub:
1425		RETERR(configure_staticstub(zoptions, zone, zname,
1426					    default_dbtype));
1427		break;
1428
1429	default:
1430		break;
1431	}
1432
1433	return (ISC_R_SUCCESS);
1434}
1435
1436
1437/*
1438 * Set up a DLZ zone as writeable
1439 */
1440isc_result_t
1441ns_zone_configure_writeable_dlz(dns_dlzdb_t *dlzdatabase, dns_zone_t *zone,
1442				dns_rdataclass_t rdclass, dns_name_t *name)
1443{
1444	dns_db_t *db = NULL;
1445	isc_time_t now;
1446	isc_result_t result;
1447
1448	TIME_NOW(&now);
1449
1450	dns_zone_settype(zone, dns_zone_dlz);
1451	result = dns_sdlz_setdb(dlzdatabase, rdclass, name, &db);
1452	if (result != ISC_R_SUCCESS)
1453		return result;
1454	result = dns_zone_dlzpostload(zone, db);
1455	dns_db_detach(&db);
1456	return result;
1457}
1458
1459isc_boolean_t
1460ns_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig) {
1461	const cfg_obj_t *zoptions = NULL;
1462	const cfg_obj_t *obj = NULL;
1463	const char *cfilename;
1464	const char *zfilename;
1465
1466	zoptions = cfg_tuple_get(zconfig, "options");
1467
1468	if (zonetype_fromconfig(zoptions) != dns_zone_gettype(zone)) {
1469		dns_zone_log(zone, ISC_LOG_DEBUG(1),
1470			     "not reusable: type mismatch");
1471		return (ISC_FALSE);
1472	}
1473
1474	/*
1475	 * We always reconfigure a static-stub zone for simplicity, assuming
1476	 * the amount of data to be loaded is small.
1477	 */
1478	if (zonetype_fromconfig(zoptions) == dns_zone_staticstub) {
1479		dns_zone_log(zone, ISC_LOG_DEBUG(1),
1480			     "not reusable: staticstub");
1481		return (ISC_FALSE);
1482	}
1483
1484	obj = NULL;
1485	(void)cfg_map_get(zoptions, "file", &obj);
1486	if (obj != NULL)
1487		cfilename = cfg_obj_asstring(obj);
1488	else
1489		cfilename = NULL;
1490	zfilename = dns_zone_getfile(zone);
1491	if (!((cfilename == NULL && zfilename == NULL) ||
1492	      (cfilename != NULL && zfilename != NULL &&
1493	       strcmp(cfilename, zfilename) == 0))) {
1494		dns_zone_log(zone, ISC_LOG_DEBUG(1),
1495			"not reusable: filename mismatch");
1496		return (ISC_FALSE);
1497	}
1498
1499	return (ISC_TRUE);
1500}