1/*	$NetBSD: server.c,v 1.12 2012/12/04 23:38:38 spz 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/*! \file */
23
24#include <config.h>
25
26#include <stdlib.h>
27#include <unistd.h>
28#include <limits.h>
29#include <ctype.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32
33#include <isc/app.h>
34#include <isc/base64.h>
35#include <isc/dir.h>
36#include <isc/entropy.h>
37#include <isc/file.h>
38#include <isc/hash.h>
39#include <isc/hex.h>
40#include <isc/httpd.h>
41#include <isc/lex.h>
42#include <isc/parseint.h>
43#include <isc/portset.h>
44#include <isc/print.h>
45#include <isc/refcount.h>
46#include <isc/resource.h>
47#include <isc/sha2.h>
48#include <isc/socket.h>
49#include <isc/stat.h>
50#include <isc/stats.h>
51#include <isc/stdio.h>
52#include <isc/string.h>
53#include <isc/task.h>
54#include <isc/timer.h>
55#include <isc/util.h>
56#include <isc/xml.h>
57
58#include <isccfg/namedconf.h>
59
60#include <bind9/check.h>
61
62#include <dns/acache.h>
63#include <dns/adb.h>
64#include <dns/cache.h>
65#include <dns/db.h>
66#include <dns/dispatch.h>
67#include <dns/dlz.h>
68#include <dns/dns64.h>
69#include <dns/forward.h>
70#include <dns/journal.h>
71#include <dns/keytable.h>
72#include <dns/keyvalues.h>
73#include <dns/lib.h>
74#include <dns/master.h>
75#include <dns/masterdump.h>
76#include <dns/order.h>
77#include <dns/peer.h>
78#include <dns/portlist.h>
79#include <dns/private.h>
80#include <dns/rbt.h>
81#include <dns/rdataclass.h>
82#include <dns/rdataset.h>
83#include <dns/rdatastruct.h>
84#include <dns/resolver.h>
85#include <dns/rootns.h>
86#include <dns/secalg.h>
87#include <dns/stats.h>
88#include <dns/tkey.h>
89#include <dns/tsig.h>
90#include <dns/view.h>
91#include <dns/zone.h>
92#include <dns/zt.h>
93
94#include <dst/dst.h>
95#include <dst/result.h>
96
97#include <named/client.h>
98#include <named/config.h>
99#include <named/control.h>
100#include <named/interfacemgr.h>
101#include <named/log.h>
102#include <named/logconf.h>
103#include <named/lwresd.h>
104#include <named/main.h>
105#include <named/os.h>
106#include <named/server.h>
107#include <named/statschannel.h>
108#include <named/tkeyconf.h>
109#include <named/tsigconf.h>
110#include <named/zoneconf.h>
111#ifdef HAVE_LIBSCF
112#include <named/ns_smf_globals.h>
113#include <stdlib.h>
114#endif
115
116#ifndef PATH_MAX
117#define PATH_MAX 1024
118#endif
119
120/*%
121 * Check an operation for failure.  Assumes that the function
122 * using it has a 'result' variable and a 'cleanup' label.
123 */
124#define CHECK(op) \
125	do { result = (op);					 \
126	       if (result != ISC_R_SUCCESS) goto cleanup;	 \
127	} while (/*CONSTCOND*/0)
128
129#define CHECKM(op, msg) \
130	do { result = (op);					  \
131	       if (result != ISC_R_SUCCESS) {			  \
132			isc_log_write(ns_g_lctx,		  \
133				      NS_LOGCATEGORY_GENERAL,	  \
134				      NS_LOGMODULE_SERVER,	  \
135				      ISC_LOG_ERROR,		  \
136				      "%s: %s", msg,		  \
137				      isc_result_totext(result)); \
138			goto cleanup;				  \
139		}						  \
140	} while (/*CONSTCOND*/0)
141
142#define CHECKMF(op, msg, file) \
143	do { result = (op);					  \
144	       if (result != ISC_R_SUCCESS) {			  \
145			isc_log_write(ns_g_lctx,		  \
146				      NS_LOGCATEGORY_GENERAL,	  \
147				      NS_LOGMODULE_SERVER,	  \
148				      ISC_LOG_ERROR,		  \
149				      "%s '%s': %s", msg, file,	  \
150				      isc_result_totext(result)); \
151			goto cleanup;				  \
152		}						  \
153	} while (/*CONSTCOND*/0)
154
155#define CHECKFATAL(op, msg) \
156	do { result = (op);					  \
157	       if (result != ISC_R_SUCCESS)			  \
158			fatal(msg, result);			  \
159	} while (/*CONSTCOND*/0)
160
161/*%
162 * Maximum ADB size for views that share a cache.  Use this limit to suppress
163 * the total of memory footprint, which should be the main reason for sharing
164 * a cache.  Only effective when a finite max-cache-size is specified.
165 * This is currently defined to be 8MB.
166 */
167#define MAX_ADB_SIZE_FOR_CACHESHARE	8388608
168
169struct ns_dispatch {
170	isc_sockaddr_t			addr;
171	unsigned int			dispatchgen;
172	dns_dispatch_t			*dispatch;
173	ISC_LINK(struct ns_dispatch)	link;
174};
175
176struct ns_cache {
177	dns_cache_t			*cache;
178	dns_view_t			*primaryview;
179	isc_boolean_t			needflush;
180	isc_boolean_t			adbsizeadjusted;
181	ISC_LINK(ns_cache_t)		link;
182};
183
184struct dumpcontext {
185	isc_mem_t			*mctx;
186	isc_boolean_t			dumpcache;
187	isc_boolean_t			dumpzones;
188	FILE				*fp;
189	ISC_LIST(struct viewlistentry)	viewlist;
190	struct viewlistentry		*view;
191	struct zonelistentry		*zone;
192	dns_dumpctx_t			*mdctx;
193	dns_db_t			*db;
194	dns_db_t			*cache;
195	isc_task_t			*task;
196	dns_dbversion_t			*version;
197};
198
199struct viewlistentry {
200	dns_view_t			*view;
201	ISC_LINK(struct viewlistentry)	link;
202	ISC_LIST(struct zonelistentry)	zonelist;
203};
204
205struct zonelistentry {
206	dns_zone_t			*zone;
207	ISC_LINK(struct zonelistentry)	link;
208};
209
210/*%
211 * Configuration context to retain for each view that allows
212 * new zones to be added at runtime.
213 */
214struct cfg_context {
215	isc_mem_t *			mctx;
216	cfg_parser_t *			parser;
217	cfg_obj_t *			config;
218	cfg_parser_t *			nzparser;
219	cfg_obj_t *			nzconfig;
220	cfg_aclconfctx_t *		actx;
221};
222
223/*%
224 * Holds state information for the initial zone loading process.
225 * Uses the isc_refcount structure to count the number of views
226 * with pending zone loads, dereferencing as each view finishes.
227 */
228typedef struct {
229		ns_server_t *server;
230		isc_refcount_t refs;
231} ns_zoneload_t;
232
233/*
234 * These zones should not leak onto the Internet.
235 */
236const char *empty_zones[] = {
237	/* RFC 1918 */
238	"10.IN-ADDR.ARPA",
239	"16.172.IN-ADDR.ARPA",
240	"17.172.IN-ADDR.ARPA",
241	"18.172.IN-ADDR.ARPA",
242	"19.172.IN-ADDR.ARPA",
243	"20.172.IN-ADDR.ARPA",
244	"21.172.IN-ADDR.ARPA",
245	"22.172.IN-ADDR.ARPA",
246	"23.172.IN-ADDR.ARPA",
247	"24.172.IN-ADDR.ARPA",
248	"25.172.IN-ADDR.ARPA",
249	"26.172.IN-ADDR.ARPA",
250	"27.172.IN-ADDR.ARPA",
251	"28.172.IN-ADDR.ARPA",
252	"29.172.IN-ADDR.ARPA",
253	"30.172.IN-ADDR.ARPA",
254	"31.172.IN-ADDR.ARPA",
255	"168.192.IN-ADDR.ARPA",
256
257	/* RFC 5735 and RFC 5737 */
258	"0.IN-ADDR.ARPA",	/* THIS NETWORK */
259	"127.IN-ADDR.ARPA",	/* LOOPBACK */
260	"254.169.IN-ADDR.ARPA",	/* LINK LOCAL */
261	"2.0.192.IN-ADDR.ARPA",	/* TEST NET */
262	"100.51.198.IN-ADDR.ARPA",	/* TEST NET 2 */
263	"113.0.203.IN-ADDR.ARPA",	/* TEST NET 3 */
264	"255.255.255.255.IN-ADDR.ARPA",	/* BROADCAST */
265
266	/* Local IPv6 Unicast Addresses */
267	"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
268	"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
269	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
270	"D.F.IP6.ARPA",
271	"8.E.F.IP6.ARPA",	/* LINK LOCAL */
272	"9.E.F.IP6.ARPA",	/* LINK LOCAL */
273	"A.E.F.IP6.ARPA",	/* LINK LOCAL */
274	"B.E.F.IP6.ARPA",	/* LINK LOCAL */
275
276	/* Example Prefix, RFC 3849. */
277	"8.B.D.0.1.0.0.2.IP6.ARPA",
278
279	NULL
280};
281
282ISC_PLATFORM_NORETURN_PRE static void
283fatal(const char *msg, isc_result_t result) ISC_PLATFORM_NORETURN_POST;
284
285static void
286ns_server_reload(isc_task_t *task, isc_event_t *event);
287
288static isc_result_t
289ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
290			cfg_aclconfctx_t *actx,
291			isc_mem_t *mctx, ns_listenelt_t **target);
292static isc_result_t
293ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
294			 cfg_aclconfctx_t *actx,
295			 isc_mem_t *mctx, ns_listenlist_t **target);
296
297static isc_result_t
298configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
299		  const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype);
300
301static isc_result_t
302configure_alternates(const cfg_obj_t *config, dns_view_t *view,
303		     const cfg_obj_t *alternates);
304
305static isc_result_t
306configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
307	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
308	       cfg_aclconfctx_t *aclconf, isc_boolean_t added);
309
310static isc_result_t
311add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
312
313static void
314end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
315
316static void
317newzone_cfgctx_destroy(void **cfgp);
318
319/*%
320 * Configure a single view ACL at '*aclp'.  Get its configuration from
321 * 'vconfig' (for per-view configuration) and maybe from 'config'
322 */
323static isc_result_t
324configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
325		   const char *aclname, const char *acltuplename,
326		   cfg_aclconfctx_t *actx, isc_mem_t *mctx, dns_acl_t **aclp)
327{
328	isc_result_t result;
329	const cfg_obj_t *maps[3];
330	const cfg_obj_t *aclobj = NULL;
331	int i = 0;
332
333	if (*aclp != NULL)
334		dns_acl_detach(aclp);
335	if (vconfig != NULL)
336		maps[i++] = cfg_tuple_get(vconfig, "options");
337	if (config != NULL) {
338		const cfg_obj_t *options = NULL;
339		(void)cfg_map_get(config, "options", &options);
340		if (options != NULL)
341			maps[i++] = options;
342	}
343	maps[i] = NULL;
344
345	(void)ns_config_get(maps, aclname, &aclobj);
346	if (aclobj == NULL)
347		/*
348		 * No value available.	*aclp == NULL.
349		 */
350		return (ISC_R_SUCCESS);
351
352	if (acltuplename != NULL) {
353		/*
354		 * If the ACL is given in an optional tuple, retrieve it.
355		 * The parser should have ensured that a valid object be
356		 * returned.
357		 */
358		aclobj = cfg_tuple_get(aclobj, acltuplename);
359	}
360
361	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
362				    actx, mctx, 0, aclp);
363
364	return (result);
365}
366
367/*%
368 * Configure a sortlist at '*aclp'.  Essentially the same as
369 * configure_view_acl() except it calls cfg_acl_fromconfig with a
370 * nest_level value of 2.
371 */
372static isc_result_t
373configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
374			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
375			dns_acl_t **aclp)
376{
377	isc_result_t result;
378	const cfg_obj_t *maps[3];
379	const cfg_obj_t *aclobj = NULL;
380	int i = 0;
381
382	if (*aclp != NULL)
383		dns_acl_detach(aclp);
384	if (vconfig != NULL)
385		maps[i++] = cfg_tuple_get(vconfig, "options");
386	if (config != NULL) {
387		const cfg_obj_t *options = NULL;
388		(void)cfg_map_get(config, "options", &options);
389		if (options != NULL)
390			maps[i++] = options;
391	}
392	maps[i] = NULL;
393
394	(void)ns_config_get(maps, "sortlist", &aclobj);
395	if (aclobj == NULL)
396		return (ISC_R_SUCCESS);
397
398	/*
399	 * Use a nest level of 3 for the "top level" of the sortlist;
400	 * this means each entry in the top three levels will be stored
401	 * as lists of separate, nested ACLs, rather than merged together
402	 * into IP tables as is usually done with ACLs.
403	 */
404	result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
405				    actx, mctx, 3, aclp);
406
407	return (result);
408}
409
410static isc_result_t
411configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
412			 const char *confname, const char *conftuplename,
413			 isc_mem_t *mctx, dns_rbt_t **rbtp)
414{
415	isc_result_t result;
416	const cfg_obj_t *maps[3];
417	const cfg_obj_t *obj = NULL;
418	const cfg_listelt_t *element;
419	int i = 0;
420	dns_fixedname_t fixed;
421	dns_name_t *name;
422	isc_buffer_t b;
423	const char *str;
424	const cfg_obj_t *nameobj;
425
426	if (*rbtp != NULL)
427		dns_rbt_destroy(rbtp);
428	if (vconfig != NULL)
429		maps[i++] = cfg_tuple_get(vconfig, "options");
430	if (config != NULL) {
431		const cfg_obj_t *options = NULL;
432		(void)cfg_map_get(config, "options", &options);
433		if (options != NULL)
434			maps[i++] = options;
435	}
436	maps[i] = NULL;
437
438	(void)ns_config_get(maps, confname, &obj);
439	if (obj == NULL)
440		/*
441		 * No value available.	*rbtp == NULL.
442		 */
443		return (ISC_R_SUCCESS);
444
445	if (conftuplename != NULL) {
446		obj = cfg_tuple_get(obj, conftuplename);
447		if (cfg_obj_isvoid(obj))
448			return (ISC_R_SUCCESS);
449	}
450
451	result = dns_rbt_create(mctx, NULL, NULL, rbtp);
452	if (result != ISC_R_SUCCESS)
453		return (result);
454
455	dns_fixedname_init(&fixed);
456	name = dns_fixedname_name(&fixed);
457	for (element = cfg_list_first(obj);
458	     element != NULL;
459	     element = cfg_list_next(element)) {
460		nameobj = cfg_listelt_value(element);
461		str = cfg_obj_asstring(nameobj);
462		isc_buffer_init(&b, str, strlen(str));
463		isc_buffer_add(&b, strlen(str));
464		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
465		/*
466		 * We don't need the node data, but need to set dummy data to
467		 * avoid a partial match with an empty node.  For example, if
468		 * we have foo.example.com and bar.example.com, we'd get a match
469		 * for baz.example.com, which is not the expected result.
470		 * We simply use (void *)1 as the dummy data.
471		 */
472		result = dns_rbt_addname(*rbtp, name, (void *)1);
473		if (result != ISC_R_SUCCESS) {
474			cfg_obj_log(nameobj, ns_g_lctx, ISC_LOG_ERROR,
475				    "failed to add %s for %s: %s",
476				    str, confname, isc_result_totext(result));
477			goto cleanup;
478		}
479
480	}
481
482	return (result);
483
484  cleanup:
485	dns_rbt_destroy(rbtp);
486	return (result);
487
488}
489
490static isc_result_t
491dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key,
492		  isc_boolean_t managed, dst_key_t **target, isc_mem_t *mctx)
493{
494	dns_rdataclass_t viewclass;
495	dns_rdata_dnskey_t keystruct;
496	isc_uint32_t flags, proto, alg;
497	const char *keystr, *keynamestr;
498	unsigned char keydata[4096];
499	isc_buffer_t keydatabuf;
500	unsigned char rrdata[4096];
501	isc_buffer_t rrdatabuf;
502	isc_region_t r;
503	dns_fixedname_t fkeyname;
504	dns_name_t *keyname;
505	isc_buffer_t namebuf;
506	isc_result_t result;
507	dst_key_t *dstkey = NULL;
508
509	INSIST(target != NULL && *target == NULL);
510
511	flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
512	proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
513	alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
514	keyname = dns_fixedname_name(&fkeyname);
515	keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
516
517	if (managed) {
518		const char *initmethod;
519		initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
520
521		if (strcasecmp(initmethod, "initial-key") != 0) {
522			cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
523				    "managed key '%s': "
524				    "invalid initialization method '%s'",
525				    keynamestr, initmethod);
526			result = ISC_R_FAILURE;
527			goto cleanup;
528		}
529	}
530
531	if (vconfig == NULL)
532		viewclass = dns_rdataclass_in;
533	else {
534		const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
535		CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
536					 &viewclass));
537	}
538	keystruct.common.rdclass = viewclass;
539	keystruct.common.rdtype = dns_rdatatype_dnskey;
540	/*
541	 * The key data in keystruct is not dynamically allocated.
542	 */
543	keystruct.mctx = NULL;
544
545	ISC_LINK_INIT(&keystruct.common, link);
546
547	if (flags > 0xffff)
548		CHECKM(ISC_R_RANGE, "key flags");
549	if (proto > 0xff)
550		CHECKM(ISC_R_RANGE, "key protocol");
551	if (alg > 0xff)
552		CHECKM(ISC_R_RANGE, "key algorithm");
553	keystruct.flags = (isc_uint16_t)flags;
554	keystruct.protocol = (isc_uint8_t)proto;
555	keystruct.algorithm = (isc_uint8_t)alg;
556
557	isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
558	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
559
560	keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
561	CHECK(isc_base64_decodestring(keystr, &keydatabuf));
562	isc_buffer_usedregion(&keydatabuf, &r);
563	keystruct.datalen = r.length;
564	keystruct.data = r.base;
565
566	if ((keystruct.algorithm == DST_ALG_RSASHA1 ||
567	     keystruct.algorithm == DST_ALG_RSAMD5) &&
568	    r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
569		cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
570			    "%s key '%s' has a weak exponent",
571			    managed ? "managed" : "trusted",
572			    keynamestr);
573
574	CHECK(dns_rdata_fromstruct(NULL,
575				   keystruct.common.rdclass,
576				   keystruct.common.rdtype,
577				   &keystruct, &rrdatabuf));
578	dns_fixedname_init(&fkeyname);
579	isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr));
580	isc_buffer_add(&namebuf, strlen(keynamestr));
581	CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL));
582	CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
583			      mctx, &dstkey));
584
585	*target = dstkey;
586	return (ISC_R_SUCCESS);
587
588 cleanup:
589	if (result == DST_R_NOCRYPTO) {
590		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
591			    "ignoring %s key for '%s': no crypto support",
592			    managed ? "managed" : "trusted",
593			    keynamestr);
594	} else if (result == DST_R_UNSUPPORTEDALG) {
595		cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
596			    "skipping %s key for '%s': %s",
597			    managed ? "managed" : "trusted",
598			    keynamestr, isc_result_totext(result));
599	} else {
600		cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
601			    "configuring %s key for '%s': %s",
602			    managed ? "managed" : "trusted",
603			    keynamestr, isc_result_totext(result));
604		result = ISC_R_FAILURE;
605	}
606
607	if (dstkey != NULL)
608		dst_key_free(&dstkey);
609
610	return (result);
611}
612
613static isc_result_t
614load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
615	       dns_view_t *view, isc_boolean_t managed,
616	       dns_name_t *keyname, isc_mem_t *mctx)
617{
618	const cfg_listelt_t *elt, *elt2;
619	const cfg_obj_t *key, *keylist;
620	dst_key_t *dstkey = NULL;
621	isc_result_t result;
622	dns_keytable_t *secroots = NULL;
623
624	CHECK(dns_view_getsecroots(view, &secroots));
625
626	for (elt = cfg_list_first(keys);
627	     elt != NULL;
628	     elt = cfg_list_next(elt)) {
629		keylist = cfg_listelt_value(elt);
630
631		for (elt2 = cfg_list_first(keylist);
632		     elt2 != NULL;
633		     elt2 = cfg_list_next(elt2)) {
634			key = cfg_listelt_value(elt2);
635			result = dstkey_fromconfig(vconfig, key, managed,
636						   &dstkey, mctx);
637			if (result ==  DST_R_UNSUPPORTEDALG) {
638				result = ISC_R_SUCCESS;
639				continue;
640			}
641			if (result != ISC_R_SUCCESS)
642				goto cleanup;
643
644			/*
645			 * If keyname was specified, we only add that key.
646			 */
647			if (keyname != NULL &&
648			    !dns_name_equal(keyname, dst_key_name(dstkey)))
649			{
650				dst_key_free(&dstkey);
651				continue;
652			}
653
654			CHECK(dns_keytable_add(secroots, managed, &dstkey));
655		}
656	}
657
658 cleanup:
659	if (dstkey != NULL)
660		dst_key_free(&dstkey);
661	if (secroots != NULL)
662		dns_keytable_detach(&secroots);
663	if (result == DST_R_NOCRYPTO)
664		result = ISC_R_SUCCESS;
665	return (result);
666}
667
668/*%
669 * Configure DNSSEC keys for a view.
670 *
671 * The per-view configuration values and the server-global defaults are read
672 * from 'vconfig' and 'config'.
673 */
674static isc_result_t
675configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
676			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
677			  isc_boolean_t auto_dlv, isc_boolean_t auto_root,
678			  isc_mem_t *mctx)
679{
680	isc_result_t result = ISC_R_SUCCESS;
681	const cfg_obj_t *view_keys = NULL;
682	const cfg_obj_t *global_keys = NULL;
683	const cfg_obj_t *view_managed_keys = NULL;
684	const cfg_obj_t *global_managed_keys = NULL;
685	const cfg_obj_t *maps[4];
686	const cfg_obj_t *voptions = NULL;
687	const cfg_obj_t *options = NULL;
688	const cfg_obj_t *obj = NULL;
689	const char *directory;
690	int i = 0;
691
692	/* We don't need trust anchors for the _bind view */
693	if (strcmp(view->name, "_bind") == 0 &&
694	    view->rdclass == dns_rdataclass_chaos) {
695		return (ISC_R_SUCCESS);
696	}
697
698	if (vconfig != NULL) {
699		voptions = cfg_tuple_get(vconfig, "options");
700		if (voptions != NULL) {
701			(void) cfg_map_get(voptions, "trusted-keys",
702					   &view_keys);
703			(void) cfg_map_get(voptions, "managed-keys",
704					   &view_managed_keys);
705			maps[i++] = voptions;
706		}
707	}
708
709	if (config != NULL) {
710		(void)cfg_map_get(config, "trusted-keys", &global_keys);
711		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
712		(void)cfg_map_get(config, "options", &options);
713		if (options != NULL) {
714			maps[i++] = options;
715		}
716	}
717
718	maps[i++] = ns_g_defaults;
719	maps[i] = NULL;
720
721	result = dns_view_initsecroots(view, mctx);
722	if (result != ISC_R_SUCCESS) {
723		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
724			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
725			      "couldn't create keytable");
726		return (ISC_R_UNEXPECTED);
727	}
728
729	if (auto_dlv && view->rdclass == dns_rdataclass_in) {
730		const cfg_obj_t *builtin_keys = NULL;
731		const cfg_obj_t *builtin_managed_keys = NULL;
732
733		isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
734			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
735			      "using built-in DLV key for view %s",
736			      view->name);
737
738		/*
739		 * If bind.keys exists, it overrides the managed-keys
740		 * clause hard-coded in ns_g_config.
741		 */
742		if (bindkeys != NULL) {
743			(void)cfg_map_get(bindkeys, "trusted-keys",
744					  &builtin_keys);
745			(void)cfg_map_get(bindkeys, "managed-keys",
746					  &builtin_managed_keys);
747		} else {
748			(void)cfg_map_get(ns_g_config, "trusted-keys",
749					  &builtin_keys);
750			(void)cfg_map_get(ns_g_config, "managed-keys",
751					  &builtin_managed_keys);
752		}
753
754		if (builtin_keys != NULL)
755			CHECK(load_view_keys(builtin_keys, vconfig, view,
756					     ISC_FALSE, view->dlv, mctx));
757		if (builtin_managed_keys != NULL)
758			CHECK(load_view_keys(builtin_managed_keys, vconfig,
759					     view, ISC_TRUE, view->dlv, mctx));
760	}
761
762	if (auto_root && view->rdclass == dns_rdataclass_in) {
763		const cfg_obj_t *builtin_keys = NULL;
764		const cfg_obj_t *builtin_managed_keys = NULL;
765
766		isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
767			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
768			      "using built-in root key for view %s",
769			      view->name);
770
771		/*
772		 * If bind.keys exists, it overrides the managed-keys
773		 * clause hard-coded in ns_g_config.
774		 */
775		if (bindkeys != NULL) {
776			(void)cfg_map_get(bindkeys, "trusted-keys",
777					  &builtin_keys);
778			(void)cfg_map_get(bindkeys, "managed-keys",
779					  &builtin_managed_keys);
780		} else {
781			(void)cfg_map_get(ns_g_config, "trusted-keys",
782					  &builtin_keys);
783			(void)cfg_map_get(ns_g_config, "managed-keys",
784					  &builtin_managed_keys);
785		}
786
787		if (builtin_keys != NULL)
788			CHECK(load_view_keys(builtin_keys, vconfig, view,
789					     ISC_FALSE, dns_rootname, mctx));
790		if (builtin_managed_keys != NULL)
791			CHECK(load_view_keys(builtin_managed_keys, vconfig,
792					     view, ISC_TRUE, dns_rootname,
793					     mctx));
794	}
795
796	CHECK(load_view_keys(view_keys, vconfig, view, ISC_FALSE,
797			     NULL, mctx));
798	CHECK(load_view_keys(view_managed_keys, vconfig, view, ISC_TRUE,
799			     NULL, mctx));
800
801	if (view->rdclass == dns_rdataclass_in) {
802		CHECK(load_view_keys(global_keys, vconfig, view, ISC_FALSE,
803				     NULL, mctx));
804		CHECK(load_view_keys(global_managed_keys, vconfig, view,
805				     ISC_TRUE, NULL, mctx));
806	}
807
808	/*
809	 * Add key zone for managed-keys.
810	 */
811	obj = NULL;
812	(void)ns_config_get(maps, "managed-keys-directory", &obj);
813	directory = obj != NULL ? cfg_obj_asstring(obj) : NULL;
814	CHECK(add_keydata_zone(view, directory, ns_g_mctx));
815
816  cleanup:
817	return (result);
818}
819
820static isc_result_t
821mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
822	const cfg_listelt_t *element;
823	const cfg_obj_t *obj;
824	const char *str;
825	dns_fixedname_t fixed;
826	dns_name_t *name;
827	isc_boolean_t value;
828	isc_result_t result;
829	isc_buffer_t b;
830
831	dns_fixedname_init(&fixed);
832	name = dns_fixedname_name(&fixed);
833	for (element = cfg_list_first(mbs);
834	     element != NULL;
835	     element = cfg_list_next(element))
836	{
837		obj = cfg_listelt_value(element);
838		str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
839		isc_buffer_init(&b, str, strlen(str));
840		isc_buffer_add(&b, strlen(str));
841		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
842		value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
843		CHECK(dns_resolver_setmustbesecure(resolver, name, value));
844	}
845
846	result = ISC_R_SUCCESS;
847
848 cleanup:
849	return (result);
850}
851
852/*%
853 * Get a dispatch appropriate for the resolver of a given view.
854 */
855static isc_result_t
856get_view_querysource_dispatch(const cfg_obj_t **maps,
857			      int af, dns_dispatch_t **dispatchp,
858			      isc_boolean_t is_firstview)
859{
860	isc_result_t result = ISC_R_FAILURE;
861	dns_dispatch_t *disp;
862	isc_sockaddr_t sa;
863	unsigned int attrs, attrmask;
864	const cfg_obj_t *obj = NULL;
865	unsigned int maxdispatchbuffers;
866
867	switch (af) {
868	case AF_INET:
869		result = ns_config_get(maps, "query-source", &obj);
870		INSIST(result == ISC_R_SUCCESS);
871		break;
872	case AF_INET6:
873		result = ns_config_get(maps, "query-source-v6", &obj);
874		INSIST(result == ISC_R_SUCCESS);
875		break;
876	default:
877		INSIST(0);
878	}
879
880	sa = *(cfg_obj_assockaddr(obj));
881	INSIST(isc_sockaddr_pf(&sa) == af);
882
883	/*
884	 * If we don't support this address family, we're done!
885	 */
886	switch (af) {
887	case AF_INET:
888		result = isc_net_probeipv4();
889		break;
890	case AF_INET6:
891		result = isc_net_probeipv6();
892		break;
893	default:
894		INSIST(0);
895	}
896	if (result != ISC_R_SUCCESS)
897		return (ISC_R_SUCCESS);
898
899	/*
900	 * Try to find a dispatcher that we can share.
901	 */
902	attrs = 0;
903	attrs |= DNS_DISPATCHATTR_UDP;
904	switch (af) {
905	case AF_INET:
906		attrs |= DNS_DISPATCHATTR_IPV4;
907		break;
908	case AF_INET6:
909		attrs |= DNS_DISPATCHATTR_IPV6;
910		break;
911	}
912	if (isc_sockaddr_getport(&sa) == 0) {
913		attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
914		maxdispatchbuffers = 4096;
915	} else {
916		INSIST(obj != NULL);
917		if (is_firstview) {
918			cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO,
919				    "using specific query-source port "
920				    "suppresses port randomization and can be "
921				    "insecure.");
922		}
923		maxdispatchbuffers = 1000;
924	}
925
926	attrmask = 0;
927	attrmask |= DNS_DISPATCHATTR_UDP;
928	attrmask |= DNS_DISPATCHATTR_TCP;
929	attrmask |= DNS_DISPATCHATTR_IPV4;
930	attrmask |= DNS_DISPATCHATTR_IPV6;
931
932	disp = NULL;
933	result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
934				     ns_g_taskmgr, &sa, 4096,
935				     maxdispatchbuffers, 32768, 16411, 16433,
936				     attrs, attrmask, &disp);
937	if (result != ISC_R_SUCCESS) {
938		isc_sockaddr_t any;
939		char buf[ISC_SOCKADDR_FORMATSIZE];
940
941		switch (af) {
942		case AF_INET:
943			isc_sockaddr_any(&any);
944			break;
945		case AF_INET6:
946			isc_sockaddr_any6(&any);
947			break;
948		}
949		if (isc_sockaddr_equal(&sa, &any))
950			return (ISC_R_SUCCESS);
951		isc_sockaddr_format(&sa, buf, sizeof(buf));
952		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
953			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
954			      "could not get query source dispatcher (%s)",
955			      buf);
956		return (result);
957	}
958
959	*dispatchp = disp;
960
961	return (ISC_R_SUCCESS);
962}
963
964static isc_result_t
965configure_order(dns_order_t *order, const cfg_obj_t *ent) {
966	dns_rdataclass_t rdclass;
967	dns_rdatatype_t rdtype;
968	const cfg_obj_t *obj;
969	dns_fixedname_t fixed;
970	unsigned int mode = 0;
971	const char *str;
972	isc_buffer_t b;
973	isc_result_t result;
974	isc_boolean_t addroot;
975
976	result = ns_config_getclass(cfg_tuple_get(ent, "class"),
977				    dns_rdataclass_any, &rdclass);
978	if (result != ISC_R_SUCCESS)
979		return (result);
980
981	result = ns_config_gettype(cfg_tuple_get(ent, "type"),
982				   dns_rdatatype_any, &rdtype);
983	if (result != ISC_R_SUCCESS)
984		return (result);
985
986	obj = cfg_tuple_get(ent, "name");
987	if (cfg_obj_isstring(obj))
988		str = cfg_obj_asstring(obj);
989	else
990		str = "*";
991	addroot = ISC_TF(strcmp(str, "*") == 0);
992	isc_buffer_init(&b, str, strlen(str));
993	isc_buffer_add(&b, strlen(str));
994	dns_fixedname_init(&fixed);
995	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
996				   dns_rootname, 0, NULL);
997	if (result != ISC_R_SUCCESS)
998		return (result);
999
1000	obj = cfg_tuple_get(ent, "ordering");
1001	INSIST(cfg_obj_isstring(obj));
1002	str = cfg_obj_asstring(obj);
1003	if (!strcasecmp(str, "fixed"))
1004		mode = DNS_RDATASETATTR_FIXEDORDER;
1005	else if (!strcasecmp(str, "random"))
1006		mode = DNS_RDATASETATTR_RANDOMIZE;
1007	else if (!strcasecmp(str, "cyclic"))
1008		mode = 0;
1009	else
1010		INSIST(0);
1011
1012	/*
1013	 * "*" should match everything including the root (BIND 8 compat).
1014	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
1015	 * explicit entry for "." when the name is "*".
1016	 */
1017	if (addroot) {
1018		result = dns_order_add(order, dns_rootname,
1019				       rdtype, rdclass, mode);
1020		if (result != ISC_R_SUCCESS)
1021			return (result);
1022	}
1023
1024	return (dns_order_add(order, dns_fixedname_name(&fixed),
1025			      rdtype, rdclass, mode));
1026}
1027
1028static isc_result_t
1029configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
1030	isc_netaddr_t na;
1031	dns_peer_t *peer;
1032	const cfg_obj_t *obj;
1033	const char *str;
1034	isc_result_t result;
1035	unsigned int prefixlen;
1036
1037	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
1038
1039	peer = NULL;
1040	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
1041	if (result != ISC_R_SUCCESS)
1042		return (result);
1043
1044	obj = NULL;
1045	(void)cfg_map_get(cpeer, "bogus", &obj);
1046	if (obj != NULL)
1047		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
1048
1049	obj = NULL;
1050	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
1051	if (obj != NULL)
1052		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
1053
1054	obj = NULL;
1055	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
1056	if (obj != NULL)
1057		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
1058
1059	obj = NULL;
1060	(void)cfg_map_get(cpeer, "request-nsid", &obj);
1061	if (obj != NULL)
1062		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
1063
1064	obj = NULL;
1065	(void)cfg_map_get(cpeer, "edns", &obj);
1066	if (obj != NULL)
1067		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
1068
1069	obj = NULL;
1070	(void)cfg_map_get(cpeer, "edns-udp-size", &obj);
1071	if (obj != NULL) {
1072		isc_uint32_t udpsize = cfg_obj_asuint32(obj);
1073		if (udpsize < 512)
1074			udpsize = 512;
1075		if (udpsize > 4096)
1076			udpsize = 4096;
1077		CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize));
1078	}
1079
1080	obj = NULL;
1081	(void)cfg_map_get(cpeer, "max-udp-size", &obj);
1082	if (obj != NULL) {
1083		isc_uint32_t udpsize = cfg_obj_asuint32(obj);
1084		if (udpsize < 512)
1085			udpsize = 512;
1086		if (udpsize > 4096)
1087			udpsize = 4096;
1088		CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize));
1089	}
1090
1091	obj = NULL;
1092	(void)cfg_map_get(cpeer, "transfers", &obj);
1093	if (obj != NULL)
1094		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
1095
1096	obj = NULL;
1097	(void)cfg_map_get(cpeer, "transfer-format", &obj);
1098	if (obj != NULL) {
1099		str = cfg_obj_asstring(obj);
1100		if (strcasecmp(str, "many-answers") == 0)
1101			CHECK(dns_peer_settransferformat(peer,
1102							 dns_many_answers));
1103		else if (strcasecmp(str, "one-answer") == 0)
1104			CHECK(dns_peer_settransferformat(peer,
1105							 dns_one_answer));
1106		else
1107			INSIST(0);
1108	}
1109
1110	obj = NULL;
1111	(void)cfg_map_get(cpeer, "keys", &obj);
1112	if (obj != NULL) {
1113		result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
1114		if (result != ISC_R_SUCCESS)
1115			goto cleanup;
1116	}
1117
1118	obj = NULL;
1119	if (na.family == AF_INET)
1120		(void)cfg_map_get(cpeer, "transfer-source", &obj);
1121	else
1122		(void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
1123	if (obj != NULL) {
1124		result = dns_peer_settransfersource(peer,
1125						    cfg_obj_assockaddr(obj));
1126		if (result != ISC_R_SUCCESS)
1127			goto cleanup;
1128		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1129	}
1130
1131	obj = NULL;
1132	if (na.family == AF_INET)
1133		(void)cfg_map_get(cpeer, "notify-source", &obj);
1134	else
1135		(void)cfg_map_get(cpeer, "notify-source-v6", &obj);
1136	if (obj != NULL) {
1137		result = dns_peer_setnotifysource(peer,
1138						  cfg_obj_assockaddr(obj));
1139		if (result != ISC_R_SUCCESS)
1140			goto cleanup;
1141		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1142	}
1143
1144	obj = NULL;
1145	if (na.family == AF_INET)
1146		(void)cfg_map_get(cpeer, "query-source", &obj);
1147	else
1148		(void)cfg_map_get(cpeer, "query-source-v6", &obj);
1149	if (obj != NULL) {
1150		result = dns_peer_setquerysource(peer,
1151						 cfg_obj_assockaddr(obj));
1152		if (result != ISC_R_SUCCESS)
1153			goto cleanup;
1154		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1155	}
1156
1157	*peerp = peer;
1158	return (ISC_R_SUCCESS);
1159
1160 cleanup:
1161	dns_peer_detach(&peer);
1162	return (result);
1163}
1164
1165static isc_result_t
1166disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1167	isc_result_t result;
1168	const cfg_obj_t *algorithms;
1169	const cfg_listelt_t *element;
1170	const char *str;
1171	dns_fixedname_t fixed;
1172	dns_name_t *name;
1173	isc_buffer_t b;
1174
1175	dns_fixedname_init(&fixed);
1176	name = dns_fixedname_name(&fixed);
1177	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1178	isc_buffer_init(&b, str, strlen(str));
1179	isc_buffer_add(&b, strlen(str));
1180	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1181
1182	algorithms = cfg_tuple_get(disabled, "algorithms");
1183	for (element = cfg_list_first(algorithms);
1184	     element != NULL;
1185	     element = cfg_list_next(element))
1186	{
1187		isc_textregion_t r;
1188		dns_secalg_t alg;
1189
1190		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1191		r.length = strlen(r.base);
1192
1193		result = dns_secalg_fromtext(&alg, &r);
1194		if (result != ISC_R_SUCCESS) {
1195			isc_uint8_t ui;
1196			result = isc_parse_uint8(&ui, r.base, 10);
1197			alg = ui;
1198		}
1199		if (result != ISC_R_SUCCESS) {
1200			cfg_obj_log(cfg_listelt_value(element),
1201				    ns_g_lctx, ISC_LOG_ERROR,
1202				    "invalid algorithm");
1203			CHECK(result);
1204		}
1205		CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
1206	}
1207 cleanup:
1208	return (result);
1209}
1210
1211static isc_boolean_t
1212on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
1213	const cfg_listelt_t *element;
1214	dns_fixedname_t fixed;
1215	dns_name_t *name;
1216	isc_result_t result;
1217	const cfg_obj_t *value;
1218	const char *str;
1219	isc_buffer_t b;
1220
1221	dns_fixedname_init(&fixed);
1222	name = dns_fixedname_name(&fixed);
1223
1224	for (element = cfg_list_first(disablelist);
1225	     element != NULL;
1226	     element = cfg_list_next(element))
1227	{
1228		value = cfg_listelt_value(element);
1229		str = cfg_obj_asstring(value);
1230		isc_buffer_init(&b, str, strlen(str));
1231		isc_buffer_add(&b, strlen(str));
1232		result = dns_name_fromtext(name, &b, dns_rootname,
1233					   0, NULL);
1234		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1235		if (dns_name_equal(name, zonename))
1236			return (ISC_TRUE);
1237	}
1238	return (ISC_FALSE);
1239}
1240
1241static void
1242check_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv,
1243	     isc_mem_t *mctx)
1244{
1245	char **argv = NULL;
1246	unsigned int i;
1247	isc_result_t result;
1248
1249	result = dns_zone_getdbtype(*zonep, &argv, mctx);
1250	if (result != ISC_R_SUCCESS) {
1251		dns_zone_detach(zonep);
1252		return;
1253	}
1254
1255	/*
1256	 * Check that all the arguments match.
1257	 */
1258	for (i = 0; i < dbtypec; i++)
1259		if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
1260			dns_zone_detach(zonep);
1261			break;
1262		}
1263
1264	/*
1265	 * Check that there are not extra arguments.
1266	 */
1267	if (i == dbtypec && argv[i] != NULL)
1268		dns_zone_detach(zonep);
1269	isc_mem_free(mctx, argv);
1270}
1271
1272static isc_result_t
1273setquerystats(dns_zone_t *zone, isc_mem_t *mctx, isc_boolean_t on) {
1274	isc_result_t result;
1275	isc_stats_t *zoneqrystats;
1276
1277	zoneqrystats = NULL;
1278	if (on) {
1279		result = isc_stats_create(mctx, &zoneqrystats,
1280					  dns_nsstatscounter_max);
1281		if (result != ISC_R_SUCCESS)
1282			return (result);
1283	}
1284	dns_zone_setrequeststats(zone, zoneqrystats);
1285	if (zoneqrystats != NULL)
1286		isc_stats_detach(&zoneqrystats);
1287
1288	return (ISC_R_SUCCESS);
1289}
1290
1291static ns_cache_t *
1292cachelist_find(ns_cachelist_t *cachelist, const char *cachename) {
1293	ns_cache_t *nsc;
1294
1295	for (nsc = ISC_LIST_HEAD(*cachelist);
1296	     nsc != NULL;
1297	     nsc = ISC_LIST_NEXT(nsc, link)) {
1298		if (strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
1299			return (nsc);
1300	}
1301
1302	return (NULL);
1303}
1304
1305static isc_boolean_t
1306cache_reusable(dns_view_t *originview, dns_view_t *view,
1307	       isc_boolean_t new_zero_no_soattl)
1308{
1309	if (originview->checknames != view->checknames ||
1310	    dns_resolver_getzeronosoattl(originview->resolver) !=
1311	    new_zero_no_soattl ||
1312	    originview->acceptexpired != view->acceptexpired ||
1313	    originview->enablevalidation != view->enablevalidation ||
1314	    originview->maxcachettl != view->maxcachettl ||
1315	    originview->maxncachettl != view->maxncachettl) {
1316		return (ISC_FALSE);
1317	}
1318
1319	return (ISC_TRUE);
1320}
1321
1322static isc_boolean_t
1323cache_sharable(dns_view_t *originview, dns_view_t *view,
1324	       isc_boolean_t new_zero_no_soattl,
1325	       unsigned int new_cleaning_interval,
1326	       isc_uint32_t new_max_cache_size)
1327{
1328	/*
1329	 * If the cache cannot even reused for the same view, it cannot be
1330	 * shared with other views.
1331	 */
1332	if (!cache_reusable(originview, view, new_zero_no_soattl))
1333		return (ISC_FALSE);
1334
1335	/*
1336	 * Check other cache related parameters that must be consistent among
1337	 * the sharing views.
1338	 */
1339	if (dns_cache_getcleaninginterval(originview->cache) !=
1340	    new_cleaning_interval ||
1341	    dns_cache_getcachesize(originview->cache) != new_max_cache_size) {
1342		return (ISC_FALSE);
1343	}
1344
1345	return (ISC_TRUE);
1346}
1347
1348/*
1349 * Callback from DLZ configure when the driver sets up a writeable zone
1350 */
1351static isc_result_t
1352dlzconfigure_callback(dns_view_t *view, dns_zone_t *zone) {
1353	dns_name_t *origin = dns_zone_getorigin(zone);
1354	dns_rdataclass_t zclass = view->rdclass;
1355	isc_result_t result;
1356
1357	result = dns_zonemgr_managezone(ns_g_server->zonemgr, zone);
1358	if (result != ISC_R_SUCCESS)
1359		return (result);
1360	dns_zone_setstats(zone, ns_g_server->zonestats);
1361
1362	return (ns_zone_configure_writeable_dlz(view->dlzdatabase,
1363						zone, zclass, origin));
1364}
1365
1366static isc_result_t
1367dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
1368	      unsigned int prefixlen, const char *server,
1369	      const char *contact)
1370{
1371	char *cp;
1372	char reverse[48+sizeof("ip6.arpa.")];
1373	const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
1374	const char *sep = ": view ";
1375	const char *viewname = view->name;
1376	const unsigned char *s6;
1377	dns_fixedname_t fixed;
1378	dns_name_t *name;
1379	dns_zone_t *zone = NULL;
1380	int dns64_dbtypec = 4;
1381	isc_buffer_t b;
1382	isc_result_t result;
1383
1384	REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
1385		prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
1386
1387	if (!strcmp(viewname, "_default")) {
1388		sep = "";
1389		viewname = "";
1390	}
1391
1392	/*
1393	 * Construct the reverse name of the zone.
1394	 */
1395	cp = reverse;
1396	s6 = na->type.in6.s6_addr;
1397	while (prefixlen > 0) {
1398		prefixlen -= 8;
1399		sprintf(cp, "%x.%x.", s6[prefixlen/8] & 0xf,
1400			(s6[prefixlen/8] >> 4) & 0xf);
1401		cp += 4;
1402	}
1403	strcat(cp, "ip6.arpa.");
1404
1405	/*
1406	 * Create the actual zone.
1407	 */
1408	if (server != NULL)
1409		dns64_dbtype[2] = server;
1410	if (contact != NULL)
1411		dns64_dbtype[3] = contact;
1412	dns_fixedname_init(&fixed);
1413	name = dns_fixedname_name(&fixed);
1414	isc_buffer_init(&b, reverse, strlen(reverse));
1415	isc_buffer_add(&b, strlen(reverse));
1416	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1417	CHECK(dns_zone_create(&zone, mctx));
1418	CHECK(dns_zone_setorigin(zone, name));
1419	dns_zone_setview(zone, view);
1420	CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
1421	dns_zone_setclass(zone, view->rdclass);
1422	dns_zone_settype(zone, dns_zone_master);
1423	dns_zone_setstats(zone, ns_g_server->zonestats);
1424	CHECK(dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype));
1425	if (view->queryacl != NULL)
1426		dns_zone_setqueryacl(zone, view->queryacl);
1427	if (view->queryonacl != NULL)
1428		dns_zone_setqueryonacl(zone, view->queryonacl);
1429	dns_zone_setdialup(zone, dns_dialuptype_no);
1430	dns_zone_setnotifytype(zone, dns_notifytype_no);
1431	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
1432	CHECK(setquerystats(zone, mctx, ISC_FALSE));	/* XXXMPA */
1433	CHECK(dns_view_addzone(view, zone));
1434	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
1435		      ISC_LOG_INFO, "dns64 reverse zone%s%s: %s", sep,
1436		      viewname, reverse);
1437
1438cleanup:
1439	if (zone != NULL)
1440		dns_zone_detach(&zone);
1441	return (result);
1442}
1443
1444static isc_result_t
1445configure_rpz(dns_view_t *view, const cfg_listelt_t *element,
1446	      isc_boolean_t recursive_only_def, dns_ttl_t ttl_def)
1447{
1448	const cfg_obj_t *rpz_obj, *policy_obj, *obj;
1449	const char *str;
1450	dns_rpz_zone_t *old, *new;
1451	dns_zone_t *zone = NULL;
1452	isc_result_t result;
1453
1454	new = isc_mem_get(view->mctx, sizeof(*new));
1455	if (new == NULL) {
1456		result = ISC_R_NOMEMORY;
1457		goto cleanup;
1458	}
1459
1460	memset(new, 0, sizeof(*new));
1461	dns_name_init(&new->origin, NULL);
1462	dns_name_init(&new->nsdname, NULL);
1463	dns_name_init(&new->cname, NULL);
1464	dns_name_init(&new->passthru, NULL);
1465	ISC_LIST_INITANDAPPEND(view->rpz_zones, new, link);
1466
1467	rpz_obj = cfg_listelt_value(element);
1468	policy_obj = cfg_tuple_get(rpz_obj, "policy");
1469	if (cfg_obj_isvoid(policy_obj)) {
1470		new->policy = DNS_RPZ_POLICY_GIVEN;
1471	} else {
1472		str = cfg_obj_asstring(cfg_tuple_get(policy_obj,
1473						     "policy name"));
1474		new->policy = dns_rpz_str2policy(str);
1475		INSIST(new->policy != DNS_RPZ_POLICY_ERROR);
1476	}
1477
1478	obj = cfg_tuple_get(rpz_obj, "recursive-only");
1479	if (cfg_obj_isvoid(obj)) {
1480		new->recursive_only = recursive_only_def;
1481	} else {
1482		new->recursive_only = cfg_obj_asboolean(obj);
1483	}
1484	if (!new->recursive_only)
1485		view->rpz_recursive_only = ISC_FALSE;
1486
1487	obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
1488	if (cfg_obj_isuint32(obj)) {
1489		new->max_policy_ttl = cfg_obj_asuint32(obj);
1490	} else {
1491		new->max_policy_ttl = ttl_def;
1492	}
1493
1494	str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
1495	result = dns_name_fromstring(&new->origin, str, DNS_NAME_DOWNCASE,
1496				     view->mctx);
1497	if (result != ISC_R_SUCCESS) {
1498		cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1499			    "invalid zone '%s'", str);
1500		goto cleanup;
1501	}
1502
1503	result = dns_name_fromstring2(&new->nsdname, DNS_RPZ_NSDNAME_ZONE,
1504				      &new->origin, DNS_NAME_DOWNCASE,
1505				      view->mctx);
1506	if (result != ISC_R_SUCCESS) {
1507		cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1508			    "invalid zone '%s'", str);
1509		goto cleanup;
1510	}
1511
1512	result = dns_name_fromstring(&new->passthru, DNS_RPZ_PASSTHRU_ZONE,
1513				     DNS_NAME_DOWNCASE, view->mctx);
1514	if (result != ISC_R_SUCCESS) {
1515		cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1516			    "invalid zone '%s'", str);
1517		goto cleanup;
1518	}
1519
1520	result = dns_view_findzone(view, &new->origin, &zone);
1521	if (result != ISC_R_SUCCESS) {
1522		cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1523			    "unknown zone '%s'", str);
1524		goto cleanup;
1525	}
1526	if (dns_zone_gettype(zone) != dns_zone_master &&
1527	    dns_zone_gettype(zone) != dns_zone_slave) {
1528		cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1529			     "zone '%s' is neither master nor slave", str);
1530		dns_zone_detach(&zone);
1531		result = DNS_R_NOTMASTER;
1532		goto cleanup;
1533	}
1534	dns_zone_detach(&zone);
1535
1536	for (old = ISC_LIST_HEAD(view->rpz_zones);
1537	     old != new;
1538	     old = ISC_LIST_NEXT(old, link)) {
1539		++new->num;
1540		if (dns_name_equal(&old->origin, &new->origin)) {
1541			cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1542				    "duplicate '%s'", str);
1543			result = DNS_R_DUPLICATE;
1544			goto cleanup;
1545		}
1546	}
1547
1548	if (new->policy == DNS_RPZ_POLICY_CNAME) {
1549		str = cfg_obj_asstring(cfg_tuple_get(policy_obj, "cname"));
1550		result = dns_name_fromstring(&new->cname, str,
1551					     DNS_NAME_DOWNCASE, view->mctx);
1552		if (result != ISC_R_SUCCESS) {
1553			cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
1554				    "invalid cname '%s'", str);
1555			goto cleanup;
1556		}
1557	}
1558
1559	return (ISC_R_SUCCESS);
1560
1561 cleanup:
1562	dns_rpz_view_destroy(view);
1563	return (result);
1564}
1565
1566/*
1567 * Configure 'view' according to 'vconfig', taking defaults from 'config'
1568 * where values are missing in 'vconfig'.
1569 *
1570 * When configuring the default view, 'vconfig' will be NULL and the
1571 * global defaults in 'config' used exclusively.
1572 */
1573static isc_result_t
1574configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
1575	       ns_cachelist_t *cachelist, const cfg_obj_t *bindkeys,
1576	       isc_mem_t *mctx, cfg_aclconfctx_t *actx,
1577	       isc_boolean_t need_hints)
1578{
1579	const cfg_obj_t *maps[4];
1580	const cfg_obj_t *cfgmaps[3];
1581	const cfg_obj_t *optionmaps[3];
1582	const cfg_obj_t *options = NULL;
1583	const cfg_obj_t *voptions = NULL;
1584	const cfg_obj_t *forwardtype;
1585	const cfg_obj_t *forwarders;
1586	const cfg_obj_t *alternates;
1587	const cfg_obj_t *zonelist;
1588	const cfg_obj_t *dlz;
1589	unsigned int dlzargc;
1590	char **dlzargv;
1591	const cfg_obj_t *disabled;
1592	const cfg_obj_t *obj;
1593	const cfg_listelt_t *element;
1594	in_port_t port;
1595	dns_cache_t *cache = NULL;
1596	isc_result_t result;
1597	isc_uint32_t max_adb_size;
1598	unsigned int cleaning_interval;
1599	isc_uint32_t max_cache_size;
1600	isc_uint32_t max_acache_size;
1601	isc_uint32_t lame_ttl;
1602	dns_tsig_keyring_t *ring = NULL;
1603	dns_view_t *pview = NULL;	/* Production view */
1604	isc_mem_t *cmctx = NULL, *hmctx = NULL;
1605	dns_dispatch_t *dispatch4 = NULL;
1606	dns_dispatch_t *dispatch6 = NULL;
1607	isc_boolean_t reused_cache = ISC_FALSE;
1608	isc_boolean_t shared_cache = ISC_FALSE;
1609	int i = 0, j = 0, k = 0;
1610	const char *str;
1611	const char *cachename = NULL;
1612	dns_order_t *order = NULL;
1613	isc_uint32_t udpsize;
1614	isc_uint32_t maxbits;
1615	unsigned int resopts = 0;
1616	dns_zone_t *zone = NULL;
1617	isc_uint32_t max_clients_per_query;
1618	const char *sep = ": view ";
1619	const char *viewname = view->name;
1620	const char *forview = " for view ";
1621	isc_boolean_t empty_zones_enable;
1622	const cfg_obj_t *disablelist = NULL;
1623	isc_stats_t *resstats = NULL;
1624	dns_stats_t *resquerystats = NULL;
1625	isc_boolean_t auto_dlv = ISC_FALSE;
1626	isc_boolean_t auto_root = ISC_FALSE;
1627	ns_cache_t *nsc;
1628	isc_boolean_t zero_no_soattl;
1629	dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
1630	unsigned int query_timeout;
1631	struct cfg_context *nzctx;
1632
1633	REQUIRE(DNS_VIEW_VALID(view));
1634
1635	if (config != NULL)
1636		(void)cfg_map_get(config, "options", &options);
1637
1638	/*
1639	 * maps: view options, options, defaults
1640	 * cfgmaps: view options, config
1641	 * optionmaps: view options, options
1642	 */
1643	if (vconfig != NULL) {
1644		voptions = cfg_tuple_get(vconfig, "options");
1645		maps[i++] = voptions;
1646		optionmaps[j++] = voptions;
1647		cfgmaps[k++] = voptions;
1648	}
1649	if (options != NULL) {
1650		maps[i++] = options;
1651		optionmaps[j++] = options;
1652	}
1653
1654	maps[i++] = ns_g_defaults;
1655	maps[i] = NULL;
1656	optionmaps[j] = NULL;
1657	if (config != NULL)
1658		cfgmaps[k++] = config;
1659	cfgmaps[k] = NULL;
1660
1661	if (!strcmp(viewname, "_default")) {
1662		sep = "";
1663		viewname = "";
1664		forview = "";
1665		POST(forview);
1666	}
1667
1668	/*
1669	 * Set the view's port number for outgoing queries.
1670	 */
1671	CHECKM(ns_config_getport(config, &port), "port");
1672	dns_view_setdstport(view, port);
1673
1674	/*
1675	 * Create additional cache for this view and zones under the view
1676	 * if explicitly enabled.
1677	 * XXX950 default to on.
1678	 */
1679	obj = NULL;
1680	(void)ns_config_get(maps, "acache-enable", &obj);
1681	if (obj != NULL && cfg_obj_asboolean(obj)) {
1682		cmctx = NULL;
1683		CHECK(isc_mem_create(0, 0, &cmctx));
1684		CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr,
1685					ns_g_timermgr));
1686		isc_mem_setname(cmctx, "acache", NULL);
1687		isc_mem_detach(&cmctx);
1688	}
1689	if (view->acache != NULL) {
1690		obj = NULL;
1691		result = ns_config_get(maps, "acache-cleaning-interval", &obj);
1692		INSIST(result == ISC_R_SUCCESS);
1693		dns_acache_setcleaninginterval(view->acache,
1694					       cfg_obj_asuint32(obj) * 60);
1695
1696		obj = NULL;
1697		result = ns_config_get(maps, "max-acache-size", &obj);
1698		INSIST(result == ISC_R_SUCCESS);
1699		if (cfg_obj_isstring(obj)) {
1700			str = cfg_obj_asstring(obj);
1701			INSIST(strcasecmp(str, "unlimited") == 0);
1702			max_acache_size = ISC_UINT32_MAX;
1703		} else {
1704			isc_resourcevalue_t value;
1705
1706			value = cfg_obj_asuint64(obj);
1707			if (value > ISC_UINT32_MAX) {
1708				cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
1709					    "'max-acache-size "
1710					    "%" ISC_PRINT_QUADFORMAT
1711					    "d' is too large",
1712					    value);
1713				result = ISC_R_RANGE;
1714				goto cleanup;
1715			}
1716			max_acache_size = (isc_uint32_t)value;
1717		}
1718		dns_acache_setcachesize(view->acache, max_acache_size);
1719	}
1720
1721	CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, actx,
1722				 ns_g_mctx, &view->queryacl));
1723	if (view->queryacl == NULL) {
1724		CHECK(configure_view_acl(NULL, ns_g_config, "allow-query",
1725					 NULL, actx, ns_g_mctx,
1726					 &view->queryacl));
1727	}
1728
1729	/*
1730	 * Configure the zones.
1731	 */
1732	zonelist = NULL;
1733	if (voptions != NULL)
1734		(void)cfg_map_get(voptions, "zone", &zonelist);
1735	else
1736		(void)cfg_map_get(config, "zone", &zonelist);
1737
1738	/*
1739	 * Load zone configuration
1740	 */
1741	for (element = cfg_list_first(zonelist);
1742	     element != NULL;
1743	     element = cfg_list_next(element))
1744	{
1745		const cfg_obj_t *zconfig = cfg_listelt_value(element);
1746		CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
1747				     actx, ISC_FALSE));
1748	}
1749
1750	/*
1751	 * If we're allowing added zones, then load zone configuration
1752	 * from the newzone file for zones that were added during previous
1753	 * runs.
1754	 */
1755	nzctx = view->new_zone_config;
1756	if (nzctx != NULL && nzctx->nzconfig != NULL) {
1757		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1758			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
1759			      "loading additional zones for view '%s'",
1760			      view->name);
1761
1762		zonelist = NULL;
1763		cfg_map_get(nzctx->nzconfig, "zone", &zonelist);
1764
1765		for (element = cfg_list_first(zonelist);
1766		     element != NULL;
1767		     element = cfg_list_next(element))
1768		{
1769			const cfg_obj_t *zconfig = cfg_listelt_value(element);
1770			CHECK(configure_zone(config, zconfig, vconfig,
1771					     mctx, view, actx,
1772					     ISC_TRUE));
1773		}
1774	}
1775
1776	/*
1777	 * Create Dynamically Loadable Zone driver.
1778	 */
1779	dlz = NULL;
1780	if (voptions != NULL)
1781		(void)cfg_map_get(voptions, "dlz", &dlz);
1782	else
1783		(void)cfg_map_get(config, "dlz", &dlz);
1784
1785	obj = NULL;
1786	if (dlz != NULL) {
1787		(void)cfg_map_get(cfg_tuple_get(dlz, "options"),
1788				  "database", &obj);
1789		if (obj != NULL) {
1790			char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
1791			if (s == NULL) {
1792				result = ISC_R_NOMEMORY;
1793				goto cleanup;
1794			}
1795
1796			result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv);
1797			if (result != ISC_R_SUCCESS) {
1798				isc_mem_free(mctx, s);
1799				goto cleanup;
1800			}
1801
1802			obj = cfg_tuple_get(dlz, "name");
1803			result = dns_dlzcreate(mctx, cfg_obj_asstring(obj),
1804					       dlzargv[0], dlzargc, dlzargv,
1805					       &view->dlzdatabase);
1806			isc_mem_free(mctx, s);
1807			isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
1808			if (result != ISC_R_SUCCESS)
1809				goto cleanup;
1810
1811			/*
1812			 * If the dlz backend supports configuration,
1813			 * then call its configure method now.
1814			 */
1815			result = dns_dlzconfigure(view, dlzconfigure_callback);
1816			if (result != ISC_R_SUCCESS)
1817				goto cleanup;
1818		}
1819	}
1820
1821	/*
1822	 * Obtain configuration parameters that affect the decision of whether
1823	 * we can reuse/share an existing cache.
1824	 */
1825	obj = NULL;
1826	result = ns_config_get(maps, "cleaning-interval", &obj);
1827	INSIST(result == ISC_R_SUCCESS);
1828	cleaning_interval = cfg_obj_asuint32(obj) * 60;
1829
1830	obj = NULL;
1831	result = ns_config_get(maps, "max-cache-size", &obj);
1832	INSIST(result == ISC_R_SUCCESS);
1833	if (cfg_obj_isstring(obj)) {
1834		str = cfg_obj_asstring(obj);
1835		INSIST(strcasecmp(str, "unlimited") == 0);
1836		max_cache_size = ISC_UINT32_MAX;
1837	} else {
1838		isc_resourcevalue_t value;
1839		value = cfg_obj_asuint64(obj);
1840		if (value > ISC_UINT32_MAX) {
1841			cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
1842				    "'max-cache-size "
1843				    "%" ISC_PRINT_QUADFORMAT "d' is too large",
1844				    value);
1845			result = ISC_R_RANGE;
1846			goto cleanup;
1847		}
1848		max_cache_size = (isc_uint32_t)value;
1849	}
1850
1851	/* Check-names. */
1852	obj = NULL;
1853	result = ns_checknames_get(maps, "response", &obj);
1854	INSIST(result == ISC_R_SUCCESS);
1855
1856	str = cfg_obj_asstring(obj);
1857	if (strcasecmp(str, "fail") == 0) {
1858		resopts |= DNS_RESOLVER_CHECKNAMES |
1859			DNS_RESOLVER_CHECKNAMESFAIL;
1860		view->checknames = ISC_TRUE;
1861	} else if (strcasecmp(str, "warn") == 0) {
1862		resopts |= DNS_RESOLVER_CHECKNAMES;
1863		view->checknames = ISC_FALSE;
1864	} else if (strcasecmp(str, "ignore") == 0) {
1865		view->checknames = ISC_FALSE;
1866	} else
1867		INSIST(0);
1868
1869	obj = NULL;
1870	result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj);
1871	INSIST(result == ISC_R_SUCCESS);
1872	zero_no_soattl = cfg_obj_asboolean(obj);
1873
1874	obj = NULL;
1875	result = ns_config_get(maps, "dns64", &obj);
1876	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
1877	    strcmp(view->name, "_meta")) {
1878		const cfg_listelt_t *element;
1879		isc_netaddr_t na, suffix, *sp;
1880		unsigned int prefixlen;
1881		const char *server, *contact;
1882		const cfg_obj_t *myobj;
1883
1884		myobj = NULL;
1885		result = ns_config_get(maps, "dns64-server", &myobj);
1886		if (result == ISC_R_SUCCESS)
1887			server = cfg_obj_asstring(myobj);
1888		else
1889			server = NULL;
1890
1891		myobj = NULL;
1892		result = ns_config_get(maps, "dns64-contact", &myobj);
1893		if (result == ISC_R_SUCCESS)
1894			contact = cfg_obj_asstring(myobj);
1895		else
1896			contact = NULL;
1897
1898		for (element = cfg_list_first(obj);
1899		     element != NULL;
1900		     element = cfg_list_next(element))
1901		{
1902			const cfg_obj_t *map = cfg_listelt_value(element);
1903			dns_dns64_t *dns64 = NULL;
1904			unsigned int dns64options = 0;
1905
1906			cfg_obj_asnetprefix(cfg_map_getname(map), &na,
1907					    &prefixlen);
1908
1909			obj = NULL;
1910			(void)cfg_map_get(map, "suffix", &obj);
1911			if (obj != NULL) {
1912				sp = &suffix;
1913				isc_netaddr_fromsockaddr(sp,
1914						      cfg_obj_assockaddr(obj));
1915			} else
1916				sp = NULL;
1917
1918			clients = mapped = excluded = NULL;
1919			obj = NULL;
1920			(void)cfg_map_get(map, "clients", &obj);
1921			if (obj != NULL) {
1922				result = cfg_acl_fromconfig(obj, config,
1923							    ns_g_lctx, actx,
1924							    mctx, 0, &clients);
1925				if (result != ISC_R_SUCCESS)
1926					goto cleanup;
1927			}
1928			obj = NULL;
1929			(void)cfg_map_get(map, "mapped", &obj);
1930			if (obj != NULL) {
1931				result = cfg_acl_fromconfig(obj, config,
1932							    ns_g_lctx, actx,
1933							    mctx, 0, &mapped);
1934				if (result != ISC_R_SUCCESS)
1935					goto cleanup;
1936			}
1937			obj = NULL;
1938			(void)cfg_map_get(map, "exclude", &obj);
1939			if (obj != NULL) {
1940				result = cfg_acl_fromconfig(obj, config,
1941							    ns_g_lctx, actx,
1942							    mctx, 0, &excluded);
1943				if (result != ISC_R_SUCCESS)
1944					goto cleanup;
1945			}
1946
1947			obj = NULL;
1948			(void)cfg_map_get(map, "recursive-only", &obj);
1949			if (obj != NULL && cfg_obj_asboolean(obj))
1950				dns64options |= DNS_DNS64_RECURSIVE_ONLY;
1951
1952			obj = NULL;
1953			(void)cfg_map_get(map, "break-dnssec", &obj);
1954			if (obj != NULL && cfg_obj_asboolean(obj))
1955				dns64options |= DNS_DNS64_BREAK_DNSSEC;
1956
1957			result = dns_dns64_create(mctx, &na, prefixlen, sp,
1958						  clients, mapped, excluded,
1959						  dns64options, &dns64);
1960			if (result != ISC_R_SUCCESS)
1961				goto cleanup;
1962			dns_dns64_append(&view->dns64, dns64);
1963			view->dns64cnt++;
1964			result = dns64_reverse(view, mctx, &na, prefixlen,
1965					       server, contact);
1966			if (result != ISC_R_SUCCESS)
1967				goto cleanup;
1968			if (clients != NULL)
1969				dns_acl_detach(&clients);
1970			if (mapped != NULL)
1971				dns_acl_detach(&mapped);
1972			if (excluded != NULL)
1973				dns_acl_detach(&excluded);
1974		}
1975	}
1976
1977	obj = NULL;
1978	result = ns_config_get(maps, "dnssec-accept-expired", &obj);
1979	INSIST(result == ISC_R_SUCCESS);
1980	view->acceptexpired = cfg_obj_asboolean(obj);
1981
1982	obj = NULL;
1983	result = ns_config_get(maps, "dnssec-validation", &obj);
1984	INSIST(result == ISC_R_SUCCESS);
1985	if (cfg_obj_isboolean(obj)) {
1986		view->enablevalidation = cfg_obj_asboolean(obj);
1987	} else {
1988		/* If dnssec-validation is not boolean, it must be "auto" */
1989		view->enablevalidation = ISC_TRUE;
1990		auto_root = ISC_TRUE;
1991	}
1992
1993	obj = NULL;
1994	result = ns_config_get(maps, "max-cache-ttl", &obj);
1995	INSIST(result == ISC_R_SUCCESS);
1996	view->maxcachettl = cfg_obj_asuint32(obj);
1997
1998	obj = NULL;
1999	result = ns_config_get(maps, "max-ncache-ttl", &obj);
2000	INSIST(result == ISC_R_SUCCESS);
2001	view->maxncachettl = cfg_obj_asuint32(obj);
2002	if (view->maxncachettl > 7 * 24 * 3600)
2003		view->maxncachettl = 7 * 24 * 3600;
2004
2005	/*
2006	 * Configure the view's cache.
2007	 *
2008	 * First, check to see if there are any attach-cache options.  If yes,
2009	 * attempt to lookup an existing cache at attach it to the view.  If
2010	 * there is not one, then try to reuse an existing cache if possible;
2011	 * otherwise create a new cache.
2012	 *
2013	 * Note that the ADB is not preserved or shared in either case.
2014	 *
2015	 * When a matching view is found, the associated statistics are also
2016	 * retrieved and reused.
2017	 *
2018	 * XXX Determining when it is safe to reuse or share a cache is tricky.
2019	 * When the view's configuration changes, the cached data may become
2020	 * invalid because it reflects our old view of the world.  We check
2021	 * some of the configuration parameters that could invalidate the cache
2022	 * or otherwise make it unsharable, but there are other configuration
2023	 * options that should be checked.  For example, if a view uses a
2024	 * forwarder, changes in the forwarder configuration may invalidate
2025	 * the cache.  At the moment, it's the administrator's responsibility to
2026	 * ensure these configuration options don't invalidate reusing/sharing.
2027	 */
2028	obj = NULL;
2029	result = ns_config_get(maps, "attach-cache", &obj);
2030	if (result == ISC_R_SUCCESS)
2031		cachename = cfg_obj_asstring(obj);
2032	else
2033		cachename = view->name;
2034	cache = NULL;
2035	nsc = cachelist_find(cachelist, cachename);
2036	if (nsc != NULL) {
2037		if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
2038				    cleaning_interval, max_cache_size)) {
2039			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2040				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
2041				      "views %s and %s can't share the cache "
2042				      "due to configuration parameter mismatch",
2043				      nsc->primaryview->name, view->name);
2044			result = ISC_R_FAILURE;
2045			goto cleanup;
2046		}
2047		dns_cache_attach(nsc->cache, &cache);
2048		shared_cache = ISC_TRUE;
2049	} else {
2050		if (strcmp(cachename, view->name) == 0) {
2051			result = dns_viewlist_find(&ns_g_server->viewlist,
2052						   cachename, view->rdclass,
2053						   &pview);
2054			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
2055				goto cleanup;
2056			if (pview != NULL) {
2057				if (!cache_reusable(pview, view,
2058						    zero_no_soattl)) {
2059					isc_log_write(ns_g_lctx,
2060						      NS_LOGCATEGORY_GENERAL,
2061						      NS_LOGMODULE_SERVER,
2062						      ISC_LOG_DEBUG(1),
2063						      "cache cannot be reused "
2064						      "for view %s due to "
2065						      "configuration parameter "
2066						      "mismatch", view->name);
2067				} else {
2068					INSIST(pview->cache != NULL);
2069					isc_log_write(ns_g_lctx,
2070						      NS_LOGCATEGORY_GENERAL,
2071						      NS_LOGMODULE_SERVER,
2072						      ISC_LOG_DEBUG(3),
2073						      "reusing existing cache");
2074					reused_cache = ISC_TRUE;
2075					dns_cache_attach(pview->cache, &cache);
2076				}
2077				dns_view_getresstats(pview, &resstats);
2078				dns_view_getresquerystats(pview,
2079							  &resquerystats);
2080				dns_view_detach(&pview);
2081			}
2082		}
2083		if (cache == NULL) {
2084			/*
2085			 * Create a cache with the desired name.  This normally
2086			 * equals the view name, but may also be a forward
2087			 * reference to a view that share the cache with this
2088			 * view but is not yet configured.  If it is not the
2089			 * view name but not a forward reference either, then it
2090			 * is simply a named cache that is not shared.
2091			 *
2092			 * We use two separate memory contexts for the
2093			 * cache, for the main cache memory and the heap
2094			 * memory.
2095			 */
2096			CHECK(isc_mem_create(0, 0, &cmctx));
2097			isc_mem_setname(cmctx, "cache", NULL);
2098			CHECK(isc_mem_create(0, 0, &hmctx));
2099			isc_mem_setname(hmctx, "cache_heap", NULL);
2100			CHECK(dns_cache_create3(cmctx, hmctx, ns_g_taskmgr,
2101						ns_g_timermgr, view->rdclass,
2102						cachename, "rbt", 0, NULL,
2103						&cache));
2104			isc_mem_detach(&cmctx);
2105			isc_mem_detach(&hmctx);
2106		}
2107		nsc = isc_mem_get(mctx, sizeof(*nsc));
2108		if (nsc == NULL) {
2109			result = ISC_R_NOMEMORY;
2110			goto cleanup;
2111		}
2112		nsc->cache = NULL;
2113		dns_cache_attach(cache, &nsc->cache);
2114		nsc->primaryview = view;
2115		nsc->needflush = ISC_FALSE;
2116		nsc->adbsizeadjusted = ISC_FALSE;
2117		ISC_LINK_INIT(nsc, link);
2118		ISC_LIST_APPEND(*cachelist, nsc, link);
2119	}
2120	dns_view_setcache2(view, cache, shared_cache);
2121
2122	/*
2123	 * cache-file cannot be inherited if views are present, but this
2124	 * should be caught by the configuration checking stage.
2125	 */
2126	obj = NULL;
2127	result = ns_config_get(maps, "cache-file", &obj);
2128	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) {
2129		CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj)));
2130		if (!reused_cache && !shared_cache)
2131			CHECK(dns_cache_load(cache));
2132	}
2133
2134	dns_cache_setcleaninginterval(cache, cleaning_interval);
2135	dns_cache_setcachesize(cache, max_cache_size);
2136
2137	dns_cache_detach(&cache);
2138
2139	/*
2140	 * Resolver.
2141	 *
2142	 * XXXRTH  Hardwired number of tasks.
2143	 */
2144	CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4,
2145					    ISC_TF(ISC_LIST_PREV(view, link)
2146						   == NULL)));
2147	CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6,
2148					    ISC_TF(ISC_LIST_PREV(view, link)
2149						   == NULL)));
2150	if (dispatch4 == NULL && dispatch6 == NULL) {
2151		UNEXPECTED_ERROR(__FILE__, __LINE__,
2152				 "unable to obtain neither an IPv4 nor"
2153				 " an IPv6 dispatch");
2154		result = ISC_R_UNEXPECTED;
2155		goto cleanup;
2156	}
2157	CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31,
2158				      ns_g_socketmgr, ns_g_timermgr,
2159				      resopts, ns_g_dispatchmgr,
2160				      dispatch4, dispatch6));
2161
2162	if (resstats == NULL) {
2163		CHECK(isc_stats_create(mctx, &resstats,
2164				       dns_resstatscounter_max));
2165	}
2166	dns_view_setresstats(view, resstats);
2167	if (resquerystats == NULL)
2168		CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
2169	dns_view_setresquerystats(view, resquerystats);
2170
2171	/*
2172	 * Set the ADB cache size to 1/8th of the max-cache-size or
2173	 * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
2174	 */
2175	max_adb_size = 0;
2176	if (max_cache_size != 0) {
2177		max_adb_size = max_cache_size / 8;
2178		if (max_adb_size == 0)
2179			max_adb_size = 1;	/* Force minimum. */
2180		if (view != nsc->primaryview &&
2181		    max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE) {
2182			max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
2183			if (!nsc->adbsizeadjusted) {
2184				dns_adb_setadbsize(nsc->primaryview->adb,
2185						   MAX_ADB_SIZE_FOR_CACHESHARE);
2186				nsc->adbsizeadjusted = ISC_TRUE;
2187			}
2188		}
2189	}
2190	dns_adb_setadbsize(view->adb, max_adb_size);
2191
2192	/*
2193	 * Set resolver's lame-ttl.
2194	 */
2195	obj = NULL;
2196	result = ns_config_get(maps, "lame-ttl", &obj);
2197	INSIST(result == ISC_R_SUCCESS);
2198	lame_ttl = cfg_obj_asuint32(obj);
2199	if (lame_ttl > 1800)
2200		lame_ttl = 1800;
2201	dns_resolver_setlamettl(view->resolver, lame_ttl);
2202
2203	/*
2204	 * Set the resolver's query timeout.
2205	 */
2206	obj = NULL;
2207	result = ns_config_get(maps, "resolver-query-timeout", &obj);
2208	INSIST(result == ISC_R_SUCCESS);
2209	query_timeout = cfg_obj_asuint32(obj);
2210	dns_resolver_settimeout(view->resolver, query_timeout);
2211
2212	/* Specify whether to use 0-TTL for negative response for SOA query */
2213	dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
2214
2215	/*
2216	 * Set the resolver's EDNS UDP size.
2217	 */
2218	obj = NULL;
2219	result = ns_config_get(maps, "edns-udp-size", &obj);
2220	INSIST(result == ISC_R_SUCCESS);
2221	udpsize = cfg_obj_asuint32(obj);
2222	if (udpsize < 512)
2223		udpsize = 512;
2224	if (udpsize > 4096)
2225		udpsize = 4096;
2226	dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize);
2227
2228	/*
2229	 * Set the maximum UDP response size.
2230	 */
2231	obj = NULL;
2232	result = ns_config_get(maps, "max-udp-size", &obj);
2233	INSIST(result == ISC_R_SUCCESS);
2234	udpsize = cfg_obj_asuint32(obj);
2235	if (udpsize < 512)
2236		udpsize = 512;
2237	if (udpsize > 4096)
2238		udpsize = 4096;
2239	view->maxudp = udpsize;
2240
2241	/*
2242	 * Set the maximum rsa exponent bits.
2243	 */
2244	obj = NULL;
2245	result = ns_config_get(maps, "max-rsa-exponent-size", &obj);
2246	INSIST(result == ISC_R_SUCCESS);
2247	maxbits = cfg_obj_asuint32(obj);
2248	if (maxbits != 0 && maxbits < 35)
2249		maxbits = 35;
2250	if (maxbits > 4096)
2251		maxbits = 4096;
2252	view->maxbits = maxbits;
2253
2254	/*
2255	 * Set supported DNSSEC algorithms.
2256	 */
2257	dns_resolver_reset_algorithms(view->resolver);
2258	disabled = NULL;
2259	(void)ns_config_get(maps, "disable-algorithms", &disabled);
2260	if (disabled != NULL) {
2261		for (element = cfg_list_first(disabled);
2262		     element != NULL;
2263		     element = cfg_list_next(element))
2264			CHECK(disable_algorithms(cfg_listelt_value(element),
2265						 view->resolver));
2266	}
2267
2268	/*
2269	 * A global or view "forwarders" option, if present,
2270	 * creates an entry for "." in the forwarding table.
2271	 */
2272	forwardtype = NULL;
2273	forwarders = NULL;
2274	(void)ns_config_get(maps, "forward", &forwardtype);
2275	(void)ns_config_get(maps, "forwarders", &forwarders);
2276	if (forwarders != NULL)
2277		CHECK(configure_forward(config, view, dns_rootname,
2278					forwarders, forwardtype));
2279
2280	/*
2281	 * Dual Stack Servers.
2282	 */
2283	alternates = NULL;
2284	(void)ns_config_get(maps, "dual-stack-servers", &alternates);
2285	if (alternates != NULL)
2286		CHECK(configure_alternates(config, view, alternates));
2287
2288	/*
2289	 * We have default hints for class IN if we need them.
2290	 */
2291	if (view->rdclass == dns_rdataclass_in && view->hints == NULL)
2292		dns_view_sethints(view, ns_g_server->in_roothints);
2293
2294	/*
2295	 * If we still have no hints, this is a non-IN view with no
2296	 * "hints zone" configured.  Issue a warning, except if this
2297	 * is a root server.  Root servers never need to consult
2298	 * their hints, so it's no point requiring users to configure
2299	 * them.
2300	 */
2301	if (view->hints == NULL) {
2302		dns_zone_t *rootzone = NULL;
2303		(void)dns_view_findzone(view, dns_rootname, &rootzone);
2304		if (rootzone != NULL) {
2305			dns_zone_detach(&rootzone);
2306			need_hints = ISC_FALSE;
2307		}
2308		if (need_hints)
2309			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2310				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
2311				      "no root hints for view '%s'",
2312				      view->name);
2313	}
2314
2315	/*
2316	 * Configure the view's TSIG keys.
2317	 */
2318	CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
2319	if (ns_g_server->sessionkey != NULL) {
2320		CHECK(dns_tsigkeyring_add(ring, ns_g_server->session_keyname,
2321					  ns_g_server->sessionkey));
2322	}
2323	dns_view_setkeyring(view, ring);
2324	dns_tsigkeyring_detach(&ring);
2325
2326	/*
2327	 * See if we can re-use a dynamic key ring.
2328	 */
2329	result = dns_viewlist_find(&ns_g_server->viewlist, view->name,
2330				   view->rdclass, &pview);
2331	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
2332		goto cleanup;
2333	if (pview != NULL) {
2334		dns_view_getdynamickeyring(pview, &ring);
2335		if (ring != NULL)
2336			dns_view_setdynamickeyring(view, ring);
2337		dns_tsigkeyring_detach(&ring);
2338		dns_view_detach(&pview);
2339	} else
2340		dns_view_restorekeyring(view);
2341
2342	/*
2343	 * Configure the view's peer list.
2344	 */
2345	{
2346		const cfg_obj_t *peers = NULL;
2347		const cfg_listelt_t *element;
2348		dns_peerlist_t *newpeers = NULL;
2349
2350		(void)ns_config_get(cfgmaps, "server", &peers);
2351		CHECK(dns_peerlist_new(mctx, &newpeers));
2352		for (element = cfg_list_first(peers);
2353		     element != NULL;
2354		     element = cfg_list_next(element))
2355		{
2356			const cfg_obj_t *cpeer = cfg_listelt_value(element);
2357			dns_peer_t *peer;
2358
2359			CHECK(configure_peer(cpeer, mctx, &peer));
2360			dns_peerlist_addpeer(newpeers, peer);
2361			dns_peer_detach(&peer);
2362		}
2363		dns_peerlist_detach(&view->peers);
2364		view->peers = newpeers; /* Transfer ownership. */
2365	}
2366
2367	/*
2368	 *	Configure the views rrset-order.
2369	 */
2370	{
2371		const cfg_obj_t *rrsetorder = NULL;
2372		const cfg_listelt_t *element;
2373
2374		(void)ns_config_get(maps, "rrset-order", &rrsetorder);
2375		CHECK(dns_order_create(mctx, &order));
2376		for (element = cfg_list_first(rrsetorder);
2377		     element != NULL;
2378		     element = cfg_list_next(element))
2379		{
2380			const cfg_obj_t *ent = cfg_listelt_value(element);
2381
2382			CHECK(configure_order(order, ent));
2383		}
2384		if (view->order != NULL)
2385			dns_order_detach(&view->order);
2386		dns_order_attach(order, &view->order);
2387		dns_order_detach(&order);
2388	}
2389	/*
2390	 * Copy the aclenv object.
2391	 */
2392	dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv);
2393
2394	/*
2395	 * Configure the "match-clients" and "match-destinations" ACL.
2396	 */
2397	CHECK(configure_view_acl(vconfig, config, "match-clients", NULL, actx,
2398				 ns_g_mctx, &view->matchclients));
2399	CHECK(configure_view_acl(vconfig, config, "match-destinations", NULL,
2400				 actx, ns_g_mctx, &view->matchdestinations));
2401
2402	/*
2403	 * Configure the "match-recursive-only" option.
2404	 */
2405	obj = NULL;
2406	(void)ns_config_get(maps, "match-recursive-only", &obj);
2407	if (obj != NULL && cfg_obj_asboolean(obj))
2408		view->matchrecursiveonly = ISC_TRUE;
2409	else
2410		view->matchrecursiveonly = ISC_FALSE;
2411
2412	/*
2413	 * Configure other configurable data.
2414	 */
2415	obj = NULL;
2416	result = ns_config_get(maps, "recursion", &obj);
2417	INSIST(result == ISC_R_SUCCESS);
2418	view->recursion = cfg_obj_asboolean(obj);
2419
2420	obj = NULL;
2421	result = ns_config_get(maps, "auth-nxdomain", &obj);
2422	INSIST(result == ISC_R_SUCCESS);
2423	view->auth_nxdomain = cfg_obj_asboolean(obj);
2424
2425	obj = NULL;
2426	result = ns_config_get(maps, "minimal-responses", &obj);
2427	INSIST(result == ISC_R_SUCCESS);
2428	view->minimalresponses = cfg_obj_asboolean(obj);
2429
2430	obj = NULL;
2431	result = ns_config_get(maps, "transfer-format", &obj);
2432	INSIST(result == ISC_R_SUCCESS);
2433	str = cfg_obj_asstring(obj);
2434	if (strcasecmp(str, "many-answers") == 0)
2435		view->transfer_format = dns_many_answers;
2436	else if (strcasecmp(str, "one-answer") == 0)
2437		view->transfer_format = dns_one_answer;
2438	else
2439		INSIST(0);
2440
2441	/*
2442	 * Set sources where additional data and CNAME/DNAME
2443	 * targets for authoritative answers may be found.
2444	 */
2445	obj = NULL;
2446	result = ns_config_get(maps, "additional-from-auth", &obj);
2447	INSIST(result == ISC_R_SUCCESS);
2448	view->additionalfromauth = cfg_obj_asboolean(obj);
2449	if (view->recursion && ! view->additionalfromauth) {
2450		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
2451			    "'additional-from-auth no' is only supported "
2452			    "with 'recursion no'");
2453		view->additionalfromauth = ISC_TRUE;
2454	}
2455
2456	obj = NULL;
2457	result = ns_config_get(maps, "additional-from-cache", &obj);
2458	INSIST(result == ISC_R_SUCCESS);
2459	view->additionalfromcache = cfg_obj_asboolean(obj);
2460	if (view->recursion && ! view->additionalfromcache) {
2461		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
2462			    "'additional-from-cache no' is only supported "
2463			    "with 'recursion no'");
2464		view->additionalfromcache = ISC_TRUE;
2465	}
2466
2467	/*
2468	 * Set "allow-query-cache", "allow-query-cache-on",
2469	 * "allow-recursion", and "allow-recursion-on" acls if
2470	 * configured in named.conf.
2471	 */
2472	CHECK(configure_view_acl(vconfig, config, "allow-query-cache", NULL,
2473				 actx, ns_g_mctx, &view->cacheacl));
2474	CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on", NULL,
2475				 actx, ns_g_mctx, &view->cacheonacl));
2476	if (view->cacheonacl == NULL)
2477		CHECK(configure_view_acl(NULL, ns_g_config,
2478					 "allow-query-cache-on", NULL, actx,
2479					 ns_g_mctx, &view->cacheonacl));
2480	if (strcmp(view->name, "_bind") != 0) {
2481		CHECK(configure_view_acl(vconfig, config, "allow-recursion",
2482					 NULL, actx, ns_g_mctx,
2483					 &view->recursionacl));
2484		CHECK(configure_view_acl(vconfig, config, "allow-recursion-on",
2485					 NULL, actx, ns_g_mctx,
2486					 &view->recursiononacl));
2487	}
2488
2489	/*
2490	 * "allow-query-cache" inherits from "allow-recursion" if set,
2491	 * otherwise from "allow-query" if set.
2492	 * "allow-recursion" inherits from "allow-query-cache" if set,
2493	 * otherwise from "allow-query" if set.
2494	 */
2495	if (view->cacheacl == NULL && view->recursionacl != NULL)
2496		dns_acl_attach(view->recursionacl, &view->cacheacl);
2497	/*
2498	 * XXXEACH: This call to configure_view_acl() is redundant.  We
2499	 * are leaving it as it is because we are making a minimal change
2500	 * for a patch release.  In the future this should be changed to
2501	 * dns_acl_attach(view->queryacl, &view->cacheacl).
2502	 */
2503	if (view->cacheacl == NULL && view->recursion)
2504		CHECK(configure_view_acl(vconfig, config, "allow-query", NULL,
2505					 actx, ns_g_mctx, &view->cacheacl));
2506	if (view->recursion &&
2507	    view->recursionacl == NULL && view->cacheacl != NULL)
2508		dns_acl_attach(view->cacheacl, &view->recursionacl);
2509
2510	/*
2511	 * Set default "allow-recursion", "allow-recursion-on" and
2512	 * "allow-query-cache" acls.
2513	 */
2514	if (view->recursionacl == NULL && view->recursion)
2515		CHECK(configure_view_acl(NULL, ns_g_config,
2516					 "allow-recursion", NULL,
2517					 actx, ns_g_mctx,
2518					 &view->recursionacl));
2519	if (view->recursiononacl == NULL && view->recursion)
2520		CHECK(configure_view_acl(NULL, ns_g_config,
2521					 "allow-recursion-on", NULL,
2522					 actx, ns_g_mctx,
2523					 &view->recursiononacl));
2524	if (view->cacheacl == NULL) {
2525		if (view->recursion)
2526			CHECK(configure_view_acl(NULL, ns_g_config,
2527						 "allow-query-cache", NULL,
2528						 actx, ns_g_mctx,
2529						 &view->cacheacl));
2530		else
2531			CHECK(dns_acl_none(mctx, &view->cacheacl));
2532	}
2533
2534	/*
2535	 * Filter setting on addresses in the answer section.
2536	 */
2537	CHECK(configure_view_acl(vconfig, config, "deny-answer-addresses",
2538				 "acl", actx, ns_g_mctx, &view->denyansweracl));
2539	CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
2540				       "except-from", ns_g_mctx,
2541				       &view->answeracl_exclude));
2542
2543	/*
2544	 * Filter setting on names (CNAME/DNAME targets) in the answer section.
2545	 */
2546	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
2547				       "name", ns_g_mctx,
2548				       &view->denyanswernames));
2549	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
2550				       "except-from", ns_g_mctx,
2551				       &view->answernames_exclude));
2552
2553	/*
2554	 * Configure sortlist, if set
2555	 */
2556	CHECK(configure_view_sortlist(vconfig, config, actx, ns_g_mctx,
2557				      &view->sortlist));
2558
2559	/*
2560	 * Configure default allow-transfer, allow-notify, allow-update
2561	 * and allow-update-forwarding ACLs, if set, so they can be
2562	 * inherited by zones.
2563	 */
2564	if (view->notifyacl == NULL)
2565		CHECK(configure_view_acl(NULL, ns_g_config,
2566					 "allow-notify", NULL, actx,
2567					 ns_g_mctx, &view->notifyacl));
2568	if (view->transferacl == NULL)
2569		CHECK(configure_view_acl(NULL, ns_g_config,
2570					 "allow-transfer", NULL, actx,
2571					 ns_g_mctx, &view->transferacl));
2572	if (view->updateacl == NULL)
2573		CHECK(configure_view_acl(NULL, ns_g_config,
2574					 "allow-update", NULL, actx,
2575					 ns_g_mctx, &view->updateacl));
2576	if (view->upfwdacl == NULL)
2577		CHECK(configure_view_acl(NULL, ns_g_config,
2578					 "allow-update-forwarding", NULL, actx,
2579					 ns_g_mctx, &view->upfwdacl));
2580
2581	obj = NULL;
2582	result = ns_config_get(maps, "provide-ixfr", &obj);
2583	INSIST(result == ISC_R_SUCCESS);
2584	view->provideixfr = cfg_obj_asboolean(obj);
2585
2586	obj = NULL;
2587	result = ns_config_get(maps, "request-nsid", &obj);
2588	INSIST(result == ISC_R_SUCCESS);
2589	view->requestnsid = cfg_obj_asboolean(obj);
2590
2591	obj = NULL;
2592	result = ns_config_get(maps, "max-clients-per-query", &obj);
2593	INSIST(result == ISC_R_SUCCESS);
2594	max_clients_per_query = cfg_obj_asuint32(obj);
2595
2596	obj = NULL;
2597	result = ns_config_get(maps, "clients-per-query", &obj);
2598	INSIST(result == ISC_R_SUCCESS);
2599	dns_resolver_setclientsperquery(view->resolver,
2600					cfg_obj_asuint32(obj),
2601					max_clients_per_query);
2602
2603#ifdef ALLOW_FILTER_AAAA_ON_V4
2604	obj = NULL;
2605	result = ns_config_get(maps, "filter-aaaa-on-v4", &obj);
2606	INSIST(result == ISC_R_SUCCESS);
2607	if (cfg_obj_isboolean(obj)) {
2608		if (cfg_obj_asboolean(obj))
2609			view->v4_aaaa = dns_v4_aaaa_filter;
2610		else
2611			view->v4_aaaa = dns_v4_aaaa_ok;
2612	} else {
2613		const char *v4_aaaastr = cfg_obj_asstring(obj);
2614		if (strcasecmp(v4_aaaastr, "break-dnssec") == 0)
2615			view->v4_aaaa = dns_v4_aaaa_break_dnssec;
2616		else
2617			INSIST(0);
2618	}
2619	CHECK(configure_view_acl(vconfig, config, "filter-aaaa", NULL,
2620				 actx, ns_g_mctx, &view->v4_aaaa_acl));
2621#endif
2622
2623	obj = NULL;
2624	result = ns_config_get(maps, "dnssec-enable", &obj);
2625	INSIST(result == ISC_R_SUCCESS);
2626	view->enablednssec = cfg_obj_asboolean(obj);
2627
2628	obj = NULL;
2629	result = ns_config_get(optionmaps, "dnssec-lookaside", &obj);
2630	if (result == ISC_R_SUCCESS) {
2631		/* If set to "auto", use the version from the defaults */
2632		const cfg_obj_t *dlvobj;
2633		const char *dom;
2634		dlvobj = cfg_listelt_value(cfg_list_first(obj));
2635		dom = cfg_obj_asstring(cfg_tuple_get(dlvobj, "domain"));
2636		if (cfg_obj_isvoid(cfg_tuple_get(dlvobj, "trust-anchor"))) {
2637			/* If "no", skip; if "auto", use global default */
2638			if (!strcasecmp(dom, "no"))
2639				result = ISC_R_NOTFOUND;
2640			else if (!strcasecmp(dom, "auto")) {
2641				auto_dlv = ISC_TRUE;
2642				obj = NULL;
2643				result = cfg_map_get(ns_g_defaults,
2644						     "dnssec-lookaside", &obj);
2645			}
2646		}
2647	}
2648
2649	if (result == ISC_R_SUCCESS) {
2650		for (element = cfg_list_first(obj);
2651		     element != NULL;
2652		     element = cfg_list_next(element))
2653		{
2654			const char *str;
2655			isc_buffer_t b;
2656			dns_name_t *dlv;
2657
2658			obj = cfg_listelt_value(element);
2659			str = cfg_obj_asstring(cfg_tuple_get(obj,
2660							     "trust-anchor"));
2661			isc_buffer_init(&b, str, strlen(str));
2662			isc_buffer_add(&b, strlen(str));
2663			dlv = dns_fixedname_name(&view->dlv_fixed);
2664			CHECK(dns_name_fromtext(dlv, &b, dns_rootname,
2665						DNS_NAME_DOWNCASE, NULL));
2666			view->dlv = dns_fixedname_name(&view->dlv_fixed);
2667		}
2668	} else
2669		view->dlv = NULL;
2670
2671	/*
2672	 * For now, there is only one kind of trusted keys, the
2673	 * "security roots".
2674	 */
2675	CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
2676					auto_dlv, auto_root, mctx));
2677	dns_resolver_resetmustbesecure(view->resolver);
2678	obj = NULL;
2679	result = ns_config_get(maps, "dnssec-must-be-secure", &obj);
2680	if (result == ISC_R_SUCCESS)
2681		CHECK(mustbesecure(obj, view->resolver));
2682
2683	obj = NULL;
2684	result = ns_config_get(maps, "preferred-glue", &obj);
2685	if (result == ISC_R_SUCCESS) {
2686		str = cfg_obj_asstring(obj);
2687		if (strcasecmp(str, "a") == 0)
2688			view->preferred_glue = dns_rdatatype_a;
2689		else if (strcasecmp(str, "aaaa") == 0)
2690			view->preferred_glue = dns_rdatatype_aaaa;
2691		else
2692			view->preferred_glue = 0;
2693	} else
2694		view->preferred_glue = 0;
2695
2696	obj = NULL;
2697	result = ns_config_get(maps, "root-delegation-only", &obj);
2698	if (result == ISC_R_SUCCESS) {
2699		dns_view_setrootdelonly(view, ISC_TRUE);
2700		if (!cfg_obj_isvoid(obj)) {
2701			dns_fixedname_t fixed;
2702			dns_name_t *name;
2703			isc_buffer_t b;
2704			const char *str;
2705			const cfg_obj_t *exclude;
2706
2707			dns_fixedname_init(&fixed);
2708			name = dns_fixedname_name(&fixed);
2709			for (element = cfg_list_first(obj);
2710			     element != NULL;
2711			     element = cfg_list_next(element)) {
2712				exclude = cfg_listelt_value(element);
2713				str = cfg_obj_asstring(exclude);
2714				isc_buffer_init(&b, str, strlen(str));
2715				isc_buffer_add(&b, strlen(str));
2716				CHECK(dns_name_fromtext(name, &b, dns_rootname,
2717							0, NULL));
2718				CHECK(dns_view_excludedelegationonly(view,
2719								     name));
2720			}
2721		}
2722	} else
2723		dns_view_setrootdelonly(view, ISC_FALSE);
2724
2725	/*
2726	 * Setup automatic empty zones.  If recursion is off then
2727	 * they are disabled by default.
2728	 */
2729	obj = NULL;
2730	(void)ns_config_get(maps, "empty-zones-enable", &obj);
2731	(void)ns_config_get(maps, "disable-empty-zone", &disablelist);
2732	if (obj == NULL && disablelist == NULL &&
2733	    view->rdclass == dns_rdataclass_in) {
2734		empty_zones_enable = view->recursion;
2735	} else if (view->rdclass == dns_rdataclass_in) {
2736		if (obj != NULL)
2737			empty_zones_enable = cfg_obj_asboolean(obj);
2738		else
2739			empty_zones_enable = view->recursion;
2740	} else {
2741		empty_zones_enable = ISC_FALSE;
2742	}
2743	if (empty_zones_enable && !lwresd_g_useresolvconf) {
2744		const char *empty;
2745		int empty_zone = 0;
2746		dns_fixedname_t fixed;
2747		dns_name_t *name;
2748		isc_buffer_t buffer;
2749		const char *str;
2750		char server[DNS_NAME_FORMATSIZE + 1];
2751		char contact[DNS_NAME_FORMATSIZE + 1];
2752		const char *empty_dbtype[4] =
2753				    { "_builtin", "empty", NULL, NULL };
2754		int empty_dbtypec = 4;
2755		isc_boolean_t zonestats_on;
2756
2757		dns_fixedname_init(&fixed);
2758		name = dns_fixedname_name(&fixed);
2759
2760		obj = NULL;
2761		result = ns_config_get(maps, "empty-server", &obj);
2762		if (result == ISC_R_SUCCESS) {
2763			str = cfg_obj_asstring(obj);
2764			isc_buffer_init(&buffer, str, strlen(str));
2765			isc_buffer_add(&buffer, strlen(str));
2766			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
2767						NULL));
2768			isc_buffer_init(&buffer, server, sizeof(server) - 1);
2769			CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
2770			server[isc_buffer_usedlength(&buffer)] = 0;
2771			empty_dbtype[2] = server;
2772		} else
2773			empty_dbtype[2] = "@";
2774
2775		obj = NULL;
2776		result = ns_config_get(maps, "empty-contact", &obj);
2777		if (result == ISC_R_SUCCESS) {
2778			str = cfg_obj_asstring(obj);
2779			isc_buffer_init(&buffer, str, strlen(str));
2780			isc_buffer_add(&buffer, strlen(str));
2781			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
2782						NULL));
2783			isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
2784			CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
2785			contact[isc_buffer_usedlength(&buffer)] = 0;
2786			empty_dbtype[3] = contact;
2787		} else
2788			empty_dbtype[3] = ".";
2789
2790		obj = NULL;
2791		result = ns_config_get(maps, "zone-statistics", &obj);
2792		INSIST(result == ISC_R_SUCCESS);
2793		zonestats_on = cfg_obj_asboolean(obj);
2794
2795		for (empty = empty_zones[empty_zone];
2796		     empty != NULL;
2797		     empty = empty_zones[++empty_zone])
2798		{
2799			dns_forwarders_t *forwarders = NULL;
2800			dns_view_t *pview = NULL;
2801
2802			isc_buffer_init(&buffer, empty, strlen(empty));
2803			isc_buffer_add(&buffer, strlen(empty));
2804			/*
2805			 * Look for zone on drop list.
2806			 */
2807			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
2808						NULL));
2809			if (disablelist != NULL &&
2810			    on_disable_list(disablelist, name))
2811				continue;
2812
2813			/*
2814			 * This zone already exists.
2815			 */
2816			(void)dns_view_findzone(view, name, &zone);
2817			if (zone != NULL) {
2818				CHECK(setquerystats(zone, mctx, zonestats_on));
2819				dns_zone_detach(&zone);
2820				continue;
2821			}
2822
2823			/*
2824			 * If we would forward this name don't add a
2825			 * empty zone for it.
2826			 */
2827			result = dns_fwdtable_find(view->fwdtable, name,
2828						   &forwarders);
2829			if (result == ISC_R_SUCCESS &&
2830			    forwarders->fwdpolicy == dns_fwdpolicy_only)
2831				continue;
2832
2833			/*
2834			 * See if we can re-use a existing zone.
2835			 */
2836			result = dns_viewlist_find(&ns_g_server->viewlist,
2837						   view->name, view->rdclass,
2838						   &pview);
2839			if (result != ISC_R_NOTFOUND &&
2840			    result != ISC_R_SUCCESS)
2841				goto cleanup;
2842
2843			if (pview != NULL) {
2844				(void)dns_view_findzone(pview, name, &zone);
2845				dns_view_detach(&pview);
2846				if (zone != NULL)
2847					check_dbtype(&zone, empty_dbtypec,
2848						     empty_dbtype, mctx);
2849				if (zone != NULL) {
2850					dns_zone_setview(zone, view);
2851					CHECK(dns_view_addzone(view, zone));
2852					CHECK(setquerystats(zone, mctx,
2853							    zonestats_on));
2854					dns_zone_detach(&zone);
2855					continue;
2856				}
2857			}
2858
2859			CHECK(dns_zone_create(&zone, mctx));
2860			CHECK(dns_zone_setorigin(zone, name));
2861			dns_zone_setview(zone, view);
2862			CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr,
2863						     zone));
2864			dns_zone_setclass(zone, view->rdclass);
2865			dns_zone_settype(zone, dns_zone_master);
2866			dns_zone_setstats(zone, ns_g_server->zonestats);
2867			CHECK(dns_zone_setdbtype(zone, empty_dbtypec,
2868						 empty_dbtype));
2869			if (view->queryacl != NULL)
2870				dns_zone_setqueryacl(zone, view->queryacl);
2871			if (view->queryonacl != NULL)
2872				dns_zone_setqueryonacl(zone, view->queryonacl);
2873			dns_zone_setdialup(zone, dns_dialuptype_no);
2874			dns_zone_setnotifytype(zone, dns_notifytype_no);
2875			dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS,
2876					   ISC_TRUE);
2877			CHECK(setquerystats(zone, mctx, zonestats_on));
2878			CHECK(dns_view_addzone(view, zone));
2879			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2880				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
2881				      "automatic empty zone%s%s: %s",
2882				      sep, viewname,  empty);
2883			dns_zone_detach(&zone);
2884		}
2885	}
2886
2887	/*
2888	 * Make the list of response policy zone names for views that
2889	 * are used for real lookups and so care about hints.
2890	 */
2891		obj = NULL;
2892	if (view->rdclass == dns_rdataclass_in && need_hints &&
2893	    ns_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS) {
2894		const cfg_obj_t *recursive_only_obj;
2895		const cfg_obj_t *break_dnssec_obj, *ttl_obj;
2896		isc_boolean_t recursive_only_def;
2897		dns_ttl_t ttl_def;
2898
2899		recursive_only_obj = cfg_tuple_get(obj, "recursive-only");
2900		if (!cfg_obj_isvoid(recursive_only_obj) &&
2901		    !cfg_obj_asboolean(recursive_only_obj))
2902			recursive_only_def = ISC_FALSE;
2903		else
2904			recursive_only_def = ISC_TRUE;
2905
2906		break_dnssec_obj = cfg_tuple_get(obj, "break-dnssec");
2907		if (!cfg_obj_isvoid(break_dnssec_obj) &&
2908		    cfg_obj_asboolean(break_dnssec_obj))
2909			view->rpz_break_dnssec = ISC_TRUE;
2910		else
2911			view->rpz_break_dnssec = ISC_FALSE;
2912
2913		ttl_obj = cfg_tuple_get(obj, "max-policy-ttl");
2914		if (cfg_obj_isuint32(ttl_obj))
2915			ttl_def = cfg_obj_asuint32(ttl_obj);
2916		else
2917			ttl_def = DNS_RPZ_MAX_TTL_DEFAULT;
2918
2919		for (element = cfg_list_first(cfg_tuple_get(obj, "zone list"));
2920		     element != NULL;
2921		     element = cfg_list_next(element)) {
2922			result = configure_rpz(view, element,
2923					       recursive_only_def, ttl_def);
2924			if (result != ISC_R_SUCCESS)
2925				goto cleanup;
2926			dns_rpz_set_need(ISC_TRUE);
2927		}
2928	}
2929
2930	result = ISC_R_SUCCESS;
2931
2932 cleanup:
2933	if (clients != NULL)
2934		dns_acl_detach(&clients);
2935	if (mapped != NULL)
2936		dns_acl_detach(&mapped);
2937	if (excluded != NULL)
2938		dns_acl_detach(&excluded);
2939	if (ring != NULL)
2940		dns_tsigkeyring_detach(&ring);
2941	if (zone != NULL)
2942		dns_zone_detach(&zone);
2943	if (dispatch4 != NULL)
2944		dns_dispatch_detach(&dispatch4);
2945	if (dispatch6 != NULL)
2946		dns_dispatch_detach(&dispatch6);
2947	if (resstats != NULL)
2948		isc_stats_detach(&resstats);
2949	if (resquerystats != NULL)
2950		dns_stats_detach(&resquerystats);
2951	if (order != NULL)
2952		dns_order_detach(&order);
2953	if (cmctx != NULL)
2954		isc_mem_detach(&cmctx);
2955	if (hmctx != NULL)
2956		isc_mem_detach(&hmctx);
2957
2958	if (cache != NULL)
2959		dns_cache_detach(&cache);
2960
2961	return (result);
2962}
2963
2964static isc_result_t
2965configure_hints(dns_view_t *view, const char *filename) {
2966	isc_result_t result;
2967	dns_db_t *db;
2968
2969	db = NULL;
2970	result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
2971	if (result == ISC_R_SUCCESS) {
2972		dns_view_sethints(view, db);
2973		dns_db_detach(&db);
2974	}
2975
2976	return (result);
2977}
2978
2979static isc_result_t
2980configure_alternates(const cfg_obj_t *config, dns_view_t *view,
2981		     const cfg_obj_t *alternates)
2982{
2983	const cfg_obj_t *portobj;
2984	const cfg_obj_t *addresses;
2985	const cfg_listelt_t *element;
2986	isc_result_t result = ISC_R_SUCCESS;
2987	in_port_t port;
2988
2989	/*
2990	 * Determine which port to send requests to.
2991	 */
2992	if (ns_g_lwresdonly && ns_g_port != 0)
2993		port = ns_g_port;
2994	else
2995		CHECKM(ns_config_getport(config, &port), "port");
2996
2997	if (alternates != NULL) {
2998		portobj = cfg_tuple_get(alternates, "port");
2999		if (cfg_obj_isuint32(portobj)) {
3000			isc_uint32_t val = cfg_obj_asuint32(portobj);
3001			if (val > ISC_UINT16_MAX) {
3002				cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
3003					    "port '%u' out of range", val);
3004				return (ISC_R_RANGE);
3005			}
3006			port = (in_port_t) val;
3007		}
3008	}
3009
3010	addresses = NULL;
3011	if (alternates != NULL)
3012		addresses = cfg_tuple_get(alternates, "addresses");
3013
3014	for (element = cfg_list_first(addresses);
3015	     element != NULL;
3016	     element = cfg_list_next(element))
3017	{
3018		const cfg_obj_t *alternate = cfg_listelt_value(element);
3019		isc_sockaddr_t sa;
3020
3021		if (!cfg_obj_issockaddr(alternate)) {
3022			dns_fixedname_t fixed;
3023			dns_name_t *name;
3024			const char *str = cfg_obj_asstring(cfg_tuple_get(
3025							   alternate, "name"));
3026			isc_buffer_t buffer;
3027			in_port_t myport = port;
3028
3029			isc_buffer_init(&buffer, str, strlen(str));
3030			isc_buffer_add(&buffer, strlen(str));
3031			dns_fixedname_init(&fixed);
3032			name = dns_fixedname_name(&fixed);
3033			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
3034						NULL));
3035
3036			portobj = cfg_tuple_get(alternate, "port");
3037			if (cfg_obj_isuint32(portobj)) {
3038				isc_uint32_t val = cfg_obj_asuint32(portobj);
3039				if (val > ISC_UINT16_MAX) {
3040					cfg_obj_log(portobj, ns_g_lctx,
3041						    ISC_LOG_ERROR,
3042						    "port '%u' out of range",
3043						     val);
3044					return (ISC_R_RANGE);
3045				}
3046				myport = (in_port_t) val;
3047			}
3048			CHECK(dns_resolver_addalternate(view->resolver, NULL,
3049							name, myport));
3050			continue;
3051		}
3052
3053		sa = *cfg_obj_assockaddr(alternate);
3054		if (isc_sockaddr_getport(&sa) == 0)
3055			isc_sockaddr_setport(&sa, port);
3056		CHECK(dns_resolver_addalternate(view->resolver, &sa,
3057						NULL, 0));
3058	}
3059
3060 cleanup:
3061	return (result);
3062}
3063
3064static isc_result_t
3065configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
3066		  const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype)
3067{
3068	const cfg_obj_t *portobj;
3069	const cfg_obj_t *faddresses;
3070	const cfg_listelt_t *element;
3071	dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
3072	isc_sockaddrlist_t addresses;
3073	isc_sockaddr_t *sa;
3074	isc_result_t result;
3075	in_port_t port;
3076
3077	ISC_LIST_INIT(addresses);
3078
3079	/*
3080	 * Determine which port to send forwarded requests to.
3081	 */
3082	if (ns_g_lwresdonly && ns_g_port != 0)
3083		port = ns_g_port;
3084	else
3085		CHECKM(ns_config_getport(config, &port), "port");
3086
3087	if (forwarders != NULL) {
3088		portobj = cfg_tuple_get(forwarders, "port");
3089		if (cfg_obj_isuint32(portobj)) {
3090			isc_uint32_t val = cfg_obj_asuint32(portobj);
3091			if (val > ISC_UINT16_MAX) {
3092				cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
3093					    "port '%u' out of range", val);
3094				return (ISC_R_RANGE);
3095			}
3096			port = (in_port_t) val;
3097		}
3098	}
3099
3100	faddresses = NULL;
3101	if (forwarders != NULL)
3102		faddresses = cfg_tuple_get(forwarders, "addresses");
3103
3104	for (element = cfg_list_first(faddresses);
3105	     element != NULL;
3106	     element = cfg_list_next(element))
3107	{
3108		const cfg_obj_t *forwarder = cfg_listelt_value(element);
3109		sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t));
3110		if (sa == NULL) {
3111			result = ISC_R_NOMEMORY;
3112			goto cleanup;
3113		}
3114		*sa = *cfg_obj_assockaddr(forwarder);
3115		if (isc_sockaddr_getport(sa) == 0)
3116			isc_sockaddr_setport(sa, port);
3117		ISC_LINK_INIT(sa, link);
3118		ISC_LIST_APPEND(addresses, sa, link);
3119	}
3120
3121	if (ISC_LIST_EMPTY(addresses)) {
3122		if (forwardtype != NULL)
3123			cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
3124				    "no forwarders seen; disabling "
3125				    "forwarding");
3126		fwdpolicy = dns_fwdpolicy_none;
3127	} else {
3128		if (forwardtype == NULL)
3129			fwdpolicy = dns_fwdpolicy_first;
3130		else {
3131			const char *forwardstr = cfg_obj_asstring(forwardtype);
3132			if (strcasecmp(forwardstr, "first") == 0)
3133				fwdpolicy = dns_fwdpolicy_first;
3134			else if (strcasecmp(forwardstr, "only") == 0)
3135				fwdpolicy = dns_fwdpolicy_only;
3136			else
3137				INSIST(0);
3138		}
3139	}
3140
3141	result = dns_fwdtable_add(view->fwdtable, origin, &addresses,
3142				  fwdpolicy);
3143	if (result != ISC_R_SUCCESS) {
3144		char namebuf[DNS_NAME_FORMATSIZE];
3145		dns_name_format(origin, namebuf, sizeof(namebuf));
3146		cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
3147			    "could not set up forwarding for domain '%s': %s",
3148			    namebuf, isc_result_totext(result));
3149		goto cleanup;
3150	}
3151
3152	result = ISC_R_SUCCESS;
3153
3154 cleanup:
3155
3156	while (!ISC_LIST_EMPTY(addresses)) {
3157		sa = ISC_LIST_HEAD(addresses);
3158		ISC_LIST_UNLINK(addresses, sa, link);
3159		isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t));
3160	}
3161
3162	return (result);
3163}
3164
3165static isc_result_t
3166get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
3167	     dns_rdataclass_t *classp)
3168{
3169	isc_result_t result = ISC_R_SUCCESS;
3170	const char *viewname;
3171	dns_rdataclass_t viewclass;
3172
3173	REQUIRE(namep != NULL && *namep == NULL);
3174	REQUIRE(classp != NULL);
3175
3176	if (vconfig != NULL) {
3177		const cfg_obj_t *classobj = NULL;
3178
3179		viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
3180		classobj = cfg_tuple_get(vconfig, "class");
3181		result = ns_config_getclass(classobj, dns_rdataclass_in,
3182					    &viewclass);
3183	} else {
3184		viewname = "_default";
3185		viewclass = dns_rdataclass_in;
3186	}
3187
3188	*namep = viewname;
3189	*classp = viewclass;
3190
3191	return (result);
3192}
3193
3194/*
3195 * Find a view based on its configuration info and attach to it.
3196 *
3197 * If 'vconfig' is NULL, attach to the default view.
3198 */
3199static isc_result_t
3200find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
3201	  dns_view_t **viewp)
3202{
3203	isc_result_t result;
3204	const char *viewname = NULL;
3205	dns_rdataclass_t viewclass;
3206	dns_view_t *view = NULL;
3207
3208	result = get_viewinfo(vconfig, &viewname, &viewclass);
3209	if (result != ISC_R_SUCCESS)
3210		return (result);
3211
3212	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
3213	if (result != ISC_R_SUCCESS)
3214		return (result);
3215
3216	*viewp = view;
3217	return (ISC_R_SUCCESS);
3218}
3219
3220/*
3221 * Create a new view and add it to the list.
3222 *
3223 * If 'vconfig' is NULL, create the default view.
3224 *
3225 * The view created is attached to '*viewp'.
3226 */
3227static isc_result_t
3228create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
3229	    dns_view_t **viewp)
3230{
3231	isc_result_t result;
3232	const char *viewname = NULL;
3233	dns_rdataclass_t viewclass;
3234	dns_view_t *view = NULL;
3235
3236	result = get_viewinfo(vconfig, &viewname, &viewclass);
3237	if (result != ISC_R_SUCCESS)
3238		return (result);
3239
3240	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
3241	if (result == ISC_R_SUCCESS)
3242		return (ISC_R_EXISTS);
3243	if (result != ISC_R_NOTFOUND)
3244		return (result);
3245	INSIST(view == NULL);
3246
3247	result = dns_view_create(ns_g_mctx, viewclass, viewname, &view);
3248	if (result != ISC_R_SUCCESS)
3249		return (result);
3250
3251	ISC_LIST_APPEND(*viewlist, view, link);
3252	dns_view_attach(view, viewp);
3253	return (ISC_R_SUCCESS);
3254}
3255
3256/*
3257 * Configure or reconfigure a zone.
3258 */
3259static isc_result_t
3260configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
3261	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
3262	       cfg_aclconfctx_t *aclconf, isc_boolean_t added)
3263{
3264	dns_view_t *pview = NULL;	/* Production view */
3265	dns_zone_t *zone = NULL;	/* New or reused zone */
3266	dns_zone_t *raw = NULL;		/* New or reused raw zone */
3267	dns_zone_t *dupzone = NULL;
3268	const cfg_obj_t *options = NULL;
3269	const cfg_obj_t *zoptions = NULL;
3270	const cfg_obj_t *typeobj = NULL;
3271	const cfg_obj_t *forwarders = NULL;
3272	const cfg_obj_t *forwardtype = NULL;
3273	const cfg_obj_t *only = NULL;
3274	const cfg_obj_t *signing = NULL;
3275	isc_result_t result;
3276	isc_result_t tresult;
3277	isc_buffer_t buffer;
3278	dns_fixedname_t fixorigin;
3279	dns_name_t *origin;
3280	const char *zname;
3281	dns_rdataclass_t zclass;
3282	const char *ztypestr;
3283
3284	options = NULL;
3285	(void)cfg_map_get(config, "options", &options);
3286
3287	zoptions = cfg_tuple_get(zconfig, "options");
3288
3289	/*
3290	 * Get the zone origin as a dns_name_t.
3291	 */
3292	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
3293	isc_buffer_init(&buffer, zname, strlen(zname));
3294	isc_buffer_add(&buffer, strlen(zname));
3295	dns_fixedname_init(&fixorigin);
3296	CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin),
3297				&buffer, dns_rootname, 0, NULL));
3298	origin = dns_fixedname_name(&fixorigin);
3299
3300	CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
3301				 view->rdclass, &zclass));
3302	if (zclass != view->rdclass) {
3303		const char *vname = NULL;
3304		if (vconfig != NULL)
3305			vname = cfg_obj_asstring(cfg_tuple_get(vconfig,
3306							       "name"));
3307		else
3308			vname = "<default view>";
3309
3310		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3311			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3312			      "zone '%s': wrong class for view '%s'",
3313			      zname, vname);
3314		result = ISC_R_FAILURE;
3315		goto cleanup;
3316	}
3317
3318	(void)cfg_map_get(zoptions, "type", &typeobj);
3319	if (typeobj == NULL) {
3320		cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
3321			    "zone '%s' 'type' not specified", zname);
3322		return (ISC_R_FAILURE);
3323	}
3324	ztypestr = cfg_obj_asstring(typeobj);
3325
3326	/*
3327	 * "hints zones" aren't zones.	If we've got one,
3328	 * configure it and return.
3329	 */
3330	if (strcasecmp(ztypestr, "hint") == 0) {
3331		const cfg_obj_t *fileobj = NULL;
3332		if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
3333			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3334				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3335				      "zone '%s': 'file' not specified",
3336				      zname);
3337			result = ISC_R_FAILURE;
3338			goto cleanup;
3339		}
3340		if (dns_name_equal(origin, dns_rootname)) {
3341			const char *hintsfile = cfg_obj_asstring(fileobj);
3342
3343			result = configure_hints(view, hintsfile);
3344			if (result != ISC_R_SUCCESS) {
3345				isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3346					      NS_LOGMODULE_SERVER,
3347					      ISC_LOG_ERROR,
3348					      "could not configure root hints "
3349					      "from '%s': %s", hintsfile,
3350					      isc_result_totext(result));
3351				goto cleanup;
3352			}
3353			/*
3354			 * Hint zones may also refer to delegation only points.
3355			 */
3356			only = NULL;
3357			tresult = cfg_map_get(zoptions, "delegation-only",
3358					      &only);
3359			if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
3360				CHECK(dns_view_adddelegationonly(view, origin));
3361		} else {
3362			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3363				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
3364				      "ignoring non-root hint zone '%s'",
3365				      zname);
3366			result = ISC_R_SUCCESS;
3367		}
3368		/* Skip ordinary zone processing. */
3369		goto cleanup;
3370	}
3371
3372	/*
3373	 * "forward zones" aren't zones either.  Translate this syntax into
3374	 * the appropriate selective forwarding configuration and return.
3375	 */
3376	if (strcasecmp(ztypestr, "forward") == 0) {
3377		forwardtype = NULL;
3378		forwarders = NULL;
3379
3380		(void)cfg_map_get(zoptions, "forward", &forwardtype);
3381		(void)cfg_map_get(zoptions, "forwarders", &forwarders);
3382		result = configure_forward(config, view, origin, forwarders,
3383					   forwardtype);
3384		goto cleanup;
3385	}
3386
3387	/*
3388	 * "delegation-only zones" aren't zones either.
3389	 */
3390	if (strcasecmp(ztypestr, "delegation-only") == 0) {
3391		result = dns_view_adddelegationonly(view, origin);
3392		goto cleanup;
3393	}
3394
3395	/*
3396	 * Redirect zones only require minimal configuration.
3397	 */
3398	if (strcasecmp(ztypestr, "redirect") == 0) {
3399		if (view->redirect != NULL) {
3400			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
3401				    "redirect zone already exists");
3402			result = ISC_R_EXISTS;
3403			goto cleanup;
3404		}
3405		result = dns_viewlist_find(&ns_g_server->viewlist, view->name,
3406					   view->rdclass, &pview);
3407		if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
3408			goto cleanup;
3409		if (pview != NULL && pview->redirect != NULL) {
3410			dns_zone_attach(pview->redirect, &zone);
3411			dns_zone_setview(zone, view);
3412		} else {
3413			CHECK(dns_zone_create(&zone, mctx));
3414			CHECK(dns_zone_setorigin(zone, origin));
3415			dns_zone_setview(zone, view);
3416			CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr,
3417						     zone));
3418			dns_zone_setstats(zone, ns_g_server->zonestats);
3419		}
3420		CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf,
3421					zone, NULL));
3422		dns_zone_attach(zone, &view->redirect);
3423		goto cleanup;
3424	}
3425
3426	/*
3427	 * Check for duplicates in the new zone table.
3428	 */
3429	result = dns_view_findzone(view, origin, &dupzone);
3430	if (result == ISC_R_SUCCESS) {
3431		/*
3432		 * We already have this zone!
3433		 */
3434		cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
3435			    "zone '%s' already exists", zname);
3436		dns_zone_detach(&dupzone);
3437		result = ISC_R_EXISTS;
3438		goto cleanup;
3439	}
3440	INSIST(dupzone == NULL);
3441
3442	/*
3443	 * See if we can reuse an existing zone.  This is
3444	 * only possible if all of these are true:
3445	 *   - The zone's view exists
3446	 *   - A zone with the right name exists in the view
3447	 *   - The zone is compatible with the config
3448	 *     options (e.g., an existing master zone cannot
3449	 *     be reused if the options specify a slave zone)
3450	 */
3451	result = dns_viewlist_find(&ns_g_server->viewlist, view->name,
3452				   view->rdclass, &pview);
3453	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
3454		goto cleanup;
3455	if (pview != NULL)
3456		result = dns_view_findzone(pview, origin, &zone);
3457	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
3458		goto cleanup;
3459
3460	if (zone != NULL && !ns_zone_reusable(zone, zconfig))
3461		dns_zone_detach(&zone);
3462
3463	if (zone != NULL) {
3464		/*
3465		 * We found a reusable zone.  Make it use the
3466		 * new view.
3467		 */
3468		dns_zone_setview(zone, view);
3469		if (view->acache != NULL)
3470			dns_zone_setacache(zone, view->acache);
3471	} else {
3472		/*
3473		 * We cannot reuse an existing zone, we have
3474		 * to create a new one.
3475		 */
3476		CHECK(dns_zone_create(&zone, mctx));
3477		CHECK(dns_zone_setorigin(zone, origin));
3478		dns_zone_setview(zone, view);
3479		if (view->acache != NULL)
3480			dns_zone_setacache(zone, view->acache);
3481		CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
3482		dns_zone_setstats(zone, ns_g_server->zonestats);
3483	}
3484
3485	/*
3486	 * If the zone contains a 'forwarders' statement, configure
3487	 * selective forwarding.
3488	 */
3489	forwarders = NULL;
3490	if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS)
3491	{
3492		forwardtype = NULL;
3493		(void)cfg_map_get(zoptions, "forward", &forwardtype);
3494		CHECK(configure_forward(config, view, origin, forwarders,
3495					forwardtype));
3496	}
3497
3498	/*
3499	 * Stub and forward zones may also refer to delegation only points.
3500	 */
3501	only = NULL;
3502	if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS)
3503	{
3504		if (cfg_obj_asboolean(only))
3505			CHECK(dns_view_adddelegationonly(view, origin));
3506	}
3507
3508	/*
3509	 * Mark whether the zone was originally added at runtime or not
3510	 */
3511	dns_zone_setadded(zone, added);
3512
3513	signing = NULL;
3514	if ((strcasecmp(ztypestr, "master") == 0 ||
3515	     strcasecmp(ztypestr, "slave") == 0) &&
3516	    cfg_map_get(zoptions, "inline-signing", &signing) == ISC_R_SUCCESS &&
3517	    cfg_obj_asboolean(signing))
3518	{
3519		dns_zone_getraw(zone, &raw);
3520		if (raw == NULL) {
3521			CHECK(dns_zone_create(&raw, mctx));
3522			CHECK(dns_zone_setorigin(raw, origin));
3523			dns_zone_setview(raw, view);
3524			if (view->acache != NULL)
3525				dns_zone_setacache(raw, view->acache);
3526			dns_zone_setstats(raw, ns_g_server->zonestats);
3527			CHECK(dns_zone_link(zone, raw));
3528		}
3529	}
3530
3531	/*
3532	 * Configure the zone.
3533	 */
3534	CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone, raw));
3535
3536	/*
3537	 * Add the zone to its view in the new view list.
3538	 */
3539	CHECK(dns_view_addzone(view, zone));
3540
3541	/*
3542	 * Ensure that zone keys are reloaded on reconfig
3543	 */
3544	if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0)
3545		dns_zone_rekey(zone, ISC_FALSE);
3546
3547 cleanup:
3548	if (zone != NULL)
3549		dns_zone_detach(&zone);
3550	if (raw != NULL)
3551		dns_zone_detach(&raw);
3552	if (pview != NULL)
3553		dns_view_detach(&pview);
3554
3555	return (result);
3556}
3557
3558/*
3559 * Configure built-in zone for storing managed-key data.
3560 */
3561
3562#define KEYZONE "managed-keys.bind"
3563#define MKEYS ".mkeys"
3564
3565static isc_result_t
3566add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
3567	isc_result_t result;
3568	dns_view_t *pview = NULL;
3569	dns_zone_t *zone = NULL;
3570	dns_acl_t *none = NULL;
3571	char filename[PATH_MAX];
3572	char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(MKEYS)];
3573	int n;
3574
3575	REQUIRE(view != NULL);
3576
3577	/* See if we can re-use an existing keydata zone. */
3578	result = dns_viewlist_find(&ns_g_server->viewlist,
3579				   view->name, view->rdclass,
3580				   &pview);
3581	if (result != ISC_R_NOTFOUND &&
3582	    result != ISC_R_SUCCESS)
3583		return (result);
3584
3585	if (pview != NULL && pview->managed_keys != NULL) {
3586		dns_zone_attach(pview->managed_keys, &view->managed_keys);
3587		dns_zone_setview(pview->managed_keys, view);
3588		dns_view_detach(&pview);
3589		dns_zone_synckeyzone(view->managed_keys);
3590		return (ISC_R_SUCCESS);
3591	}
3592
3593	/* No existing keydata zone was found; create one */
3594	CHECK(dns_zone_create(&zone, mctx));
3595	CHECK(dns_zone_setorigin(zone, dns_rootname));
3596
3597	isc_sha256_data((void *)view->name, strlen(view->name), buffer);
3598	strcat(buffer, MKEYS);
3599	n = snprintf(filename, sizeof(filename), "%s%s%s",
3600		     directory ? directory : "", directory ? "/" : "",
3601		     strcmp(view->name, "_default") == 0 ? KEYZONE : buffer);
3602	if (n < 0 || (size_t)n >= sizeof(filename)) {
3603		result = (n < 0) ? ISC_R_FAILURE : ISC_R_NOSPACE;
3604		goto cleanup;
3605	}
3606	CHECK(dns_zone_setfile(zone, filename));
3607
3608	dns_zone_setview(zone, view);
3609	dns_zone_settype(zone, dns_zone_key);
3610	dns_zone_setclass(zone, view->rdclass);
3611
3612	CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
3613
3614	if (view->acache != NULL)
3615		dns_zone_setacache(zone, view->acache);
3616
3617	CHECK(dns_acl_none(mctx, &none));
3618	dns_zone_setqueryacl(zone, none);
3619	dns_zone_setqueryonacl(zone, none);
3620	dns_acl_detach(&none);
3621
3622	dns_zone_setdialup(zone, dns_dialuptype_no);
3623	dns_zone_setnotifytype(zone, dns_notifytype_no);
3624	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
3625	dns_zone_setjournalsize(zone, 0);
3626
3627	dns_zone_setstats(zone, ns_g_server->zonestats);
3628	CHECK(setquerystats(zone, mctx, ISC_FALSE));
3629
3630	if (view->managed_keys != NULL)
3631		dns_zone_detach(&view->managed_keys);
3632	dns_zone_attach(zone, &view->managed_keys);
3633
3634	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3635		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3636		      "set up managed keys zone for view %s, file '%s'",
3637		      view->name, filename);
3638
3639cleanup:
3640	if (zone != NULL)
3641		dns_zone_detach(&zone);
3642	if (none != NULL)
3643		dns_acl_detach(&none);
3644
3645	return (result);
3646}
3647
3648/*
3649 * Configure a single server quota.
3650 */
3651static void
3652configure_server_quota(const cfg_obj_t **maps, const char *name,
3653		       isc_quota_t *quota)
3654{
3655	const cfg_obj_t *obj = NULL;
3656	isc_result_t result;
3657
3658	result = ns_config_get(maps, name, &obj);
3659	INSIST(result == ISC_R_SUCCESS);
3660	isc_quota_max(quota, cfg_obj_asuint32(obj));
3661}
3662
3663/*
3664 * This function is called as soon as the 'directory' statement has been
3665 * parsed.  This can be extended to support other options if necessary.
3666 */
3667static isc_result_t
3668directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
3669	isc_result_t result;
3670	const char *directory;
3671
3672	REQUIRE(strcasecmp("directory", clausename) == 0);
3673
3674	UNUSED(arg);
3675	UNUSED(clausename);
3676
3677	/*
3678	 * Change directory.
3679	 */
3680	directory = cfg_obj_asstring(obj);
3681
3682	if (! isc_file_ischdiridempotent(directory))
3683		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
3684			    "option 'directory' contains relative path '%s'",
3685			    directory);
3686
3687	result = isc_dir_chdir(directory);
3688	if (result != ISC_R_SUCCESS) {
3689		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
3690			    "change directory to '%s' failed: %s",
3691			    directory, isc_result_totext(result));
3692		return (result);
3693	}
3694
3695	return (ISC_R_SUCCESS);
3696}
3697
3698static void
3699scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
3700	isc_boolean_t match_mapped = server->aclenv.match_mapped;
3701
3702	ns_interfacemgr_scan(server->interfacemgr, verbose);
3703	/*
3704	 * Update the "localhost" and "localnets" ACLs to match the
3705	 * current set of network interfaces.
3706	 */
3707	dns_aclenv_copy(&server->aclenv,
3708			ns_interfacemgr_getaclenv(server->interfacemgr));
3709
3710	server->aclenv.match_mapped = match_mapped;
3711}
3712
3713static isc_result_t
3714add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr,
3715	      isc_boolean_t wcardport_ok)
3716{
3717	ns_listenelt_t *lelt = NULL;
3718	dns_acl_t *src_acl = NULL;
3719	isc_result_t result;
3720	isc_sockaddr_t any_sa6;
3721	isc_netaddr_t netaddr;
3722
3723	REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
3724
3725	isc_sockaddr_any6(&any_sa6);
3726	if (!isc_sockaddr_equal(&any_sa6, addr) &&
3727	    (wcardport_ok || isc_sockaddr_getport(addr) != 0)) {
3728		isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr);
3729
3730		result = dns_acl_create(mctx, 0, &src_acl);
3731		if (result != ISC_R_SUCCESS)
3732			return (result);
3733
3734		result = dns_iptable_addprefix(src_acl->iptable,
3735					       &netaddr, 128, ISC_TRUE);
3736		if (result != ISC_R_SUCCESS)
3737			goto clean;
3738
3739		result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr),
3740					     src_acl, &lelt);
3741		if (result != ISC_R_SUCCESS)
3742			goto clean;
3743		ISC_LIST_APPEND(list->elts, lelt, link);
3744	}
3745
3746	return (ISC_R_SUCCESS);
3747
3748 clean:
3749	INSIST(lelt == NULL);
3750	dns_acl_detach(&src_acl);
3751
3752	return (result);
3753}
3754
3755/*
3756 * Make a list of xxx-source addresses and call ns_interfacemgr_adjust()
3757 * to update the listening interfaces accordingly.
3758 * We currently only consider IPv6, because this only affects IPv6 wildcard
3759 * sockets.
3760 */
3761static void
3762adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
3763	isc_result_t result;
3764	ns_listenlist_t *list = NULL;
3765	dns_view_t *view;
3766	dns_zone_t *zone, *next;
3767	isc_sockaddr_t addr, *addrp;
3768
3769	result = ns_listenlist_create(mctx, &list);
3770	if (result != ISC_R_SUCCESS)
3771		return;
3772
3773	for (view = ISC_LIST_HEAD(server->viewlist);
3774	     view != NULL;
3775	     view = ISC_LIST_NEXT(view, link)) {
3776		dns_dispatch_t *dispatch6;
3777
3778		dispatch6 = dns_resolver_dispatchv6(view->resolver);
3779		if (dispatch6 == NULL)
3780			continue;
3781		result = dns_dispatch_getlocaladdress(dispatch6, &addr);
3782		if (result != ISC_R_SUCCESS)
3783			goto fail;
3784
3785		/*
3786		 * We always add non-wildcard address regardless of whether
3787		 * the port is 'any' (the fourth arg is TRUE): if the port is
3788		 * specific, we need to add it since it may conflict with a
3789		 * listening interface; if it's zero, we'll dynamically open
3790		 * query ports, and some of them may override an existing
3791		 * wildcard IPv6 port.
3792		 */
3793		result = add_listenelt(mctx, list, &addr, ISC_TRUE);
3794		if (result != ISC_R_SUCCESS)
3795			goto fail;
3796	}
3797
3798	zone = NULL;
3799	for (result = dns_zone_first(server->zonemgr, &zone);
3800	     result == ISC_R_SUCCESS;
3801	     next = NULL, result = dns_zone_next(zone, &next), zone = next) {
3802		dns_view_t *zoneview;
3803
3804		/*
3805		 * At this point the zone list may contain a stale zone
3806		 * just removed from the configuration.  To see the validity,
3807		 * check if the corresponding view is in our current view list.
3808		 * There may also be old zones that are still in the process
3809		 * of shutting down and have detached from their old view
3810		 * (zoneview == NULL).
3811		 */
3812		zoneview = dns_zone_getview(zone);
3813		if (zoneview == NULL)
3814			continue;
3815		for (view = ISC_LIST_HEAD(server->viewlist);
3816		     view != NULL && view != zoneview;
3817		     view = ISC_LIST_NEXT(view, link))
3818			;
3819		if (view == NULL)
3820			continue;
3821
3822		addrp = dns_zone_getnotifysrc6(zone);
3823		result = add_listenelt(mctx, list, addrp, ISC_FALSE);
3824		if (result != ISC_R_SUCCESS)
3825			goto fail;
3826
3827		addrp = dns_zone_getxfrsource6(zone);
3828		result = add_listenelt(mctx, list, addrp, ISC_FALSE);
3829		if (result != ISC_R_SUCCESS)
3830			goto fail;
3831	}
3832
3833	ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE);
3834
3835 clean:
3836	ns_listenlist_detach(&list);
3837	return;
3838
3839 fail:
3840	/*
3841	 * Even when we failed the procedure, most of other interfaces
3842	 * should work correctly.  We therefore just warn it.
3843	 */
3844	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3845		      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
3846		      "could not adjust the listen-on list; "
3847		      "some interfaces may not work");
3848	goto clean;
3849}
3850
3851/*
3852 * This event callback is invoked to do periodic network
3853 * interface scanning.
3854 */
3855static void
3856interface_timer_tick(isc_task_t *task, isc_event_t *event) {
3857	isc_result_t result;
3858	ns_server_t *server = (ns_server_t *) event->ev_arg;
3859	INSIST(task == server->task);
3860	UNUSED(task);
3861	isc_event_free(&event);
3862	/*
3863	 * XXX should scan interfaces unlocked and get exclusive access
3864	 * only to replace ACLs.
3865	 */
3866	result = isc_task_beginexclusive(server->task);
3867	RUNTIME_CHECK(result == ISC_R_SUCCESS);
3868	scan_interfaces(server, ISC_FALSE);
3869	isc_task_endexclusive(server->task);
3870}
3871
3872static void
3873heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
3874	ns_server_t *server = (ns_server_t *) event->ev_arg;
3875	dns_view_t *view;
3876
3877	UNUSED(task);
3878	isc_event_free(&event);
3879	view = ISC_LIST_HEAD(server->viewlist);
3880	while (view != NULL) {
3881		dns_view_dialup(view);
3882		view = ISC_LIST_NEXT(view, link);
3883	}
3884}
3885
3886static void
3887pps_timer_tick(isc_task_t *task, isc_event_t *event) {
3888	static unsigned int oldrequests = 0;
3889	unsigned int requests = ns_client_requests;
3890
3891	UNUSED(task);
3892	isc_event_free(&event);
3893
3894	/*
3895	 * Don't worry about wrapping as the overflow result will be right.
3896	 */
3897	dns_pps = (requests - oldrequests) / 1200;
3898	oldrequests = requests;
3899}
3900
3901/*
3902 * Replace the current value of '*field', a dynamically allocated
3903 * string or NULL, with a dynamically allocated copy of the
3904 * null-terminated string pointed to by 'value', or NULL.
3905 */
3906static isc_result_t
3907setstring(ns_server_t *server, char **field, const char *value) {
3908	char *copy;
3909
3910	if (value != NULL) {
3911		copy = isc_mem_strdup(server->mctx, value);
3912		if (copy == NULL)
3913			return (ISC_R_NOMEMORY);
3914	} else {
3915		copy = NULL;
3916	}
3917
3918	if (*field != NULL)
3919		isc_mem_free(server->mctx, *field);
3920
3921	*field = copy;
3922	return (ISC_R_SUCCESS);
3923}
3924
3925/*
3926 * Replace the current value of '*field', a dynamically allocated
3927 * string or NULL, with another dynamically allocated string
3928 * or NULL if whether 'obj' is a string or void value, respectively.
3929 */
3930static isc_result_t
3931setoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) {
3932	if (cfg_obj_isvoid(obj))
3933		return (setstring(server, field, NULL));
3934	else
3935		return (setstring(server, field, cfg_obj_asstring(obj)));
3936}
3937
3938static void
3939set_limit(const cfg_obj_t **maps, const char *configname,
3940	  const char *description, isc_resource_t resourceid,
3941	  isc_resourcevalue_t defaultvalue)
3942{
3943	const cfg_obj_t *obj = NULL;
3944	const char *resource;
3945	isc_resourcevalue_t value;
3946	isc_result_t result;
3947
3948	if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS)
3949		return;
3950
3951	if (cfg_obj_isstring(obj)) {
3952		resource = cfg_obj_asstring(obj);
3953		if (strcasecmp(resource, "unlimited") == 0)
3954			value = ISC_RESOURCE_UNLIMITED;
3955		else {
3956			INSIST(strcasecmp(resource, "default") == 0);
3957			value = defaultvalue;
3958		}
3959	} else
3960		value = cfg_obj_asuint64(obj);
3961
3962	result = isc_resource_setlimit(resourceid, value);
3963	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
3964		      result == ISC_R_SUCCESS ?
3965			ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
3966		      "set maximum %s to %" ISC_PRINT_QUADFORMAT "u: %s",
3967		      description, value, isc_result_totext(result));
3968}
3969
3970#define SETLIMIT(cfgvar, resource, description) \
3971	set_limit(maps, cfgvar, description, isc_resource_ ## resource, \
3972		  ns_g_init ## resource)
3973
3974static void
3975set_limits(const cfg_obj_t **maps) {
3976	SETLIMIT("stacksize", stacksize, "stack size");
3977	SETLIMIT("datasize", datasize, "data size");
3978	SETLIMIT("coresize", coresize, "core size");
3979	SETLIMIT("files", openfiles, "open files");
3980}
3981
3982static void
3983portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
3984		 isc_boolean_t positive)
3985{
3986	const cfg_listelt_t *element;
3987
3988	for (element = cfg_list_first(ports);
3989	     element != NULL;
3990	     element = cfg_list_next(element)) {
3991		const cfg_obj_t *obj = cfg_listelt_value(element);
3992
3993		if (cfg_obj_isuint32(obj)) {
3994			in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
3995
3996			if (positive)
3997				isc_portset_add(portset, port);
3998			else
3999				isc_portset_remove(portset, port);
4000		} else {
4001			const cfg_obj_t *obj_loport, *obj_hiport;
4002			in_port_t loport, hiport;
4003
4004			obj_loport = cfg_tuple_get(obj, "loport");
4005			loport = (in_port_t)cfg_obj_asuint32(obj_loport);
4006			obj_hiport = cfg_tuple_get(obj, "hiport");
4007			hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
4008
4009			if (positive)
4010				isc_portset_addrange(portset, loport, hiport);
4011			else {
4012				isc_portset_removerange(portset, loport,
4013							hiport);
4014			}
4015		}
4016	}
4017}
4018
4019static isc_result_t
4020removed(dns_zone_t *zone, void *uap) {
4021	const char *type;
4022
4023	if (dns_zone_getview(zone) != uap)
4024		return (ISC_R_SUCCESS);
4025
4026	switch (dns_zone_gettype(zone)) {
4027	case dns_zone_master:
4028		type = "master";
4029		break;
4030	case dns_zone_slave:
4031		type = "slave";
4032		break;
4033	case dns_zone_stub:
4034		type = "stub";
4035		break;
4036	case dns_zone_redirect:
4037		type = "redirect";
4038		break;
4039	default:
4040		type = "other";
4041		break;
4042	}
4043	dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type);
4044	return (ISC_R_SUCCESS);
4045}
4046
4047static void
4048cleanup_session_key(ns_server_t *server, isc_mem_t *mctx) {
4049	if (server->session_keyfile != NULL) {
4050		isc_file_remove(server->session_keyfile);
4051		isc_mem_free(mctx, server->session_keyfile);
4052		server->session_keyfile = NULL;
4053	}
4054
4055	if (server->session_keyname != NULL) {
4056		if (dns_name_dynamic(server->session_keyname))
4057			dns_name_free(server->session_keyname, mctx);
4058		isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
4059		server->session_keyname = NULL;
4060	}
4061
4062	if (server->sessionkey != NULL)
4063		dns_tsigkey_detach(&server->sessionkey);
4064
4065	server->session_keyalg = DST_ALG_UNKNOWN;
4066	server->session_keybits = 0;
4067}
4068
4069static isc_result_t
4070generate_session_key(const char *filename, const char *keynamestr,
4071		     dns_name_t *keyname, const char *algstr,
4072		     dns_name_t *algname, unsigned int algtype,
4073		     isc_uint16_t bits, isc_mem_t *mctx,
4074		     dns_tsigkey_t **tsigkeyp)
4075{
4076	isc_result_t result = ISC_R_SUCCESS;
4077	dst_key_t *key = NULL;
4078	isc_buffer_t key_txtbuffer;
4079	isc_buffer_t key_rawbuffer;
4080	char key_txtsecret[256];
4081	char key_rawsecret[64];
4082	isc_region_t key_rawregion;
4083	isc_stdtime_t now;
4084	dns_tsigkey_t *tsigkey = NULL;
4085	FILE *fp = NULL;
4086
4087	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4088		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4089		      "generating session key for dynamic DNS");
4090
4091	/* generate key */
4092	result = dst_key_generate(keyname, algtype, bits, 1, 0,
4093				  DNS_KEYPROTO_ANY, dns_rdataclass_in,
4094				  mctx, &key);
4095	if (result != ISC_R_SUCCESS)
4096		return (result);
4097
4098	/*
4099	 * Dump the key to the buffer for later use.  Should be done before
4100	 * we transfer the ownership of key to tsigkey.
4101	 */
4102	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
4103	CHECK(dst_key_tobuffer(key, &key_rawbuffer));
4104
4105	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
4106	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
4107	CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
4108
4109	/* Store the key in tsigkey. */
4110	isc_stdtime_get(&now);
4111	CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key,
4112					ISC_FALSE, NULL, now, now, mctx, NULL,
4113					&tsigkey));
4114
4115	/* Dump the key to the key file. */
4116	fp = ns_os_openfile(filename, S_IRUSR|S_IWUSR, ISC_TRUE);
4117	if (fp == NULL) {
4118		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4119			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4120			      "could not create %s", filename);
4121		result = ISC_R_NOPERM;
4122		goto cleanup;
4123	}
4124
4125	fprintf(fp, "key \"%s\" {\n"
4126		"\talgorithm %s;\n"
4127		"\tsecret \"%.*s\";\n};\n", keynamestr, algstr,
4128		(int) isc_buffer_usedlength(&key_txtbuffer),
4129		(char*) isc_buffer_base(&key_txtbuffer));
4130
4131	RUNTIME_CHECK(isc_stdio_flush(fp) == ISC_R_SUCCESS);
4132	RUNTIME_CHECK(isc_stdio_close(fp) == ISC_R_SUCCESS);
4133
4134	dst_key_free(&key);
4135
4136	*tsigkeyp = tsigkey;
4137
4138	return (ISC_R_SUCCESS);
4139
4140  cleanup:
4141	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4142		      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4143		      "failed to generate session key "
4144		      "for dynamic DNS: %s", isc_result_totext(result));
4145	if (tsigkey != NULL)
4146		dns_tsigkey_detach(&tsigkey);
4147	if (key != NULL)
4148		dst_key_free(&key);
4149
4150	return (result);
4151}
4152
4153static isc_result_t
4154configure_session_key(const cfg_obj_t **maps, ns_server_t *server,
4155		      isc_mem_t *mctx)
4156{
4157	const char *keyfile, *keynamestr, *algstr;
4158	unsigned int algtype;
4159	dns_fixedname_t fname;
4160	dns_name_t *keyname, *algname;
4161	isc_buffer_t buffer;
4162	isc_uint16_t bits;
4163	const cfg_obj_t *obj;
4164	isc_boolean_t need_deleteold = ISC_FALSE;
4165	isc_boolean_t need_createnew = ISC_FALSE;
4166	isc_result_t result;
4167
4168	obj = NULL;
4169	result = ns_config_get(maps, "session-keyfile", &obj);
4170	if (result == ISC_R_SUCCESS) {
4171		if (cfg_obj_isvoid(obj))
4172			keyfile = NULL; /* disable it */
4173		else
4174			keyfile = cfg_obj_asstring(obj);
4175	} else
4176		keyfile = ns_g_defaultsessionkeyfile;
4177
4178	obj = NULL;
4179	result = ns_config_get(maps, "session-keyname", &obj);
4180	INSIST(result == ISC_R_SUCCESS);
4181	keynamestr = cfg_obj_asstring(obj);
4182	dns_fixedname_init(&fname);
4183	isc_buffer_init(&buffer, keynamestr, strlen(keynamestr));
4184	isc_buffer_add(&buffer, strlen(keynamestr));
4185	keyname = dns_fixedname_name(&fname);
4186	result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
4187	if (result != ISC_R_SUCCESS)
4188		return (result);
4189
4190	obj = NULL;
4191	result = ns_config_get(maps, "session-keyalg", &obj);
4192	INSIST(result == ISC_R_SUCCESS);
4193	algstr = cfg_obj_asstring(obj);
4194	algname = NULL;
4195	result = ns_config_getkeyalgorithm2(algstr, &algname, &algtype, &bits);
4196	if (result != ISC_R_SUCCESS) {
4197		const char *s = " (keeping current key)";
4198
4199		cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "session-keyalg: "
4200			    "unsupported or unknown algorithm '%s'%s",
4201			    algstr,
4202			    server->session_keyfile != NULL ? s : "");
4203		return (result);
4204	}
4205
4206	/* See if we need to (re)generate a new key. */
4207	if (keyfile == NULL) {
4208		if (server->session_keyfile != NULL)
4209			need_deleteold = ISC_TRUE;
4210	} else if (server->session_keyfile == NULL)
4211		need_createnew = ISC_TRUE;
4212	else if (strcmp(keyfile, server->session_keyfile) != 0 ||
4213		 !dns_name_equal(server->session_keyname, keyname) ||
4214		 server->session_keyalg != algtype ||
4215		 server->session_keybits != bits) {
4216		need_deleteold = ISC_TRUE;
4217		need_createnew = ISC_TRUE;
4218	}
4219
4220	if (need_deleteold) {
4221		INSIST(server->session_keyfile != NULL);
4222		INSIST(server->session_keyname != NULL);
4223		INSIST(server->sessionkey != NULL);
4224
4225		cleanup_session_key(server, mctx);
4226	}
4227
4228	if (need_createnew) {
4229		INSIST(server->sessionkey == NULL);
4230		INSIST(server->session_keyfile == NULL);
4231		INSIST(server->session_keyname == NULL);
4232		INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
4233		INSIST(server->session_keybits == 0);
4234
4235		server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
4236		if (server->session_keyname == NULL)
4237			goto cleanup;
4238		dns_name_init(server->session_keyname, NULL);
4239		CHECK(dns_name_dup(keyname, mctx, server->session_keyname));
4240
4241		server->session_keyfile = isc_mem_strdup(mctx, keyfile);
4242		if (server->session_keyfile == NULL)
4243			goto cleanup;
4244
4245		server->session_keyalg = algtype;
4246		server->session_keybits = bits;
4247
4248		CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr,
4249					   algname, algtype, bits, mctx,
4250					   &server->sessionkey));
4251	}
4252
4253	return (result);
4254
4255  cleanup:
4256	cleanup_session_key(server, mctx);
4257	return (result);
4258}
4259
4260static isc_result_t
4261setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
4262	       cfg_parser_t *parser, cfg_aclconfctx_t *actx)
4263{
4264	isc_result_t result = ISC_R_SUCCESS;
4265	isc_boolean_t allow = ISC_FALSE;
4266	struct cfg_context *nzcfg = NULL;
4267	cfg_parser_t *nzparser = NULL;
4268	cfg_obj_t *nzconfig = NULL;
4269	const cfg_obj_t *maps[4];
4270	const cfg_obj_t *options = NULL, *voptions = NULL;
4271	const cfg_obj_t *nz = NULL;
4272	int i = 0;
4273
4274	REQUIRE (config != NULL);
4275
4276	if (vconfig != NULL)
4277		voptions = cfg_tuple_get(vconfig, "options");
4278	if (voptions != NULL)
4279		maps[i++] = voptions;
4280	result = cfg_map_get(config, "options", &options);
4281	if (result == ISC_R_SUCCESS)
4282		maps[i++] = options;
4283	maps[i++] = ns_g_defaults;
4284	maps[i] = NULL;
4285
4286	result = ns_config_get(maps, "allow-new-zones", &nz);
4287	if (result == ISC_R_SUCCESS)
4288		allow = cfg_obj_asboolean(nz);
4289
4290	if (!allow) {
4291		dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
4292		return (ISC_R_SUCCESS);
4293	}
4294
4295	nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
4296	if (nzcfg == NULL) {
4297		dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
4298		return (ISC_R_NOMEMORY);
4299	}
4300
4301	dns_view_setnewzones(view, allow, nzcfg, newzone_cfgctx_destroy);
4302
4303	memset(nzcfg, 0, sizeof(*nzcfg));
4304	isc_mem_attach(view->mctx, &nzcfg->mctx);
4305	cfg_obj_attach(config, &nzcfg->config);
4306	cfg_parser_attach(parser, &nzcfg->parser);
4307	cfg_aclconfctx_attach(actx, &nzcfg->actx);
4308
4309	/*
4310	 * Attempt to create a parser and parse the newzones
4311	 * file.  If successful, preserve both; otherwise leave
4312	 * them NULL.
4313	 */
4314	result = cfg_parser_create(view->mctx, ns_g_lctx, &nzparser);
4315	if (result == ISC_R_SUCCESS)
4316		result = cfg_parse_file(nzparser, view->new_zone_file,
4317					&cfg_type_newzones, &nzconfig);
4318	if (result == ISC_R_SUCCESS) {
4319		cfg_parser_attach(nzparser, &nzcfg->nzparser);
4320		cfg_obj_attach(nzconfig, &nzcfg->nzconfig);
4321	}
4322
4323	if (nzparser != NULL) {
4324		if (nzconfig != NULL)
4325			cfg_obj_destroy(nzparser, &nzconfig);
4326		cfg_parser_destroy(&nzparser);
4327	}
4328
4329	return (ISC_R_SUCCESS);
4330}
4331
4332static int
4333count_zones(const cfg_obj_t *conf) {
4334	const cfg_obj_t *zonelist = NULL;
4335	const cfg_listelt_t *element;
4336	int n = 0;
4337
4338	REQUIRE(conf != NULL);
4339
4340	cfg_map_get(conf, "zone", &zonelist);
4341	for (element = cfg_list_first(zonelist);
4342	     element != NULL;
4343	     element = cfg_list_next(element))
4344		n++;
4345
4346	return (n);
4347}
4348
4349static isc_result_t
4350load_configuration(const char *filename, ns_server_t *server,
4351		   isc_boolean_t first_time)
4352{
4353	cfg_obj_t *config = NULL, *bindkeys = NULL;
4354	cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
4355	const cfg_listelt_t *element;
4356	const cfg_obj_t *builtin_views;
4357	const cfg_obj_t *maps[3];
4358	const cfg_obj_t *obj;
4359	const cfg_obj_t *options;
4360	const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
4361	const cfg_obj_t *views;
4362	dns_view_t *view = NULL;
4363	dns_view_t *view_next;
4364	dns_viewlist_t tmpviewlist;
4365	dns_viewlist_t viewlist, builtin_viewlist;
4366	in_port_t listen_port, udpport_low, udpport_high;
4367	int i;
4368	isc_interval_t interval;
4369	isc_portset_t *v4portset = NULL;
4370	isc_portset_t *v6portset = NULL;
4371	isc_resourcevalue_t nfiles;
4372	isc_result_t result;
4373	isc_uint32_t heartbeat_interval;
4374	isc_uint32_t interface_interval;
4375	isc_uint32_t reserved;
4376	isc_uint32_t udpsize;
4377	ns_cachelist_t cachelist, tmpcachelist;
4378	unsigned int maxsocks;
4379	ns_cache_t *nsc;
4380	struct cfg_context *nzctx;
4381	int num_zones = 0;
4382	isc_boolean_t exclusive = ISC_FALSE;
4383
4384	ISC_LIST_INIT(viewlist);
4385	ISC_LIST_INIT(builtin_viewlist);
4386	ISC_LIST_INIT(cachelist);
4387
4388	/* Create the ACL configuration context */
4389	if (ns_g_aclconfctx != NULL)
4390		cfg_aclconfctx_detach(&ns_g_aclconfctx);
4391	CHECK(cfg_aclconfctx_create(ns_g_mctx, &ns_g_aclconfctx));
4392
4393	/*
4394	 * Parse the global default pseudo-config file.
4395	 */
4396	if (first_time) {
4397		CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config));
4398		RUNTIME_CHECK(cfg_map_get(ns_g_config, "options",
4399					  &ns_g_defaults) == ISC_R_SUCCESS);
4400	}
4401
4402	/*
4403	 * Parse the configuration file using the new config code.
4404	 */
4405	result = ISC_R_FAILURE;
4406	config = NULL;
4407
4408	/*
4409	 * Unless this is lwresd with the -C option, parse the config file.
4410	 */
4411	if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) {
4412		isc_log_write(ns_g_lctx,
4413			      NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
4414			      ISC_LOG_INFO, "loading configuration from '%s'",
4415			      filename);
4416		CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser));
4417		cfg_parser_setcallback(conf_parser, directory_callback, NULL);
4418		result = cfg_parse_file(conf_parser, filename,
4419					&cfg_type_namedconf, &config);
4420	}
4421
4422	/*
4423	 * If this is lwresd with the -C option, or lwresd with no -C or -c
4424	 * option where the above parsing failed, parse resolv.conf.
4425	 */
4426	if (ns_g_lwresdonly &&
4427	    (lwresd_g_useresolvconf ||
4428	     (!ns_g_conffileset && result == ISC_R_FILENOTFOUND)))
4429	{
4430		isc_log_write(ns_g_lctx,
4431			      NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
4432			      ISC_LOG_INFO, "loading configuration from '%s'",
4433			      lwresd_g_resolvconffile);
4434		if (conf_parser != NULL)
4435			cfg_parser_destroy(&conf_parser);
4436		CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser));
4437		result = ns_lwresd_parseeresolvconf(ns_g_mctx, conf_parser,
4438						    &config);
4439	}
4440	CHECK(result);
4441
4442	/*
4443	 * Check the validity of the configuration.
4444	 */
4445	CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx));
4446
4447	/*
4448	 * Fill in the maps array, used for resolving defaults.
4449	 */
4450	i = 0;
4451	options = NULL;
4452	result = cfg_map_get(config, "options", &options);
4453	if (result == ISC_R_SUCCESS)
4454		maps[i++] = options;
4455	maps[i++] = ns_g_defaults;
4456	maps[i] = NULL;
4457
4458	/*
4459	 * If bind.keys exists, load it.  If "dnssec-lookaside auto"
4460	 * is turned on, the keys found there will be used as default
4461	 * trust anchors.
4462	 */
4463	obj = NULL;
4464	result = ns_config_get(maps, "bindkeys-file", &obj);
4465	INSIST(result == ISC_R_SUCCESS);
4466	CHECKM(setstring(server, &server->bindkeysfile,
4467	       cfg_obj_asstring(obj)), "strdup");
4468
4469	if (access(server->bindkeysfile, R_OK) == 0) {
4470		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4471			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4472			      "reading built-in trusted "
4473			      "keys from file '%s'", server->bindkeysfile);
4474
4475		CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx,
4476					&bindkeys_parser));
4477
4478		result = cfg_parse_file(bindkeys_parser, server->bindkeysfile,
4479					&cfg_type_bindkeys, &bindkeys);
4480		CHECK(result);
4481	}
4482
4483	/* Ensure exclusive access to configuration data. */
4484	if (!exclusive) {
4485		result = isc_task_beginexclusive(server->task);
4486		RUNTIME_CHECK(result == ISC_R_SUCCESS);
4487		exclusive = ISC_TRUE;
4488	}
4489
4490	/*
4491	 * Set process limits, which (usually) needs to be done as root.
4492	 */
4493	set_limits(maps);
4494
4495	/*
4496	 * Check if max number of open sockets that the system allows is
4497	 * sufficiently large.	Failing this condition is not necessarily fatal,
4498	 * but may cause subsequent runtime failures for a busy recursive
4499	 * server.
4500	 */
4501	result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &maxsocks);
4502	if (result != ISC_R_SUCCESS)
4503		maxsocks = 0;
4504	result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles);
4505	if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) {
4506		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4507			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
4508			      "max open files (%" ISC_PRINT_QUADFORMAT "u)"
4509			      " is smaller than max sockets (%u)",
4510			      nfiles, maxsocks);
4511	}
4512
4513	/*
4514	 * Set the number of socket reserved for TCP, stdio etc.
4515	 */
4516	obj = NULL;
4517	result = ns_config_get(maps, "reserved-sockets", &obj);
4518	INSIST(result == ISC_R_SUCCESS);
4519	reserved = cfg_obj_asuint32(obj);
4520	if (maxsocks != 0) {
4521		if (maxsocks < 128U)			/* Prevent underflow. */
4522			reserved = 0;
4523		else if (reserved > maxsocks - 128U)	/* Minimum UDP space. */
4524			reserved = maxsocks - 128;
4525	}
4526	/* Minimum TCP/stdio space. */
4527	if (reserved < 128U)
4528		reserved = 128;
4529	if (reserved + 128U > maxsocks && maxsocks != 0) {
4530		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4531			      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
4532			      "less than 128 UDP sockets available after "
4533			      "applying 'reserved-sockets' and 'maxsockets'");
4534	}
4535	isc__socketmgr_setreserved(ns_g_socketmgr, reserved);
4536
4537	/*
4538	 * Configure various server options.
4539	 */
4540	configure_server_quota(maps, "transfers-out", &server->xfroutquota);
4541	configure_server_quota(maps, "tcp-clients", &server->tcpquota);
4542	configure_server_quota(maps, "recursive-clients",
4543			       &server->recursionquota);
4544	if (server->recursionquota.max > 1000)
4545		isc_quota_soft(&server->recursionquota,
4546			       server->recursionquota.max - 100);
4547	else
4548		isc_quota_soft(&server->recursionquota, 0);
4549
4550	CHECK(configure_view_acl(NULL, config, "blackhole", NULL,
4551				 ns_g_aclconfctx, ns_g_mctx,
4552				 &server->blackholeacl));
4553	if (server->blackholeacl != NULL)
4554		dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
4555					     server->blackholeacl);
4556
4557	obj = NULL;
4558	result = ns_config_get(maps, "match-mapped-addresses", &obj);
4559	INSIST(result == ISC_R_SUCCESS);
4560	server->aclenv.match_mapped = cfg_obj_asboolean(obj);
4561
4562	CHECKM(ns_statschannels_configure(ns_g_server, config, ns_g_aclconfctx),
4563	       "configuring statistics server(s)");
4564
4565	/*
4566	 * Configure sets of UDP query source ports.
4567	 */
4568	CHECKM(isc_portset_create(ns_g_mctx, &v4portset),
4569	       "creating UDP port set");
4570	CHECKM(isc_portset_create(ns_g_mctx, &v6portset),
4571	       "creating UDP port set");
4572
4573	usev4ports = NULL;
4574	usev6ports = NULL;
4575	avoidv4ports = NULL;
4576	avoidv6ports = NULL;
4577
4578	(void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports);
4579	if (usev4ports != NULL)
4580		portset_fromconf(v4portset, usev4ports, ISC_TRUE);
4581	else {
4582		CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
4583					       &udpport_high),
4584		       "get the default UDP/IPv4 port range");
4585		if (udpport_low == udpport_high)
4586			isc_portset_add(v4portset, udpport_low);
4587		else {
4588			isc_portset_addrange(v4portset, udpport_low,
4589					     udpport_high);
4590		}
4591		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4592			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4593			      "using default UDP/IPv4 port range: [%d, %d]",
4594			      udpport_low, udpport_high);
4595	}
4596	(void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
4597	if (avoidv4ports != NULL)
4598		portset_fromconf(v4portset, avoidv4ports, ISC_FALSE);
4599
4600	(void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports);
4601	if (usev6ports != NULL)
4602		portset_fromconf(v6portset, usev6ports, ISC_TRUE);
4603	else {
4604		CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
4605					       &udpport_high),
4606		       "get the default UDP/IPv6 port range");
4607		if (udpport_low == udpport_high)
4608			isc_portset_add(v6portset, udpport_low);
4609		else {
4610			isc_portset_addrange(v6portset, udpport_low,
4611					     udpport_high);
4612		}
4613		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4614			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4615			      "using default UDP/IPv6 port range: [%d, %d]",
4616			      udpport_low, udpport_high);
4617	}
4618	(void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
4619	if (avoidv6ports != NULL)
4620		portset_fromconf(v6portset, avoidv6ports, ISC_FALSE);
4621
4622	dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset);
4623
4624	/*
4625	 * Set the EDNS UDP size when we don't match a view.
4626	 */
4627	obj = NULL;
4628	result = ns_config_get(maps, "edns-udp-size", &obj);
4629	INSIST(result == ISC_R_SUCCESS);
4630	udpsize = cfg_obj_asuint32(obj);
4631	if (udpsize < 512)
4632		udpsize = 512;
4633	if (udpsize > 4096)
4634		udpsize = 4096;
4635	ns_g_udpsize = (isc_uint16_t)udpsize;
4636
4637	/*
4638	 * Configure the zone manager.
4639	 */
4640	obj = NULL;
4641	result = ns_config_get(maps, "transfers-in", &obj);
4642	INSIST(result == ISC_R_SUCCESS);
4643	dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
4644
4645	obj = NULL;
4646	result = ns_config_get(maps, "transfers-per-ns", &obj);
4647	INSIST(result == ISC_R_SUCCESS);
4648	dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
4649
4650	obj = NULL;
4651	result = ns_config_get(maps, "serial-query-rate", &obj);
4652	INSIST(result == ISC_R_SUCCESS);
4653	dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
4654
4655	/*
4656	 * Determine which port to use for listening for incoming connections.
4657	 */
4658	if (ns_g_port != 0)
4659		listen_port = ns_g_port;
4660	else
4661		CHECKM(ns_config_getport(config, &listen_port), "port");
4662
4663	/*
4664	 * Find the listen queue depth.
4665	 */
4666	obj = NULL;
4667	result = ns_config_get(maps, "tcp-listen-queue", &obj);
4668	INSIST(result == ISC_R_SUCCESS);
4669	ns_g_listen = cfg_obj_asuint32(obj);
4670	if (ns_g_listen < 3)
4671		ns_g_listen = 3;
4672
4673	/*
4674	 * Configure the interface manager according to the "listen-on"
4675	 * statement.
4676	 */
4677	{
4678		const cfg_obj_t *clistenon = NULL;
4679		ns_listenlist_t *listenon = NULL;
4680
4681		clistenon = NULL;
4682		/*
4683		 * Even though listen-on is present in the default
4684		 * configuration, we can't use it here, since it isn't
4685		 * used if we're in lwresd mode.  This way is easier.
4686		 */
4687		if (options != NULL)
4688			(void)cfg_map_get(options, "listen-on", &clistenon);
4689		if (clistenon != NULL) {
4690			/* check return code? */
4691			(void)ns_listenlist_fromconfig(clistenon, config,
4692						       ns_g_aclconfctx,
4693						       ns_g_mctx, &listenon);
4694		} else if (!ns_g_lwresdonly) {
4695			/*
4696			 * Not specified, use default.
4697			 */
4698			CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
4699						    ISC_TRUE, &listenon));
4700		}
4701		if (listenon != NULL) {
4702			ns_interfacemgr_setlistenon4(server->interfacemgr,
4703						     listenon);
4704			ns_listenlist_detach(&listenon);
4705		}
4706	}
4707	/*
4708	 * Ditto for IPv6.
4709	 */
4710	{
4711		const cfg_obj_t *clistenon = NULL;
4712		ns_listenlist_t *listenon = NULL;
4713
4714		if (options != NULL)
4715			(void)cfg_map_get(options, "listen-on-v6", &clistenon);
4716		if (clistenon != NULL) {
4717			/* check return code? */
4718			(void)ns_listenlist_fromconfig(clistenon, config,
4719						       ns_g_aclconfctx,
4720						       ns_g_mctx, &listenon);
4721		} else if (!ns_g_lwresdonly) {
4722			isc_boolean_t enable;
4723			/*
4724			 * Not specified, use default.
4725			 */
4726			enable = ISC_TF(isc_net_probeipv4() != ISC_R_SUCCESS);
4727			CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
4728						    enable, &listenon));
4729		}
4730		if (listenon != NULL) {
4731			ns_interfacemgr_setlistenon6(server->interfacemgr,
4732						     listenon);
4733			ns_listenlist_detach(&listenon);
4734		}
4735	}
4736
4737	/*
4738	 * Rescan the interface list to pick up changes in the
4739	 * listen-on option.  It's important that we do this before we try
4740	 * to configure the query source, since the dispatcher we use might
4741	 * be shared with an interface.
4742	 */
4743	scan_interfaces(server, ISC_TRUE);
4744
4745	/*
4746	 * Arrange for further interface scanning to occur periodically
4747	 * as specified by the "interface-interval" option.
4748	 */
4749	obj = NULL;
4750	result = ns_config_get(maps, "interface-interval", &obj);
4751	INSIST(result == ISC_R_SUCCESS);
4752	interface_interval = cfg_obj_asuint32(obj) * 60;
4753	if (interface_interval == 0) {
4754		CHECK(isc_timer_reset(server->interface_timer,
4755				      isc_timertype_inactive,
4756				      NULL, NULL, ISC_TRUE));
4757	} else if (server->interface_interval != interface_interval) {
4758		isc_interval_set(&interval, interface_interval, 0);
4759		CHECK(isc_timer_reset(server->interface_timer,
4760				      isc_timertype_ticker,
4761				      NULL, &interval, ISC_FALSE));
4762	}
4763	server->interface_interval = interface_interval;
4764
4765	/*
4766	 * Configure the dialup heartbeat timer.
4767	 */
4768	obj = NULL;
4769	result = ns_config_get(maps, "heartbeat-interval", &obj);
4770	INSIST(result == ISC_R_SUCCESS);
4771	heartbeat_interval = cfg_obj_asuint32(obj) * 60;
4772	if (heartbeat_interval == 0) {
4773		CHECK(isc_timer_reset(server->heartbeat_timer,
4774				      isc_timertype_inactive,
4775				      NULL, NULL, ISC_TRUE));
4776	} else if (server->heartbeat_interval != heartbeat_interval) {
4777		isc_interval_set(&interval, heartbeat_interval, 0);
4778		CHECK(isc_timer_reset(server->heartbeat_timer,
4779				      isc_timertype_ticker,
4780				      NULL, &interval, ISC_FALSE));
4781	}
4782	server->heartbeat_interval = heartbeat_interval;
4783
4784	isc_interval_set(&interval, 1200, 0);
4785	CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
4786			      &interval, ISC_FALSE));
4787
4788	/*
4789	 * Write the PID file.
4790	 */
4791	obj = NULL;
4792	if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS)
4793		if (cfg_obj_isvoid(obj))
4794			ns_os_writepidfile(NULL, first_time);
4795		else
4796			ns_os_writepidfile(cfg_obj_asstring(obj), first_time);
4797	else if (ns_g_lwresdonly)
4798		ns_os_writepidfile(lwresd_g_defaultpidfile, first_time);
4799	else
4800		ns_os_writepidfile(ns_g_defaultpidfile, first_time);
4801
4802	/*
4803	 * Configure the server-wide session key.  This must be done before
4804	 * configure views because zone configuration may need to know
4805	 * session-keyname.
4806	 *
4807	 * Failure of session key generation isn't fatal at this time; if it
4808	 * turns out that a session key is really needed but doesn't exist,
4809	 * we'll treat it as a fatal error then.
4810	 */
4811	(void)configure_session_key(maps, server, ns_g_mctx);
4812
4813	views = NULL;
4814	(void)cfg_map_get(config, "view", &views);
4815
4816	/*
4817	 * Create the views and count all the configured zones in
4818	 * order to correctly size the zone manager's task table.
4819	 * (We only count zones for configured views; the built-in
4820	 * "bind" view can be ignored as it only adds a negligible
4821	 * number of zones.)
4822	 *
4823	 * If we're allowing new zones, we need to be able to find the
4824	 * new zone file and count those as well.  So we setup the new
4825	 * zone configuration context, but otherwise view configuration
4826	 * waits until after the zone manager's task list has been sized.
4827	 */
4828	for (element = cfg_list_first(views);
4829	     element != NULL;
4830	     element = cfg_list_next(element))
4831	{
4832		cfg_obj_t *vconfig = cfg_listelt_value(element);
4833		const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
4834		view = NULL;
4835
4836		CHECK(create_view(vconfig, &viewlist, &view));
4837		INSIST(view != NULL);
4838
4839		num_zones += count_zones(voptions);
4840		CHECK(setup_newzones(view, config, vconfig, conf_parser,
4841				     ns_g_aclconfctx));
4842
4843		nzctx = view->new_zone_config;
4844		if (nzctx != NULL && nzctx->nzconfig != NULL)
4845			num_zones += count_zones(nzctx->nzconfig);
4846
4847		dns_view_detach(&view);
4848	}
4849
4850	/*
4851	 * If there were no explicit views then we do the default
4852	 * view here.
4853	 */
4854	if (views == NULL) {
4855		CHECK(create_view(NULL, &viewlist, &view));
4856		INSIST(view != NULL);
4857
4858		num_zones = count_zones(config);
4859
4860		CHECK(setup_newzones(view, config, NULL,  conf_parser,
4861				     ns_g_aclconfctx));
4862
4863		nzctx = view->new_zone_config;
4864		if (nzctx != NULL && nzctx->nzconfig != NULL)
4865			num_zones += count_zones(nzctx->nzconfig);
4866
4867		dns_view_detach(&view);
4868	}
4869
4870	/*
4871	 * Zones have been counted; set the zone manager task pool size.
4872	 */
4873	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4874		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4875		      "sizing zone task pool based on %d zones", num_zones);
4876	CHECK(dns_zonemgr_setsize(ns_g_server->zonemgr, num_zones));
4877
4878	/*
4879	 * Configure and freeze all explicit views.  Explicit
4880	 * views that have zones were already created at parsing
4881	 * time, but views with no zones must be created here.
4882	 */
4883	for (element = cfg_list_first(views);
4884	     element != NULL;
4885	     element = cfg_list_next(element))
4886	{
4887		cfg_obj_t *vconfig = cfg_listelt_value(element);
4888
4889		view = NULL;
4890		CHECK(find_view(vconfig, &viewlist, &view));
4891		CHECK(configure_view(view, config, vconfig,
4892				     &cachelist, bindkeys, ns_g_mctx,
4893				     ns_g_aclconfctx, ISC_TRUE));
4894		dns_view_freeze(view);
4895		dns_view_detach(&view);
4896	}
4897
4898	/*
4899	 * Make sure we have a default view if and only if there
4900	 * were no explicit views.
4901	 */
4902	if (views == NULL) {
4903		view = NULL;
4904		CHECK(find_view(NULL, &viewlist, &view));
4905		CHECK(configure_view(view, config, NULL,
4906				     &cachelist, bindkeys,
4907				     ns_g_mctx, ns_g_aclconfctx, ISC_TRUE));
4908		dns_view_freeze(view);
4909		dns_view_detach(&view);
4910	}
4911
4912	/*
4913	 * Create (or recreate) the built-in views.
4914	 */
4915	builtin_views = NULL;
4916	RUNTIME_CHECK(cfg_map_get(ns_g_config, "view",
4917				  &builtin_views) == ISC_R_SUCCESS);
4918	for (element = cfg_list_first(builtin_views);
4919	     element != NULL;
4920	     element = cfg_list_next(element))
4921	{
4922		cfg_obj_t *vconfig = cfg_listelt_value(element);
4923
4924		CHECK(create_view(vconfig, &builtin_viewlist, &view));
4925		CHECK(configure_view(view, config, vconfig,
4926				     &cachelist, bindkeys,
4927				     ns_g_mctx, ns_g_aclconfctx, ISC_FALSE));
4928		dns_view_freeze(view);
4929		dns_view_detach(&view);
4930		view = NULL;
4931	}
4932
4933	/* Now combine the two viewlists into one */
4934	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
4935
4936	/* Swap our new view list with the production one. */
4937	tmpviewlist = server->viewlist;
4938	server->viewlist = viewlist;
4939	viewlist = tmpviewlist;
4940
4941	/* Make the view list available to each of the views */
4942	view = ISC_LIST_HEAD(server->viewlist);
4943	while (view != NULL) {
4944		view->viewlist = &server->viewlist;
4945		view = ISC_LIST_NEXT(view, link);
4946	}
4947
4948	/* Swap our new cache list with the production one. */
4949	tmpcachelist = server->cachelist;
4950	server->cachelist = cachelist;
4951	cachelist = tmpcachelist;
4952
4953	/* Load the TKEY information from the configuration. */
4954	if (options != NULL) {
4955		dns_tkeyctx_t *t = NULL;
4956		CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy,
4957					     &t),
4958		       "configuring TKEY");
4959		if (server->tkeyctx != NULL)
4960			dns_tkeyctx_destroy(&server->tkeyctx);
4961		server->tkeyctx = t;
4962	}
4963
4964	/*
4965	 * Bind the control port(s).
4966	 */
4967	CHECKM(ns_controls_configure(ns_g_server->controls, config,
4968				     ns_g_aclconfctx),
4969	       "binding control channel(s)");
4970
4971	/*
4972	 * Bind the lwresd port(s).
4973	 */
4974	CHECKM(ns_lwresd_configure(ns_g_mctx, config),
4975	       "binding lightweight resolver ports");
4976
4977	/*
4978	 * Open the source of entropy.
4979	 */
4980	if (first_time) {
4981		obj = NULL;
4982		result = ns_config_get(maps, "random-device", &obj);
4983		if (result != ISC_R_SUCCESS) {
4984			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4985				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4986				      "no source of entropy found");
4987		} else {
4988			const char *randomdev = cfg_obj_asstring(obj);
4989			result = isc_entropy_createfilesource(ns_g_entropy,
4990							      randomdev);
4991			if (result != ISC_R_SUCCESS)
4992				isc_log_write(ns_g_lctx,
4993					      NS_LOGCATEGORY_GENERAL,
4994					      NS_LOGMODULE_SERVER,
4995					      ISC_LOG_INFO,
4996					      "could not open entropy source "
4997					      "%s: %s",
4998					      randomdev,
4999					      isc_result_totext(result));
5000#ifdef PATH_RANDOMDEV
5001			if (ns_g_fallbackentropy != NULL) {
5002				if (result != ISC_R_SUCCESS) {
5003					isc_log_write(ns_g_lctx,
5004						      NS_LOGCATEGORY_GENERAL,
5005						      NS_LOGMODULE_SERVER,
5006						      ISC_LOG_INFO,
5007						      "using pre-chroot entropy source "
5008						      "%s",
5009						      PATH_RANDOMDEV);
5010					isc_entropy_detach(&ns_g_entropy);
5011					isc_entropy_attach(ns_g_fallbackentropy,
5012							   &ns_g_entropy);
5013				}
5014				isc_entropy_detach(&ns_g_fallbackentropy);
5015			}
5016#endif
5017		}
5018	}
5019
5020	/*
5021	 * Relinquish root privileges.
5022	 */
5023	if (first_time)
5024		ns_os_changeuser();
5025
5026#if 0
5027	/*
5028	 * Check that the working directory is writable.
5029	 */
5030	if (access(".", W_OK) != 0) {
5031		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5032			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5033			      "the working directory is not writable");
5034	}
5035#endif
5036
5037	/*
5038	 * Configure the logging system.
5039	 *
5040	 * Do this after changing UID to make sure that any log
5041	 * files specified in named.conf get created by the
5042	 * unprivileged user, not root.
5043	 */
5044	if (ns_g_logstderr) {
5045		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5046			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5047			      "ignoring config file logging "
5048			      "statement due to -g option");
5049	} else {
5050		const cfg_obj_t *logobj = NULL;
5051		isc_logconfig_t *logc = NULL;
5052
5053		CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
5054		       "creating new logging configuration");
5055
5056		logobj = NULL;
5057		(void)cfg_map_get(config, "logging", &logobj);
5058		if (logobj != NULL) {
5059			CHECKM(ns_log_configure(logc, logobj),
5060			       "configuring logging");
5061		} else {
5062			CHECKM(ns_log_setdefaultchannels(logc),
5063			       "setting up default logging channels");
5064			CHECKM(ns_log_setunmatchedcategory(logc),
5065			       "setting up default 'category unmatched'");
5066			CHECKM(ns_log_setdefaultcategory(logc),
5067			       "setting up default 'category default'");
5068		}
5069
5070		result = isc_logconfig_use(ns_g_lctx, logc);
5071		if (result != ISC_R_SUCCESS) {
5072			isc_logconfig_destroy(&logc);
5073			CHECKM(result, "installing logging configuration");
5074		}
5075
5076		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5077			      NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
5078			      "now using logging configuration from "
5079			      "config file");
5080	}
5081
5082	/*
5083	 * Set the default value of the query logging flag depending
5084	 * whether a "queries" category has been defined.  This is
5085	 * a disgusting hack, but we need to do this for BIND 8
5086	 * compatibility.
5087	 */
5088	if (first_time) {
5089		const cfg_obj_t *logobj = NULL;
5090		const cfg_obj_t *categories = NULL;
5091
5092		obj = NULL;
5093		if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
5094			server->log_queries = cfg_obj_asboolean(obj);
5095		} else {
5096
5097			(void)cfg_map_get(config, "logging", &logobj);
5098			if (logobj != NULL)
5099				(void)cfg_map_get(logobj, "category",
5100						  &categories);
5101			if (categories != NULL) {
5102				const cfg_listelt_t *element;
5103				for (element = cfg_list_first(categories);
5104				     element != NULL;
5105				     element = cfg_list_next(element))
5106				{
5107					const cfg_obj_t *catobj;
5108					const char *str;
5109
5110					obj = cfg_listelt_value(element);
5111					catobj = cfg_tuple_get(obj, "name");
5112					str = cfg_obj_asstring(catobj);
5113					if (strcasecmp(str, "queries") == 0)
5114						server->log_queries = ISC_TRUE;
5115				}
5116			}
5117		}
5118	}
5119
5120
5121	obj = NULL;
5122	if (options != NULL &&
5123	    cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
5124		ns_g_memstatistics = cfg_obj_asboolean(obj);
5125	else
5126		ns_g_memstatistics =
5127			ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
5128
5129	obj = NULL;
5130	if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
5131		ns_main_setmemstats(cfg_obj_asstring(obj));
5132	else if (ns_g_memstatistics)
5133		ns_main_setmemstats("named.memstats");
5134	else
5135		ns_main_setmemstats(NULL);
5136
5137	obj = NULL;
5138	result = ns_config_get(maps, "statistics-file", &obj);
5139	INSIST(result == ISC_R_SUCCESS);
5140	CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
5141	       "strdup");
5142
5143	obj = NULL;
5144	result = ns_config_get(maps, "dump-file", &obj);
5145	INSIST(result == ISC_R_SUCCESS);
5146	CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
5147	       "strdup");
5148
5149	obj = NULL;
5150	result = ns_config_get(maps, "secroots-file", &obj);
5151	INSIST(result == ISC_R_SUCCESS);
5152	CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)),
5153	       "strdup");
5154
5155	obj = NULL;
5156	result = ns_config_get(maps, "recursing-file", &obj);
5157	INSIST(result == ISC_R_SUCCESS);
5158	CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
5159	       "strdup");
5160
5161	obj = NULL;
5162	result = ns_config_get(maps, "version", &obj);
5163	if (result == ISC_R_SUCCESS) {
5164		CHECKM(setoptstring(server, &server->version, obj), "strdup");
5165		server->version_set = ISC_TRUE;
5166	} else {
5167		server->version_set = ISC_FALSE;
5168	}
5169
5170	obj = NULL;
5171	result = ns_config_get(maps, "hostname", &obj);
5172	if (result == ISC_R_SUCCESS) {
5173		CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
5174		server->hostname_set = ISC_TRUE;
5175	} else {
5176		server->hostname_set = ISC_FALSE;
5177	}
5178
5179	obj = NULL;
5180	result = ns_config_get(maps, "server-id", &obj);
5181	server->server_usehostname = ISC_FALSE;
5182	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
5183		/* The parser translates "hostname" to ISC_TRUE */
5184		server->server_usehostname = cfg_obj_asboolean(obj);
5185		result = setstring(server, &server->server_id, NULL);
5186		RUNTIME_CHECK(result == ISC_R_SUCCESS);
5187	} else if (result == ISC_R_SUCCESS) {
5188		/* Found a quoted string */
5189		CHECKM(setoptstring(server, &server->server_id, obj), "strdup");
5190	} else {
5191		result = setstring(server, &server->server_id, NULL);
5192		RUNTIME_CHECK(result == ISC_R_SUCCESS);
5193	}
5194
5195	obj = NULL;
5196	result = ns_config_get(maps, "flush-zones-on-shutdown", &obj);
5197	if (result == ISC_R_SUCCESS) {
5198		server->flushonshutdown = cfg_obj_asboolean(obj);
5199	} else {
5200		server->flushonshutdown = ISC_FALSE;
5201	}
5202
5203	result = ISC_R_SUCCESS;
5204
5205 cleanup:
5206	if (v4portset != NULL)
5207		isc_portset_destroy(ns_g_mctx, &v4portset);
5208
5209	if (v6portset != NULL)
5210		isc_portset_destroy(ns_g_mctx, &v6portset);
5211
5212	if (conf_parser != NULL) {
5213		if (config != NULL)
5214			cfg_obj_destroy(conf_parser, &config);
5215		cfg_parser_destroy(&conf_parser);
5216	}
5217
5218	if (bindkeys_parser != NULL) {
5219		if (bindkeys  != NULL)
5220			cfg_obj_destroy(bindkeys_parser, &bindkeys);
5221		cfg_parser_destroy(&bindkeys_parser);
5222	}
5223
5224	if (view != NULL)
5225		dns_view_detach(&view);
5226
5227	/*
5228	 * This cleans up either the old production view list
5229	 * or our temporary list depending on whether they
5230	 * were swapped above or not.
5231	 */
5232	for (view = ISC_LIST_HEAD(viewlist);
5233	     view != NULL;
5234	     view = view_next) {
5235		view_next = ISC_LIST_NEXT(view, link);
5236		ISC_LIST_UNLINK(viewlist, view, link);
5237		if (result == ISC_R_SUCCESS &&
5238		    strcmp(view->name, "_bind") != 0)
5239			(void)dns_zt_apply(view->zonetable, ISC_FALSE,
5240					   removed, view);
5241		dns_view_detach(&view);
5242	}
5243
5244	/* Same cleanup for cache list. */
5245	while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
5246		ISC_LIST_UNLINK(cachelist, nsc, link);
5247		dns_cache_detach(&nsc->cache);
5248		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
5249	}
5250
5251	/*
5252	 * Adjust the listening interfaces in accordance with the source
5253	 * addresses specified in views and zones.
5254	 */
5255	if (isc_net_probeipv6() == ISC_R_SUCCESS)
5256		adjust_interfaces(server, ns_g_mctx);
5257
5258	/* Relinquish exclusive access to configuration data. */
5259	if (exclusive)
5260		isc_task_endexclusive(server->task);
5261
5262	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5263		      ISC_LOG_DEBUG(1), "load_configuration: %s",
5264		      isc_result_totext(result));
5265
5266	return (result);
5267}
5268
5269static isc_result_t
5270view_loaded(void *arg) {
5271	isc_result_t result;
5272	ns_zoneload_t *zl = (ns_zoneload_t *) arg;
5273	ns_server_t *server = zl->server;
5274	unsigned int refs;
5275
5276
5277	/*
5278	 * Force zone maintenance.  Do this after loading
5279	 * so that we know when we need to force AXFR of
5280	 * slave zones whose master files are missing.
5281	 *
5282	 * We use the zoneload reference counter to let us
5283	 * know when all views are finished.
5284	 */
5285	isc_refcount_decrement(&zl->refs, &refs);
5286	if (refs != 0)
5287		return (ISC_R_SUCCESS);
5288
5289	isc_refcount_destroy(&zl->refs);
5290	isc_mem_put(server->mctx, zl, sizeof (*zl));
5291
5292	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5293		      ISC_LOG_NOTICE, "all zones loaded");
5294	CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
5295		   "forcing zone maintenance");
5296
5297	ns_os_started();
5298	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5299		      ISC_LOG_NOTICE, "running");
5300
5301	return (ISC_R_SUCCESS);
5302}
5303
5304static isc_result_t
5305load_zones(ns_server_t *server) {
5306	isc_result_t result;
5307	dns_view_t *view;
5308	ns_zoneload_t *zl;
5309	unsigned int refs = 0;
5310
5311	zl = isc_mem_get(server->mctx, sizeof (*zl));
5312	if (zl == NULL)
5313		return (ISC_R_NOMEMORY);
5314	zl->server = server;
5315
5316	result = isc_task_beginexclusive(server->task);
5317	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5318
5319	isc_refcount_init(&zl->refs, 1);
5320
5321	/*
5322	 * Schedule zones to be loaded from disk.
5323	 */
5324	for (view = ISC_LIST_HEAD(server->viewlist);
5325	     view != NULL;
5326	     view = ISC_LIST_NEXT(view, link))
5327	{
5328		if (view->managed_keys != NULL) {
5329			result = dns_zone_load(view->managed_keys);
5330			if (result != ISC_R_SUCCESS && result != DNS_R_UPTODATE)
5331				goto cleanup;
5332		}
5333		if (view->redirect != NULL) {
5334			result = dns_zone_load(view->redirect);
5335			if (result != ISC_R_SUCCESS && result != DNS_R_UPTODATE)
5336				goto cleanup;
5337		}
5338
5339		/*
5340		 * 'dns_view_asyncload' calls view_loaded if there are no
5341		 * zones.
5342		 */
5343		isc_refcount_increment(&zl->refs, NULL);
5344		CHECK(dns_view_asyncload(view, view_loaded, zl));
5345	}
5346
5347 cleanup:
5348	isc_refcount_decrement(&zl->refs, &refs);
5349	if (refs == 0) {
5350		isc_refcount_destroy(&zl->refs);
5351		isc_mem_put(server->mctx, zl, sizeof (*zl));
5352	} else {
5353		/*
5354		 * Place the task manager into privileged mode.  This
5355		 * ensures that after we leave task-exclusive mode, no
5356		 * other tasks will be able to run except for the ones
5357		 * that are loading zones.
5358		 */
5359		isc_taskmgr_setmode(ns_g_taskmgr, isc_taskmgrmode_privileged);
5360	}
5361
5362	isc_task_endexclusive(server->task);
5363	return (result);
5364}
5365
5366static isc_result_t
5367load_new_zones(ns_server_t *server, isc_boolean_t stop) {
5368	isc_result_t result;
5369	dns_view_t *view;
5370
5371	result = isc_task_beginexclusive(server->task);
5372	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5373
5374	/*
5375	 * Load zone data from disk.
5376	 */
5377	for (view = ISC_LIST_HEAD(server->viewlist);
5378	     view != NULL;
5379	     view = ISC_LIST_NEXT(view, link))
5380	{
5381		CHECK(dns_view_loadnew(view, stop));
5382
5383		/* Load managed-keys data */
5384		if (view->managed_keys != NULL)
5385			CHECK(dns_zone_loadnew(view->managed_keys));
5386		if (view->redirect != NULL)
5387			CHECK(dns_zone_loadnew(view->redirect));
5388	}
5389
5390	/*
5391	 * Resume zone XFRs.
5392	 */
5393	dns_zonemgr_resumexfrs(server->zonemgr);
5394 cleanup:
5395	isc_task_endexclusive(server->task);
5396	return (result);
5397}
5398
5399static void
5400run_server(isc_task_t *task, isc_event_t *event) {
5401	isc_result_t result;
5402	ns_server_t *server = (ns_server_t *)event->ev_arg;
5403
5404	INSIST(task == server->task);
5405
5406	isc_event_free(&event);
5407
5408	CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy,
5409					  &ns_g_dispatchmgr),
5410		   "creating dispatch manager");
5411
5412	dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats);
5413
5414	CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
5415					  ns_g_socketmgr, ns_g_dispatchmgr,
5416					  &server->interfacemgr),
5417		   "creating interface manager");
5418
5419	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
5420				    NULL, NULL, server->task,
5421				    interface_timer_tick,
5422				    server, &server->interface_timer),
5423		   "creating interface timer");
5424
5425	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
5426				    NULL, NULL, server->task,
5427				    heartbeat_timer_tick,
5428				    server, &server->heartbeat_timer),
5429		   "creating heartbeat timer");
5430
5431	CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
5432				    NULL, NULL, server->task, pps_timer_tick,
5433				    server, &server->pps_timer),
5434		   "creating pps timer");
5435
5436	CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser),
5437		   "creating default configuration parser");
5438
5439	if (ns_g_lwresdonly)
5440		CHECKFATAL(load_configuration(lwresd_g_conffile, server,
5441					      ISC_TRUE),
5442			   "loading configuration");
5443	else
5444		CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE),
5445			   "loading configuration");
5446
5447	isc_hash_init();
5448
5449	CHECKFATAL(load_zones(server), "loading zones");
5450}
5451
5452void
5453ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) {
5454
5455	REQUIRE(NS_SERVER_VALID(server));
5456
5457	server->flushonshutdown = flush;
5458}
5459
5460static void
5461shutdown_server(isc_task_t *task, isc_event_t *event) {
5462	isc_result_t result;
5463	dns_view_t *view, *view_next;
5464	ns_server_t *server = (ns_server_t *)event->ev_arg;
5465	isc_boolean_t flush = server->flushonshutdown;
5466	ns_cache_t *nsc;
5467
5468	UNUSED(task);
5469	INSIST(task == server->task);
5470
5471	result = isc_task_beginexclusive(server->task);
5472	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5473
5474	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5475		      ISC_LOG_INFO, "shutting down%s",
5476		      flush ? ": flushing changes" : "");
5477
5478	ns_statschannels_shutdown(server);
5479	ns_controls_shutdown(server->controls);
5480	end_reserved_dispatches(server, ISC_TRUE);
5481	cleanup_session_key(server, server->mctx);
5482
5483	if (ns_g_aclconfctx != NULL)
5484		cfg_aclconfctx_detach(&ns_g_aclconfctx);
5485
5486	cfg_obj_destroy(ns_g_parser, &ns_g_config);
5487	cfg_parser_destroy(&ns_g_parser);
5488
5489	for (view = ISC_LIST_HEAD(server->viewlist);
5490	     view != NULL;
5491	     view = view_next) {
5492		view_next = ISC_LIST_NEXT(view, link);
5493		ISC_LIST_UNLINK(server->viewlist, view, link);
5494		if (flush)
5495			dns_view_flushanddetach(&view);
5496		else
5497			dns_view_detach(&view);
5498	}
5499
5500	while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
5501		ISC_LIST_UNLINK(server->cachelist, nsc, link);
5502		dns_cache_detach(&nsc->cache);
5503		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
5504	}
5505
5506	isc_timer_detach(&server->interface_timer);
5507	isc_timer_detach(&server->heartbeat_timer);
5508	isc_timer_detach(&server->pps_timer);
5509
5510	ns_interfacemgr_shutdown(server->interfacemgr);
5511	ns_interfacemgr_detach(&server->interfacemgr);
5512
5513	dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
5514
5515	dns_zonemgr_shutdown(server->zonemgr);
5516
5517	if (ns_g_sessionkey != NULL) {
5518		dns_tsigkey_detach(&ns_g_sessionkey);
5519		dns_name_free(&ns_g_sessionkeyname, server->mctx);
5520	}
5521
5522	if (server->blackholeacl != NULL)
5523		dns_acl_detach(&server->blackholeacl);
5524
5525	dns_db_detach(&server->in_roothints);
5526
5527	isc_task_endexclusive(server->task);
5528
5529	isc_task_detach(&server->task);
5530
5531	isc_event_free(&event);
5532}
5533
5534void
5535ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
5536	isc_result_t result;
5537	ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
5538
5539	if (server == NULL)
5540		fatal("allocating server object", ISC_R_NOMEMORY);
5541
5542	server->mctx = mctx;
5543	server->task = NULL;
5544
5545	/* Initialize configuration data with default values. */
5546
5547	result = isc_quota_init(&server->xfroutquota, 10);
5548	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5549	result = isc_quota_init(&server->tcpquota, 10);
5550	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5551	result = isc_quota_init(&server->recursionquota, 100);
5552	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5553
5554	result = dns_aclenv_init(mctx, &server->aclenv);
5555	RUNTIME_CHECK(result == ISC_R_SUCCESS);
5556
5557	/* Initialize server data structures. */
5558	server->zonemgr = NULL;
5559	server->interfacemgr = NULL;
5560	ISC_LIST_INIT(server->viewlist);
5561	server->in_roothints = NULL;
5562	server->blackholeacl = NULL;
5563
5564	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
5565				     &server->in_roothints),
5566		   "setting up root hints");
5567
5568	CHECKFATAL(isc_mutex_init(&server->reload_event_lock),
5569		   "initializing reload event lock");
5570	server->reload_event =
5571		isc_event_allocate(ns_g_mctx, server,
5572				   NS_EVENT_RELOAD,
5573				   ns_server_reload,
5574				   server,
5575				   sizeof(isc_event_t));
5576	CHECKFATAL(server->reload_event == NULL ?
5577		   ISC_R_NOMEMORY : ISC_R_SUCCESS,
5578		   "allocating reload event");
5579
5580	CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy,
5581				 ns_g_engine, ISC_ENTROPY_GOODONLY),
5582		   "initializing DST");
5583
5584	server->tkeyctx = NULL;
5585	CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
5586				      &server->tkeyctx),
5587		   "creating TKEY context");
5588
5589	/*
5590	 * Setup the server task, which is responsible for coordinating
5591	 * startup and shutdown of the server, as well as all exclusive
5592	 * tasks.
5593	 */
5594	CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task),
5595		   "creating server task");
5596	isc_task_setname(server->task, "server", server);
5597	isc_taskmgr_setexcltask(ns_g_taskmgr, server->task);
5598	CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
5599		   "isc_task_onshutdown");
5600	CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
5601		   "isc_app_onrun");
5602
5603	server->interface_timer = NULL;
5604	server->heartbeat_timer = NULL;
5605	server->pps_timer = NULL;
5606
5607	server->interface_interval = 0;
5608	server->heartbeat_interval = 0;
5609
5610	CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
5611				      ns_g_socketmgr, &server->zonemgr),
5612		   "dns_zonemgr_create");
5613	CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000),
5614		   "dns_zonemgr_setsize");
5615
5616	server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
5617	CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
5618		   "isc_mem_strdup");
5619	server->nsstats = NULL;
5620	server->rcvquerystats = NULL;
5621	server->opcodestats = NULL;
5622	server->zonestats = NULL;
5623	server->resolverstats = NULL;
5624	server->sockstats = NULL;
5625	CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
5626				    isc_sockstatscounter_max),
5627		   "isc_stats_create");
5628	isc_socketmgr_setstats(ns_g_socketmgr, server->sockstats);
5629
5630	server->bindkeysfile = isc_mem_strdup(server->mctx, "bind.keys");
5631	CHECKFATAL(server->bindkeysfile == NULL ? ISC_R_NOMEMORY :
5632						  ISC_R_SUCCESS,
5633		   "isc_mem_strdup");
5634
5635	server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
5636	CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
5637		   "isc_mem_strdup");
5638
5639	server->secrootsfile = isc_mem_strdup(server->mctx, "named.secroots");
5640	CHECKFATAL(server->secrootsfile == NULL ? ISC_R_NOMEMORY :
5641						  ISC_R_SUCCESS,
5642		   "isc_mem_strdup");
5643
5644	server->recfile = isc_mem_strdup(server->mctx, "named.recursing");
5645	CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
5646		   "isc_mem_strdup");
5647
5648	server->hostname_set = ISC_FALSE;
5649	server->hostname = NULL;
5650	server->version_set = ISC_FALSE;
5651	server->version = NULL;
5652	server->server_usehostname = ISC_FALSE;
5653	server->server_id = NULL;
5654
5655	CHECKFATAL(isc_stats_create(ns_g_mctx, &server->nsstats,
5656				    dns_nsstatscounter_max),
5657		   "dns_stats_create (server)");
5658
5659	CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx,
5660					     &server->rcvquerystats),
5661		   "dns_stats_create (rcvquery)");
5662
5663	CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats),
5664		   "dns_stats_create (opcode)");
5665
5666	CHECKFATAL(isc_stats_create(ns_g_mctx, &server->zonestats,
5667				    dns_zonestatscounter_max),
5668		   "dns_stats_create (zone)");
5669
5670	CHECKFATAL(isc_stats_create(ns_g_mctx, &server->resolverstats,
5671				    dns_resstatscounter_max),
5672		   "dns_stats_create (resolver)");
5673
5674	server->flushonshutdown = ISC_FALSE;
5675	server->log_queries = ISC_FALSE;
5676
5677	server->controls = NULL;
5678	CHECKFATAL(ns_controls_create(server, &server->controls),
5679		   "ns_controls_create");
5680	server->dispatchgen = 0;
5681	ISC_LIST_INIT(server->dispatches);
5682
5683	ISC_LIST_INIT(server->statschannels);
5684
5685	ISC_LIST_INIT(server->cachelist);
5686
5687	server->sessionkey = NULL;
5688	server->session_keyfile = NULL;
5689	server->session_keyname = NULL;
5690	server->session_keyalg = DST_ALG_UNKNOWN;
5691	server->session_keybits = 0;
5692
5693	server->magic = NS_SERVER_MAGIC;
5694	*serverp = server;
5695}
5696
5697void
5698ns_server_destroy(ns_server_t **serverp) {
5699	ns_server_t *server = *serverp;
5700	REQUIRE(NS_SERVER_VALID(server));
5701
5702	ns_controls_destroy(&server->controls);
5703
5704	isc_stats_detach(&server->nsstats);
5705	dns_stats_detach(&server->rcvquerystats);
5706	dns_stats_detach(&server->opcodestats);
5707	isc_stats_detach(&server->zonestats);
5708	isc_stats_detach(&server->resolverstats);
5709	isc_stats_detach(&server->sockstats);
5710
5711	isc_mem_free(server->mctx, server->statsfile);
5712	isc_mem_free(server->mctx, server->bindkeysfile);
5713	isc_mem_free(server->mctx, server->dumpfile);
5714	isc_mem_free(server->mctx, server->secrootsfile);
5715	isc_mem_free(server->mctx, server->recfile);
5716
5717	if (server->version != NULL)
5718		isc_mem_free(server->mctx, server->version);
5719	if (server->hostname != NULL)
5720		isc_mem_free(server->mctx, server->hostname);
5721	if (server->server_id != NULL)
5722		isc_mem_free(server->mctx, server->server_id);
5723
5724	if (server->zonemgr != NULL)
5725		dns_zonemgr_detach(&server->zonemgr);
5726
5727	if (server->tkeyctx != NULL)
5728		dns_tkeyctx_destroy(&server->tkeyctx);
5729
5730	dst_lib_destroy();
5731
5732	isc_event_free(&server->reload_event);
5733
5734	INSIST(ISC_LIST_EMPTY(server->viewlist));
5735	INSIST(ISC_LIST_EMPTY(server->cachelist));
5736
5737	dns_aclenv_destroy(&server->aclenv);
5738
5739	isc_quota_destroy(&server->recursionquota);
5740	isc_quota_destroy(&server->tcpquota);
5741	isc_quota_destroy(&server->xfroutquota);
5742
5743	server->magic = 0;
5744	isc_mem_put(server->mctx, server, sizeof(*server));
5745	*serverp = NULL;
5746}
5747
5748static void
5749fatal(const char *msg, isc_result_t result) {
5750	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5751		      ISC_LOG_CRITICAL, "%s: %s", msg,
5752		      isc_result_totext(result));
5753	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5754		      ISC_LOG_CRITICAL, "exiting (due to fatal error)");
5755	exit(1);
5756}
5757
5758static void
5759start_reserved_dispatches(ns_server_t *server) {
5760
5761	REQUIRE(NS_SERVER_VALID(server));
5762
5763	server->dispatchgen++;
5764}
5765
5766static void
5767end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) {
5768	ns_dispatch_t *dispatch, *nextdispatch;
5769
5770	REQUIRE(NS_SERVER_VALID(server));
5771
5772	for (dispatch = ISC_LIST_HEAD(server->dispatches);
5773	     dispatch != NULL;
5774	     dispatch = nextdispatch) {
5775		nextdispatch = ISC_LIST_NEXT(dispatch, link);
5776		if (!all && server->dispatchgen == dispatch-> dispatchgen)
5777			continue;
5778		ISC_LIST_UNLINK(server->dispatches, dispatch, link);
5779		dns_dispatch_detach(&dispatch->dispatch);
5780		isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
5781	}
5782}
5783
5784void
5785ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) {
5786	ns_dispatch_t *dispatch;
5787	in_port_t port;
5788	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
5789	isc_result_t result;
5790	unsigned int attrs, attrmask;
5791
5792	REQUIRE(NS_SERVER_VALID(server));
5793
5794	port = isc_sockaddr_getport(addr);
5795	if (port == 0 || port >= 1024)
5796		return;
5797
5798	for (dispatch = ISC_LIST_HEAD(server->dispatches);
5799	     dispatch != NULL;
5800	     dispatch = ISC_LIST_NEXT(dispatch, link)) {
5801		if (isc_sockaddr_equal(&dispatch->addr, addr))
5802			break;
5803	}
5804	if (dispatch != NULL) {
5805		dispatch->dispatchgen = server->dispatchgen;
5806		return;
5807	}
5808
5809	dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
5810	if (dispatch == NULL) {
5811		result = ISC_R_NOMEMORY;
5812		goto cleanup;
5813	}
5814
5815	dispatch->addr = *addr;
5816	dispatch->dispatchgen = server->dispatchgen;
5817	dispatch->dispatch = NULL;
5818
5819	attrs = 0;
5820	attrs |= DNS_DISPATCHATTR_UDP;
5821	switch (isc_sockaddr_pf(addr)) {
5822	case AF_INET:
5823		attrs |= DNS_DISPATCHATTR_IPV4;
5824		break;
5825	case AF_INET6:
5826		attrs |= DNS_DISPATCHATTR_IPV6;
5827		break;
5828	default:
5829		result = ISC_R_NOTIMPLEMENTED;
5830		goto cleanup;
5831	}
5832	attrmask = 0;
5833	attrmask |= DNS_DISPATCHATTR_UDP;
5834	attrmask |= DNS_DISPATCHATTR_TCP;
5835	attrmask |= DNS_DISPATCHATTR_IPV4;
5836	attrmask |= DNS_DISPATCHATTR_IPV6;
5837
5838	result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
5839				     ns_g_taskmgr, &dispatch->addr, 4096,
5840				     1000, 32768, 16411, 16433,
5841				     attrs, attrmask, &dispatch->dispatch);
5842	if (result != ISC_R_SUCCESS)
5843		goto cleanup;
5844
5845	ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
5846
5847	return;
5848
5849 cleanup:
5850	if (dispatch != NULL)
5851		isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
5852	isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
5853	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5854		      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
5855		      "unable to create dispatch for reserved port %s: %s",
5856		      addrbuf, isc_result_totext(result));
5857}
5858
5859
5860static isc_result_t
5861loadconfig(ns_server_t *server) {
5862	isc_result_t result;
5863	start_reserved_dispatches(server);
5864	result = load_configuration(ns_g_lwresdonly ?
5865				    lwresd_g_conffile : ns_g_conffile,
5866				    server, ISC_FALSE);
5867	if (result == ISC_R_SUCCESS) {
5868		end_reserved_dispatches(server, ISC_FALSE);
5869		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5870			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5871			      "reloading configuration succeeded");
5872	} else {
5873		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5874			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5875			      "reloading configuration failed: %s",
5876			      isc_result_totext(result));
5877	}
5878	return (result);
5879}
5880
5881static isc_result_t
5882reload(ns_server_t *server) {
5883	isc_result_t result;
5884	CHECK(loadconfig(server));
5885
5886	result = load_zones(server);
5887	if (result == ISC_R_SUCCESS)
5888		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5889			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5890			      "reloading zones succeeded");
5891	else
5892		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5893			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5894			      "reloading zones failed: %s",
5895			      isc_result_totext(result));
5896
5897 cleanup:
5898	return (result);
5899}
5900
5901static void
5902reconfig(ns_server_t *server) {
5903	isc_result_t result;
5904	CHECK(loadconfig(server));
5905
5906	result = load_new_zones(server, ISC_FALSE);
5907	if (result == ISC_R_SUCCESS)
5908		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5909			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5910			      "any newly configured zones are now loaded");
5911	else
5912		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5913			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5914			      "loading new zones failed: %s",
5915			      isc_result_totext(result));
5916
5917 cleanup: ;
5918}
5919
5920/*
5921 * Handle a reload event (from SIGHUP).
5922 */
5923static void
5924ns_server_reload(isc_task_t *task, isc_event_t *event) {
5925	ns_server_t *server = (ns_server_t *)event->ev_arg;
5926
5927	INSIST(task = server->task);
5928	UNUSED(task);
5929
5930	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5931		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5932		      "received SIGHUP signal to reload zones");
5933	(void)reload(server);
5934
5935	LOCK(&server->reload_event_lock);
5936	INSIST(server->reload_event == NULL);
5937	server->reload_event = event;
5938	UNLOCK(&server->reload_event_lock);
5939}
5940
5941void
5942ns_server_reloadwanted(ns_server_t *server) {
5943	LOCK(&server->reload_event_lock);
5944	if (server->reload_event != NULL)
5945		isc_task_send(server->task, &server->reload_event);
5946	UNLOCK(&server->reload_event_lock);
5947}
5948
5949static char *
5950next_token(char **stringp, const char *delim) {
5951	char *res;
5952
5953	do {
5954		res = strsep(stringp, delim);
5955		if (res == NULL)
5956			break;
5957	} while (*res == '\0');
5958	return (res);
5959}
5960
5961/*
5962 * Find the zone specified in the control channel command 'args',
5963 * if any.  If a zone is specified, point '*zonep' at it, otherwise
5964 * set '*zonep' to NULL.
5965 */
5966static isc_result_t
5967zone_from_args(ns_server_t *server, char *args, const char *zonetxt,
5968	       dns_zone_t **zonep, const char **zonename, isc_boolean_t skip)
5969{
5970	char *input, *ptr;
5971	char *classtxt;
5972	const char *viewtxt = NULL;
5973	dns_fixedname_t name;
5974	isc_result_t result;
5975	isc_buffer_t buf;
5976	dns_view_t *view = NULL;
5977	dns_rdataclass_t rdclass;
5978
5979	REQUIRE(zonep != NULL && *zonep == NULL);
5980
5981	input = args;
5982
5983	if (skip) {
5984		/* Skip the command name. */
5985		ptr = next_token(&input, " \t");
5986		if (ptr == NULL)
5987			return (ISC_R_UNEXPECTEDEND);
5988	}
5989
5990	/* Look for the zone name. */
5991	if (zonetxt == NULL)
5992		zonetxt = next_token(&input, " \t");
5993	if (zonetxt == NULL)
5994		return (ISC_R_SUCCESS);
5995	if (zonename)
5996		*zonename = zonetxt;
5997
5998	/* Look for the optional class name. */
5999	classtxt = next_token(&input, " \t");
6000	if (classtxt != NULL) {
6001		/* Look for the optional view name. */
6002		viewtxt = next_token(&input, " \t");
6003	}
6004
6005	isc_buffer_init(&buf, zonetxt, strlen(zonetxt));
6006	isc_buffer_add(&buf, strlen(zonetxt));
6007	dns_fixedname_init(&name);
6008	result = dns_name_fromtext(dns_fixedname_name(&name),
6009				   &buf, dns_rootname, 0, NULL);
6010	if (result != ISC_R_SUCCESS)
6011		goto fail1;
6012
6013	if (classtxt != NULL) {
6014		isc_textregion_t r;
6015		r.base = classtxt;
6016		r.length = strlen(classtxt);
6017		result = dns_rdataclass_fromtext(&rdclass, &r);
6018		if (result != ISC_R_SUCCESS)
6019			goto fail1;
6020	} else
6021		rdclass = dns_rdataclass_in;
6022
6023	if (viewtxt == NULL) {
6024		result = dns_viewlist_findzone(&server->viewlist,
6025					       dns_fixedname_name(&name),
6026					       ISC_TF(classtxt == NULL),
6027					       rdclass, zonep);
6028	} else {
6029		result = dns_viewlist_find(&server->viewlist, viewtxt,
6030					   rdclass, &view);
6031		if (result != ISC_R_SUCCESS)
6032			goto fail1;
6033
6034		result = dns_zt_find(view->zonetable, dns_fixedname_name(&name),
6035				     0, NULL, zonep);
6036		dns_view_detach(&view);
6037	}
6038
6039	/* Partial match? */
6040	if (result != ISC_R_SUCCESS && *zonep != NULL)
6041		dns_zone_detach(zonep);
6042	if (result == DNS_R_PARTIALMATCH)
6043		result = ISC_R_NOTFOUND;
6044 fail1:
6045	return (result);
6046}
6047
6048/*
6049 * Act on a "retransfer" command from the command channel.
6050 */
6051isc_result_t
6052ns_server_retransfercommand(ns_server_t *server, char *args) {
6053	isc_result_t result;
6054	dns_zone_t *zone = NULL;
6055	dns_zone_t *raw = NULL;
6056	dns_zonetype_t type;
6057
6058	result = zone_from_args(server, args, NULL, &zone, NULL, ISC_TRUE);
6059	if (result != ISC_R_SUCCESS)
6060		return (result);
6061	if (zone == NULL)
6062		return (ISC_R_UNEXPECTEDEND);
6063	dns_zone_getraw(zone, &raw);
6064	if (raw != NULL) {
6065		dns_zone_detach(&zone);
6066		dns_zone_attach(raw, &zone);
6067		dns_zone_detach(&raw);
6068	}
6069	type = dns_zone_gettype(zone);
6070	if (type == dns_zone_slave || type == dns_zone_stub)
6071		dns_zone_forcereload(zone);
6072	else
6073		result = ISC_R_NOTFOUND;
6074	dns_zone_detach(&zone);
6075	return (result);
6076}
6077
6078/*
6079 * Act on a "reload" command from the command channel.
6080 */
6081isc_result_t
6082ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
6083	isc_result_t result;
6084	dns_zone_t *zone = NULL;
6085	dns_zonetype_t type;
6086	const char *msg = NULL;
6087
6088	result = zone_from_args(server, args, NULL, &zone, NULL, ISC_TRUE);
6089	if (result != ISC_R_SUCCESS)
6090		return (result);
6091	if (zone == NULL) {
6092		result = reload(server);
6093		if (result == ISC_R_SUCCESS)
6094			msg = "server reload successful";
6095	} else {
6096		type = dns_zone_gettype(zone);
6097		if (type == dns_zone_slave || type == dns_zone_stub) {
6098			dns_zone_refresh(zone);
6099			dns_zone_detach(&zone);
6100			msg = "zone refresh queued";
6101		} else {
6102			result = dns_zone_load(zone);
6103			dns_zone_detach(&zone);
6104			switch (result) {
6105			case ISC_R_SUCCESS:
6106				 msg = "zone reload successful";
6107				 break;
6108			case DNS_R_CONTINUE:
6109				msg = "zone reload queued";
6110				result = ISC_R_SUCCESS;
6111				break;
6112			case DNS_R_UPTODATE:
6113				msg = "zone reload up-to-date";
6114				result = ISC_R_SUCCESS;
6115				break;
6116			default:
6117				/* failure message will be generated by rndc */
6118				break;
6119			}
6120		}
6121	}
6122	if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
6123		isc_buffer_putmem(text, (const unsigned char *)msg,
6124				  strlen(msg) + 1);
6125	return (result);
6126}
6127
6128/*
6129 * Act on a "reconfig" command from the command channel.
6130 */
6131isc_result_t
6132ns_server_reconfigcommand(ns_server_t *server, char *args) {
6133	UNUSED(args);
6134
6135	reconfig(server);
6136	return (ISC_R_SUCCESS);
6137}
6138
6139/*
6140 * Act on a "notify" command from the command channel.
6141 */
6142isc_result_t
6143ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) {
6144	isc_result_t result;
6145	dns_zone_t *zone = NULL;
6146	const unsigned char msg[] = "zone notify queued";
6147
6148	result = zone_from_args(server, args, NULL, &zone, NULL, ISC_TRUE);
6149	if (result != ISC_R_SUCCESS)
6150		return (result);
6151	if (zone == NULL)
6152		return (ISC_R_UNEXPECTEDEND);
6153
6154	dns_zone_notify(zone);
6155	dns_zone_detach(&zone);
6156	if (sizeof(msg) <= isc_buffer_availablelength(text))
6157		isc_buffer_putmem(text, msg, sizeof(msg));
6158
6159	return (ISC_R_SUCCESS);
6160}
6161
6162/*
6163 * Act on a "refresh" command from the command channel.
6164 */
6165isc_result_t
6166ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
6167	isc_result_t result;
6168	dns_zone_t *zone = NULL;
6169	const unsigned char msg1[] = "zone refresh queued";
6170	const unsigned char msg2[] = "not a slave or stub zone";
6171	dns_zonetype_t type;
6172
6173	result = zone_from_args(server, args, NULL, &zone, NULL, ISC_TRUE);
6174	if (result != ISC_R_SUCCESS)
6175		return (result);
6176	if (zone == NULL)
6177		return (ISC_R_UNEXPECTEDEND);
6178
6179	type = dns_zone_gettype(zone);
6180	if (type == dns_zone_slave || type == dns_zone_stub) {
6181		dns_zone_refresh(zone);
6182		dns_zone_detach(&zone);
6183		if (sizeof(msg1) <= isc_buffer_availablelength(text))
6184			isc_buffer_putmem(text, msg1, sizeof(msg1));
6185		return (ISC_R_SUCCESS);
6186	}
6187
6188	dns_zone_detach(&zone);
6189	if (sizeof(msg2) <= isc_buffer_availablelength(text))
6190		isc_buffer_putmem(text, msg2, sizeof(msg2));
6191	return (ISC_R_FAILURE);
6192}
6193
6194isc_result_t
6195ns_server_togglequerylog(ns_server_t *server, char *args) {
6196	isc_boolean_t value;
6197	char *ptr;
6198
6199	/* Skip the command name. */
6200	ptr = next_token(&args, " \t");
6201	if (ptr == NULL)
6202		return (ISC_R_UNEXPECTEDEND);
6203
6204	ptr = next_token(&args, " \t");
6205	if (ptr == NULL)
6206		value = server->log_queries ? ISC_FALSE : ISC_TRUE;
6207	else if (strcasecmp(ptr, "yes") == 0 || strcasecmp(ptr, "on") == 0)
6208		value = ISC_TRUE;
6209	else if (strcasecmp(ptr, "no") == 0 || strcasecmp(ptr, "off") == 0)
6210		value = ISC_FALSE;
6211	else
6212		return (ISC_R_NOTFOUND);
6213
6214	if (server->log_queries == value)
6215		return (ISC_R_SUCCESS);
6216
6217	server->log_queries = value;
6218
6219	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6220		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6221		      "query logging is now %s",
6222		      server->log_queries ? "on" : "off");
6223	return (ISC_R_SUCCESS);
6224}
6225
6226static isc_result_t
6227ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
6228			 cfg_aclconfctx_t *actx,
6229			 isc_mem_t *mctx, ns_listenlist_t **target)
6230{
6231	isc_result_t result;
6232	const cfg_listelt_t *element;
6233	ns_listenlist_t *dlist = NULL;
6234
6235	REQUIRE(target != NULL && *target == NULL);
6236
6237	result = ns_listenlist_create(mctx, &dlist);
6238	if (result != ISC_R_SUCCESS)
6239		return (result);
6240
6241	for (element = cfg_list_first(listenlist);
6242	     element != NULL;
6243	     element = cfg_list_next(element))
6244	{
6245		ns_listenelt_t *delt = NULL;
6246		const cfg_obj_t *listener = cfg_listelt_value(element);
6247		result = ns_listenelt_fromconfig(listener, config, actx,
6248						 mctx, &delt);
6249		if (result != ISC_R_SUCCESS)
6250			goto cleanup;
6251		ISC_LIST_APPEND(dlist->elts, delt, link);
6252	}
6253	*target = dlist;
6254	return (ISC_R_SUCCESS);
6255
6256 cleanup:
6257	ns_listenlist_detach(&dlist);
6258	return (result);
6259}
6260
6261/*
6262 * Create a listen list from the corresponding configuration
6263 * data structure.
6264 */
6265static isc_result_t
6266ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
6267			cfg_aclconfctx_t *actx,
6268			isc_mem_t *mctx, ns_listenelt_t **target)
6269{
6270	isc_result_t result;
6271	const cfg_obj_t *portobj;
6272	in_port_t port;
6273	ns_listenelt_t *delt = NULL;
6274	REQUIRE(target != NULL && *target == NULL);
6275
6276	portobj = cfg_tuple_get(listener, "port");
6277	if (!cfg_obj_isuint32(portobj)) {
6278		if (ns_g_port != 0) {
6279			port = ns_g_port;
6280		} else {
6281			result = ns_config_getport(config, &port);
6282			if (result != ISC_R_SUCCESS)
6283				return (result);
6284		}
6285	} else {
6286		if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
6287			cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
6288				    "port value '%u' is out of range",
6289				    cfg_obj_asuint32(portobj));
6290			return (ISC_R_RANGE);
6291		}
6292		port = (in_port_t)cfg_obj_asuint32(portobj);
6293	}
6294
6295	result = ns_listenelt_create(mctx, port, NULL, &delt);
6296	if (result != ISC_R_SUCCESS)
6297		return (result);
6298
6299	result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"),
6300				   config, ns_g_lctx, actx, mctx, 0,
6301				   &delt->acl);
6302	if (result != ISC_R_SUCCESS) {
6303		ns_listenelt_destroy(delt);
6304		return (result);
6305	}
6306	*target = delt;
6307	return (ISC_R_SUCCESS);
6308}
6309
6310isc_result_t
6311ns_server_dumpstats(ns_server_t *server) {
6312	isc_result_t result;
6313	FILE *fp = NULL;
6314
6315	CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
6316		"could not open statistics dump file", server->statsfile);
6317
6318	result = ns_stats_dump(server, fp);
6319
6320 cleanup:
6321	if (fp != NULL)
6322		(void)isc_stdio_close(fp);
6323	if (result == ISC_R_SUCCESS)
6324		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6325			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6326			      "dumpstats complete");
6327	else
6328		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6329			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6330			      "dumpstats failed: %s",
6331			      dns_result_totext(result));
6332	return (result);
6333}
6334
6335static isc_result_t
6336add_zone_tolist(dns_zone_t *zone, void *uap) {
6337	struct dumpcontext *dctx = uap;
6338	struct zonelistentry *zle;
6339
6340	zle = isc_mem_get(dctx->mctx, sizeof *zle);
6341	if (zle ==  NULL)
6342		return (ISC_R_NOMEMORY);
6343	zle->zone = NULL;
6344	dns_zone_attach(zone, &zle->zone);
6345	ISC_LINK_INIT(zle, link);
6346	ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
6347	return (ISC_R_SUCCESS);
6348}
6349
6350static isc_result_t
6351add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
6352	struct viewlistentry *vle;
6353	isc_result_t result = ISC_R_SUCCESS;
6354
6355	/*
6356	 * Prevent duplicate views.
6357	 */
6358	for (vle = ISC_LIST_HEAD(dctx->viewlist);
6359	     vle != NULL;
6360	     vle = ISC_LIST_NEXT(vle, link))
6361		if (vle->view == view)
6362			return (ISC_R_SUCCESS);
6363
6364	vle = isc_mem_get(dctx->mctx, sizeof *vle);
6365	if (vle == NULL)
6366		return (ISC_R_NOMEMORY);
6367	vle->view = NULL;
6368	dns_view_attach(view, &vle->view);
6369	ISC_LINK_INIT(vle, link);
6370	ISC_LIST_INIT(vle->zonelist);
6371	ISC_LIST_APPEND(dctx->viewlist, vle, link);
6372	if (dctx->dumpzones)
6373		result = dns_zt_apply(view->zonetable, ISC_TRUE,
6374				      add_zone_tolist, dctx);
6375	return (result);
6376}
6377
6378static void
6379dumpcontext_destroy(struct dumpcontext *dctx) {
6380	struct viewlistentry *vle;
6381	struct zonelistentry *zle;
6382
6383	vle = ISC_LIST_HEAD(dctx->viewlist);
6384	while (vle != NULL) {
6385		ISC_LIST_UNLINK(dctx->viewlist, vle, link);
6386		zle = ISC_LIST_HEAD(vle->zonelist);
6387		while (zle != NULL) {
6388			ISC_LIST_UNLINK(vle->zonelist, zle, link);
6389			dns_zone_detach(&zle->zone);
6390			isc_mem_put(dctx->mctx, zle, sizeof *zle);
6391			zle = ISC_LIST_HEAD(vle->zonelist);
6392		}
6393		dns_view_detach(&vle->view);
6394		isc_mem_put(dctx->mctx, vle, sizeof *vle);
6395		vle = ISC_LIST_HEAD(dctx->viewlist);
6396	}
6397	if (dctx->version != NULL)
6398		dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
6399	if (dctx->db != NULL)
6400		dns_db_detach(&dctx->db);
6401	if (dctx->cache != NULL)
6402		dns_db_detach(&dctx->cache);
6403	if (dctx->task != NULL)
6404		isc_task_detach(&dctx->task);
6405	if (dctx->fp != NULL)
6406		(void)isc_stdio_close(dctx->fp);
6407	if (dctx->mdctx != NULL)
6408		dns_dumpctx_detach(&dctx->mdctx);
6409	isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
6410}
6411
6412static void
6413dumpdone(void *arg, isc_result_t result) {
6414	struct dumpcontext *dctx = arg;
6415	char buf[1024+32];
6416	const dns_master_style_t *style;
6417
6418	if (result != ISC_R_SUCCESS)
6419		goto cleanup;
6420	if (dctx->mdctx != NULL)
6421		dns_dumpctx_detach(&dctx->mdctx);
6422	if (dctx->view == NULL) {
6423		dctx->view = ISC_LIST_HEAD(dctx->viewlist);
6424		if (dctx->view == NULL)
6425			goto done;
6426		INSIST(dctx->zone == NULL);
6427	} else
6428		goto resume;
6429 nextview:
6430	fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
6431 resume:
6432	if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
6433		fprintf(dctx->fp,
6434			";\n; Cache of view '%s' is shared as '%s'\n",
6435			dctx->view->view->name,
6436			dns_cache_getname(dctx->view->view->cache));
6437	} else if (dctx->zone == NULL && dctx->cache == NULL &&
6438		   dctx->dumpcache)
6439	{
6440		style = &dns_master_style_cache;
6441		/* start cache dump */
6442		if (dctx->view->view->cachedb != NULL)
6443			dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
6444		if (dctx->cache != NULL) {
6445			fprintf(dctx->fp,
6446				";\n; Cache dump of view '%s' (cache %s)\n;\n",
6447				dctx->view->view->name,
6448				dns_cache_getname(dctx->view->view->cache));
6449			result = dns_master_dumptostreaminc(dctx->mctx,
6450							    dctx->cache, NULL,
6451							    style, dctx->fp,
6452							    dctx->task,
6453							    dumpdone, dctx,
6454							    &dctx->mdctx);
6455			if (result == DNS_R_CONTINUE)
6456				return;
6457			if (result == ISC_R_NOTIMPLEMENTED)
6458				fprintf(dctx->fp, "; %s\n",
6459					dns_result_totext(result));
6460			else if (result != ISC_R_SUCCESS)
6461				goto cleanup;
6462		}
6463	}
6464	if (dctx->cache != NULL) {
6465		dns_adb_dump(dctx->view->view->adb, dctx->fp);
6466		dns_resolver_printbadcache(dctx->view->view->resolver,
6467					   dctx->fp);
6468		dns_db_detach(&dctx->cache);
6469	}
6470	if (dctx->dumpzones) {
6471		style = &dns_master_style_full;
6472 nextzone:
6473		if (dctx->version != NULL)
6474			dns_db_closeversion(dctx->db, &dctx->version,
6475					    ISC_FALSE);
6476		if (dctx->db != NULL)
6477			dns_db_detach(&dctx->db);
6478		if (dctx->zone == NULL)
6479			dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
6480		else
6481			dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
6482		if (dctx->zone != NULL) {
6483			/* start zone dump */
6484			dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
6485			fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
6486			result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
6487			if (result != ISC_R_SUCCESS) {
6488				fprintf(dctx->fp, "; %s\n",
6489					dns_result_totext(result));
6490				goto nextzone;
6491			}
6492			dns_db_currentversion(dctx->db, &dctx->version);
6493			result = dns_master_dumptostreaminc(dctx->mctx,
6494							    dctx->db,
6495							    dctx->version,
6496							    style, dctx->fp,
6497							    dctx->task,
6498							    dumpdone, dctx,
6499							    &dctx->mdctx);
6500			if (result == DNS_R_CONTINUE)
6501				return;
6502			if (result == ISC_R_NOTIMPLEMENTED) {
6503				fprintf(dctx->fp, "; %s\n",
6504					dns_result_totext(result));
6505				result = ISC_R_SUCCESS;
6506				POST(result);
6507				goto nextzone;
6508			}
6509			if (result != ISC_R_SUCCESS)
6510				goto cleanup;
6511		}
6512	}
6513	if (dctx->view != NULL)
6514		dctx->view = ISC_LIST_NEXT(dctx->view, link);
6515	if (dctx->view != NULL)
6516		goto nextview;
6517 done:
6518	fprintf(dctx->fp, "; Dump complete\n");
6519	result = isc_stdio_flush(dctx->fp);
6520	if (result == ISC_R_SUCCESS)
6521		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6522			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6523			      "dumpdb complete");
6524 cleanup:
6525	if (result != ISC_R_SUCCESS)
6526		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6527			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6528			      "dumpdb failed: %s", dns_result_totext(result));
6529	dumpcontext_destroy(dctx);
6530}
6531
6532isc_result_t
6533ns_server_dumpdb(ns_server_t *server, char *args) {
6534	struct dumpcontext *dctx = NULL;
6535	dns_view_t *view;
6536	isc_result_t result;
6537	char *ptr;
6538	const char *sep;
6539
6540	/* Skip the command name. */
6541	ptr = next_token(&args, " \t");
6542	if (ptr == NULL)
6543		return (ISC_R_UNEXPECTEDEND);
6544
6545	dctx = isc_mem_get(server->mctx, sizeof(*dctx));
6546	if (dctx == NULL)
6547		return (ISC_R_NOMEMORY);
6548
6549	dctx->mctx = server->mctx;
6550	dctx->dumpcache = ISC_TRUE;
6551	dctx->dumpzones = ISC_FALSE;
6552	dctx->fp = NULL;
6553	ISC_LIST_INIT(dctx->viewlist);
6554	dctx->view = NULL;
6555	dctx->zone = NULL;
6556	dctx->cache = NULL;
6557	dctx->mdctx = NULL;
6558	dctx->db = NULL;
6559	dctx->cache = NULL;
6560	dctx->task = NULL;
6561	dctx->version = NULL;
6562	isc_task_attach(server->task, &dctx->task);
6563
6564	CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
6565		"could not open dump file", server->dumpfile);
6566
6567	sep = (args == NULL) ? "" : ": ";
6568	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6569		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6570		      "dumpdb started%s%s", sep, (args != NULL) ? args : "");
6571
6572	ptr = next_token(&args, " \t");
6573	if (ptr != NULL && strcmp(ptr, "-all") == 0) {
6574		dctx->dumpzones = ISC_TRUE;
6575		dctx->dumpcache = ISC_TRUE;
6576		ptr = next_token(&args, " \t");
6577	} else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
6578		dctx->dumpzones = ISC_FALSE;
6579		dctx->dumpcache = ISC_TRUE;
6580		ptr = next_token(&args, " \t");
6581	} else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
6582		dctx->dumpzones = ISC_TRUE;
6583		dctx->dumpcache = ISC_FALSE;
6584		ptr = next_token(&args, " \t");
6585	}
6586
6587 nextview:
6588	for (view = ISC_LIST_HEAD(server->viewlist);
6589	     view != NULL;
6590	     view = ISC_LIST_NEXT(view, link))
6591	{
6592		if (ptr != NULL && strcmp(view->name, ptr) != 0)
6593			continue;
6594		CHECK(add_view_tolist(dctx, view));
6595	}
6596	if (ptr != NULL) {
6597		ptr = next_token(&args, " \t");
6598		if (ptr != NULL)
6599			goto nextview;
6600	}
6601	dumpdone(dctx, ISC_R_SUCCESS);
6602	return (ISC_R_SUCCESS);
6603
6604 cleanup:
6605	if (dctx != NULL)
6606		dumpcontext_destroy(dctx);
6607	return (result);
6608}
6609
6610isc_result_t
6611ns_server_dumpsecroots(ns_server_t *server, char *args) {
6612	dns_view_t *view;
6613	dns_keytable_t *secroots = NULL;
6614	isc_result_t result;
6615	char *ptr;
6616	FILE *fp = NULL;
6617	isc_time_t now;
6618	char tbuf[64];
6619
6620	/* Skip the command name. */
6621	ptr = next_token(&args, " \t");
6622	if (ptr == NULL)
6623		return (ISC_R_UNEXPECTEDEND);
6624
6625	ptr = next_token(&args, " \t");
6626
6627	CHECKMF(isc_stdio_open(server->secrootsfile, "w", &fp),
6628		"could not open secroots dump file", server->secrootsfile);
6629	TIME_NOW(&now);
6630	isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
6631	fprintf(fp, "%s\n", tbuf);
6632
6633	do {
6634		for (view = ISC_LIST_HEAD(server->viewlist);
6635		     view != NULL;
6636		     view = ISC_LIST_NEXT(view, link))
6637		{
6638			if (ptr != NULL && strcmp(view->name, ptr) != 0)
6639				continue;
6640			if (secroots != NULL)
6641				dns_keytable_detach(&secroots);
6642			result = dns_view_getsecroots(view, &secroots);
6643			if (result == ISC_R_NOTFOUND) {
6644				result = ISC_R_SUCCESS;
6645				continue;
6646			}
6647			fprintf(fp, "\n Start view %s\n\n", view->name);
6648			result = dns_keytable_dump(secroots, fp);
6649			if (result != ISC_R_SUCCESS)
6650				fprintf(fp, " dumpsecroots failed: %s\n",
6651					isc_result_totext(result));
6652		}
6653		if (ptr != NULL)
6654			ptr = next_token(&args, " \t");
6655	} while (ptr != NULL);
6656
6657 cleanup:
6658	if (secroots != NULL)
6659		dns_keytable_detach(&secroots);
6660	if (fp != NULL)
6661		(void)isc_stdio_close(fp);
6662	if (result == ISC_R_SUCCESS)
6663		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6664			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6665			      "dumpsecroots complete");
6666	else
6667		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6668			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6669			      "dumpsecroots failed: %s",
6670			      dns_result_totext(result));
6671	return (result);
6672}
6673
6674isc_result_t
6675ns_server_dumprecursing(ns_server_t *server) {
6676	FILE *fp = NULL;
6677	isc_result_t result;
6678
6679	CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
6680		"could not open dump file", server->recfile);
6681	fprintf(fp,";\n; Recursing Queries\n;\n");
6682	ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
6683	fprintf(fp, "; Dump complete\n");
6684
6685 cleanup:
6686	if (fp != NULL)
6687		result = isc_stdio_close(fp);
6688	if (result == ISC_R_SUCCESS)
6689		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6690			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6691			      "dumprecursing complete");
6692	else
6693		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6694			      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6695			      "dumprecursing failed: %s",
6696			      dns_result_totext(result));
6697	return (result);
6698}
6699
6700isc_result_t
6701ns_server_setdebuglevel(ns_server_t *server, char *args) {
6702	char *ptr;
6703	char *levelstr;
6704	char *endp;
6705	long newlevel;
6706
6707	UNUSED(server);
6708
6709	/* Skip the command name. */
6710	ptr = next_token(&args, " \t");
6711	if (ptr == NULL)
6712		return (ISC_R_UNEXPECTEDEND);
6713
6714	/* Look for the new level name. */
6715	levelstr = next_token(&args, " \t");
6716	if (levelstr == NULL) {
6717		if (ns_g_debuglevel < 99)
6718			ns_g_debuglevel++;
6719	} else {
6720		newlevel = strtol(levelstr, &endp, 10);
6721		if (*endp != '\0' || newlevel < 0 || newlevel > 99)
6722			return (ISC_R_RANGE);
6723		ns_g_debuglevel = (unsigned int)newlevel;
6724	}
6725	isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel);
6726	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6727		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6728		      "debug level is now %d", ns_g_debuglevel);
6729	return (ISC_R_SUCCESS);
6730}
6731
6732isc_result_t
6733ns_server_validation(ns_server_t *server, char *args) {
6734	char *ptr, *viewname;
6735	dns_view_t *view;
6736	isc_boolean_t changed = ISC_FALSE;
6737	isc_result_t result;
6738	isc_boolean_t enable;
6739
6740	/* Skip the command name. */
6741	ptr = next_token(&args, " \t");
6742	if (ptr == NULL)
6743		return (ISC_R_UNEXPECTEDEND);
6744
6745	/* Find out what we are to do. */
6746	ptr = next_token(&args, " \t");
6747	if (ptr == NULL)
6748		return (ISC_R_UNEXPECTEDEND);
6749
6750	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
6751	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
6752		enable = ISC_TRUE;
6753	else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
6754		 !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
6755		enable = ISC_FALSE;
6756	else
6757		return (DNS_R_SYNTAX);
6758
6759	/* Look for the view name. */
6760	viewname = next_token(&args, " \t");
6761
6762	result = isc_task_beginexclusive(server->task);
6763	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6764	for (view = ISC_LIST_HEAD(server->viewlist);
6765	     view != NULL;
6766	     view = ISC_LIST_NEXT(view, link))
6767	{
6768		if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
6769			continue;
6770		result = dns_view_flushcache(view);
6771		if (result != ISC_R_SUCCESS)
6772			goto out;
6773		view->enablevalidation = enable;
6774		changed = ISC_TRUE;
6775	}
6776	if (changed)
6777		result = ISC_R_SUCCESS;
6778	else
6779		result = ISC_R_FAILURE;
6780 out:
6781	isc_task_endexclusive(server->task);
6782	return (result);
6783}
6784
6785isc_result_t
6786ns_server_flushcache(ns_server_t *server, char *args) {
6787	char *ptr, *viewname;
6788	dns_view_t *view;
6789	isc_boolean_t flushed;
6790	isc_boolean_t found;
6791	isc_result_t result;
6792	ns_cache_t *nsc;
6793
6794	/* Skip the command name. */
6795	ptr = next_token(&args, " \t");
6796	if (ptr == NULL)
6797		return (ISC_R_UNEXPECTEDEND);
6798
6799	/* Look for the view name. */
6800	viewname = next_token(&args, " \t");
6801
6802	result = isc_task_beginexclusive(server->task);
6803	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6804	flushed = ISC_TRUE;
6805	found = ISC_FALSE;
6806
6807	/*
6808	 * Flushing a cache is tricky when caches are shared by multiple views.
6809	 * We first identify which caches should be flushed in the local cache
6810	 * list, flush these caches, and then update other views that refer to
6811	 * the flushed cache DB.
6812	 */
6813	if (viewname != NULL) {
6814		/*
6815		 * Mark caches that need to be flushed.  This is an O(#view^2)
6816		 * operation in the very worst case, but should be normally
6817		 * much more lightweight because only a few (most typically just
6818		 * one) views will match.
6819		 */
6820		for (view = ISC_LIST_HEAD(server->viewlist);
6821		     view != NULL;
6822		     view = ISC_LIST_NEXT(view, link))
6823		{
6824			if (strcasecmp(viewname, view->name) != 0)
6825				continue;
6826			found = ISC_TRUE;
6827			for (nsc = ISC_LIST_HEAD(server->cachelist);
6828			     nsc != NULL;
6829			     nsc = ISC_LIST_NEXT(nsc, link)) {
6830				if (nsc->cache == view->cache)
6831					break;
6832			}
6833			INSIST(nsc != NULL);
6834			nsc->needflush = ISC_TRUE;
6835		}
6836	} else
6837		found = ISC_TRUE;
6838
6839	/* Perform flush */
6840	for (nsc = ISC_LIST_HEAD(server->cachelist);
6841	     nsc != NULL;
6842	     nsc = ISC_LIST_NEXT(nsc, link)) {
6843		if (viewname != NULL && !nsc->needflush)
6844			continue;
6845		nsc->needflush = ISC_TRUE;
6846		result = dns_view_flushcache2(nsc->primaryview, ISC_FALSE);
6847		if (result != ISC_R_SUCCESS) {
6848			flushed = ISC_FALSE;
6849			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6850				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6851				      "flushing cache in view '%s' failed: %s",
6852				      nsc->primaryview->name,
6853				      isc_result_totext(result));
6854		}
6855	}
6856
6857	/*
6858	 * Fix up views that share a flushed cache: let the views update the
6859	 * cache DB they're referring to.  This could also be an expensive
6860	 * operation, but should typically be marginal: the inner loop is only
6861	 * necessary for views that share a cache, and if there are many such
6862	 * views the number of shared cache should normally be small.
6863	 * A worst case is that we have n views and n/2 caches, each shared by
6864	 * two views.  Then this will be a O(n^2/4) operation.
6865	 */
6866	for (view = ISC_LIST_HEAD(server->viewlist);
6867	     view != NULL;
6868	     view = ISC_LIST_NEXT(view, link))
6869	{
6870		if (!dns_view_iscacheshared(view))
6871			continue;
6872		for (nsc = ISC_LIST_HEAD(server->cachelist);
6873		     nsc != NULL;
6874		     nsc = ISC_LIST_NEXT(nsc, link)) {
6875			if (!nsc->needflush || nsc->cache != view->cache)
6876				continue;
6877			result = dns_view_flushcache2(view, ISC_TRUE);
6878			if (result != ISC_R_SUCCESS) {
6879				flushed = ISC_FALSE;
6880				isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6881					      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6882					      "fixing cache in view '%s' "
6883					      "failed: %s", view->name,
6884					      isc_result_totext(result));
6885			}
6886		}
6887	}
6888
6889	/* Cleanup the cache list. */
6890	for (nsc = ISC_LIST_HEAD(server->cachelist);
6891	     nsc != NULL;
6892	     nsc = ISC_LIST_NEXT(nsc, link)) {
6893		nsc->needflush = ISC_FALSE;
6894	}
6895
6896	if (flushed && found) {
6897		if (viewname != NULL)
6898			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6899				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6900				      "flushing cache in view '%s' succeeded",
6901				      viewname);
6902		else
6903			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6904				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6905				      "flushing caches in all views succeeded");
6906		result = ISC_R_SUCCESS;
6907	} else {
6908		if (!found) {
6909			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6910				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6911				      "flushing cache in view '%s' failed: "
6912				      "view not found", viewname);
6913			result = ISC_R_NOTFOUND;
6914		} else
6915			result = ISC_R_FAILURE;
6916	}
6917	isc_task_endexclusive(server->task);
6918	return (result);
6919}
6920
6921isc_result_t
6922ns_server_flushnode(ns_server_t *server, char *args, isc_boolean_t tree) {
6923	char *ptr, *target, *viewname;
6924	dns_view_t *view;
6925	isc_boolean_t flushed;
6926	isc_boolean_t found;
6927	isc_result_t result;
6928	isc_buffer_t b;
6929	dns_fixedname_t fixed;
6930	dns_name_t *name;
6931
6932	/* Skip the command name. */
6933	ptr = next_token(&args, " \t");
6934	if (ptr == NULL)
6935		return (ISC_R_UNEXPECTEDEND);
6936
6937	/* Find the domain name to flush. */
6938	target = next_token(&args, " \t");
6939	if (target == NULL)
6940		return (ISC_R_UNEXPECTEDEND);
6941
6942	isc_buffer_init(&b, target, strlen(target));
6943	isc_buffer_add(&b, strlen(target));
6944	dns_fixedname_init(&fixed);
6945	name = dns_fixedname_name(&fixed);
6946	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
6947	if (result != ISC_R_SUCCESS)
6948		return (result);
6949
6950	/* Look for the view name. */
6951	viewname = next_token(&args, " \t");
6952
6953	result = isc_task_beginexclusive(server->task);
6954	RUNTIME_CHECK(result == ISC_R_SUCCESS);
6955	flushed = ISC_TRUE;
6956	found = ISC_FALSE;
6957	for (view = ISC_LIST_HEAD(server->viewlist);
6958	     view != NULL;
6959	     view = ISC_LIST_NEXT(view, link))
6960	{
6961		if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
6962			continue;
6963		found = ISC_TRUE;
6964		/*
6965		 * It's a little inefficient to try flushing name for all views
6966		 * if some of the views share a single cache.  But since the
6967		 * operation is lightweight we prefer simplicity here.
6968		 */
6969		result = dns_view_flushnode(view, name, tree);
6970		if (result != ISC_R_SUCCESS) {
6971			flushed = ISC_FALSE;
6972			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6973				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6974				      "flushing %s '%s' in cache view '%s' "
6975				      "failed: %s",
6976				      tree ? "tree" : "name",
6977				      target, view->name,
6978				      isc_result_totext(result));
6979		}
6980	}
6981	if (flushed && found) {
6982		if (viewname != NULL)
6983			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6984				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6985				      "flushing %s '%s' in cache view '%s' "
6986				      "succeeded",
6987				      tree ? "tree" : "name",
6988				      target, viewname);
6989		else
6990			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6991				      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6992				      "flushing %s '%s' in all cache views "
6993				      "succeeded",
6994				      tree ? "tree" : "name",
6995				      target);
6996		result = ISC_R_SUCCESS;
6997	} else {
6998		if (!found)
6999			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7000				      NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7001				      "flushing %s '%s' in cache view '%s' "
7002				      "failed: view not found",
7003				      tree ? "tree" : "name",
7004				      target, viewname);
7005		result = ISC_R_FAILURE;
7006	}
7007	isc_task_endexclusive(server->task);
7008	return (result);
7009}
7010
7011isc_result_t
7012ns_server_status(ns_server_t *server, isc_buffer_t *text) {
7013	int zonecount, xferrunning, xferdeferred, soaqueries;
7014	unsigned int n;
7015	const char *ob = "", *cb = "", *alt = "";
7016
7017	if (ns_g_server->version_set) {
7018		ob = " (";
7019		cb = ")";
7020		if (ns_g_server->version == NULL)
7021			alt = "version.bind/txt/ch disabled";
7022		else
7023			alt = ns_g_server->version;
7024	}
7025	zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
7026	xferrunning = dns_zonemgr_getcount(server->zonemgr,
7027					   DNS_ZONESTATE_XFERRUNNING);
7028	xferdeferred = dns_zonemgr_getcount(server->zonemgr,
7029					    DNS_ZONESTATE_XFERDEFERRED);
7030	soaqueries = dns_zonemgr_getcount(server->zonemgr,
7031					  DNS_ZONESTATE_SOAQUERY);
7032
7033	n = snprintf((char *)isc_buffer_used(text),
7034		     isc_buffer_availablelength(text),
7035		     "version: %s%s%s%s\n"
7036#ifdef ISC_PLATFORM_USETHREADS
7037		     "CPUs found: %u\n"
7038		     "worker threads: %u\n"
7039		     "UDP listeners per interface: %u\n"
7040#endif
7041		     "number of zones: %u\n"
7042		     "debug level: %d\n"
7043		     "xfers running: %u\n"
7044		     "xfers deferred: %u\n"
7045		     "soa queries in progress: %u\n"
7046		     "query logging is %s\n"
7047		     "recursive clients: %d/%d/%d\n"
7048		     "tcp clients: %d/%d\n"
7049		     "server is up and running",
7050		     ns_g_version, ob, alt, cb,
7051#ifdef ISC_PLATFORM_USETHREADS
7052		     ns_g_cpus_detected, ns_g_cpus, ns_g_udpdisp,
7053#endif
7054		     zonecount, ns_g_debuglevel, xferrunning, xferdeferred,
7055		     soaqueries, server->log_queries ? "ON" : "OFF",
7056		     server->recursionquota.used, server->recursionquota.soft,
7057		     server->recursionquota.max,
7058		     server->tcpquota.used, server->tcpquota.max);
7059	if (n >= isc_buffer_availablelength(text))
7060		return (ISC_R_NOSPACE);
7061	isc_buffer_add(text, n);
7062	return (ISC_R_SUCCESS);
7063}
7064
7065static isc_result_t
7066delete_keynames(dns_tsig_keyring_t *ring, char *target,
7067		unsigned int *foundkeys)
7068{
7069	char namestr[DNS_NAME_FORMATSIZE];
7070	isc_result_t result;
7071	dns_rbtnodechain_t chain;
7072	dns_name_t foundname;
7073	dns_fixedname_t fixedorigin;
7074	dns_name_t *origin;
7075	dns_rbtnode_t *node;
7076	dns_tsigkey_t *tkey;
7077
7078	dns_name_init(&foundname, NULL);
7079	dns_fixedname_init(&fixedorigin);
7080	origin = dns_fixedname_name(&fixedorigin);
7081
7082 again:
7083	dns_rbtnodechain_init(&chain, ring->mctx);
7084	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
7085					origin);
7086	if (result == ISC_R_NOTFOUND) {
7087		dns_rbtnodechain_invalidate(&chain);
7088		return (ISC_R_SUCCESS);
7089	}
7090	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
7091		dns_rbtnodechain_invalidate(&chain);
7092		return (result);
7093	}
7094
7095	for (;;) {
7096		node = NULL;
7097		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
7098		tkey = node->data;
7099
7100		if (tkey != NULL) {
7101			if (!tkey->generated)
7102				goto nextkey;
7103
7104			dns_name_format(&tkey->name, namestr, sizeof(namestr));
7105			if (strcmp(namestr, target) == 0) {
7106				(*foundkeys)++;
7107				dns_rbtnodechain_invalidate(&chain);
7108				(void)dns_rbt_deletename(ring->keys,
7109							 &tkey->name,
7110							 ISC_FALSE);
7111				goto again;
7112			}
7113		}
7114
7115	nextkey:
7116		result = dns_rbtnodechain_next(&chain, &foundname, origin);
7117		if (result == ISC_R_NOMORE)
7118			break;
7119		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
7120			dns_rbtnodechain_invalidate(&chain);
7121			return (result);
7122		}
7123	}
7124
7125	return (ISC_R_SUCCESS);
7126}
7127
7128isc_result_t
7129ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text) {
7130	isc_result_t result;
7131	unsigned int n;
7132	dns_view_t *view;
7133	unsigned int foundkeys = 0;
7134	char *target;
7135	char *viewname;
7136
7137	(void)next_token(&command, " \t");  /* skip command name */
7138	target = next_token(&command, " \t");
7139	if (target == NULL)
7140		return (ISC_R_UNEXPECTEDEND);
7141	viewname = next_token(&command, " \t");
7142
7143	result = isc_task_beginexclusive(server->task);
7144	RUNTIME_CHECK(result == ISC_R_SUCCESS);
7145	for (view = ISC_LIST_HEAD(server->viewlist);
7146	     view != NULL;
7147	     view = ISC_LIST_NEXT(view, link)) {
7148		if (viewname == NULL || strcmp(view->name, viewname) == 0) {
7149			RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
7150			result = delete_keynames(view->dynamickeys, target,
7151						 &foundkeys);
7152			RWUNLOCK(&view->dynamickeys->lock,
7153				 isc_rwlocktype_write);
7154			if (result != ISC_R_SUCCESS) {
7155				isc_task_endexclusive(server->task);
7156				return (result);
7157			}
7158		}
7159	}
7160	isc_task_endexclusive(server->task);
7161
7162	n = snprintf((char *)isc_buffer_used(text),
7163		     isc_buffer_availablelength(text),
7164		     "%d tsig keys deleted.\n", foundkeys);
7165	if (n >= isc_buffer_availablelength(text))
7166		return (ISC_R_NOSPACE);
7167	isc_buffer_add(text, n);
7168
7169	return (ISC_R_SUCCESS);
7170}
7171
7172static isc_result_t
7173list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text,
7174	     unsigned int *foundkeys)
7175{
7176	char namestr[DNS_NAME_FORMATSIZE];
7177	char creatorstr[DNS_NAME_FORMATSIZE];
7178	isc_result_t result;
7179	dns_rbtnodechain_t chain;
7180	dns_name_t foundname;
7181	dns_fixedname_t fixedorigin;
7182	dns_name_t *origin;
7183	dns_rbtnode_t *node;
7184	dns_tsigkey_t *tkey;
7185	unsigned int n;
7186	const char *viewname;
7187
7188	if (view != NULL)
7189		viewname = view->name;
7190	else
7191		viewname = "(global)";
7192
7193	dns_name_init(&foundname, NULL);
7194	dns_fixedname_init(&fixedorigin);
7195	origin = dns_fixedname_name(&fixedorigin);
7196	dns_rbtnodechain_init(&chain, ring->mctx);
7197	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
7198					origin);
7199	if (result == ISC_R_NOTFOUND) {
7200		dns_rbtnodechain_invalidate(&chain);
7201		return (ISC_R_SUCCESS);
7202	}
7203	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
7204		dns_rbtnodechain_invalidate(&chain);
7205		return (result);
7206	}
7207
7208	for (;;) {
7209		node = NULL;
7210		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
7211		tkey = node->data;
7212
7213		if (tkey != NULL) {
7214			(*foundkeys)++;
7215			dns_name_format(&tkey->name, namestr, sizeof(namestr));
7216			if (tkey->generated) {
7217				dns_name_format(tkey->creator, creatorstr,
7218						sizeof(creatorstr));
7219				n = snprintf((char *)isc_buffer_used(text),
7220					     isc_buffer_availablelength(text),
7221					     "view \"%s\"; type \"dynamic\"; key \"%s\"; creator \"%s\";\n",
7222					     viewname, namestr, creatorstr);
7223			} else {
7224				n = snprintf((char *)isc_buffer_used(text),
7225					     isc_buffer_availablelength(text),
7226					     "view \"%s\"; type \"static\"; key \"%s\";\n",
7227					     viewname, namestr);
7228			}
7229			if (n >= isc_buffer_availablelength(text)) {
7230				dns_rbtnodechain_invalidate(&chain);
7231				return (ISC_R_NOSPACE);
7232			}
7233			isc_buffer_add(text, n);
7234		}
7235		result = dns_rbtnodechain_next(&chain, &foundname, origin);
7236		if (result == ISC_R_NOMORE)
7237			break;
7238		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
7239			dns_rbtnodechain_invalidate(&chain);
7240			return (result);
7241		}
7242	}
7243
7244	return (ISC_R_SUCCESS);
7245}
7246
7247isc_result_t
7248ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) {
7249	isc_result_t result;
7250	unsigned int n;
7251	dns_view_t *view;
7252	unsigned int foundkeys = 0;
7253
7254	result = isc_task_beginexclusive(server->task);
7255	RUNTIME_CHECK(result == ISC_R_SUCCESS);
7256	for (view = ISC_LIST_HEAD(server->viewlist);
7257	     view != NULL;
7258	     view = ISC_LIST_NEXT(view, link)) {
7259		RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
7260		result = list_keynames(view, view->statickeys, text,
7261				       &foundkeys);
7262		RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
7263		if (result != ISC_R_SUCCESS) {
7264			isc_task_endexclusive(server->task);
7265			return (result);
7266		}
7267		RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
7268		result = list_keynames(view, view->dynamickeys, text,
7269				       &foundkeys);
7270		RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
7271		if (result != ISC_R_SUCCESS) {
7272			isc_task_endexclusive(server->task);
7273			return (result);
7274		}
7275	}
7276	isc_task_endexclusive(server->task);
7277
7278	if (foundkeys == 0) {
7279		n = snprintf((char *)isc_buffer_used(text),
7280			     isc_buffer_availablelength(text),
7281			     "no tsig keys found.\n");
7282		if (n >= isc_buffer_availablelength(text))
7283			return (ISC_R_NOSPACE);
7284		isc_buffer_add(text, n);
7285	}
7286
7287	return (ISC_R_SUCCESS);
7288}
7289
7290/*
7291 * Act on a "sign" or "loadkeys" command from the command channel.
7292 */
7293isc_result_t
7294ns_server_rekey(ns_server_t *server, char *args) {
7295	isc_result_t result;
7296	dns_zone_t *zone = NULL;
7297	dns_zonetype_t type;
7298	isc_uint16_t keyopts;
7299	isc_boolean_t fullsign = ISC_FALSE;
7300
7301	if (strncasecmp(args, NS_COMMAND_SIGN, strlen(NS_COMMAND_SIGN)) == 0)
7302	    fullsign = ISC_TRUE;
7303
7304	result = zone_from_args(server, args, NULL, &zone, NULL, ISC_TRUE);
7305	if (result != ISC_R_SUCCESS)
7306		return (result);
7307	if (zone == NULL)
7308		return (ISC_R_UNEXPECTEDEND);   /* XXX: or do all zones? */
7309
7310	type = dns_zone_gettype(zone);
7311	if (type != dns_zone_master) {
7312		dns_zone_detach(&zone);
7313		return (DNS_R_NOTMASTER);
7314	}
7315
7316	keyopts = dns_zone_getkeyopts(zone);
7317
7318	/* "rndc loadkeys" requires "auto-dnssec maintain". */
7319	if ((keyopts & DNS_ZONEKEY_ALLOW) == 0)
7320		result = ISC_R_NOPERM;
7321	else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign)
7322		result = ISC_R_NOPERM;
7323	else
7324		dns_zone_rekey(zone, fullsign);
7325
7326	dns_zone_detach(&zone);
7327	return (result);
7328}
7329
7330/*
7331 * Act on a "sync" command from the command channel.
7332*/
7333static isc_result_t
7334synczone(dns_zone_t *zone, void *uap) {
7335	isc_boolean_t cleanup = *(isc_boolean_t *)uap;
7336	isc_result_t result;
7337	dns_zone_t *raw = NULL;
7338	char *journal;
7339
7340	dns_zone_getraw(zone, &raw);
7341	if (raw != NULL) {
7342		synczone(raw, uap);
7343		dns_zone_detach(&raw);
7344	}
7345
7346	result = dns_zone_flush(zone);
7347	if (result != ISC_R_SUCCESS)
7348		cleanup = ISC_FALSE;
7349	if (cleanup) {
7350		journal = dns_zone_getjournal(zone);
7351		if (journal != NULL)
7352			(void)isc_file_remove(journal);
7353	}
7354
7355	return (result);
7356}
7357
7358isc_result_t
7359ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text) {
7360	isc_result_t result, tresult;
7361	dns_view_t *view;
7362	dns_zone_t *zone = NULL;
7363	char classstr[DNS_RDATACLASS_FORMATSIZE];
7364	char zonename[DNS_NAME_FORMATSIZE];
7365	const char *vname, *sep, *msg = NULL, *arg;
7366	isc_boolean_t cleanup = ISC_FALSE;
7367
7368	(void) next_token(&args, " \t");
7369
7370	arg = next_token(&args, " \t");
7371	if (arg != NULL &&
7372	    (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0)) {
7373		cleanup = ISC_TRUE;
7374		arg = next_token(&args, " \t");
7375	}
7376
7377	result = zone_from_args(server, args, arg, &zone, NULL, ISC_FALSE);
7378	if (result != ISC_R_SUCCESS)
7379		return (result);
7380
7381	if (zone == NULL) {
7382		result = isc_task_beginexclusive(server->task);
7383		RUNTIME_CHECK(result == ISC_R_SUCCESS);
7384		tresult = ISC_R_SUCCESS;
7385		for (view = ISC_LIST_HEAD(server->viewlist);
7386		     view != NULL;
7387		     view = ISC_LIST_NEXT(view, link)) {
7388			result = dns_zt_apply(view->zonetable, ISC_FALSE,
7389					      synczone, &cleanup);
7390			if (result != ISC_R_SUCCESS &&
7391			    tresult == ISC_R_SUCCESS)
7392				tresult = result;
7393		}
7394		isc_task_endexclusive(server->task);
7395		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7396			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7397			      "dumping all zones%s: %s",
7398			      cleanup ? ", removing journal files" : "",
7399			      isc_result_totext(result));
7400		return (tresult);
7401	}
7402
7403	result = isc_task_beginexclusive(server->task);
7404	RUNTIME_CHECK(result == ISC_R_SUCCESS);
7405	result = synczone(zone, &cleanup);
7406	isc_task_endexclusive(server->task);
7407
7408	if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
7409		isc_buffer_putmem(text, (const unsigned char *)msg,
7410				  strlen(msg) + 1);
7411
7412	view = dns_zone_getview(zone);
7413	if (strcmp(view->name, "_default") == 0 ||
7414	    strcmp(view->name, "_bind") == 0)
7415	{
7416		vname = "";
7417		sep = "";
7418	} else {
7419		vname = view->name;
7420		sep = " ";
7421	}
7422	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
7423			      sizeof(classstr));
7424	dns_name_format(dns_zone_getorigin(zone),
7425			zonename, sizeof(zonename));
7426	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7427		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7428		      "sync: dumping zone '%s/%s'%s%s%s: %s",
7429		      zonename, classstr, sep, vname,
7430		      cleanup ? ", removing journal file" : "",
7431		      isc_result_totext(result));
7432	dns_zone_detach(&zone);
7433	return (result);
7434}
7435
7436/*
7437 * Act on a "freeze" or "thaw" command from the command channel.
7438 */
7439isc_result_t
7440ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
7441		 isc_buffer_t *text)
7442{
7443	isc_result_t result, tresult;
7444	dns_zone_t *zone = NULL, *raw = NULL;
7445	dns_zonetype_t type;
7446	char classstr[DNS_RDATACLASS_FORMATSIZE];
7447	char zonename[DNS_NAME_FORMATSIZE];
7448	dns_view_t *view;
7449	const char *vname, *sep;
7450	isc_boolean_t frozen;
7451	const char *msg = NULL;
7452
7453	result = zone_from_args(server, args, NULL, &zone, NULL, ISC_TRUE);
7454	if (result != ISC_R_SUCCESS)
7455		return (result);
7456	if (zone == NULL) {
7457		result = isc_task_beginexclusive(server->task);
7458		RUNTIME_CHECK(result == ISC_R_SUCCESS);
7459		tresult = ISC_R_SUCCESS;
7460		for (view = ISC_LIST_HEAD(server->viewlist);
7461		     view != NULL;
7462		     view = ISC_LIST_NEXT(view, link)) {
7463			result = dns_view_freezezones(view, freeze);
7464			if (result != ISC_R_SUCCESS &&
7465			    tresult == ISC_R_SUCCESS)
7466				tresult = result;
7467		}
7468		isc_task_endexclusive(server->task);
7469		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7470			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7471			      "%s all zones: %s",
7472			      freeze ? "freezing" : "thawing",
7473			      isc_result_totext(tresult));
7474		return (tresult);
7475	}
7476	dns_zone_getraw(zone, &raw);
7477	if (raw != NULL) {
7478		dns_zone_detach(&zone);
7479		dns_zone_attach(raw, &zone);
7480		dns_zone_detach(&raw);
7481	}
7482	type = dns_zone_gettype(zone);
7483	if (type != dns_zone_master) {
7484		dns_zone_detach(&zone);
7485		return (DNS_R_NOTMASTER);
7486	}
7487
7488	if (freeze && !dns_zone_isdynamic(zone, ISC_TRUE)) {
7489		dns_zone_detach(&zone);
7490		return (DNS_R_NOTDYNAMIC);
7491	}
7492
7493	result = isc_task_beginexclusive(server->task);
7494	RUNTIME_CHECK(result == ISC_R_SUCCESS);
7495	frozen = dns_zone_getupdatedisabled(zone);
7496	if (freeze) {
7497		if (frozen) {
7498			msg = "WARNING: The zone was already frozen.\n"
7499			      "Someone else may be editing it or "
7500			      "it may still be re-loading.";
7501			result = DNS_R_FROZEN;
7502		}
7503		if (result == ISC_R_SUCCESS) {
7504			result = dns_zone_flush(zone);
7505			if (result != ISC_R_SUCCESS)
7506				msg = "Flushing the zone updates to "
7507				      "disk failed.";
7508		}
7509		if (result == ISC_R_SUCCESS)
7510			dns_zone_setupdatedisabled(zone, freeze);
7511	} else {
7512		if (frozen) {
7513			result = dns_zone_loadandthaw(zone);
7514			switch (result) {
7515			case ISC_R_SUCCESS:
7516			case DNS_R_UPTODATE:
7517				msg = "The zone reload and thaw was "
7518				      "successful.";
7519				result = ISC_R_SUCCESS;
7520				break;
7521			case DNS_R_CONTINUE:
7522				msg = "A zone reload and thaw was started.\n"
7523				      "Check the logs to see the result.";
7524				result = ISC_R_SUCCESS;
7525				break;
7526			}
7527		}
7528	}
7529	isc_task_endexclusive(server->task);
7530
7531	if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
7532		isc_buffer_putmem(text, (const unsigned char *)msg,
7533				  strlen(msg) + 1);
7534
7535	view = dns_zone_getview(zone);
7536	if (strcmp(view->name, "_default") == 0 ||
7537	    strcmp(view->name, "_bind") == 0)
7538	{
7539		vname = "";
7540		sep = "";
7541	} else {
7542		vname = view->name;
7543		sep = " ";
7544	}
7545	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
7546			      sizeof(classstr));
7547	dns_name_format(dns_zone_getorigin(zone),
7548			zonename, sizeof(zonename));
7549	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7550		      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7551		      "%s zone '%s/%s'%s%s: %s",
7552		      freeze ? "freezing" : "thawing",
7553		      zonename, classstr, sep, vname,
7554		      isc_result_totext(result));
7555	dns_zone_detach(&zone);
7556	return (result);
7557}
7558
7559#ifdef HAVE_LIBSCF
7560/*
7561 * This function adds a message for rndc to echo if named
7562 * is managed by smf and is also running chroot.
7563 */
7564isc_result_t
7565ns_smf_add_message(isc_buffer_t *text) {
7566	unsigned int n;
7567
7568	n = snprintf((char *)isc_buffer_used(text),
7569		isc_buffer_availablelength(text),
7570		"use svcadm(1M) to manage named");
7571	if (n >= isc_buffer_availablelength(text))
7572		return (ISC_R_NOSPACE);
7573	isc_buffer_add(text, n);
7574	return (ISC_R_SUCCESS);
7575}
7576#endif /* HAVE_LIBSCF */
7577
7578/*
7579 * Act on an "addzone" command from the command channel.
7580 */
7581isc_result_t
7582ns_server_add_zone(ns_server_t *server, char *args) {
7583	isc_result_t	     result;
7584	isc_buffer_t	     argbuf;
7585	size_t		     arglen;
7586	cfg_parser_t	    *parser = NULL;
7587	cfg_obj_t	    *config = NULL;
7588	const cfg_obj_t	    *vconfig = NULL;
7589	const cfg_obj_t	    *views = NULL;
7590	const cfg_obj_t     *parms = NULL;
7591	const cfg_obj_t     *obj = NULL;
7592	const cfg_listelt_t *element;
7593	const char	    *zonename;
7594	const char	    *classname = NULL;
7595	const char	    *argp;
7596	const char	    *viewname = NULL;
7597	dns_rdataclass_t     rdclass;
7598	dns_view_t	    *view = 0;
7599	isc_buffer_t	     buf, *nbuf = NULL;
7600	dns_name_t	     dnsname;
7601	dns_zone_t	    *zone = NULL;
7602	FILE		    *fp = NULL;
7603	struct cfg_context  *cfg = NULL;
7604
7605	/* Try to parse the argument string */
7606	arglen = strlen(args);
7607	isc_buffer_init(&argbuf, args, arglen);
7608	isc_buffer_add(&argbuf, strlen(args));
7609	CHECK(cfg_parser_create(server->mctx, ns_g_lctx, &parser));
7610	CHECK(cfg_parse_buffer(parser, &argbuf, &cfg_type_addzoneconf,
7611			       &config));
7612	CHECK(cfg_map_get(config, "addzone", &parms));
7613
7614	zonename = cfg_obj_asstring(cfg_tuple_get(parms, "name"));
7615	isc_buffer_init(&buf, zonename, strlen(zonename));
7616	isc_buffer_add(&buf, strlen(zonename));
7617	dns_name_init(&dnsname, NULL);
7618	isc_buffer_allocate(server->mctx, &nbuf, 256);
7619	dns_name_setbuffer(&dnsname, nbuf);
7620	CHECK(dns_name_fromtext(&dnsname, &buf, dns_rootname, ISC_FALSE, NULL));
7621
7622	/* Make sense of optional class argument */
7623	obj = cfg_tuple_get(parms, "class");
7624	CHECK(ns_config_getclass(obj, dns_rdataclass_in, &rdclass));
7625	if (rdclass != dns_rdataclass_in && obj)
7626		classname = cfg_obj_asstring(obj);
7627
7628	/* Make sense of optional view argument */
7629	obj = cfg_tuple_get(parms, "view");
7630	if (obj && cfg_obj_isstring(obj))
7631		viewname = cfg_obj_asstring(obj);
7632	if (viewname == NULL || *viewname == '\0')
7633		viewname = "_default";
7634	CHECK(dns_viewlist_find(&server->viewlist, viewname, rdclass, &view));
7635
7636	/* Are we accepting new zones? */
7637	if (view->new_zone_file == NULL) {
7638		result = ISC_R_NOPERM;
7639		goto cleanup;
7640	}
7641
7642	cfg = (struct cfg_context *) view->new_zone_config;
7643	if (cfg == NULL) {
7644		result = ISC_R_FAILURE;
7645		goto cleanup;
7646	}
7647
7648	/* Zone shouldn't already exist */
7649	result = dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone);
7650	if (result == ISC_R_SUCCESS) {
7651		result = ISC_R_EXISTS;
7652		goto cleanup;
7653	} else if (result == DNS_R_PARTIALMATCH) {
7654		/* Create our sub-zone anyway */
7655		dns_zone_detach(&zone);
7656		zone = NULL;
7657	}
7658	else if (result != ISC_R_NOTFOUND)
7659		goto cleanup;
7660
7661	/* Find the view statement */
7662	cfg_map_get(cfg->config, "view", &views);
7663	for (element = cfg_list_first(views);
7664	     element != NULL;
7665	     element = cfg_list_next(element))
7666	{
7667		const char *vname;
7668		vconfig = cfg_listelt_value(element);
7669		vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
7670		if (vname && !strcasecmp(vname, viewname))
7671			break;
7672		vconfig = NULL;
7673	}
7674
7675	/* Open save file for write configuration */
7676	CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
7677
7678	/* Mark view unfrozen so that zone can be added */
7679	isc_task_beginexclusive(server->task);
7680	dns_view_thaw(view);
7681	result = configure_zone(cfg->config, parms, vconfig,
7682				server->mctx, view, cfg->actx, ISC_FALSE);
7683	dns_view_freeze(view);
7684	isc_task_endexclusive(server->task);
7685	if (result != ISC_R_SUCCESS)
7686		goto cleanup;
7687
7688	/* Is it there yet? */
7689	CHECK(dns_zt_find(view->zonetable, &dnsname, 0, NULL, &zone));
7690
7691	/*
7692	 * Load the zone from the master file.  If this fails, we'll
7693	 * need to undo the configuration we've done already.
7694	 */
7695	result = dns_zone_loadnew(zone);
7696	if (result != ISC_R_SUCCESS) {
7697		dns_db_t *dbp = NULL;
7698
7699		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7700			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7701			      "addzone failed; reverting.");
7702
7703		/* If the zone loaded partially, unload it */
7704		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
7705			dns_db_detach(&dbp);
7706			dns_zone_unload(zone);
7707		}
7708
7709		/* Remove the zone from the zone table */
7710		dns_zt_unmount(view->zonetable, zone);
7711		goto cleanup;
7712	}
7713
7714	/* Flag the zone as having been added at runtime */
7715	dns_zone_setadded(zone, ISC_TRUE);
7716
7717	/* Emit just the zone name from args */
7718	CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
7719	CHECK(isc_stdio_write(zonename, strlen(zonename), 1, fp, NULL));
7720	CHECK(isc_stdio_write(" ", 1, 1, fp, NULL));
7721
7722	/* Classname, if not default */
7723	if (classname != NULL && *classname != '\0') {
7724		CHECK(isc_stdio_write(classname, strlen(classname), 1, fp,
7725				      NULL));
7726		CHECK(isc_stdio_write(" ", 1, 1, fp, NULL));
7727	}
7728
7729	/* Find beginning of option block from args */
7730	for (argp = args; *argp; argp++, arglen--) {
7731		if (*argp == '{') {	/* Assume matching '}' */
7732			/* Add that to our file */
7733			CHECK(isc_stdio_write(argp, arglen, 1, fp, NULL));
7734
7735			/* Make sure we end with a LF */
7736			if (argp[arglen-1] != '\n') {
7737				CHECK(isc_stdio_write("\n", 1, 1, fp, NULL));
7738			}
7739			break;
7740		}
7741	}
7742
7743	CHECK(isc_stdio_close(fp));
7744	fp = NULL;
7745	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7746				  NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7747				  "zone %s added to view %s via addzone",
7748				  zonename, viewname);
7749
7750	result = ISC_R_SUCCESS;
7751
7752 cleanup:
7753	if (fp != NULL)
7754		isc_stdio_close(fp);
7755	if (parser != NULL) {
7756		if (config != NULL)
7757			cfg_obj_destroy(parser, &config);
7758		cfg_parser_destroy(&parser);
7759	}
7760	if (zone != NULL)
7761		dns_zone_detach(&zone);
7762	if (view != NULL)
7763		dns_view_detach(&view);
7764	if (nbuf != NULL)
7765		isc_buffer_free(&nbuf);
7766
7767	return (result);
7768}
7769
7770/*
7771 * Act on a "delzone" command from the command channel.
7772 */
7773isc_result_t
7774ns_server_del_zone(ns_server_t *server, char *args) {
7775	isc_result_t	       result;
7776	dns_zone_t	      *zone = NULL;
7777	dns_view_t	      *view = NULL;
7778	dns_db_t	      *dbp = NULL;
7779	const char	      *filename = NULL;
7780	char		      *tmpname = NULL;
7781	char		       buf[1024];
7782	const char	      *zonename = NULL;
7783	size_t		       znamelen = 0;
7784	FILE		      *ifp = NULL, *ofp = NULL;
7785
7786	/* Parse parameters */
7787	CHECK(zone_from_args(server, args, NULL, &zone, &zonename, ISC_TRUE));
7788	if (result != ISC_R_SUCCESS)
7789		return (result);
7790	if (zone == NULL) {
7791		result = ISC_R_UNEXPECTEDEND;
7792		goto cleanup;
7793	}
7794
7795	/*
7796	 * Was this zone originally added at runtime?
7797	 * If not, we can't delete it now.
7798	 */
7799	if (!dns_zone_getadded(zone)) {
7800		result = ISC_R_NOPERM;
7801		goto cleanup;
7802	}
7803
7804	if (zonename != NULL)
7805		znamelen = strlen(zonename);
7806
7807	/* Dig out configuration for this zone */
7808	view = dns_zone_getview(zone);
7809	filename = view->new_zone_file;
7810	if (filename == NULL) {
7811		/* No adding zones in this view */
7812		result = ISC_R_FAILURE;
7813		goto cleanup;
7814	}
7815
7816	/* Rewrite zone list */
7817	result = isc_stdio_open(filename, "r", &ifp);
7818	if (ifp != NULL && result == ISC_R_SUCCESS) {
7819		char *found = NULL, *p = NULL;
7820		size_t n;
7821
7822		/* Create a temporary file */
7823		CHECK(isc_string_printf(buf, 1023, "%s.%ld", filename,
7824					(long)getpid()));
7825		if (!(tmpname = isc_mem_strdup(server->mctx, buf))) {
7826			result = ISC_R_NOMEMORY;
7827			goto cleanup;
7828		}
7829		CHECK(isc_stdio_open(tmpname, "w", &ofp));
7830
7831		/* Look for the entry for that zone */
7832		while (fgets(buf, 1024, ifp)) {
7833			/* A 'zone' line */
7834			if (strncasecmp(buf, "zone", 4)) {
7835				fputs(buf, ofp);
7836				continue;
7837			}
7838			p = buf+4;
7839
7840			/* Locate a name */
7841			while (*p &&
7842			       ((*p == '"') || isspace((unsigned char)*p)))
7843				p++;
7844
7845			/* Is that the zone we're looking for */
7846			if (strncasecmp(p, zonename, znamelen)) {
7847				fputs(buf, ofp);
7848				continue;
7849			}
7850
7851			/* And nothing else? */
7852			p += znamelen;
7853			if (isspace((unsigned char)*p) ||
7854			    *p == '"' || *p == '{') {
7855				/* This must be the entry */
7856				found = p;
7857				break;
7858			}
7859
7860			/* Spit it out, keep looking */
7861			fputs(buf, ofp);
7862		}
7863
7864		/* Skip over an option block (matching # of braces) */
7865		if (found) {
7866			int obrace = 0, cbrace = 0;
7867			for (;;) {
7868				while (*p) {
7869					if (*p == '{') obrace++;
7870					if (*p == '}') cbrace++;
7871					p++;
7872				}
7873				if (obrace && (obrace == cbrace))
7874					break;
7875				if (!fgets(buf, 1024, ifp))
7876					break;
7877				p = buf;
7878			}
7879
7880			/* Just spool the remainder of the file out */
7881			result = isc_stdio_read(buf, 1, 1024, ifp, &n);
7882			while (n > 0U) {
7883				if (result == ISC_R_EOF)
7884					result = ISC_R_SUCCESS;
7885				CHECK(result);
7886				isc_stdio_write(buf, 1, n, ofp, NULL);
7887				result = isc_stdio_read(buf, 1, 1024, ifp, &n);
7888			}
7889
7890			/* Move temporary into place */
7891			CHECK(isc_file_rename(tmpname, view->new_zone_file));
7892		} else {
7893			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7894				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
7895				      "deleted zone %s was missing from "
7896				      "new zone file", zonename);
7897			goto cleanup;
7898		}
7899	}
7900
7901	/* Stop answering for this zone */
7902	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
7903		dns_db_detach(&dbp);
7904		dns_zone_unload(zone);
7905	}
7906
7907	CHECK(dns_zt_unmount(view->zonetable, zone));
7908
7909	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7910				  NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7911				  "zone %s removed via delzone", zonename);
7912
7913	result = ISC_R_SUCCESS;
7914
7915 cleanup:
7916	if (ifp != NULL)
7917		isc_stdio_close(ifp);
7918	if (ofp != NULL) {
7919		isc_stdio_close(ofp);
7920		isc_file_remove(tmpname);
7921	}
7922	if (tmpname != NULL)
7923		isc_mem_free(server->mctx, tmpname);
7924	if (zone != NULL)
7925		dns_zone_detach(&zone);
7926
7927	return (result);
7928}
7929
7930static void
7931newzone_cfgctx_destroy(void **cfgp) {
7932	struct cfg_context *cfg;
7933
7934	REQUIRE(cfgp != NULL && *cfgp != NULL);
7935
7936	cfg = *cfgp;
7937
7938	if (cfg->actx != NULL)
7939		cfg_aclconfctx_detach(&cfg->actx);
7940
7941	if (cfg->parser != NULL) {
7942		if (cfg->config != NULL)
7943			cfg_obj_destroy(cfg->parser, &cfg->config);
7944		cfg_parser_destroy(&cfg->parser);
7945	}
7946	if (cfg->nzparser != NULL) {
7947		if (cfg->nzconfig != NULL)
7948			cfg_obj_destroy(cfg->nzparser, &cfg->nzconfig);
7949		cfg_parser_destroy(&cfg->nzparser);
7950	}
7951
7952	isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
7953	*cfgp = NULL;
7954}
7955
7956isc_result_t
7957ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text) {
7958	isc_result_t result = ISC_R_SUCCESS;
7959	dns_zone_t *zone = NULL;
7960	dns_name_t *origin;
7961	dns_db_t *db = NULL;
7962	dns_dbnode_t *node = NULL;
7963	dns_dbversion_t *version = NULL;
7964	dns_rdatatype_t privatetype;
7965	dns_rdataset_t privset;
7966	isc_boolean_t first = ISC_TRUE;
7967	isc_boolean_t list = ISC_FALSE, clear = ISC_FALSE;
7968	isc_boolean_t chain = ISC_FALSE;
7969	char keystr[DNS_SECALG_FORMATSIZE + 7];
7970	isc_uint8_t hash = 0, flags = 0, iter = 0, saltlen = 0;
7971	unsigned char salt[255];
7972	const char *ptr;
7973	size_t n;
7974
7975	dns_rdataset_init(&privset);
7976
7977	/* Skip the command name. */
7978	ptr = next_token(&args, " \t");
7979	if (ptr == NULL)
7980		return (ISC_R_UNEXPECTEDEND);
7981
7982	/* Find out what we are to do. */
7983	ptr = next_token(&args, " \t");
7984	if (ptr == NULL)
7985		return (ISC_R_UNEXPECTEDEND);
7986
7987	if (strcasecmp(ptr, "-list") == 0)
7988		list = ISC_TRUE;
7989	else if ((strcasecmp(ptr, "-clear") == 0)  ||
7990		 (strcasecmp(ptr, "-clean") == 0)) {
7991		clear = ISC_TRUE;
7992		ptr = next_token(&args, " \t");
7993		if (ptr == NULL)
7994			return (ISC_R_UNEXPECTEDEND);
7995		memcpy(keystr, ptr, sizeof(keystr));
7996	} else if(strcasecmp(ptr, "-nsec3param") == 0) {
7997		const char *hashstr, *flagstr, *iterstr;
7998		char nbuf[512];
7999
8000		chain = ISC_TRUE;
8001		hashstr = next_token(&args, " \t");
8002		if (hashstr == NULL)
8003			return (ISC_R_UNEXPECTEDEND);
8004
8005		if (strcasecmp(hashstr, "none") == 0)
8006			hash = 0;
8007		else {
8008			flagstr = next_token(&args, " \t");
8009			iterstr = next_token(&args, " \t");
8010			if (flagstr == NULL || iterstr == NULL)
8011				return (ISC_R_UNEXPECTEDEND);
8012
8013			n = snprintf(nbuf, sizeof(nbuf), "%s %s %s",
8014				     hashstr, flagstr, iterstr);
8015			if (n == sizeof(nbuf))
8016				return (ISC_R_NOSPACE);
8017			n = sscanf(nbuf, "%hhd %hhd %hhd",
8018				   &hash, &flags, &iter);
8019			if (n != 3)
8020				return (ISC_R_BADNUMBER);
8021
8022			ptr = next_token(&args, " \t");
8023			if (ptr == NULL)
8024				return (ISC_R_UNEXPECTEDEND);
8025			if (strcmp(ptr, "-") != 0) {
8026				isc_buffer_t buf;
8027
8028			isc_buffer_init(&buf, salt, sizeof(salt));
8029			CHECK(isc_hex_decodestring(ptr, &buf));
8030			saltlen = isc_buffer_usedlength(&buf);
8031		}
8032		}
8033	} else
8034		CHECK(DNS_R_SYNTAX);
8035
8036	CHECK(zone_from_args(server, args, NULL, &zone, NULL, ISC_FALSE));
8037	if (zone == NULL)
8038		CHECK(ISC_R_UNEXPECTEDEND);
8039
8040	if (clear) {
8041		CHECK(dns_zone_keydone(zone, keystr));
8042		isc_buffer_putstr(text, "request queued");
8043		isc_buffer_putuint8(text, 0);
8044	} else if (chain) {
8045		CHECK(dns_zone_setnsec3param(zone, hash, flags, iter,
8046						saltlen, salt, ISC_TRUE));
8047		isc_buffer_putstr(text, "request queued");
8048		isc_buffer_putuint8(text, 0);
8049	} else if (list) {
8050		privatetype = dns_zone_getprivatetype(zone);
8051		origin = dns_zone_getorigin(zone);
8052		CHECK(dns_zone_getdb(zone, &db));
8053		CHECK(dns_db_findnode(db, origin, ISC_FALSE, &node));
8054		dns_db_currentversion(db, &version);
8055
8056		result = dns_db_findrdataset(db, node, version, privatetype,
8057					     dns_rdatatype_none, 0,
8058					     &privset, NULL);
8059		if (result == ISC_R_NOTFOUND) {
8060			isc_buffer_putstr(text, "No signing records found");
8061			isc_buffer_putuint8(text, 0);
8062			result = ISC_R_SUCCESS;
8063			goto cleanup;
8064		}
8065
8066		for (result = dns_rdataset_first(&privset);
8067		     result == ISC_R_SUCCESS;
8068		     result = dns_rdataset_next(&privset))
8069		{
8070			dns_rdata_t priv = DNS_RDATA_INIT;
8071			char output[BUFSIZ];
8072			isc_buffer_t buf;
8073
8074			dns_rdataset_current(&privset, &priv);
8075
8076			isc_buffer_init(&buf, output, sizeof(output));
8077			CHECK(dns_private_totext(&priv, &buf));
8078
8079			if (!first)
8080				isc_buffer_putstr(text, "\n");
8081			first = ISC_FALSE;
8082
8083			n = snprintf((char *)isc_buffer_used(text),
8084				     isc_buffer_availablelength(text),
8085				     "%s", output);
8086			if (n >= isc_buffer_availablelength(text))
8087				CHECK(ISC_R_NOSPACE);
8088
8089			isc_buffer_add(text, n);
8090		}
8091
8092		if (result == ISC_R_NOMORE)
8093			result = ISC_R_SUCCESS;
8094	}
8095
8096 cleanup:
8097	if (dns_rdataset_isassociated(&privset))
8098		dns_rdataset_disassociate(&privset);
8099	if (node != NULL)
8100		dns_db_detachnode(db, &node);
8101	if (version != NULL)
8102		dns_db_closeversion(db, &version, ISC_FALSE);
8103	if (db != NULL)
8104		dns_db_detach(&db);
8105	if (zone != NULL)
8106		dns_zone_detach(&zone);
8107
8108	return (result);
8109}
8110