1/*
2 * Copyright (C) 2004-2014  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/* $Id$ */
19
20/*% */
21
22#include <config.h>
23
24#include <isc/buffer.h>
25#include <isc/file.h>
26#include <isc/mem.h>
27#include <isc/print.h>
28#include <isc/stats.h>
29#include <isc/string.h>		/* Required for HP/UX (and others?) */
30#include <isc/util.h>
31
32#include <dns/acl.h>
33#include <dns/db.h>
34#include <dns/fixedname.h>
35#include <dns/log.h>
36#include <dns/name.h>
37#include <dns/rdata.h>
38#include <dns/rdatatype.h>
39#include <dns/rdataset.h>
40#include <dns/rdatalist.h>
41#include <dns/result.h>
42#include <dns/sdlz.h>
43#include <dns/ssu.h>
44#include <dns/stats.h>
45#include <dns/view.h>
46#include <dns/zone.h>
47
48#include <named/client.h>
49#include <named/config.h>
50#include <named/globals.h>
51#include <named/log.h>
52#include <named/server.h>
53#include <named/zoneconf.h>
54
55/* ACLs associated with zone */
56typedef enum {
57	allow_notify,
58	allow_query,
59	allow_query_on,
60	allow_transfer,
61	allow_update,
62	allow_update_forwarding
63} acl_type_t;
64
65#define RETERR(x) do { \
66	isc_result_t _r = (x); \
67	if (_r != ISC_R_SUCCESS) \
68		return (_r); \
69	} while (0)
70
71#define CHECK(x) do { \
72	result = (x); \
73	if (result != ISC_R_SUCCESS) \
74		goto cleanup; \
75	} while (0)
76
77/*%
78 * Convenience function for configuring a single zone ACL.
79 */
80static isc_result_t
81configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
82		   const cfg_obj_t *config, acl_type_t acltype,
83		   cfg_aclconfctx_t *actx, dns_zone_t *zone,
84		   void (*setzacl)(dns_zone_t *, dns_acl_t *),
85		   void (*clearzacl)(dns_zone_t *))
86{
87	isc_result_t result;
88	const cfg_obj_t *maps[5] = {NULL, NULL, NULL, NULL, NULL};
89	const cfg_obj_t *aclobj = NULL;
90	int i = 0;
91	dns_acl_t **aclp = NULL, *acl = NULL;
92	const char *aclname;
93	dns_view_t *view;
94
95	view = dns_zone_getview(zone);
96
97	switch (acltype) {
98	    case allow_notify:
99		if (view != NULL)
100			aclp = &view->notifyacl;
101		aclname = "allow-notify";
102		break;
103	    case allow_query:
104		if (view != NULL)
105			aclp = &view->queryacl;
106		aclname = "allow-query";
107		break;
108	    case allow_query_on:
109		if (view != NULL)
110			aclp = &view->queryonacl;
111		aclname = "allow-query-on";
112		break;
113	    case allow_transfer:
114		if (view != NULL)
115			aclp = &view->transferacl;
116		aclname = "allow-transfer";
117		break;
118	    case allow_update:
119		if (view != NULL)
120			aclp = &view->updateacl;
121		aclname = "allow-update";
122		break;
123	    case allow_update_forwarding:
124		if (view != NULL)
125			aclp = &view->upfwdacl;
126		aclname = "allow-update-forwarding";
127		break;
128	    default:
129		INSIST(0);
130		return (ISC_R_FAILURE);
131	}
132
133	/* First check to see if ACL is defined within the zone */
134	if (zconfig != NULL) {
135		maps[0] = cfg_tuple_get(zconfig, "options");
136		(void)ns_config_get(maps, aclname, &aclobj);
137		if (aclobj != NULL) {
138			aclp = NULL;
139			goto parse_acl;
140		}
141	}
142
143	/* Failing that, see if there's a default ACL already in the view */
144	if (aclp != NULL && *aclp != NULL) {
145		(*setzacl)(zone, *aclp);
146		return (ISC_R_SUCCESS);
147	}
148
149	/* Check for default ACLs that haven't been parsed yet */
150	if (vconfig != NULL) {
151		const cfg_obj_t *options = cfg_tuple_get(vconfig, "options");
152		if (options != NULL)
153			maps[i++] = options;
154	}
155	if (config != NULL) {
156		const cfg_obj_t *options = NULL;
157		(void)cfg_map_get(config, "options", &options);
158		if (options != NULL)
159			maps[i++] = options;
160	}
161	maps[i++] = ns_g_defaults;
162	maps[i] = NULL;
163
164	(void)ns_config_get(maps, aclname, &aclobj);
165	if (aclobj == NULL) {
166		(*clearzacl)(zone);
167		return (ISC_R_SUCCESS);
168	}
169
170parse_acl:
171	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, actx,
172				    dns_zone_getmctx(zone), 0, &acl);
173	if (result != ISC_R_SUCCESS)
174		return (result);
175	(*setzacl)(zone, acl);
176
177	/* Set the view default now */
178	if (aclp != NULL)
179		dns_acl_attach(acl, aclp);
180
181	dns_acl_detach(&acl);
182	return (ISC_R_SUCCESS);
183}
184
185/*%
186 * Parse the zone update-policy statement.
187 */
188static isc_result_t
189configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
190			const char *zname)
191{
192	const cfg_obj_t *updatepolicy = NULL;
193	const cfg_listelt_t *element, *element2;
194	dns_ssutable_t *table = NULL;
195	isc_mem_t *mctx = dns_zone_getmctx(zone);
196	isc_boolean_t autoddns = ISC_FALSE;
197	isc_result_t result;
198
199	(void)cfg_map_get(zconfig, "update-policy", &updatepolicy);
200
201	if (updatepolicy == NULL) {
202		dns_zone_setssutable(zone, NULL);
203		return (ISC_R_SUCCESS);
204	}
205
206	if (cfg_obj_isstring(updatepolicy) &&
207	    strcmp("local", cfg_obj_asstring(updatepolicy)) == 0) {
208		autoddns = ISC_TRUE;
209		updatepolicy = NULL;
210	}
211
212	result = dns_ssutable_create(mctx, &table);
213	if (result != ISC_R_SUCCESS)
214		return (result);
215
216	for (element = cfg_list_first(updatepolicy);
217	     element != NULL;
218	     element = cfg_list_next(element))
219	{
220		const cfg_obj_t *stmt = cfg_listelt_value(element);
221		const cfg_obj_t *mode = cfg_tuple_get(stmt, "mode");
222		const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
223		const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
224		const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
225		const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
226		const char *str;
227		isc_boolean_t grant = ISC_FALSE;
228		isc_boolean_t usezone = ISC_FALSE;
229		unsigned int mtype = DNS_SSUMATCHTYPE_NAME;
230		dns_fixedname_t fname, fident;
231		isc_buffer_t b;
232		dns_rdatatype_t *types;
233		unsigned int i, n;
234
235		str = cfg_obj_asstring(mode);
236		if (strcasecmp(str, "grant") == 0)
237			grant = ISC_TRUE;
238		else if (strcasecmp(str, "deny") == 0)
239			grant = ISC_FALSE;
240		else
241			INSIST(0);
242
243		str = cfg_obj_asstring(matchtype);
244		if (strcasecmp(str, "name") == 0)
245			mtype = DNS_SSUMATCHTYPE_NAME;
246		else if (strcasecmp(str, "subdomain") == 0)
247			mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
248		else if (strcasecmp(str, "wildcard") == 0)
249			mtype = DNS_SSUMATCHTYPE_WILDCARD;
250		else if (strcasecmp(str, "self") == 0)
251			mtype = DNS_SSUMATCHTYPE_SELF;
252		else if (strcasecmp(str, "selfsub") == 0)
253			mtype = DNS_SSUMATCHTYPE_SELFSUB;
254		else if (strcasecmp(str, "selfwild") == 0)
255			mtype = DNS_SSUMATCHTYPE_SELFWILD;
256		else if (strcasecmp(str, "ms-self") == 0)
257			mtype = DNS_SSUMATCHTYPE_SELFMS;
258		else if (strcasecmp(str, "krb5-self") == 0)
259			mtype = DNS_SSUMATCHTYPE_SELFKRB5;
260		else if (strcasecmp(str, "ms-subdomain") == 0)
261			mtype = DNS_SSUMATCHTYPE_SUBDOMAINMS;
262		else if (strcasecmp(str, "krb5-subdomain") == 0)
263			mtype = DNS_SSUMATCHTYPE_SUBDOMAINKRB5;
264		else if (strcasecmp(str, "tcp-self") == 0)
265			mtype = DNS_SSUMATCHTYPE_TCPSELF;
266		else if (strcasecmp(str, "6to4-self") == 0)
267			mtype = DNS_SSUMATCHTYPE_6TO4SELF;
268		else if (strcasecmp(str, "zonesub") == 0) {
269			mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
270			usezone = ISC_TRUE;
271		} else if (strcasecmp(str, "external") == 0)
272			mtype = DNS_SSUMATCHTYPE_EXTERNAL;
273		else
274			INSIST(0);
275
276		dns_fixedname_init(&fident);
277		str = cfg_obj_asstring(identity);
278		isc_buffer_constinit(&b, str, strlen(str));
279		isc_buffer_add(&b, strlen(str));
280		result = dns_name_fromtext(dns_fixedname_name(&fident), &b,
281					   dns_rootname, 0, NULL);
282		if (result != ISC_R_SUCCESS) {
283			cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
284				    "'%s' is not a valid name", str);
285			goto cleanup;
286		}
287
288		dns_fixedname_init(&fname);
289		if (usezone) {
290			result = dns_name_copy(dns_zone_getorigin(zone),
291					       dns_fixedname_name(&fname),
292					       NULL);
293			if (result != ISC_R_SUCCESS) {
294				cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
295					    "error copying origin: %s",
296					    isc_result_totext(result));
297				goto cleanup;
298			}
299		} else {
300			str = cfg_obj_asstring(dname);
301			isc_buffer_constinit(&b, str, strlen(str));
302			isc_buffer_add(&b, strlen(str));
303			result = dns_name_fromtext(dns_fixedname_name(&fname),
304						   &b, dns_rootname, 0, NULL);
305			if (result != ISC_R_SUCCESS) {
306				cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
307					    "'%s' is not a valid name", str);
308				goto cleanup;
309			}
310		}
311
312		n = ns_config_listcount(typelist);
313		if (n == 0)
314			types = NULL;
315		else {
316			types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t));
317			if (types == NULL) {
318				result = ISC_R_NOMEMORY;
319				goto cleanup;
320			}
321		}
322
323		i = 0;
324		for (element2 = cfg_list_first(typelist);
325		     element2 != NULL;
326		     element2 = cfg_list_next(element2))
327		{
328			const cfg_obj_t *typeobj;
329			isc_textregion_t r;
330
331			INSIST(i < n);
332
333			typeobj = cfg_listelt_value(element2);
334			str = cfg_obj_asstring(typeobj);
335			DE_CONST(str, r.base);
336			r.length = strlen(str);
337
338			result = dns_rdatatype_fromtext(&types[i++], &r);
339			if (result != ISC_R_SUCCESS) {
340				cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
341					    "'%s' is not a valid type", str);
342				isc_mem_put(mctx, types,
343					    n * sizeof(dns_rdatatype_t));
344				goto cleanup;
345			}
346		}
347		INSIST(i == n);
348
349		result = dns_ssutable_addrule(table, grant,
350					      dns_fixedname_name(&fident),
351					      mtype,
352					      dns_fixedname_name(&fname),
353					      n, types);
354		if (types != NULL)
355			isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t));
356		if (result != ISC_R_SUCCESS) {
357			goto cleanup;
358		}
359	}
360
361	/*
362	 * If "update-policy local;" and a session key exists,
363	 * then use the default policy, which is equivalent to:
364	 * update-policy { grant <session-keyname> zonesub any; };
365	 */
366	if (autoddns) {
367		dns_rdatatype_t any = dns_rdatatype_any;
368
369		if (ns_g_server->session_keyname == NULL) {
370			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
371				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
372				      "failed to enable auto DDNS policy "
373				      "for zone %s: session key not found",
374				      zname);
375			result = ISC_R_NOTFOUND;
376			goto cleanup;
377		}
378
379		result = dns_ssutable_addrule(table, ISC_TRUE,
380					      ns_g_server->session_keyname,
381					      DNS_SSUMATCHTYPE_SUBDOMAIN,
382					      dns_zone_getorigin(zone),
383					      1, &any);
384
385		if (result != ISC_R_SUCCESS)
386			goto cleanup;
387	}
388
389	result = ISC_R_SUCCESS;
390	dns_zone_setssutable(zone, table);
391
392 cleanup:
393	dns_ssutable_detach(&table);
394	return (result);
395}
396
397/*
398 * This is the TTL used for internally generated RRsets for static-stub zones.
399 * The value doesn't matter because the mapping is static, but needs to be
400 * defined for the sake of implementation.
401 */
402#define STATICSTUB_SERVER_TTL 86400
403
404/*%
405 * Configure an apex NS with glues for a static-stub zone.
406 * For example, for the zone named "example.com", the following RRs will be
407 * added to the zone DB:
408 * example.com. NS example.com.
409 * example.com. A 192.0.2.1
410 * example.com. AAAA 2001:db8::1
411 */
412static isc_result_t
413configure_staticstub_serveraddrs(const cfg_obj_t *zconfig, dns_zone_t *zone,
414				 dns_rdatalist_t *rdatalist_ns,
415				 dns_rdatalist_t *rdatalist_a,
416				 dns_rdatalist_t *rdatalist_aaaa)
417{
418	const cfg_listelt_t *element;
419	isc_mem_t *mctx = dns_zone_getmctx(zone);
420	isc_region_t region, sregion;
421	dns_rdata_t *rdata;
422	isc_result_t result = ISC_R_SUCCESS;
423
424	for (element = cfg_list_first(zconfig);
425	     element != NULL;
426	     element = cfg_list_next(element))
427	{
428		const isc_sockaddr_t* sa;
429		isc_netaddr_t na;
430		const cfg_obj_t *address = cfg_listelt_value(element);
431		dns_rdatalist_t *rdatalist;
432
433		sa = cfg_obj_assockaddr(address);
434		if (isc_sockaddr_getport(sa) != 0) {
435			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
436				    "port is not configurable for "
437				    "static stub server-addresses");
438			return (ISC_R_FAILURE);
439		}
440		isc_netaddr_fromsockaddr(&na, sa);
441		if (isc_netaddr_getzone(&na) != 0) {
442			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
443					    "scoped address is not allowed "
444					    "for static stub "
445					    "server-addresses");
446			return (ISC_R_FAILURE);
447		}
448
449		switch (na.family) {
450		case AF_INET:
451			region.length = sizeof(na.type.in);
452			rdatalist = rdatalist_a;
453			break;
454		default:
455			INSIST(na.family == AF_INET6);
456			region.length = sizeof(na.type.in6);
457			rdatalist = rdatalist_aaaa;
458			break;
459		}
460
461		rdata = isc_mem_get(mctx, sizeof(*rdata) + region.length);
462		if (rdata == NULL)
463			return (ISC_R_NOMEMORY);
464		region.base = (unsigned char *)(rdata + 1);
465		memmove(region.base, &na.type, region.length);
466		dns_rdata_init(rdata);
467		dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
468				     rdatalist->type, &region);
469		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
470	}
471
472	/*
473	 * If no address is specified (unlikely in this context, but possible),
474	 * there's nothing to do anymore.
475	 */
476	if (ISC_LIST_EMPTY(rdatalist_a->rdata) &&
477	    ISC_LIST_EMPTY(rdatalist_aaaa->rdata)) {
478		return (ISC_R_SUCCESS);
479	}
480
481	/* Add to the list an apex NS with the ns name being the origin name */
482	dns_name_toregion(dns_zone_getorigin(zone), &sregion);
483	rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length);
484	if (rdata == NULL) {
485		/*
486		 * Already allocated data will be freed in the caller, so
487		 * we can simply return here.
488		 */
489		return (ISC_R_NOMEMORY);
490	}
491	region.length = sregion.length;
492	region.base = (unsigned char *)(rdata + 1);
493	memmove(region.base, sregion.base, region.length);
494	dns_rdata_init(rdata);
495	dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
496			     dns_rdatatype_ns, &region);
497	ISC_LIST_APPEND(rdatalist_ns->rdata, rdata, link);
498
499	return (result);
500}
501
502/*%
503 * Configure an apex NS with an out-of-zone NS names for a static-stub zone.
504 * For example, for the zone named "example.com", something like the following
505 * RRs will be added to the zone DB:
506 * example.com. NS ns.example.net.
507 */
508static isc_result_t
509configure_staticstub_servernames(const cfg_obj_t *zconfig, dns_zone_t *zone,
510				 dns_rdatalist_t *rdatalist, const char *zname)
511{
512	const cfg_listelt_t *element;
513	isc_mem_t *mctx = dns_zone_getmctx(zone);
514	dns_rdata_t *rdata;
515	isc_region_t sregion, region;
516	isc_result_t result = ISC_R_SUCCESS;
517
518	for (element = cfg_list_first(zconfig);
519	     element != NULL;
520	     element = cfg_list_next(element))
521	{
522		const cfg_obj_t *obj;
523		const char *str;
524		dns_fixedname_t fixed_name;
525		dns_name_t *nsname;
526		isc_buffer_t b;
527
528		obj = cfg_listelt_value(element);
529		str = cfg_obj_asstring(obj);
530
531		dns_fixedname_init(&fixed_name);
532		nsname = dns_fixedname_name(&fixed_name);
533
534		isc_buffer_constinit(&b, str, strlen(str));
535		isc_buffer_add(&b, strlen(str));
536		result = dns_name_fromtext(nsname, &b, dns_rootname, 0, NULL);
537		if (result != ISC_R_SUCCESS) {
538			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
539					    "server-name '%s' is not a valid "
540					    "name", str);
541			return (result);
542		}
543		if (dns_name_issubdomain(nsname, dns_zone_getorigin(zone))) {
544			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
545				    "server-name '%s' must not be a "
546				    "subdomain of zone name '%s'",
547				    str, zname);
548			return (ISC_R_FAILURE);
549		}
550
551		dns_name_toregion(nsname, &sregion);
552		rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length);
553		if (rdata == NULL)
554			return (ISC_R_NOMEMORY);
555		region.length = sregion.length;
556		region.base = (unsigned char *)(rdata + 1);
557		memmove(region.base, sregion.base, region.length);
558		dns_rdata_init(rdata);
559		dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
560				     dns_rdatatype_ns, &region);
561		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
562	}
563
564	return (result);
565}
566
567/*%
568 * Configure static-stub zone.
569 */
570static isc_result_t
571configure_staticstub(const cfg_obj_t *zconfig, dns_zone_t *zone,
572		     const char *zname, const char *dbtype)
573{
574	int i = 0;
575	const cfg_obj_t *obj;
576	isc_mem_t *mctx = dns_zone_getmctx(zone);
577	dns_db_t *db = NULL;
578	dns_dbversion_t *dbversion = NULL;
579	dns_dbnode_t *apexnode = NULL;
580	dns_name_t apexname;
581	isc_result_t result;
582	dns_rdataset_t rdataset;
583	dns_rdatalist_t rdatalist_ns, rdatalist_a, rdatalist_aaaa;
584	dns_rdatalist_t* rdatalists[] = {
585		&rdatalist_ns, &rdatalist_a, &rdatalist_aaaa, NULL
586	};
587	dns_rdata_t *rdata;
588	isc_region_t region;
589
590	/* Create the DB beforehand */
591	RETERR(dns_db_create(mctx, dbtype, dns_zone_getorigin(zone),
592			     dns_dbtype_stub, dns_zone_getclass(zone),
593			     0, NULL, &db));
594	dns_zone_setdb(zone, db);
595
596	dns_rdatalist_init(&rdatalist_ns);
597	rdatalist_ns.rdclass = dns_zone_getclass(zone);
598	rdatalist_ns.type = dns_rdatatype_ns;
599	rdatalist_ns.ttl = STATICSTUB_SERVER_TTL;
600
601	dns_rdatalist_init(&rdatalist_a);
602	rdatalist_a.rdclass = dns_zone_getclass(zone);
603	rdatalist_a.type = dns_rdatatype_a;
604	rdatalist_a.ttl = STATICSTUB_SERVER_TTL;
605
606	dns_rdatalist_init(&rdatalist_aaaa);
607	rdatalist_aaaa.rdclass = dns_zone_getclass(zone);
608	rdatalist_aaaa.type = dns_rdatatype_aaaa;
609	rdatalist_aaaa.ttl = STATICSTUB_SERVER_TTL;
610
611	/* Prepare zone RRs from the configuration */
612	obj = NULL;
613	result = cfg_map_get(zconfig, "server-addresses", &obj);
614	if (result == ISC_R_SUCCESS) {
615		INSIST(obj != NULL);
616		result = configure_staticstub_serveraddrs(obj, zone,
617							  &rdatalist_ns,
618							  &rdatalist_a,
619							  &rdatalist_aaaa);
620		if (result != ISC_R_SUCCESS)
621			goto cleanup;
622	}
623
624	obj = NULL;
625	result = cfg_map_get(zconfig, "server-names", &obj);
626	if (result == ISC_R_SUCCESS) {
627		INSIST(obj != NULL);
628		result = configure_staticstub_servernames(obj, zone,
629							  &rdatalist_ns,
630							  zname);
631		if (result != ISC_R_SUCCESS)
632			goto cleanup;
633	}
634
635	/*
636	 * Sanity check: there should be at least one NS RR at the zone apex
637	 * to trigger delegation.
638	 */
639	if (ISC_LIST_EMPTY(rdatalist_ns.rdata)) {
640		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
641			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
642			      "No NS record is configured for a "
643			      "static-stub zone '%s'", zname);
644		result = ISC_R_FAILURE;
645		goto cleanup;
646	}
647
648	/*
649	 * Now add NS and glue A/AAAA RRsets to the zone DB.
650	 * First open a new version for the add operation and get a pointer
651	 * to the apex node (all RRs are of the apex name).
652	 */
653	result = dns_db_newversion(db, &dbversion);
654	if (result != ISC_R_SUCCESS)
655		goto cleanup;
656	dns_name_init(&apexname, NULL);
657	dns_name_clone(dns_zone_getorigin(zone), &apexname);
658	result = dns_db_findnode(db, &apexname, ISC_FALSE, &apexnode);
659	if (result != ISC_R_SUCCESS)
660		goto cleanup;
661
662	/* Add NS RRset */
663	dns_rdataset_init(&rdataset);
664	RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_ns, &rdataset)
665		      == ISC_R_SUCCESS);
666	result = dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset,
667				    0, NULL);
668	dns_rdataset_disassociate(&rdataset);
669	if (result != ISC_R_SUCCESS)
670		goto cleanup;
671
672	/* Add glue A RRset, if any */
673	if (!ISC_LIST_EMPTY(rdatalist_a.rdata)) {
674		RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_a, &rdataset)
675			      == ISC_R_SUCCESS);
676		result = dns_db_addrdataset(db, apexnode, dbversion, 0,
677					    &rdataset, 0, NULL);
678		dns_rdataset_disassociate(&rdataset);
679		if (result != ISC_R_SUCCESS)
680			goto cleanup;
681	}
682
683	/* Add glue AAAA RRset, if any */
684	if (!ISC_LIST_EMPTY(rdatalist_aaaa.rdata)) {
685		RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_aaaa,
686						       &rdataset)
687			      == ISC_R_SUCCESS);
688		result = dns_db_addrdataset(db, apexnode, dbversion, 0,
689					    &rdataset, 0, NULL);
690		dns_rdataset_disassociate(&rdataset);
691		if (result != ISC_R_SUCCESS)
692			goto cleanup;
693	}
694
695	result = ISC_R_SUCCESS;
696
697  cleanup:
698	if (apexnode != NULL)
699		dns_db_detachnode(db, &apexnode);
700	if (dbversion != NULL)
701		dns_db_closeversion(db, &dbversion, ISC_TRUE);
702	if (db != NULL)
703		dns_db_detach(&db);
704	for (i = 0; rdatalists[i] != NULL; i++) {
705		while ((rdata = ISC_LIST_HEAD(rdatalists[i]->rdata)) != NULL) {
706			ISC_LIST_UNLINK(rdatalists[i]->rdata, rdata, link);
707			dns_rdata_toregion(rdata, &region);
708			isc_mem_put(mctx, rdata,
709				    sizeof(*rdata) + region.length);
710		}
711	}
712
713	return (result);
714}
715
716/*%
717 * Convert a config file zone type into a server zone type.
718 */
719static inline dns_zonetype_t
720zonetype_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 */
732static isc_result_t
733strtoargvsub(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 */
770static isc_result_t
771strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) {
772	return (strtoargvsub(mctx, s, argcp, argvp, 0));
773}
774
775static void
776checknames(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
792isc_result_t
793ns_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			isc_uint32_t addrcount;
1087			addrs = NULL;
1088			keynames = NULL;
1089			RETERR(ns_config_getipandkeylist(config, obj, mctx,
1090							 &addrs, &keynames,
1091							 &addrcount));
1092			result = dns_zone_setalsonotifywithkeys(zone, addrs,
1093								keynames,
1094								addrcount);
1095			if (addrcount != 0)
1096				ns_config_putipandkeylist(mctx, &addrs,
1097							  &keynames, addrcount);
1098			else
1099				INSIST(addrs == NULL && keynames == NULL);
1100			RETERR(result);
1101		} else
1102			RETERR(dns_zone_setalsonotify(zone, NULL, 0));
1103
1104		obj = NULL;
1105		result = ns_config_get(maps, "notify-source", &obj);
1106		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1107		RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj)));
1108		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1109
1110		obj = NULL;
1111		result = ns_config_get(maps, "notify-source-v6", &obj);
1112		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1113		RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj)));
1114		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1115
1116		obj = NULL;
1117		result = ns_config_get(maps, "notify-to-soa", &obj);
1118		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1119		dns_zone_setoption(zone, DNS_ZONEOPT_NOTIFYTOSOA,
1120				   cfg_obj_asboolean(obj));
1121
1122		dns_zone_setisself(zone, ns_client_isself, NULL);
1123
1124		RETERR(configure_zone_acl(zconfig, vconfig, config,
1125					  allow_transfer, ac, zone,
1126					  dns_zone_setxfracl,
1127					  dns_zone_clearxfracl));
1128
1129		obj = NULL;
1130		result = ns_config_get(maps, "max-transfer-time-out", &obj);
1131		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1132		dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60);
1133
1134		obj = NULL;
1135		result = ns_config_get(maps, "max-transfer-idle-out", &obj);
1136		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1137		dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60);
1138
1139		obj = NULL;
1140		result = ns_config_get(maps, "max-journal-size", &obj);
1141		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1142		if (raw != NULL)
1143			dns_zone_setjournalsize(raw, -1);
1144		dns_zone_setjournalsize(zone, -1);
1145		if (cfg_obj_isstring(obj)) {
1146			const char *str = cfg_obj_asstring(obj);
1147			INSIST(strcasecmp(str, "unlimited") == 0);
1148			journal_size = ISC_UINT32_MAX / 2;
1149		} else {
1150			isc_resourcevalue_t value;
1151			value = cfg_obj_asuint64(obj);
1152			if (value > ISC_UINT32_MAX / 2) {
1153				cfg_obj_log(obj, ns_g_lctx,
1154					    ISC_LOG_ERROR,
1155					    "'max-journal-size "
1156					    "%" ISC_PRINT_QUADFORMAT "d' "
1157					    "is too large",
1158					    value);
1159				RETERR(ISC_R_RANGE);
1160			}
1161			journal_size = (isc_uint32_t)value;
1162		}
1163		if (raw != NULL)
1164			dns_zone_setjournalsize(raw, journal_size);
1165		dns_zone_setjournalsize(zone, journal_size);
1166
1167		obj = NULL;
1168		result = ns_config_get(maps, "ixfr-from-differences", &obj);
1169		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1170		if (cfg_obj_isboolean(obj))
1171			ixfrdiff = cfg_obj_asboolean(obj);
1172		else if (!strcasecmp(cfg_obj_asstring(obj), "master") &&
1173			 ztype == dns_zone_master)
1174			ixfrdiff = ISC_TRUE;
1175		else if (!strcasecmp(cfg_obj_asstring(obj), "slave") &&
1176			ztype == dns_zone_slave)
1177			ixfrdiff = ISC_TRUE;
1178		else
1179			ixfrdiff = ISC_FALSE;
1180		if (raw != NULL) {
1181			dns_zone_setoption(raw, DNS_ZONEOPT_IXFRFROMDIFFS,
1182					   ISC_TRUE);
1183			dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS,
1184					   ISC_TRUE);
1185		} else
1186			dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS,
1187					   ixfrdiff);
1188
1189		obj = NULL;
1190		result = ns_config_get(maps, "request-ixfr", &obj);
1191		INSIST(result == ISC_R_SUCCESS);
1192		dns_zone_setrequestixfr(zone, cfg_obj_asboolean(obj));
1193
1194		checknames(ztype, maps, &obj);
1195		INSIST(obj != NULL);
1196		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1197			fail = ISC_FALSE;
1198			check = ISC_TRUE;
1199		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1200			fail = check = ISC_TRUE;
1201		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1202			fail = check = ISC_FALSE;
1203		} else
1204			INSIST(0);
1205		if (raw != NULL) {
1206			dns_zone_setoption(raw, DNS_ZONEOPT_CHECKNAMES,
1207					   check);
1208			dns_zone_setoption(raw, DNS_ZONEOPT_CHECKNAMESFAIL,
1209					   fail);
1210			dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES,
1211					   ISC_FALSE);
1212			dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL,
1213					   ISC_FALSE);
1214		} else {
1215			dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES,
1216					   check);
1217			dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL,
1218					   fail);
1219		}
1220
1221		obj = NULL;
1222		result = ns_config_get(maps, "notify-delay", &obj);
1223		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1224		dns_zone_setnotifydelay(zone, cfg_obj_asuint32(obj));
1225
1226		obj = NULL;
1227		result = ns_config_get(maps, "check-sibling", &obj);
1228		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1229		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSIBLING,
1230				   cfg_obj_asboolean(obj));
1231
1232		obj = NULL;
1233		result = ns_config_get(maps, "check-spf", &obj);
1234		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1235		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1236			check = ISC_TRUE;
1237		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1238			check = ISC_FALSE;
1239		} else
1240			INSIST(0);
1241		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSPF, check);
1242
1243		obj = NULL;
1244		result = ns_config_get(maps, "zero-no-soa-ttl", &obj);
1245		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1246		dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj));
1247
1248		obj = NULL;
1249		result = ns_config_get(maps, "nsec3-test-zone", &obj);
1250		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1251		dns_zone_setoption(zone, DNS_ZONEOPT_NSEC3TESTZONE,
1252				   cfg_obj_asboolean(obj));
1253	} else if (ztype == dns_zone_redirect) {
1254		dns_zone_setnotifytype(zone, dns_notifytype_no);
1255
1256		obj = NULL;
1257		result = ns_config_get(maps, "max-journal-size", &obj);
1258		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1259		dns_zone_setjournalsize(zone, -1);
1260		if (cfg_obj_isstring(obj)) {
1261			const char *str = cfg_obj_asstring(obj);
1262			INSIST(strcasecmp(str, "unlimited") == 0);
1263			journal_size = ISC_UINT32_MAX / 2;
1264		} else {
1265			isc_resourcevalue_t value;
1266			value = cfg_obj_asuint64(obj);
1267			if (value > ISC_UINT32_MAX / 2) {
1268				cfg_obj_log(obj, ns_g_lctx,
1269					    ISC_LOG_ERROR,
1270					    "'max-journal-size "
1271					    "%" ISC_PRINT_QUADFORMAT "d' "
1272					    "is too large",
1273					    value);
1274				RETERR(ISC_R_RANGE);
1275			}
1276			journal_size = (isc_uint32_t)value;
1277		}
1278		dns_zone_setjournalsize(zone, journal_size);
1279	}
1280
1281	/*
1282	 * Configure update-related options.  These apply to
1283	 * primary masters only.
1284	 */
1285	if (ztype == dns_zone_master) {
1286		dns_acl_t *updateacl;
1287
1288		RETERR(configure_zone_acl(zconfig, vconfig, config,
1289					  allow_update, ac, mayberaw,
1290					  dns_zone_setupdateacl,
1291					  dns_zone_clearupdateacl));
1292
1293		updateacl = dns_zone_getupdateacl(mayberaw);
1294		if (updateacl != NULL  && dns_acl_isinsecure(updateacl))
1295			isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
1296				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1297				      "zone '%s' allows updates by IP "
1298				      "address, which is insecure",
1299				      zname);
1300
1301		RETERR(configure_zone_ssutable(zoptions, mayberaw, zname));
1302	}
1303
1304	if (ztype == dns_zone_master || raw != NULL) {
1305		isc_boolean_t allow = ISC_FALSE, maint = ISC_FALSE;
1306
1307		obj = NULL;
1308		result = ns_config_get(maps, "sig-validity-interval", &obj);
1309		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1310		{
1311			const cfg_obj_t *validity, *resign;
1312
1313			validity = cfg_tuple_get(obj, "validity");
1314			seconds = cfg_obj_asuint32(validity) * 86400;
1315			dns_zone_setsigvalidityinterval(zone, seconds);
1316
1317			resign = cfg_tuple_get(obj, "re-sign");
1318			if (cfg_obj_isvoid(resign)) {
1319				seconds /= 4;
1320			} else {
1321				if (seconds > 7 * 86400)
1322					seconds = cfg_obj_asuint32(resign) *
1323							86400;
1324				else
1325					seconds = cfg_obj_asuint32(resign) *
1326							3600;
1327			}
1328			dns_zone_setsigresigninginterval(zone, seconds);
1329		}
1330
1331		obj = NULL;
1332		result = ns_config_get(maps, "key-directory", &obj);
1333		if (result == ISC_R_SUCCESS) {
1334			filename = cfg_obj_asstring(obj);
1335			RETERR(dns_zone_setkeydirectory(zone, filename));
1336		}
1337
1338		obj = NULL;
1339		result = ns_config_get(maps, "sig-signing-signatures", &obj);
1340		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1341		dns_zone_setsignatures(zone, cfg_obj_asuint32(obj));
1342
1343		obj = NULL;
1344		result = ns_config_get(maps, "sig-signing-nodes", &obj);
1345		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1346		dns_zone_setnodes(zone, cfg_obj_asuint32(obj));
1347
1348		obj = NULL;
1349		result = ns_config_get(maps, "sig-signing-type", &obj);
1350		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1351		dns_zone_setprivatetype(zone, cfg_obj_asuint32(obj));
1352
1353		obj = NULL;
1354		result = ns_config_get(maps, "update-check-ksk", &obj);
1355		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1356		dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK,
1357				   cfg_obj_asboolean(obj));
1358
1359		obj = NULL;
1360		result = ns_config_get(maps, "dnssec-dnskey-kskonly", &obj);
1361		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1362		dns_zone_setoption(zone, DNS_ZONEOPT_DNSKEYKSKONLY,
1363				   cfg_obj_asboolean(obj));
1364
1365		obj = NULL;
1366		result = ns_config_get(maps, "dnssec-loadkeys-interval", &obj);
1367		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1368		RETERR(dns_zone_setrefreshkeyinterval(zone,
1369						      cfg_obj_asuint32(obj)));
1370
1371		obj = NULL;
1372		result = cfg_map_get(zoptions, "auto-dnssec", &obj);
1373		if (result == ISC_R_SUCCESS) {
1374			const char *arg = cfg_obj_asstring(obj);
1375			if (strcasecmp(arg, "allow") == 0)
1376				allow = ISC_TRUE;
1377			else if (strcasecmp(arg, "maintain") == 0)
1378				allow = maint = ISC_TRUE;
1379			else if (strcasecmp(arg, "off") == 0)
1380				;
1381			else
1382				INSIST(0);
1383			dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow);
1384			dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint);
1385		}
1386	}
1387
1388	if (ztype == dns_zone_slave) {
1389		RETERR(configure_zone_acl(zconfig, vconfig, config,
1390					  allow_update_forwarding, ac,
1391					  mayberaw, dns_zone_setforwardacl,
1392					  dns_zone_clearforwardacl));
1393	}
1394
1395	/*%
1396	 * Primary master functionality.
1397	 */
1398	if (ztype == dns_zone_master) {
1399		obj = NULL;
1400		result = ns_config_get(maps, "check-wildcard", &obj);
1401		if (result == ISC_R_SUCCESS)
1402			check = cfg_obj_asboolean(obj);
1403		else
1404			check = ISC_FALSE;
1405		dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKWILDCARD, check);
1406
1407		obj = NULL;
1408		result = ns_config_get(maps, "check-dup-records", &obj);
1409		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1410		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1411			fail = ISC_FALSE;
1412			check = ISC_TRUE;
1413		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1414			fail = check = ISC_TRUE;
1415		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1416			fail = check = ISC_FALSE;
1417		} else
1418			INSIST(0);
1419		dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKDUPRR, check);
1420		dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKDUPRRFAIL, fail);
1421
1422		obj = NULL;
1423		result = ns_config_get(maps, "check-mx", &obj);
1424		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1425		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1426			fail = ISC_FALSE;
1427			check = ISC_TRUE;
1428		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1429			fail = check = ISC_TRUE;
1430		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1431			fail = check = ISC_FALSE;
1432		} else
1433			INSIST(0);
1434		dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKMX, check);
1435		dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKMXFAIL, fail);
1436
1437		obj = NULL;
1438		result = ns_config_get(maps, "check-integrity", &obj);
1439		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1440		dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKINTEGRITY,
1441				   cfg_obj_asboolean(obj));
1442
1443		obj = NULL;
1444		result = ns_config_get(maps, "check-mx-cname", &obj);
1445		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1446		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1447			warn = ISC_TRUE;
1448			ignore = ISC_FALSE;
1449		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1450			warn = ignore = ISC_FALSE;
1451		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1452			warn = ignore = ISC_TRUE;
1453		} else
1454			INSIST(0);
1455		dns_zone_setoption(mayberaw, DNS_ZONEOPT_WARNMXCNAME, warn);
1456		dns_zone_setoption(mayberaw, DNS_ZONEOPT_IGNOREMXCNAME, ignore);
1457
1458		obj = NULL;
1459		result = ns_config_get(maps, "check-srv-cname", &obj);
1460		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1461		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1462			warn = ISC_TRUE;
1463			ignore = ISC_FALSE;
1464		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1465			warn = ignore = ISC_FALSE;
1466		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1467			warn = ignore = ISC_TRUE;
1468		} else
1469			INSIST(0);
1470		dns_zone_setoption(mayberaw, DNS_ZONEOPT_WARNSRVCNAME, warn);
1471		dns_zone_setoption(mayberaw, DNS_ZONEOPT_IGNORESRVCNAME,
1472				   ignore);
1473
1474		obj = NULL;
1475		result = ns_config_get(maps, "dnssec-secure-to-insecure", &obj);
1476		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1477		dns_zone_setoption(mayberaw, DNS_ZONEOPT_SECURETOINSECURE,
1478				   cfg_obj_asboolean(obj));
1479
1480		obj = NULL;
1481		result = cfg_map_get(zoptions, "dnssec-update-mode", &obj);
1482		if (result == ISC_R_SUCCESS) {
1483			const char *arg = cfg_obj_asstring(obj);
1484			if (strcasecmp(arg, "no-resign") == 0)
1485				dns_zone_setkeyopt(zone, DNS_ZONEKEY_NORESIGN,
1486						   ISC_TRUE);
1487			else if (strcasecmp(arg, "maintain") == 0)
1488				;
1489			else
1490				INSIST(0);
1491		}
1492
1493		obj = NULL;
1494		result = ns_config_get(maps, "serial-update-method", &obj);
1495		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1496		if (strcasecmp(cfg_obj_asstring(obj), "unixtime") == 0)
1497			dns_zone_setserialupdatemethod(zone,
1498						    dns_updatemethod_unixtime);
1499		else
1500			dns_zone_setserialupdatemethod(zone,
1501						  dns_updatemethod_increment);
1502	}
1503
1504	/*
1505	 * Configure slave functionality.
1506	 */
1507	switch (ztype) {
1508	case dns_zone_slave:
1509	case dns_zone_stub:
1510	case dns_zone_redirect:
1511		count = 0;
1512		obj = NULL;
1513		(void)cfg_map_get(zoptions, "masters", &obj);
1514		if (obj != NULL) {
1515			addrs = NULL;
1516			keynames = NULL;
1517			RETERR(ns_config_getipandkeylist(config, obj, mctx,
1518							 &addrs, &keynames,
1519							 &count));
1520			result = dns_zone_setmasterswithkeys(mayberaw, addrs,
1521							     keynames, count);
1522			if (count != 0)
1523				ns_config_putipandkeylist(mctx, &addrs,
1524							  &keynames, count);
1525			else
1526				INSIST(addrs == NULL && keynames == NULL);
1527		} else
1528			result = dns_zone_setmasters(mayberaw, NULL, 0);
1529		RETERR(result);
1530
1531		multi = ISC_FALSE;
1532		if (count > 1) {
1533			obj = NULL;
1534			result = ns_config_get(maps, "multi-master", &obj);
1535			INSIST(result == ISC_R_SUCCESS && obj != NULL);
1536			multi = cfg_obj_asboolean(obj);
1537		}
1538		dns_zone_setoption(mayberaw, DNS_ZONEOPT_MULTIMASTER, multi);
1539
1540		obj = NULL;
1541		result = ns_config_get(maps, "max-transfer-time-in", &obj);
1542		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1543		dns_zone_setmaxxfrin(mayberaw, cfg_obj_asuint32(obj) * 60);
1544
1545		obj = NULL;
1546		result = ns_config_get(maps, "max-transfer-idle-in", &obj);
1547		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1548		dns_zone_setidlein(mayberaw, cfg_obj_asuint32(obj) * 60);
1549
1550		obj = NULL;
1551		result = ns_config_get(maps, "max-refresh-time", &obj);
1552		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1553		dns_zone_setmaxrefreshtime(mayberaw, cfg_obj_asuint32(obj));
1554
1555		obj = NULL;
1556		result = ns_config_get(maps, "min-refresh-time", &obj);
1557		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1558		dns_zone_setminrefreshtime(mayberaw, cfg_obj_asuint32(obj));
1559
1560		obj = NULL;
1561		result = ns_config_get(maps, "max-retry-time", &obj);
1562		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1563		dns_zone_setmaxretrytime(mayberaw, cfg_obj_asuint32(obj));
1564
1565		obj = NULL;
1566		result = ns_config_get(maps, "min-retry-time", &obj);
1567		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1568		dns_zone_setminretrytime(mayberaw, cfg_obj_asuint32(obj));
1569
1570		obj = NULL;
1571		result = ns_config_get(maps, "transfer-source", &obj);
1572		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1573		RETERR(dns_zone_setxfrsource4(mayberaw,
1574					      cfg_obj_assockaddr(obj)));
1575		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1576
1577		obj = NULL;
1578		result = ns_config_get(maps, "transfer-source-v6", &obj);
1579		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1580		RETERR(dns_zone_setxfrsource6(mayberaw,
1581					      cfg_obj_assockaddr(obj)));
1582		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1583
1584		obj = NULL;
1585		result = ns_config_get(maps, "alt-transfer-source", &obj);
1586		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1587		RETERR(dns_zone_setaltxfrsource4(mayberaw,
1588						 cfg_obj_assockaddr(obj)));
1589
1590		obj = NULL;
1591		result = ns_config_get(maps, "alt-transfer-source-v6", &obj);
1592		INSIST(result == ISC_R_SUCCESS && obj != NULL);
1593		RETERR(dns_zone_setaltxfrsource6(mayberaw,
1594						 cfg_obj_assockaddr(obj)));
1595
1596		obj = NULL;
1597		(void)ns_config_get(maps, "use-alt-transfer-source", &obj);
1598		if (obj == NULL) {
1599			/*
1600			 * Default off when views are in use otherwise
1601			 * on for BIND 8 compatibility.
1602			 */
1603			view = dns_zone_getview(zone);
1604			if (view != NULL && strcmp(view->name, "_default") == 0)
1605				alt = ISC_TRUE;
1606			else
1607				alt = ISC_FALSE;
1608		} else
1609			alt = cfg_obj_asboolean(obj);
1610		dns_zone_setoption(mayberaw, DNS_ZONEOPT_USEALTXFRSRC, alt);
1611
1612		obj = NULL;
1613		(void)ns_config_get(maps, "try-tcp-refresh", &obj);
1614		dns_zone_setoption(mayberaw, DNS_ZONEOPT_TRYTCPREFRESH,
1615				   cfg_obj_asboolean(obj));
1616		break;
1617
1618	case dns_zone_staticstub:
1619		RETERR(configure_staticstub(zoptions, zone, zname,
1620					    default_dbtype));
1621		break;
1622
1623	default:
1624		break;
1625	}
1626
1627	return (ISC_R_SUCCESS);
1628}
1629
1630
1631/*
1632 * Set up a DLZ zone as writeable
1633 */
1634isc_result_t
1635ns_zone_configure_writeable_dlz(dns_dlzdb_t *dlzdatabase, dns_zone_t *zone,
1636				dns_rdataclass_t rdclass, dns_name_t *name)
1637{
1638	dns_db_t *db = NULL;
1639	isc_time_t now;
1640	isc_result_t result;
1641
1642	TIME_NOW(&now);
1643
1644	dns_zone_settype(zone, dns_zone_dlz);
1645	result = dns_sdlz_setdb(dlzdatabase, rdclass, name, &db);
1646	if (result != ISC_R_SUCCESS)
1647		return (result);
1648	result = dns_zone_dlzpostload(zone, db);
1649	dns_db_detach(&db);
1650	return (result);
1651}
1652
1653isc_boolean_t
1654ns_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig) {
1655	const cfg_obj_t *zoptions = NULL;
1656	const cfg_obj_t *obj = NULL;
1657	const char *cfilename;
1658	const char *zfilename;
1659	dns_zone_t *raw = NULL;
1660	isc_boolean_t has_raw;
1661	dns_zonetype_t ztype;
1662
1663	zoptions = cfg_tuple_get(zconfig, "options");
1664
1665	/*
1666	 * We always reconfigure a static-stub zone for simplicity, assuming
1667	 * the amount of data to be loaded is small.
1668	 */
1669	if (zonetype_fromconfig(zoptions) == dns_zone_staticstub) {
1670		dns_zone_log(zone, ISC_LOG_DEBUG(1),
1671			     "not reusable: staticstub");
1672		return (ISC_FALSE);
1673	}
1674
1675	/* If there's a raw zone, use that for filename and type comparison */
1676	dns_zone_getraw(zone, &raw);
1677	if (raw != NULL) {
1678		zfilename = dns_zone_getfile(raw);
1679		ztype = dns_zone_gettype(raw);
1680		dns_zone_detach(&raw);
1681		has_raw = ISC_TRUE;
1682	} else {
1683		zfilename = dns_zone_getfile(zone);
1684		ztype = dns_zone_gettype(zone);
1685		has_raw = ISC_FALSE;
1686	}
1687
1688	obj = NULL;
1689	(void)cfg_map_get(zoptions, "inline-signing", &obj);
1690	if ((obj == NULL || !cfg_obj_asboolean(obj)) && has_raw) {
1691		dns_zone_log(zone, ISC_LOG_DEBUG(1),
1692			     "not reusable: old zone was inline-signing");
1693		return (ISC_FALSE);
1694	} else if ((obj != NULL && cfg_obj_asboolean(obj)) && !has_raw) {
1695		dns_zone_log(zone, ISC_LOG_DEBUG(1),
1696			     "not reusable: old zone was not inline-signing");
1697		return (ISC_FALSE);
1698	}
1699
1700	if (zonetype_fromconfig(zoptions) != ztype) {
1701		dns_zone_log(zone, ISC_LOG_DEBUG(1),
1702			     "not reusable: type mismatch");
1703		return (ISC_FALSE);
1704	}
1705
1706	obj = NULL;
1707	(void)cfg_map_get(zoptions, "file", &obj);
1708	if (obj != NULL)
1709		cfilename = cfg_obj_asstring(obj);
1710	else
1711		cfilename = NULL;
1712	if (!((cfilename == NULL && zfilename == NULL) ||
1713	      (cfilename != NULL && zfilename != NULL &&
1714	       strcmp(cfilename, zfilename) == 0)))
1715	{
1716		dns_zone_log(zone, ISC_LOG_DEBUG(1),
1717			     "not reusable: filename mismatch");
1718		return (ISC_FALSE);
1719	}
1720
1721	return (ISC_TRUE);
1722}
1723