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