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