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