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