xref: /netbsd-src/external/mpl/bind/dist/bin/named/zoneconf.c (revision 70f7362772ba52b749c976fb5e86e39a8b2c9afc)
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 */
58 typedef 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  */
84 static isc_result_t
85 configure_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 
180 parse_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  */
200 static isc_result_t
201 configure_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 
380 cleanup:
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  */
400 static isc_result_t
401 configure_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  */
486 static isc_result_t
487 configure_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  */
545 static isc_result_t
546 configure_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 
660 cleanup:
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  */
690 static dns_zonetype_t
691 zonetype_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  */
703 static isc_result_t
704 strtoargvsub(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  */
742 static isc_result_t
743 strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) {
744 	return (strtoargvsub(mctx, s, argcp, argvp, 0));
745 }
746 
747 static const char *const primary_synonyms[] = { "primary", "master", NULL };
748 
749 static const char *const secondary_synonyms[] = { "secondary", "slave", NULL };
750 
751 static void
752 checknames(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  */
779 static bool
780 isself(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  */
848 static dns_notifytype_t
849 process_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 
875 isc_result_t
876 named_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 
2004 cleanup:
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  */
2014 isc_result_t
2015 named_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 
2033 bool
2034 named_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 
2104 bool
2105 named_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