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