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