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