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