1/*	$NetBSD: zoneconf.c,v 1.15 2024/02/21 22:51:05 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16#include <inttypes.h>
17#include <stdbool.h>
18
19#include <isc/buffer.h>
20#include <isc/file.h>
21#include <isc/mem.h>
22#include <isc/print.h>
23#include <isc/result.h>
24#include <isc/stats.h>
25#include <isc/string.h> /* Required for HP/UX (and others?) */
26#include <isc/util.h>
27
28#include <dns/acl.h>
29#include <dns/db.h>
30#include <dns/fixedname.h>
31#include <dns/ipkeylist.h>
32#include <dns/journal.h>
33#include <dns/kasp.h>
34#include <dns/log.h>
35#include <dns/masterdump.h>
36#include <dns/name.h>
37#include <dns/nsec3.h>
38#include <dns/rdata.h>
39#include <dns/rdatalist.h>
40#include <dns/rdataset.h>
41#include <dns/rdatatype.h>
42#include <dns/sdlz.h>
43#include <dns/ssu.h>
44#include <dns/stats.h>
45#include <dns/tsig.h>
46#include <dns/view.h>
47#include <dns/zone.h>
48
49#include <ns/client.h>
50
51#include <named/config.h>
52#include <named/globals.h>
53#include <named/log.h>
54#include <named/server.h>
55#include <named/zoneconf.h>
56
57/* ACLs associated with zone */
58typedef enum {
59	allow_notify,
60	allow_query,
61	allow_query_on,
62	allow_transfer,
63	allow_update,
64	allow_update_forwarding
65} acl_type_t;
66
67#define RETERR(x)                        \
68	do {                             \
69		isc_result_t _r = (x);   \
70		if (_r != ISC_R_SUCCESS) \
71			return ((_r));   \
72	} while (0)
73
74#define CHECK(x)                             \
75	do {                                 \
76		result = (x);                \
77		if (result != ISC_R_SUCCESS) \
78			goto cleanup;        \
79	} while (0)
80
81/*%
82 * Convenience function for configuring a single zone ACL.
83 */
84static isc_result_t
85configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
86		   const cfg_obj_t *config, acl_type_t acltype,
87		   cfg_aclconfctx_t *actx, dns_zone_t *zone,
88		   void (*setzacl)(dns_zone_t *, dns_acl_t *),
89		   void (*clearzacl)(dns_zone_t *)) {
90	isc_result_t result;
91	const cfg_obj_t *maps[5] = { NULL, NULL, NULL, NULL, NULL };
92	const cfg_obj_t *aclobj = NULL;
93	int i = 0;
94	dns_acl_t **aclp = NULL, *acl = NULL;
95	const char *aclname;
96	dns_view_t *view;
97
98	view = dns_zone_getview(zone);
99
100	switch (acltype) {
101	case allow_notify:
102		if (view != NULL) {
103			aclp = &view->notifyacl;
104		}
105		aclname = "allow-notify";
106		break;
107	case allow_query:
108		if (view != NULL) {
109			aclp = &view->queryacl;
110		}
111		aclname = "allow-query";
112		break;
113	case allow_query_on:
114		if (view != NULL) {
115			aclp = &view->queryonacl;
116		}
117		aclname = "allow-query-on";
118		break;
119	case allow_transfer:
120		if (view != NULL) {
121			aclp = &view->transferacl;
122		}
123		aclname = "allow-transfer";
124		break;
125	case allow_update:
126		if (view != NULL) {
127			aclp = &view->updateacl;
128		}
129		aclname = "allow-update";
130		break;
131	case allow_update_forwarding:
132		if (view != NULL) {
133			aclp = &view->upfwdacl;
134		}
135		aclname = "allow-update-forwarding";
136		break;
137	default:
138		UNREACHABLE();
139	}
140
141	/* First check to see if ACL is defined within the zone */
142	if (zconfig != NULL) {
143		maps[0] = cfg_tuple_get(zconfig, "options");
144		(void)named_config_get(maps, aclname, &aclobj);
145		if (aclobj != NULL) {
146			aclp = NULL;
147			goto parse_acl;
148		}
149	}
150
151	/* Failing that, see if there's a default ACL already in the view */
152	if (aclp != NULL && *aclp != NULL) {
153		(*setzacl)(zone, *aclp);
154		return (ISC_R_SUCCESS);
155	}
156
157	/* Check for default ACLs that haven't been parsed yet */
158	if (vconfig != NULL) {
159		const cfg_obj_t *options = cfg_tuple_get(vconfig, "options");
160		if (options != NULL) {
161			maps[i++] = options;
162		}
163	}
164	if (config != NULL) {
165		const cfg_obj_t *options = NULL;
166		(void)cfg_map_get(config, "options", &options);
167		if (options != NULL) {
168			maps[i++] = options;
169		}
170	}
171	maps[i++] = named_g_defaults;
172	maps[i] = NULL;
173
174	(void)named_config_get(maps, aclname, &aclobj);
175	if (aclobj == NULL) {
176		(*clearzacl)(zone);
177		return (ISC_R_SUCCESS);
178	}
179
180parse_acl:
181	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx,
182				    named_g_mctx, 0, &acl);
183	if (result != ISC_R_SUCCESS) {
184		return (result);
185	}
186	(*setzacl)(zone, acl);
187
188	/* Set the view default now */
189	if (aclp != NULL) {
190		dns_acl_attach(acl, aclp);
191	}
192
193	dns_acl_detach(&acl);
194	return (ISC_R_SUCCESS);
195}
196
197/*%
198 * Parse the zone update-policy statement.
199 */
200static isc_result_t
201configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
202			const char *zname) {
203	const cfg_obj_t *updatepolicy = NULL;
204	const cfg_listelt_t *element, *element2;
205	dns_ssutable_t *table = NULL;
206	isc_mem_t *mctx = dns_zone_getmctx(zone);
207	bool autoddns = false;
208	isc_result_t result = ISC_R_SUCCESS;
209
210	(void)cfg_map_get(zconfig, "update-policy", &updatepolicy);
211
212	if (updatepolicy == NULL) {
213		dns_zone_setssutable(zone, NULL);
214		return (ISC_R_SUCCESS);
215	}
216
217	if (cfg_obj_isstring(updatepolicy) &&
218	    strcmp("local", cfg_obj_asstring(updatepolicy)) == 0)
219	{
220		autoddns = true;
221		updatepolicy = NULL;
222	}
223
224	dns_ssutable_create(mctx, &table);
225
226	for (element = cfg_list_first(updatepolicy); element != NULL;
227	     element = cfg_list_next(element))
228	{
229		const cfg_obj_t *stmt = cfg_listelt_value(element);
230		const cfg_obj_t *mode = cfg_tuple_get(stmt, "mode");
231		const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
232		const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
233		const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
234		const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
235		const char *str;
236		bool grant = false;
237		bool usezone = false;
238		dns_ssumatchtype_t mtype = dns_ssumatchtype_name;
239		dns_fixedname_t fname, fident;
240		isc_buffer_t b;
241		dns_ssuruletype_t *types;
242		unsigned int i, n;
243
244		str = cfg_obj_asstring(mode);
245		if (strcasecmp(str, "grant") == 0) {
246			grant = true;
247		} else if (strcasecmp(str, "deny") == 0) {
248			grant = false;
249		} else {
250			UNREACHABLE();
251		}
252
253		str = cfg_obj_asstring(matchtype);
254		CHECK(dns_ssu_mtypefromstring(str, &mtype));
255		if (mtype == dns_ssumatchtype_subdomain &&
256		    strcasecmp(str, "zonesub") == 0)
257		{
258			usezone = true;
259		}
260
261		dns_fixedname_init(&fident);
262		str = cfg_obj_asstring(identity);
263		isc_buffer_constinit(&b, str, strlen(str));
264		isc_buffer_add(&b, strlen(str));
265		result = dns_name_fromtext(dns_fixedname_name(&fident), &b,
266					   dns_rootname, 0, NULL);
267		if (result != ISC_R_SUCCESS) {
268			cfg_obj_log(identity, named_g_lctx, ISC_LOG_ERROR,
269				    "'%s' is not a valid name", str);
270			goto cleanup;
271		}
272
273		dns_fixedname_init(&fname);
274		if (usezone) {
275			dns_name_copy(dns_zone_getorigin(zone),
276				      dns_fixedname_name(&fname));
277		} else {
278			str = cfg_obj_asstring(dname);
279			isc_buffer_constinit(&b, str, strlen(str));
280			isc_buffer_add(&b, strlen(str));
281			result = dns_name_fromtext(dns_fixedname_name(&fname),
282						   &b, dns_rootname, 0, NULL);
283			if (result != ISC_R_SUCCESS) {
284				cfg_obj_log(identity, named_g_lctx,
285					    ISC_LOG_ERROR,
286					    "'%s' is not a valid name", str);
287				goto cleanup;
288			}
289		}
290
291		n = named_config_listcount(typelist);
292		if (n == 0) {
293			types = NULL;
294		} else {
295			types = isc_mem_get(mctx, n * sizeof(*types));
296		}
297
298		i = 0;
299		for (element2 = cfg_list_first(typelist); element2 != NULL;
300		     element2 = cfg_list_next(element2))
301		{
302			const cfg_obj_t *typeobj;
303			const char *bracket;
304			isc_textregion_t r;
305			unsigned long max = 0;
306
307			INSIST(i < n);
308
309			typeobj = cfg_listelt_value(element2);
310			str = cfg_obj_asstring(typeobj);
311			DE_CONST(str, r.base);
312
313			bracket = strchr(str, '(' /*)*/);
314			if (bracket != NULL) {
315				char *end = NULL;
316				r.length = bracket - str;
317				max = strtoul(bracket + 1, &end, 10);
318				if (max > 0xffff || end[0] != /*(*/ ')' ||
319				    end[1] != 0)
320				{
321					cfg_obj_log(identity, named_g_lctx,
322						    ISC_LOG_ERROR,
323						    "'%s' is not a valid count",
324						    bracket);
325					isc_mem_put(mctx, types,
326						    n * sizeof(*types));
327					goto cleanup;
328				}
329			} else {
330				r.length = strlen(str);
331			}
332			types[i].max = max;
333
334			result = dns_rdatatype_fromtext(&types[i++].type, &r);
335			if (result != ISC_R_SUCCESS) {
336				cfg_obj_log(identity, named_g_lctx,
337					    ISC_LOG_ERROR,
338					    "'%.*s' is not a valid type",
339					    (int)r.length, str);
340				isc_mem_put(mctx, types, n * sizeof(*types));
341				goto cleanup;
342			}
343		}
344		INSIST(i == n);
345
346		dns_ssutable_addrule(table, grant, dns_fixedname_name(&fident),
347				     mtype, dns_fixedname_name(&fname), n,
348				     types);
349		if (types != NULL) {
350			isc_mem_put(mctx, types, n * sizeof(*types));
351		}
352	}
353
354	/*
355	 * If "update-policy local;" and a session key exists,
356	 * then use the default policy, which is equivalent to:
357	 * update-policy { grant <session-keyname> zonesub any; };
358	 */
359	if (autoddns) {
360		dns_ssuruletype_t any = { dns_rdatatype_any, 0 };
361
362		if (named_g_server->session_keyname == NULL) {
363			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
364				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
365				      "failed to enable auto DDNS policy "
366				      "for zone %s: session key not found",
367				      zname);
368			result = ISC_R_NOTFOUND;
369			goto cleanup;
370		}
371
372		dns_ssutable_addrule(table, true,
373				     named_g_server->session_keyname,
374				     dns_ssumatchtype_local,
375				     dns_zone_getorigin(zone), 1, &any);
376	}
377
378	dns_zone_setssutable(zone, table);
379
380cleanup:
381	dns_ssutable_detach(&table);
382	return (result);
383}
384
385/*
386 * This is the TTL used for internally generated RRsets for static-stub zones.
387 * The value doesn't matter because the mapping is static, but needs to be
388 * defined for the sake of implementation.
389 */
390#define STATICSTUB_SERVER_TTL 86400
391
392/*%
393 * Configure an apex NS with glues for a static-stub zone.
394 * For example, for the zone named "example.com", the following RRs will be
395 * added to the zone DB:
396 * example.com. NS example.com.
397 * example.com. A 192.0.2.1
398 * example.com. AAAA 2001:db8::1
399 */
400static isc_result_t
401configure_staticstub_serveraddrs(const cfg_obj_t *zconfig, dns_zone_t *zone,
402				 dns_rdatalist_t *rdatalist_ns,
403				 dns_rdatalist_t *rdatalist_a,
404				 dns_rdatalist_t *rdatalist_aaaa) {
405	const cfg_listelt_t *element;
406	isc_mem_t *mctx = dns_zone_getmctx(zone);
407	isc_region_t region, sregion;
408	dns_rdata_t *rdata;
409	isc_result_t result = ISC_R_SUCCESS;
410
411	for (element = cfg_list_first(zconfig); element != NULL;
412	     element = cfg_list_next(element))
413	{
414		const isc_sockaddr_t *sa;
415		isc_netaddr_t na;
416		const cfg_obj_t *address = cfg_listelt_value(element);
417		dns_rdatalist_t *rdatalist;
418
419		sa = cfg_obj_assockaddr(address);
420		if (isc_sockaddr_getport(sa) != 0) {
421			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
422				    "port is not configurable for "
423				    "static stub server-addresses");
424			return (ISC_R_FAILURE);
425		}
426		isc_netaddr_fromsockaddr(&na, sa);
427		if (isc_netaddr_getzone(&na) != 0) {
428			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
429				    "scoped address is not allowed "
430				    "for static stub "
431				    "server-addresses");
432			return (ISC_R_FAILURE);
433		}
434
435		switch (na.family) {
436		case AF_INET:
437			region.length = sizeof(na.type.in);
438			rdatalist = rdatalist_a;
439			break;
440		default:
441			INSIST(na.family == AF_INET6);
442			region.length = sizeof(na.type.in6);
443			rdatalist = rdatalist_aaaa;
444			break;
445		}
446
447		rdata = isc_mem_get(mctx, sizeof(*rdata) + region.length);
448		region.base = (unsigned char *)(rdata + 1);
449		memmove(region.base, &na.type, region.length);
450		dns_rdata_init(rdata);
451		dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
452				     rdatalist->type, &region);
453		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
454	}
455
456	/*
457	 * If no address is specified (unlikely in this context, but possible),
458	 * there's nothing to do anymore.
459	 */
460	if (ISC_LIST_EMPTY(rdatalist_a->rdata) &&
461	    ISC_LIST_EMPTY(rdatalist_aaaa->rdata))
462	{
463		return (ISC_R_SUCCESS);
464	}
465
466	/* Add to the list an apex NS with the ns name being the origin name */
467	dns_name_toregion(dns_zone_getorigin(zone), &sregion);
468	rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length);
469	region.length = sregion.length;
470	region.base = (unsigned char *)(rdata + 1);
471	memmove(region.base, sregion.base, region.length);
472	dns_rdata_init(rdata);
473	dns_rdata_fromregion(rdata, dns_zone_getclass(zone), dns_rdatatype_ns,
474			     &region);
475	ISC_LIST_APPEND(rdatalist_ns->rdata, rdata, link);
476
477	return (result);
478}
479
480/*%
481 * Configure an apex NS with an out-of-zone NS names for a static-stub zone.
482 * For example, for the zone named "example.com", something like the following
483 * RRs will be added to the zone DB:
484 * example.com. NS ns.example.net.
485 */
486static isc_result_t
487configure_staticstub_servernames(const cfg_obj_t *zconfig, dns_zone_t *zone,
488				 dns_rdatalist_t *rdatalist,
489				 const char *zname) {
490	const cfg_listelt_t *element;
491	isc_mem_t *mctx = dns_zone_getmctx(zone);
492	dns_rdata_t *rdata;
493	isc_region_t sregion, region;
494	isc_result_t result = ISC_R_SUCCESS;
495
496	for (element = cfg_list_first(zconfig); element != NULL;
497	     element = cfg_list_next(element))
498	{
499		const cfg_obj_t *obj;
500		const char *str;
501		dns_fixedname_t fixed_name;
502		dns_name_t *nsname;
503		isc_buffer_t b;
504
505		obj = cfg_listelt_value(element);
506		str = cfg_obj_asstring(obj);
507
508		nsname = dns_fixedname_initname(&fixed_name);
509
510		isc_buffer_constinit(&b, str, strlen(str));
511		isc_buffer_add(&b, strlen(str));
512		result = dns_name_fromtext(nsname, &b, dns_rootname, 0, NULL);
513		if (result != ISC_R_SUCCESS) {
514			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
515				    "server-name '%s' is not a valid "
516				    "name",
517				    str);
518			return (result);
519		}
520		if (dns_name_issubdomain(nsname, dns_zone_getorigin(zone))) {
521			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
522				    "server-name '%s' must not be a "
523				    "subdomain of zone name '%s'",
524				    str, zname);
525			return (ISC_R_FAILURE);
526		}
527
528		dns_name_toregion(nsname, &sregion);
529		rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length);
530		region.length = sregion.length;
531		region.base = (unsigned char *)(rdata + 1);
532		memmove(region.base, sregion.base, region.length);
533		dns_rdata_init(rdata);
534		dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
535				     dns_rdatatype_ns, &region);
536		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
537	}
538
539	return (result);
540}
541
542/*%
543 * Configure static-stub zone.
544 */
545static isc_result_t
546configure_staticstub(const cfg_obj_t *zconfig, dns_zone_t *zone,
547		     const char *zname, const char *dbtype) {
548	int i = 0;
549	const cfg_obj_t *obj;
550	isc_mem_t *mctx = dns_zone_getmctx(zone);
551	dns_db_t *db = NULL;
552	dns_dbversion_t *dbversion = NULL;
553	dns_dbnode_t *apexnode = NULL;
554	dns_name_t apexname;
555	isc_result_t result;
556	dns_rdataset_t rdataset;
557	dns_rdatalist_t rdatalist_ns, rdatalist_a, rdatalist_aaaa;
558	dns_rdatalist_t *rdatalists[] = { &rdatalist_ns, &rdatalist_a,
559					  &rdatalist_aaaa, NULL };
560	dns_rdata_t *rdata;
561	isc_region_t region;
562
563	/* Create the DB beforehand */
564	RETERR(dns_db_create(mctx, dbtype, dns_zone_getorigin(zone),
565			     dns_dbtype_stub, dns_zone_getclass(zone), 0, NULL,
566			     &db));
567
568	dns_rdataset_init(&rdataset);
569
570	dns_rdatalist_init(&rdatalist_ns);
571	rdatalist_ns.rdclass = dns_zone_getclass(zone);
572	rdatalist_ns.type = dns_rdatatype_ns;
573	rdatalist_ns.ttl = STATICSTUB_SERVER_TTL;
574
575	dns_rdatalist_init(&rdatalist_a);
576	rdatalist_a.rdclass = dns_zone_getclass(zone);
577	rdatalist_a.type = dns_rdatatype_a;
578	rdatalist_a.ttl = STATICSTUB_SERVER_TTL;
579
580	dns_rdatalist_init(&rdatalist_aaaa);
581	rdatalist_aaaa.rdclass = dns_zone_getclass(zone);
582	rdatalist_aaaa.type = dns_rdatatype_aaaa;
583	rdatalist_aaaa.ttl = STATICSTUB_SERVER_TTL;
584
585	/* Prepare zone RRs from the configuration */
586	obj = NULL;
587	result = cfg_map_get(zconfig, "server-addresses", &obj);
588	if (result == ISC_R_SUCCESS) {
589		INSIST(obj != NULL);
590		CHECK(configure_staticstub_serveraddrs(obj, zone, &rdatalist_ns,
591						       &rdatalist_a,
592						       &rdatalist_aaaa));
593	}
594
595	obj = NULL;
596	result = cfg_map_get(zconfig, "server-names", &obj);
597	if (result == ISC_R_SUCCESS) {
598		INSIST(obj != NULL);
599		CHECK(configure_staticstub_servernames(obj, zone, &rdatalist_ns,
600						       zname));
601	}
602
603	/*
604	 * Sanity check: there should be at least one NS RR at the zone apex
605	 * to trigger delegation.
606	 */
607	if (ISC_LIST_EMPTY(rdatalist_ns.rdata)) {
608		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
609			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
610			      "No NS record is configured for a "
611			      "static-stub zone '%s'",
612			      zname);
613		result = ISC_R_FAILURE;
614		goto cleanup;
615	}
616
617	/*
618	 * Now add NS and glue A/AAAA RRsets to the zone DB.
619	 * First open a new version for the add operation and get a pointer
620	 * to the apex node (all RRs are of the apex name).
621	 */
622	CHECK(dns_db_newversion(db, &dbversion));
623
624	dns_name_init(&apexname, NULL);
625	dns_name_clone(dns_zone_getorigin(zone), &apexname);
626	CHECK(dns_db_findnode(db, &apexname, false, &apexnode));
627
628	/* Add NS RRset */
629	RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_ns, &rdataset) ==
630		      ISC_R_SUCCESS);
631	CHECK(dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset, 0,
632				 NULL));
633	dns_rdataset_disassociate(&rdataset);
634
635	/* Add glue A RRset, if any */
636	if (!ISC_LIST_EMPTY(rdatalist_a.rdata)) {
637		RUNTIME_CHECK(
638			dns_rdatalist_tordataset(&rdatalist_a, &rdataset) ==
639			ISC_R_SUCCESS);
640		CHECK(dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset,
641					 0, NULL));
642		dns_rdataset_disassociate(&rdataset);
643	}
644
645	/* Add glue AAAA RRset, if any */
646	if (!ISC_LIST_EMPTY(rdatalist_aaaa.rdata)) {
647		RUNTIME_CHECK(
648			dns_rdatalist_tordataset(&rdatalist_aaaa, &rdataset) ==
649			ISC_R_SUCCESS);
650		CHECK(dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset,
651					 0, NULL));
652		dns_rdataset_disassociate(&rdataset);
653	}
654
655	dns_db_closeversion(db, &dbversion, true);
656	dns_zone_setdb(zone, db);
657
658	result = ISC_R_SUCCESS;
659
660cleanup:
661	if (dns_rdataset_isassociated(&rdataset)) {
662		dns_rdataset_disassociate(&rdataset);
663	}
664	if (apexnode != NULL) {
665		dns_db_detachnode(db, &apexnode);
666	}
667	if (dbversion != NULL) {
668		dns_db_closeversion(db, &dbversion, false);
669	}
670	if (db != NULL) {
671		dns_db_detach(&db);
672	}
673	for (i = 0; rdatalists[i] != NULL; i++) {
674		while ((rdata = ISC_LIST_HEAD(rdatalists[i]->rdata)) != NULL) {
675			ISC_LIST_UNLINK(rdatalists[i]->rdata, rdata, link);
676			dns_rdata_toregion(rdata, &region);
677			isc_mem_put(mctx, rdata,
678				    sizeof(*rdata) + region.length);
679		}
680	}
681
682	INSIST(dbversion == NULL);
683
684	return (result);
685}
686
687/*%
688 * Convert a config file zone type into a server zone type.
689 */
690static dns_zonetype_t
691zonetype_fromconfig(const cfg_obj_t *map) {
692	const cfg_obj_t *obj = NULL;
693	isc_result_t result;
694
695	result = cfg_map_get(map, "type", &obj);
696	INSIST(result == ISC_R_SUCCESS && obj != NULL);
697	return (named_config_getzonetype(obj));
698}
699
700/*%
701 * Helper function for strtoargv().  Pardon the gratuitous recursion.
702 */
703static isc_result_t
704strtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp,
705	     unsigned int n) {
706	isc_result_t result;
707
708	/* Discard leading whitespace. */
709	while (*s == ' ' || *s == '\t') {
710		s++;
711	}
712
713	if (*s == '\0') {
714		/* We have reached the end of the string. */
715		*argcp = n;
716		*argvp = isc_mem_get(mctx, n * sizeof(char *));
717	} else {
718		char *p = s;
719		while (*p != ' ' && *p != '\t' && *p != '\0') {
720			p++;
721		}
722		if (*p != '\0') {
723			*p++ = '\0';
724		}
725
726		result = strtoargvsub(mctx, p, argcp, argvp, n + 1);
727		if (result != ISC_R_SUCCESS) {
728			return (result);
729		}
730		(*argvp)[n] = s;
731	}
732	return (ISC_R_SUCCESS);
733}
734
735/*%
736 * Tokenize the string "s" into whitespace-separated words,
737 * return the number of words in '*argcp' and an array
738 * of pointers to the words in '*argvp'.  The caller
739 * must free the array using isc_mem_put().  The string
740 * is modified in-place.
741 */
742static isc_result_t
743strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) {
744	return (strtoargvsub(mctx, s, argcp, argvp, 0));
745}
746
747static const char *const primary_synonyms[] = { "primary", "master", NULL };
748
749static const char *const secondary_synonyms[] = { "secondary", "slave", NULL };
750
751static void
752checknames(dns_zonetype_t ztype, const cfg_obj_t **maps,
753	   const cfg_obj_t **objp) {
754	isc_result_t result;
755
756	switch (ztype) {
757	case dns_zone_secondary:
758	case dns_zone_mirror:
759		result = named_checknames_get(maps, secondary_synonyms, objp);
760		break;
761	case dns_zone_primary:
762		result = named_checknames_get(maps, primary_synonyms, objp);
763		break;
764	default:
765		UNREACHABLE();
766	}
767
768	INSIST(result == ISC_R_SUCCESS && objp != NULL && *objp != NULL);
769}
770
771/*
772 * Callback to see if a non-recursive query coming from 'srcaddr' to
773 * 'destaddr', with optional key 'mykey' for class 'rdclass' would be
774 * delivered to 'myview'.
775 *
776 * We run this unlocked as both the view list and the interface list
777 * are updated when the appropriate task has exclusivity.
778 */
779static bool
780isself(dns_view_t *myview, dns_tsigkey_t *mykey, const isc_sockaddr_t *srcaddr,
781       const isc_sockaddr_t *dstaddr, dns_rdataclass_t rdclass, void *arg) {
782	dns_aclenv_t *env = NULL;
783	dns_view_t *view = NULL;
784	dns_tsigkey_t *key = NULL;
785	isc_netaddr_t netsrc;
786	isc_netaddr_t netdst;
787
788	UNUSED(arg);
789
790	/* interfacemgr can be destroyed only in exclusive mode. */
791	if (named_g_server->interfacemgr == NULL) {
792		return (true);
793	}
794
795	if (!ns_interfacemgr_listeningon(named_g_server->interfacemgr, dstaddr))
796	{
797		return (false);
798	}
799
800	isc_netaddr_fromsockaddr(&netsrc, srcaddr);
801	isc_netaddr_fromsockaddr(&netdst, dstaddr);
802	env = ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
803
804	for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL;
805	     view = ISC_LIST_NEXT(view, link))
806	{
807		const dns_name_t *tsig = NULL;
808
809		if (view->matchrecursiveonly) {
810			continue;
811		}
812
813		if (rdclass != view->rdclass) {
814			continue;
815		}
816
817		if (mykey != NULL) {
818			bool match;
819			isc_result_t result;
820
821			result = dns_view_gettsig(view, &mykey->name, &key);
822			if (result != ISC_R_SUCCESS) {
823				continue;
824			}
825			match = dst_key_compare(mykey->key, key->key);
826			dns_tsigkey_detach(&key);
827			if (!match) {
828				continue;
829			}
830			tsig = dns_tsigkey_identity(mykey);
831		}
832
833		if (dns_acl_allowed(&netsrc, tsig, view->matchclients, env) &&
834		    dns_acl_allowed(&netdst, tsig, view->matchdestinations,
835				    env))
836		{
837			break;
838		}
839	}
840	return (view == myview);
841}
842
843/*%
844 * For mirror zones, change "notify yes;" to "notify explicit;", informing the
845 * user only if "notify" was explicitly configured rather than inherited from
846 * default configuration.
847 */
848static dns_notifytype_t
849process_notifytype(dns_notifytype_t ntype, dns_zonetype_t ztype,
850		   const char *zname, const cfg_obj_t **maps) {
851	const cfg_obj_t *obj = NULL;
852
853	/*
854	 * Return the original setting if this is not a mirror zone or if the
855	 * zone is configured with something else than "notify yes;".
856	 */
857	if (ztype != dns_zone_mirror || ntype != dns_notifytype_yes) {
858		return (ntype);
859	}
860
861	/*
862	 * Only log a message if "notify" was set in the configuration
863	 * hierarchy supplied in 'maps'.
864	 */
865	if (named_config_get(maps, "notify", &obj) == ISC_R_SUCCESS) {
866		cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
867			    "'notify explicit;' will be used for mirror zone "
868			    "'%s'",
869			    zname);
870	}
871
872	return (dns_notifytype_explicit);
873}
874
875isc_result_t
876named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
877		     const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac,
878		     dns_kasplist_t *kasplist, dns_zone_t *zone,
879		     dns_zone_t *raw) {
880	isc_result_t result;
881	const char *zname;
882	dns_rdataclass_t zclass;
883	dns_rdataclass_t vclass;
884	const cfg_obj_t *maps[5];
885	const cfg_obj_t *nodefault[4];
886	const cfg_obj_t *zoptions = NULL;
887	const cfg_obj_t *options = NULL;
888	const cfg_obj_t *obj;
889	const char *filename = NULL;
890	const char *kaspname = NULL;
891	const char *dupcheck;
892	dns_notifytype_t notifytype = dns_notifytype_yes;
893	uint32_t count;
894	unsigned int dbargc;
895	char **dbargv;
896	static char default_dbtype[] = "rbt";
897	static char dlz_dbtype[] = "dlz";
898	char *cpval = default_dbtype;
899	isc_mem_t *mctx = dns_zone_getmctx(zone);
900	dns_dialuptype_t dialup = dns_dialuptype_no;
901	dns_zonetype_t ztype;
902	int i;
903	int32_t journal_size;
904	bool multi;
905	bool alt;
906	dns_view_t *view = NULL;
907	dns_kasp_t *kasp = NULL;
908	bool check = false, fail = false;
909	bool warn = false, ignore = false;
910	bool ixfrdiff;
911	bool use_kasp = false;
912	dns_masterformat_t masterformat;
913	const dns_master_style_t *masterstyle = &dns_master_style_default;
914	isc_stats_t *zoneqrystats;
915	dns_stats_t *rcvquerystats;
916	dns_stats_t *dnssecsignstats;
917	dns_zonestat_level_t statlevel = dns_zonestat_none;
918	int seconds;
919	dns_ttl_t maxttl = 0; /* unlimited */
920	dns_zone_t *mayberaw = (raw != NULL) ? raw : zone;
921	bool transferinsecs = ns_server_getoption(named_g_server->sctx,
922						  NS_SERVER_TRANSFERINSECS);
923
924	i = 0;
925	if (zconfig != NULL) {
926		zoptions = cfg_tuple_get(zconfig, "options");
927		nodefault[i] = maps[i] = zoptions;
928		i++;
929	}
930	if (vconfig != NULL) {
931		nodefault[i] = maps[i] = cfg_tuple_get(vconfig, "options");
932		i++;
933	}
934	if (config != NULL) {
935		(void)cfg_map_get(config, "options", &options);
936		if (options != NULL) {
937			nodefault[i] = maps[i] = options;
938			i++;
939		}
940	}
941	nodefault[i] = NULL;
942	maps[i++] = named_g_defaults;
943	maps[i] = NULL;
944
945	if (vconfig != NULL) {
946		CHECK(named_config_getclass(cfg_tuple_get(vconfig, "class"),
947					    dns_rdataclass_in, &vclass));
948	} else {
949		vclass = dns_rdataclass_in;
950	}
951
952	/*
953	 * Configure values common to all zone types.
954	 */
955
956	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
957
958	CHECK(named_config_getclass(cfg_tuple_get(zconfig, "class"), vclass,
959				    &zclass));
960	dns_zone_setclass(zone, zclass);
961	if (raw != NULL) {
962		dns_zone_setclass(raw, zclass);
963	}
964
965	ztype = zonetype_fromconfig(zoptions);
966	if (raw != NULL) {
967		dns_zone_settype(raw, ztype);
968		dns_zone_settype(zone, dns_zone_primary);
969	} else {
970		dns_zone_settype(zone, ztype);
971	}
972
973	obj = NULL;
974	result = cfg_map_get(zoptions, "database", &obj);
975	if (result == ISC_R_SUCCESS) {
976		cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
977	}
978	if (cpval == NULL) {
979		CHECK(ISC_R_NOMEMORY);
980	}
981
982	obj = NULL;
983	result = cfg_map_get(zoptions, "dlz", &obj);
984	if (result == ISC_R_SUCCESS) {
985		const char *dlzname = cfg_obj_asstring(obj);
986		size_t len;
987
988		if (cpval != default_dbtype) {
989			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
990				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
991				      "zone '%s': both 'database' and 'dlz' "
992				      "specified",
993				      zname);
994			CHECK(ISC_R_FAILURE);
995		}
996
997		len = strlen(dlzname) + 5;
998		cpval = isc_mem_allocate(mctx, len);
999		snprintf(cpval, len, "dlz %s", dlzname);
1000	}
1001
1002	result = strtoargv(mctx, cpval, &dbargc, &dbargv);
1003	if (result != ISC_R_SUCCESS && cpval != default_dbtype) {
1004		isc_mem_free(mctx, cpval);
1005		CHECK(result);
1006	}
1007
1008	/*
1009	 * ANSI C is strange here.  There is no logical reason why (char **)
1010	 * cannot be promoted automatically to (const char * const *) by the
1011	 * compiler w/o generating a warning.
1012	 */
1013	dns_zone_setdbtype(zone, dbargc, (const char *const *)dbargv);
1014	isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv));
1015	if (cpval != default_dbtype && cpval != dlz_dbtype) {
1016		isc_mem_free(mctx, cpval);
1017	}
1018
1019	obj = NULL;
1020	result = cfg_map_get(zoptions, "file", &obj);
1021	if (result == ISC_R_SUCCESS) {
1022		filename = cfg_obj_asstring(obj);
1023	}
1024
1025	/*
1026	 * Unless we're using some alternative database, a primary zone
1027	 * will be needing a master file.
1028	 */
1029	if (ztype == dns_zone_primary && cpval == default_dbtype &&
1030	    filename == NULL)
1031	{
1032		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1033			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1034			      "zone '%s': 'file' not specified", zname);
1035		CHECK(ISC_R_FAILURE);
1036	}
1037
1038	if (ztype == dns_zone_secondary || ztype == dns_zone_mirror) {
1039		masterformat = dns_masterformat_raw;
1040	} else {
1041		masterformat = dns_masterformat_text;
1042	}
1043	obj = NULL;
1044	result = named_config_get(maps, "masterfile-format", &obj);
1045	if (result == ISC_R_SUCCESS) {
1046		const char *masterformatstr = cfg_obj_asstring(obj);
1047
1048		if (strcasecmp(masterformatstr, "text") == 0) {
1049			masterformat = dns_masterformat_text;
1050		} else if (strcasecmp(masterformatstr, "raw") == 0) {
1051			masterformat = dns_masterformat_raw;
1052		} else {
1053			UNREACHABLE();
1054		}
1055	}
1056
1057	obj = NULL;
1058	result = named_config_get(maps, "masterfile-style", &obj);
1059	if (result == ISC_R_SUCCESS) {
1060		const char *masterstylestr = cfg_obj_asstring(obj);
1061
1062		if (masterformat != dns_masterformat_text) {
1063			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
1064				    "zone '%s': 'masterfile-style' "
1065				    "can only be used with "
1066				    "'masterfile-format text'",
1067				    zname);
1068			CHECK(ISC_R_FAILURE);
1069		}
1070
1071		if (strcasecmp(masterstylestr, "full") == 0) {
1072			masterstyle = &dns_master_style_full;
1073		} else if (strcasecmp(masterstylestr, "relative") == 0) {
1074			masterstyle = &dns_master_style_default;
1075		} else {
1076			UNREACHABLE();
1077		}
1078	}
1079
1080	obj = NULL;
1081	result = named_config_get(maps, "max-records", &obj);
1082	INSIST(result == ISC_R_SUCCESS && obj != NULL);
1083	dns_zone_setmaxrecords(mayberaw, cfg_obj_asuint32(obj));
1084	if (zone != mayberaw) {
1085		dns_zone_setmaxrecords(zone, 0);
1086	}
1087
1088	if (raw != NULL && filename != NULL) {
1089#define SIGNED ".signed"
1090		size_t signedlen = strlen(filename) + sizeof(SIGNED);
1091		char *signedname;
1092
1093		CHECK(dns_zone_setfile(raw, filename, masterformat,
1094				       masterstyle));
1095		signedname = isc_mem_get(mctx, signedlen);
1096
1097		(void)snprintf(signedname, signedlen, "%s" SIGNED, filename);
1098		result = dns_zone_setfile(zone, signedname,
1099					  dns_masterformat_raw, NULL);
1100		isc_mem_put(mctx, signedname, signedlen);
1101		CHECK(result);
1102	} else {
1103		CHECK(dns_zone_setfile(zone, filename, masterformat,
1104				       masterstyle));
1105	}
1106
1107	obj = NULL;
1108	result = cfg_map_get(zoptions, "journal", &obj);
1109	if (result == ISC_R_SUCCESS) {
1110		CHECK(dns_zone_setjournal(mayberaw, cfg_obj_asstring(obj)));
1111	}
1112
1113	/*
1114	 * Notify messages are processed by the raw zone if it exists.
1115	 */
1116	if (ztype == dns_zone_secondary || ztype == dns_zone_mirror) {
1117		CHECK(configure_zone_acl(zconfig, vconfig, config, allow_notify,
1118					 ac, mayberaw, dns_zone_setnotifyacl,
1119					 dns_zone_clearnotifyacl));
1120	}
1121
1122	/*
1123	 * XXXAG This probably does not make sense for stubs.
1124	 */
1125	CHECK(configure_zone_acl(zconfig, vconfig, config, allow_query, ac,
1126				 zone, dns_zone_setqueryacl,
1127				 dns_zone_clearqueryacl));
1128
1129	CHECK(configure_zone_acl(zconfig, vconfig, config, allow_query_on, ac,
1130				 zone, dns_zone_setqueryonacl,
1131				 dns_zone_clearqueryonacl));
1132
1133	obj = NULL;
1134	result = named_config_get(maps, "dialup", &obj);
1135	INSIST(result == ISC_R_SUCCESS && obj != NULL);
1136	if (cfg_obj_isboolean(obj)) {
1137		if (cfg_obj_asboolean(obj)) {
1138			dialup = dns_dialuptype_yes;
1139		} else {
1140			dialup = dns_dialuptype_no;
1141		}
1142	} else {
1143		const char *dialupstr = cfg_obj_asstring(obj);
1144		if (strcasecmp(dialupstr, "notify") == 0) {
1145			dialup = dns_dialuptype_notify;
1146		} else if (strcasecmp(dialupstr, "notify-passive") == 0) {
1147			dialup = dns_dialuptype_notifypassive;
1148		} else if (strcasecmp(dialupstr, "refresh") == 0) {
1149			dialup = dns_dialuptype_refresh;
1150		} else if (strcasecmp(dialupstr, "passive") == 0) {
1151			dialup = dns_dialuptype_passive;
1152		} else {
1153			UNREACHABLE();
1154		}
1155	}
1156	if (raw != NULL) {
1157		dns_zone_setdialup(raw, dialup);
1158	}
1159	dns_zone_setdialup(zone, dialup);
1160
1161	obj = NULL;
1162	result = named_config_get(maps, "zone-statistics", &obj);
1163	INSIST(result == ISC_R_SUCCESS && obj != NULL);
1164	if (cfg_obj_isboolean(obj)) {
1165		if (cfg_obj_asboolean(obj)) {
1166			statlevel = dns_zonestat_full;
1167		} else {
1168			statlevel = dns_zonestat_none;
1169		}
1170	} else {
1171		const char *levelstr = cfg_obj_asstring(obj);
1172		if (strcasecmp(levelstr, "full") == 0) {
1173			statlevel = dns_zonestat_full;
1174		} else if (strcasecmp(levelstr, "terse") == 0) {
1175			statlevel = dns_zonestat_terse;
1176		} else if (strcasecmp(levelstr, "none") == 0) {
1177			statlevel = dns_zonestat_none;
1178		} else {
1179			UNREACHABLE();
1180		}
1181	}
1182	dns_zone_setstatlevel(zone, statlevel);
1183
1184	zoneqrystats = NULL;
1185	rcvquerystats = NULL;
1186	dnssecsignstats = NULL;
1187	if (statlevel == dns_zonestat_full) {
1188		CHECK(isc_stats_create(mctx, &zoneqrystats,
1189				       ns_statscounter_max));
1190		CHECK(dns_rdatatypestats_create(mctx, &rcvquerystats));
1191		CHECK(dns_dnssecsignstats_create(mctx, &dnssecsignstats));
1192	}
1193	dns_zone_setrequeststats(zone, zoneqrystats);
1194	dns_zone_setrcvquerystats(zone, rcvquerystats);
1195	dns_zone_setdnssecsignstats(zone, dnssecsignstats);
1196
1197	if (zoneqrystats != NULL) {
1198		isc_stats_detach(&zoneqrystats);
1199	}
1200
1201	if (rcvquerystats != NULL) {
1202		dns_stats_detach(&rcvquerystats);
1203	}
1204
1205	if (dnssecsignstats != NULL) {
1206		dns_stats_detach(&dnssecsignstats);
1207	}
1208
1209	/*
1210	 * Configure authoritative zone functionality.  This applies
1211	 * to primary servers (type "primary") and secondaries
1212	 * acting as primaries (type "secondary"), but not to stubs.
1213	 */
1214	if (ztype != dns_zone_stub && ztype != dns_zone_staticstub &&
1215	    ztype != dns_zone_redirect)
1216	{
1217		obj = NULL;
1218		result = named_config_get(maps, "dnssec-policy", &obj);
1219		if (result == ISC_R_SUCCESS) {
1220			kaspname = cfg_obj_asstring(obj);
1221			if (strcmp(kaspname, "none") != 0) {
1222				result = dns_kasplist_find(kasplist, kaspname,
1223							   &kasp);
1224				if (result != ISC_R_SUCCESS) {
1225					cfg_obj_log(
1226						obj, named_g_lctx,
1227						ISC_LOG_ERROR,
1228						"dnssec-policy '%s' not found ",
1229						kaspname);
1230					CHECK(result);
1231				}
1232				dns_zone_setkasp(zone, kasp);
1233				use_kasp = true;
1234			}
1235		}
1236		if (!use_kasp) {
1237			dns_zone_setkasp(zone, NULL);
1238		}
1239
1240		obj = NULL;
1241		result = named_config_get(maps, "notify", &obj);
1242		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1243		if (cfg_obj_isboolean(obj)) {
1244			if (cfg_obj_asboolean(obj)) {
1245				notifytype = dns_notifytype_yes;
1246			} else {
1247				notifytype = dns_notifytype_no;
1248			}
1249		} else {
1250			const char *str = cfg_obj_asstring(obj);
1251			if (strcasecmp(str, "explicit") == 0) {
1252				notifytype = dns_notifytype_explicit;
1253			} else if (strcasecmp(str, "master-only") == 0 ||
1254				   strcasecmp(str, "primary-only") == 0)
1255			{
1256				notifytype = dns_notifytype_masteronly;
1257			} else {
1258				UNREACHABLE();
1259			}
1260		}
1261		notifytype = process_notifytype(notifytype, ztype, zname,
1262						nodefault);
1263		if (raw != NULL) {
1264			dns_zone_setnotifytype(raw, dns_notifytype_no);
1265		}
1266		dns_zone_setnotifytype(zone, notifytype);
1267
1268		obj = NULL;
1269		result = named_config_get(maps, "also-notify", &obj);
1270		if (result == ISC_R_SUCCESS &&
1271		    (notifytype == dns_notifytype_yes ||
1272		     notifytype == dns_notifytype_explicit ||
1273		     (notifytype == dns_notifytype_masteronly &&
1274		      ztype == dns_zone_primary)))
1275		{
1276			dns_ipkeylist_t ipkl;
1277			dns_ipkeylist_init(&ipkl);
1278
1279			CHECK(named_config_getipandkeylist(config, "primaries",
1280							   obj, mctx, &ipkl));
1281			dns_zone_setalsonotify(zone, ipkl.addrs, ipkl.keys,
1282					       ipkl.tlss, ipkl.count);
1283			dns_ipkeylist_clear(mctx, &ipkl);
1284		} else {
1285			dns_zone_setalsonotify(zone, NULL, NULL, NULL, 0);
1286		}
1287
1288		obj = NULL;
1289		result = named_config_get(maps, "parental-source", &obj);
1290		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1291
1292		CHECK(dns_zone_setparentalsrc4(zone, cfg_obj_assockaddr(obj)));
1293		named_add_reserved_dispatch(named_g_server,
1294					    cfg_obj_assockaddr(obj));
1295
1296		obj = NULL;
1297		result = named_config_get(maps, "parental-source-v6", &obj);
1298		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1299
1300		CHECK(dns_zone_setparentalsrc6(zone, cfg_obj_assockaddr(obj)));
1301		named_add_reserved_dispatch(named_g_server,
1302					    cfg_obj_assockaddr(obj));
1303
1304		obj = NULL;
1305		result = named_config_get(maps, "notify-source", &obj);
1306		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1307		CHECK(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj)));
1308		named_add_reserved_dispatch(named_g_server,
1309					    cfg_obj_assockaddr(obj));
1310
1311		obj = NULL;
1312		result = named_config_get(maps, "notify-source-v6", &obj);
1313		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1314		CHECK(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj)));
1315		named_add_reserved_dispatch(named_g_server,
1316					    cfg_obj_assockaddr(obj));
1317
1318		obj = NULL;
1319		result = named_config_get(maps, "notify-to-soa", &obj);
1320		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1321		dns_zone_setoption(zone, DNS_ZONEOPT_NOTIFYTOSOA,
1322				   cfg_obj_asboolean(obj));
1323
1324		dns_zone_setisself(zone, isself, NULL);
1325
1326		CHECK(configure_zone_acl(
1327			zconfig, vconfig, config, allow_transfer, ac, zone,
1328			dns_zone_setxfracl, dns_zone_clearxfracl));
1329
1330		obj = NULL;
1331		result = named_config_get(maps, "max-transfer-time-out", &obj);
1332		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1333		dns_zone_setmaxxfrout(
1334			zone, transferinsecs ? cfg_obj_asuint32(obj)
1335					     : cfg_obj_asuint32(obj) * 60);
1336
1337		obj = NULL;
1338		result = named_config_get(maps, "max-transfer-idle-out", &obj);
1339		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1340		dns_zone_setidleout(zone, transferinsecs
1341						  ? cfg_obj_asuint32(obj)
1342						  : cfg_obj_asuint32(obj) * 60);
1343
1344		obj = NULL;
1345		result = named_config_get(maps, "max-journal-size", &obj);
1346		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1347		if (raw != NULL) {
1348			dns_zone_setjournalsize(raw, -1);
1349		}
1350		dns_zone_setjournalsize(zone, -1);
1351		if (cfg_obj_isstring(obj)) {
1352			const char *str = cfg_obj_asstring(obj);
1353			if (strcasecmp(str, "unlimited") == 0) {
1354				journal_size = DNS_JOURNAL_SIZE_MAX;
1355			} else {
1356				INSIST(strcasecmp(str, "default") == 0);
1357				journal_size = -1;
1358			}
1359		} else {
1360			isc_resourcevalue_t value;
1361			value = cfg_obj_asuint64(obj);
1362			if (value > DNS_JOURNAL_SIZE_MAX) {
1363				cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
1364					    "'max-journal-size "
1365					    "%" PRId64 "' "
1366					    "is too large",
1367					    value);
1368				CHECK(ISC_R_RANGE);
1369			}
1370			journal_size = (uint32_t)value;
1371		}
1372		if (raw != NULL) {
1373			dns_zone_setjournalsize(raw, journal_size);
1374		}
1375		dns_zone_setjournalsize(zone, journal_size);
1376
1377		obj = NULL;
1378		result = named_config_get(maps, "ixfr-from-differences", &obj);
1379		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1380		if (cfg_obj_isboolean(obj)) {
1381			ixfrdiff = cfg_obj_asboolean(obj);
1382		} else if ((strcasecmp(cfg_obj_asstring(obj), "primary") == 0 ||
1383			    strcasecmp(cfg_obj_asstring(obj), "master") == 0) &&
1384			   ztype == dns_zone_primary)
1385		{
1386			ixfrdiff = true;
1387		} else if ((strcasecmp(cfg_obj_asstring(obj), "secondary") ==
1388				    0 ||
1389			    strcasecmp(cfg_obj_asstring(obj), "slave") == 0) &&
1390			   ztype == dns_zone_secondary)
1391		{
1392			ixfrdiff = true;
1393		} else {
1394			ixfrdiff = false;
1395		}
1396		if (raw != NULL) {
1397			dns_zone_setoption(raw, DNS_ZONEOPT_IXFRFROMDIFFS,
1398					   true);
1399			dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS,
1400					   false);
1401		} else {
1402			dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS,
1403					   ixfrdiff);
1404		}
1405
1406		obj = NULL;
1407		result = named_config_get(maps, "max-ixfr-ratio", &obj);
1408		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1409		if (cfg_obj_isstring(obj)) {
1410			dns_zone_setixfrratio(zone, 0);
1411		} else {
1412			dns_zone_setixfrratio(zone, cfg_obj_aspercentage(obj));
1413		}
1414
1415		obj = NULL;
1416		result = named_config_get(maps, "request-expire", &obj);
1417		INSIST(result == ISC_R_SUCCESS);
1418		dns_zone_setrequestexpire(zone, cfg_obj_asboolean(obj));
1419
1420		obj = NULL;
1421		result = named_config_get(maps, "request-ixfr", &obj);
1422		INSIST(result == ISC_R_SUCCESS);
1423		dns_zone_setrequestixfr(zone, cfg_obj_asboolean(obj));
1424
1425		obj = NULL;
1426		checknames(ztype, maps, &obj);
1427		INSIST(obj != NULL);
1428		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1429			fail = false;
1430			check = true;
1431		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1432			fail = check = true;
1433		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1434			fail = check = false;
1435		} else {
1436			UNREACHABLE();
1437		}
1438		if (raw != NULL) {
1439			dns_zone_setoption(raw, DNS_ZONEOPT_CHECKNAMES, check);
1440			dns_zone_setoption(raw, DNS_ZONEOPT_CHECKNAMESFAIL,
1441					   fail);
1442			dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, false);
1443			dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL,
1444					   false);
1445		} else {
1446			dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, check);
1447			dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL,
1448					   fail);
1449		}
1450
1451		obj = NULL;
1452		result = named_config_get(maps, "notify-delay", &obj);
1453		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1454		dns_zone_setnotifydelay(zone, cfg_obj_asuint32(obj));
1455
1456		obj = NULL;
1457		result = named_config_get(maps, "check-sibling", &obj);
1458		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1459		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSIBLING,
1460				   cfg_obj_asboolean(obj));
1461
1462		obj = NULL;
1463		result = named_config_get(maps, "check-spf", &obj);
1464		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1465		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1466			check = true;
1467		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1468			check = false;
1469		} else {
1470			UNREACHABLE();
1471		}
1472		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSPF, check);
1473
1474		obj = NULL;
1475		result = named_config_get(maps, "zero-no-soa-ttl", &obj);
1476		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1477		dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj));
1478
1479		obj = NULL;
1480		result = named_config_get(maps, "nsec3-test-zone", &obj);
1481		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1482		dns_zone_setoption(zone, DNS_ZONEOPT_NSEC3TESTZONE,
1483				   cfg_obj_asboolean(obj));
1484	} else if (ztype == dns_zone_redirect) {
1485		dns_zone_setnotifytype(zone, dns_notifytype_no);
1486
1487		obj = NULL;
1488		result = named_config_get(maps, "max-journal-size", &obj);
1489		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1490		dns_zone_setjournalsize(zone, -1);
1491		if (cfg_obj_isstring(obj)) {
1492			const char *str = cfg_obj_asstring(obj);
1493			if (strcasecmp(str, "unlimited") == 0) {
1494				journal_size = DNS_JOURNAL_SIZE_MAX;
1495			} else {
1496				INSIST(strcasecmp(str, "default") == 0);
1497				journal_size = -1;
1498			}
1499		} else {
1500			isc_resourcevalue_t value;
1501			value = cfg_obj_asuint64(obj);
1502			if (value > DNS_JOURNAL_SIZE_MAX) {
1503				cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
1504					    "'max-journal-size "
1505					    "%" PRId64 "' "
1506					    "is too large",
1507					    value);
1508				CHECK(ISC_R_RANGE);
1509			}
1510			journal_size = (uint32_t)value;
1511		}
1512		dns_zone_setjournalsize(zone, journal_size);
1513	}
1514
1515	if (use_kasp) {
1516		maxttl = dns_kasp_zonemaxttl(dns_zone_getkasp(zone), false);
1517	} else {
1518		obj = NULL;
1519		result = named_config_get(maps, "max-zone-ttl", &obj);
1520		if (result == ISC_R_SUCCESS) {
1521			if (cfg_obj_isduration(obj)) {
1522				maxttl = cfg_obj_asduration(obj);
1523			}
1524		}
1525	}
1526	dns_zone_setmaxttl(zone, maxttl);
1527	if (raw != NULL) {
1528		dns_zone_setmaxttl(raw, maxttl);
1529	}
1530
1531	/*
1532	 * Configure update-related options.  These apply to
1533	 * primary servers only.
1534	 */
1535	if (ztype == dns_zone_primary) {
1536		dns_acl_t *updateacl;
1537
1538		CHECK(configure_zone_acl(zconfig, vconfig, config, allow_update,
1539					 ac, mayberaw, dns_zone_setupdateacl,
1540					 dns_zone_clearupdateacl));
1541
1542		updateacl = dns_zone_getupdateacl(mayberaw);
1543		if (updateacl != NULL && dns_acl_isinsecure(updateacl)) {
1544			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1545				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
1546				      "zone '%s' allows unsigned updates "
1547				      "from remote hosts, which is insecure",
1548				      zname);
1549		}
1550
1551		CHECK(configure_zone_ssutable(zoptions, mayberaw, zname));
1552	}
1553
1554	/*
1555	 * Configure DNSSEC signing. These apply to primary zones or zones that
1556	 * use inline-signing (raw != NULL).
1557	 */
1558	if (ztype == dns_zone_primary || raw != NULL) {
1559		const cfg_obj_t *validity, *resign;
1560		bool allow = false, maint = false;
1561		bool sigvalinsecs;
1562
1563		if (use_kasp) {
1564			if (dns_kasp_nsec3(kasp)) {
1565				result = dns_zone_setnsec3param(
1566					zone, 1, dns_kasp_nsec3flags(kasp),
1567					dns_kasp_nsec3iter(kasp),
1568					dns_kasp_nsec3saltlen(kasp), NULL, true,
1569					false);
1570			} else {
1571				result = dns_zone_setnsec3param(
1572					zone, 0, 0, 0, 0, NULL, true, false);
1573			}
1574			INSIST(result == ISC_R_SUCCESS);
1575		}
1576
1577		if (use_kasp) {
1578			seconds = (uint32_t)dns_kasp_sigvalidity_dnskey(kasp);
1579		} else {
1580			obj = NULL;
1581			result = named_config_get(maps, "dnskey-sig-validity",
1582						  &obj);
1583			INSIST(result == ISC_R_SUCCESS && obj != NULL);
1584			seconds = cfg_obj_asuint32(obj) * 86400;
1585		}
1586		dns_zone_setkeyvalidityinterval(zone, seconds);
1587
1588		if (use_kasp) {
1589			seconds = (uint32_t)dns_kasp_sigvalidity(kasp);
1590			dns_zone_setsigvalidityinterval(zone, seconds);
1591			seconds = (uint32_t)dns_kasp_sigrefresh(kasp);
1592			dns_zone_setsigresigninginterval(zone, seconds);
1593		} else {
1594			obj = NULL;
1595			result = named_config_get(maps, "sig-validity-interval",
1596						  &obj);
1597			INSIST(result == ISC_R_SUCCESS && obj != NULL);
1598
1599			sigvalinsecs = ns_server_getoption(
1600				named_g_server->sctx, NS_SERVER_SIGVALINSECS);
1601			validity = cfg_tuple_get(obj, "validity");
1602			seconds = cfg_obj_asuint32(validity);
1603			if (!sigvalinsecs) {
1604				seconds *= 86400;
1605			}
1606			dns_zone_setsigvalidityinterval(zone, seconds);
1607
1608			resign = cfg_tuple_get(obj, "re-sign");
1609			if (cfg_obj_isvoid(resign)) {
1610				seconds /= 4;
1611			} else if (!sigvalinsecs) {
1612				uint32_t r = cfg_obj_asuint32(resign);
1613				if (seconds > 7 * 86400) {
1614					seconds = r * 86400;
1615				} else {
1616					seconds = r * 3600;
1617				}
1618			} else {
1619				seconds = cfg_obj_asuint32(resign);
1620			}
1621			dns_zone_setsigresigninginterval(zone, seconds);
1622		}
1623
1624		obj = NULL;
1625		result = named_config_get(maps, "key-directory", &obj);
1626		if (result == ISC_R_SUCCESS) {
1627			filename = cfg_obj_asstring(obj);
1628			CHECK(dns_zone_setkeydirectory(zone, filename));
1629		}
1630
1631		obj = NULL;
1632		result = named_config_get(maps, "sig-signing-signatures", &obj);
1633		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1634		dns_zone_setsignatures(zone, cfg_obj_asuint32(obj));
1635
1636		obj = NULL;
1637		result = named_config_get(maps, "sig-signing-nodes", &obj);
1638		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1639		dns_zone_setnodes(zone, cfg_obj_asuint32(obj));
1640
1641		obj = NULL;
1642		result = named_config_get(maps, "sig-signing-type", &obj);
1643		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1644		dns_zone_setprivatetype(zone, cfg_obj_asuint32(obj));
1645
1646		obj = NULL;
1647		result = named_config_get(maps, "update-check-ksk", &obj);
1648		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1649		dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK,
1650				   cfg_obj_asboolean(obj));
1651		/*
1652		 * This setting will be ignored if dnssec-policy is used.
1653		 * named-checkconf will error if both are configured.
1654		 */
1655
1656		obj = NULL;
1657		result = named_config_get(maps, "dnssec-dnskey-kskonly", &obj);
1658		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1659		dns_zone_setoption(zone, DNS_ZONEOPT_DNSKEYKSKONLY,
1660				   cfg_obj_asboolean(obj));
1661		/*
1662		 * This setting will be ignored if dnssec-policy is used.
1663		 * named-checkconf will error if both are configured.
1664		 */
1665
1666		obj = NULL;
1667		result = named_config_get(maps, "dnssec-loadkeys-interval",
1668					  &obj);
1669		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1670		CHECK(dns_zone_setrefreshkeyinterval(zone,
1671						     cfg_obj_asuint32(obj)));
1672
1673		obj = NULL;
1674		result = cfg_map_get(zoptions, "auto-dnssec", &obj);
1675		if (kasp != NULL) {
1676			bool s2i = (strcmp(dns_kasp_getname(kasp),
1677					   "insecure") != 0);
1678			dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, true);
1679			dns_zone_setkeyopt(zone, DNS_ZONEKEY_CREATE, !s2i);
1680			dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, true);
1681		} else if (result == ISC_R_SUCCESS) {
1682			const char *arg = cfg_obj_asstring(obj);
1683			if (strcasecmp(arg, "allow") == 0) {
1684				allow = true;
1685			} else if (strcasecmp(arg, "maintain") == 0) {
1686				allow = maint = true;
1687			} else if (strcasecmp(arg, "off") == 0) {
1688				/* Default */
1689			} else {
1690				UNREACHABLE();
1691			}
1692			dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow);
1693			dns_zone_setkeyopt(zone, DNS_ZONEKEY_CREATE, false);
1694			dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint);
1695		}
1696	}
1697
1698	if (ztype == dns_zone_secondary || ztype == dns_zone_mirror) {
1699		CHECK(configure_zone_acl(zconfig, vconfig, config,
1700					 allow_update_forwarding, ac, mayberaw,
1701					 dns_zone_setforwardacl,
1702					 dns_zone_clearforwardacl));
1703	}
1704
1705	/*%
1706	 * Configure parental agents, applies to primary and secondary zones.
1707	 */
1708	if (ztype == dns_zone_primary || ztype == dns_zone_secondary) {
1709		obj = NULL;
1710		(void)cfg_map_get(zoptions, "parental-agents", &obj);
1711		if (obj != NULL) {
1712			dns_ipkeylist_t ipkl;
1713			dns_ipkeylist_init(&ipkl);
1714			CHECK(named_config_getipandkeylist(
1715				config, "parental-agents", obj, mctx, &ipkl));
1716			dns_zone_setparentals(zone, ipkl.addrs, ipkl.keys,
1717					      ipkl.tlss, ipkl.count);
1718			dns_ipkeylist_clear(mctx, &ipkl);
1719		} else {
1720			dns_zone_setparentals(zone, NULL, NULL, NULL, 0);
1721		}
1722	}
1723
1724	/*%
1725	 * Configure primary zone functionality.
1726	 */
1727	if (ztype == dns_zone_primary) {
1728		obj = NULL;
1729		result = named_config_get(maps, "check-wildcard", &obj);
1730		if (result == ISC_R_SUCCESS) {
1731			check = cfg_obj_asboolean(obj);
1732		} else {
1733			check = false;
1734		}
1735		dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKWILDCARD, check);
1736
1737		obj = NULL;
1738		result = named_config_get(maps, "check-dup-records", &obj);
1739		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1740		dupcheck = cfg_obj_asstring(obj);
1741		if (strcasecmp(dupcheck, "warn") == 0) {
1742			fail = false;
1743			check = true;
1744		} else if (strcasecmp(dupcheck, "fail") == 0) {
1745			fail = check = true;
1746		} else if (strcasecmp(dupcheck, "ignore") == 0) {
1747			fail = check = false;
1748		} else {
1749			UNREACHABLE();
1750		}
1751		dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKDUPRR, check);
1752		dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKDUPRRFAIL, fail);
1753
1754		obj = NULL;
1755		result = named_config_get(maps, "check-mx", &obj);
1756		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1757		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1758			fail = false;
1759			check = true;
1760		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1761			fail = check = true;
1762		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1763			fail = check = false;
1764		} else {
1765			UNREACHABLE();
1766		}
1767		dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKMX, check);
1768		dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKMXFAIL, fail);
1769
1770		obj = NULL;
1771		result = named_config_get(maps, "check-integrity", &obj);
1772		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1773		dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKINTEGRITY,
1774				   cfg_obj_asboolean(obj));
1775
1776		obj = NULL;
1777		result = named_config_get(maps, "check-mx-cname", &obj);
1778		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1779		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1780			warn = true;
1781			ignore = false;
1782		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1783			warn = ignore = false;
1784		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1785			warn = ignore = true;
1786		} else {
1787			UNREACHABLE();
1788		}
1789		dns_zone_setoption(mayberaw, DNS_ZONEOPT_WARNMXCNAME, warn);
1790		dns_zone_setoption(mayberaw, DNS_ZONEOPT_IGNOREMXCNAME, ignore);
1791
1792		obj = NULL;
1793		result = named_config_get(maps, "check-srv-cname", &obj);
1794		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1795		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1796			warn = true;
1797			ignore = false;
1798		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1799			warn = ignore = false;
1800		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1801			warn = ignore = true;
1802		} else {
1803			UNREACHABLE();
1804		}
1805		dns_zone_setoption(mayberaw, DNS_ZONEOPT_WARNSRVCNAME, warn);
1806		dns_zone_setoption(mayberaw, DNS_ZONEOPT_IGNORESRVCNAME,
1807				   ignore);
1808
1809		obj = NULL;
1810		result = named_config_get(maps, "dnssec-secure-to-insecure",
1811					  &obj);
1812		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1813		dns_zone_setoption(mayberaw, DNS_ZONEOPT_SECURETOINSECURE,
1814				   cfg_obj_asboolean(obj));
1815
1816		obj = NULL;
1817		result = cfg_map_get(zoptions, "dnssec-update-mode", &obj);
1818		if (result == ISC_R_SUCCESS) {
1819			const char *arg = cfg_obj_asstring(obj);
1820			if (strcasecmp(arg, "no-resign") == 0) {
1821				dns_zone_setkeyopt(zone, DNS_ZONEKEY_NORESIGN,
1822						   true);
1823			} else if (strcasecmp(arg, "maintain") == 0) {
1824				/* Default */
1825			} else {
1826				UNREACHABLE();
1827			}
1828		}
1829
1830		obj = NULL;
1831		result = named_config_get(maps, "serial-update-method", &obj);
1832		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1833		if (strcasecmp(cfg_obj_asstring(obj), "unixtime") == 0) {
1834			dns_zone_setserialupdatemethod(
1835				zone, dns_updatemethod_unixtime);
1836		} else if (strcasecmp(cfg_obj_asstring(obj), "date") == 0) {
1837			dns_zone_setserialupdatemethod(zone,
1838						       dns_updatemethod_date);
1839		} else {
1840			dns_zone_setserialupdatemethod(
1841				zone, dns_updatemethod_increment);
1842		}
1843	}
1844
1845	/*
1846	 * Configure secondary zone functionality.
1847	 */
1848	switch (ztype) {
1849	case dns_zone_mirror:
1850		/*
1851		 * Disable outgoing zone transfers for mirror zones unless they
1852		 * are explicitly enabled by zone configuration.
1853		 */
1854		obj = NULL;
1855		(void)cfg_map_get(zoptions, "allow-transfer", &obj);
1856		if (obj == NULL) {
1857			dns_acl_t *none;
1858			CHECK(dns_acl_none(mctx, &none));
1859			dns_zone_setxfracl(zone, none);
1860			dns_acl_detach(&none);
1861		}
1862		FALLTHROUGH;
1863	case dns_zone_secondary:
1864	case dns_zone_stub:
1865	case dns_zone_redirect:
1866		count = 0;
1867		obj = NULL;
1868		(void)cfg_map_get(zoptions, "primaries", &obj);
1869		if (obj == NULL) {
1870			(void)cfg_map_get(zoptions, "masters", &obj);
1871		}
1872
1873		/*
1874		 * Use the built-in primary server list if one was not
1875		 * explicitly specified and this is a root zone mirror.
1876		 */
1877		if (obj == NULL && ztype == dns_zone_mirror &&
1878		    dns_name_equal(dns_zone_getorigin(zone), dns_rootname))
1879		{
1880			result = named_config_getremotesdef(
1881				named_g_config, "primaries",
1882				DEFAULT_IANA_ROOT_ZONE_PRIMARIES, &obj);
1883			CHECK(result);
1884		}
1885		if (obj != NULL) {
1886			dns_ipkeylist_t ipkl;
1887			dns_ipkeylist_init(&ipkl);
1888
1889			CHECK(named_config_getipandkeylist(config, "primaries",
1890							   obj, mctx, &ipkl));
1891			dns_zone_setprimaries(mayberaw, ipkl.addrs, ipkl.keys,
1892					      ipkl.tlss, ipkl.count);
1893			count = ipkl.count;
1894			dns_ipkeylist_clear(mctx, &ipkl);
1895		} else {
1896			dns_zone_setprimaries(mayberaw, NULL, NULL, NULL, 0);
1897		}
1898
1899		multi = false;
1900		if (count > 1) {
1901			obj = NULL;
1902			result = named_config_get(maps, "multi-master", &obj);
1903			INSIST(result == ISC_R_SUCCESS && obj != NULL);
1904			multi = cfg_obj_asboolean(obj);
1905		}
1906		dns_zone_setoption(mayberaw, DNS_ZONEOPT_MULTIMASTER, multi);
1907
1908		obj = NULL;
1909		result = named_config_get(maps, "max-transfer-time-in", &obj);
1910		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1911		dns_zone_setmaxxfrin(
1912			mayberaw, transferinsecs ? cfg_obj_asuint32(obj)
1913						 : cfg_obj_asuint32(obj) * 60);
1914
1915		obj = NULL;
1916		result = named_config_get(maps, "max-transfer-idle-in", &obj);
1917		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1918		dns_zone_setidlein(mayberaw,
1919				   transferinsecs ? cfg_obj_asuint32(obj)
1920						  : cfg_obj_asuint32(obj) * 60);
1921
1922		obj = NULL;
1923		result = named_config_get(maps, "max-refresh-time", &obj);
1924		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1925		dns_zone_setmaxrefreshtime(mayberaw, cfg_obj_asuint32(obj));
1926
1927		obj = NULL;
1928		result = named_config_get(maps, "min-refresh-time", &obj);
1929		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1930		dns_zone_setminrefreshtime(mayberaw, cfg_obj_asuint32(obj));
1931
1932		obj = NULL;
1933		result = named_config_get(maps, "max-retry-time", &obj);
1934		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1935		dns_zone_setmaxretrytime(mayberaw, cfg_obj_asuint32(obj));
1936
1937		obj = NULL;
1938		result = named_config_get(maps, "min-retry-time", &obj);
1939		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1940		dns_zone_setminretrytime(mayberaw, cfg_obj_asuint32(obj));
1941
1942		obj = NULL;
1943		result = named_config_get(maps, "transfer-source", &obj);
1944		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1945		CHECK(dns_zone_setxfrsource4(mayberaw,
1946					     cfg_obj_assockaddr(obj)));
1947		named_add_reserved_dispatch(named_g_server,
1948					    cfg_obj_assockaddr(obj));
1949
1950		obj = NULL;
1951		result = named_config_get(maps, "transfer-source-v6", &obj);
1952		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1953		CHECK(dns_zone_setxfrsource6(mayberaw,
1954					     cfg_obj_assockaddr(obj)));
1955		named_add_reserved_dispatch(named_g_server,
1956					    cfg_obj_assockaddr(obj));
1957
1958		obj = NULL;
1959		result = named_config_get(maps, "alt-transfer-source", &obj);
1960		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1961		CHECK(dns_zone_setaltxfrsource4(mayberaw,
1962						cfg_obj_assockaddr(obj)));
1963		obj = NULL;
1964		result = named_config_get(maps, "alt-transfer-source-v6", &obj);
1965		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1966		CHECK(dns_zone_setaltxfrsource6(mayberaw,
1967						cfg_obj_assockaddr(obj)));
1968		obj = NULL;
1969		(void)named_config_get(maps, "use-alt-transfer-source", &obj);
1970		if (obj == NULL) {
1971			/*
1972			 * Default off when views are in use otherwise
1973			 * on for BIND 8 compatibility.
1974			 */
1975			view = dns_zone_getview(zone);
1976			if (view != NULL && strcmp(view->name, "_default") == 0)
1977			{
1978				alt = true;
1979			} else {
1980				alt = false;
1981			}
1982		} else {
1983			alt = cfg_obj_asboolean(obj);
1984		}
1985		dns_zone_setoption(mayberaw, DNS_ZONEOPT_USEALTXFRSRC, alt);
1986
1987		obj = NULL;
1988		(void)named_config_get(maps, "try-tcp-refresh", &obj);
1989		dns_zone_setoption(mayberaw, DNS_ZONEOPT_TRYTCPREFRESH,
1990				   cfg_obj_asboolean(obj));
1991		break;
1992
1993	case dns_zone_staticstub:
1994		CHECK(configure_staticstub(zoptions, zone, zname,
1995					   default_dbtype));
1996		break;
1997
1998	default:
1999		break;
2000	}
2001
2002	result = ISC_R_SUCCESS;
2003
2004cleanup:
2005	if (kasp != NULL) {
2006		dns_kasp_detach(&kasp);
2007	}
2008	return (result);
2009}
2010
2011/*
2012 * Set up a DLZ zone as writeable
2013 */
2014isc_result_t
2015named_zone_configure_writeable_dlz(dns_dlzdb_t *dlzdatabase, dns_zone_t *zone,
2016				   dns_rdataclass_t rdclass, dns_name_t *name) {
2017	dns_db_t *db = NULL;
2018	isc_time_t now;
2019	isc_result_t result;
2020
2021	TIME_NOW(&now);
2022
2023	dns_zone_settype(zone, dns_zone_dlz);
2024	result = dns_sdlz_setdb(dlzdatabase, rdclass, name, &db);
2025	if (result != ISC_R_SUCCESS) {
2026		return (result);
2027	}
2028	result = dns_zone_dlzpostload(zone, db);
2029	dns_db_detach(&db);
2030	return (result);
2031}
2032
2033bool
2034named_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig) {
2035	const cfg_obj_t *zoptions = NULL;
2036	const cfg_obj_t *obj = NULL;
2037	const char *cfilename;
2038	const char *zfilename;
2039	dns_zone_t *raw = NULL;
2040	bool has_raw, inline_signing;
2041	dns_zonetype_t ztype;
2042
2043	zoptions = cfg_tuple_get(zconfig, "options");
2044
2045	/*
2046	 * We always reconfigure a static-stub zone for simplicity, assuming
2047	 * the amount of data to be loaded is small.
2048	 */
2049	if (zonetype_fromconfig(zoptions) == dns_zone_staticstub) {
2050		dns_zone_log(zone, ISC_LOG_DEBUG(1),
2051			     "not reusable: staticstub");
2052		return (false);
2053	}
2054
2055	/* If there's a raw zone, use that for filename and type comparison */
2056	dns_zone_getraw(zone, &raw);
2057	if (raw != NULL) {
2058		zfilename = dns_zone_getfile(raw);
2059		ztype = dns_zone_gettype(raw);
2060		dns_zone_detach(&raw);
2061		has_raw = true;
2062	} else {
2063		zfilename = dns_zone_getfile(zone);
2064		ztype = dns_zone_gettype(zone);
2065		has_raw = false;
2066	}
2067
2068	inline_signing = named_zone_inlinesigning(zconfig);
2069	if (!inline_signing && has_raw) {
2070		dns_zone_log(zone, ISC_LOG_DEBUG(1),
2071			     "not reusable: old zone was inline-signing");
2072		return (false);
2073	} else if (inline_signing && !has_raw) {
2074		dns_zone_log(zone, ISC_LOG_DEBUG(1),
2075			     "not reusable: old zone was not inline-signing");
2076		return (false);
2077	}
2078
2079	if (zonetype_fromconfig(zoptions) != ztype) {
2080		dns_zone_log(zone, ISC_LOG_DEBUG(1),
2081			     "not reusable: type mismatch");
2082		return (false);
2083	}
2084
2085	obj = NULL;
2086	(void)cfg_map_get(zoptions, "file", &obj);
2087	if (obj != NULL) {
2088		cfilename = cfg_obj_asstring(obj);
2089	} else {
2090		cfilename = NULL;
2091	}
2092	if (!((cfilename == NULL && zfilename == NULL) ||
2093	      (cfilename != NULL && zfilename != NULL &&
2094	       strcmp(cfilename, zfilename) == 0)))
2095	{
2096		dns_zone_log(zone, ISC_LOG_DEBUG(1),
2097			     "not reusable: filename mismatch");
2098		return (false);
2099	}
2100
2101	return (true);
2102}
2103
2104bool
2105named_zone_inlinesigning(const cfg_obj_t *zconfig) {
2106	const cfg_obj_t *zoptions = NULL;
2107	const cfg_obj_t *signing = NULL;
2108	bool inline_signing = false;
2109
2110	zoptions = cfg_tuple_get(zconfig, "options");
2111	inline_signing = (cfg_map_get(zoptions, "inline-signing", &signing) ==
2112				  ISC_R_SUCCESS &&
2113			  cfg_obj_asboolean(signing));
2114
2115	return (inline_signing);
2116}
2117