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