]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/bin/named/server.c
MFV 262445:
[FreeBSD/stable/9.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 #ifdef ALLOW_FILTER_AAAA_ON_V4
3145         obj = NULL;
3146         result = ns_config_get(maps, "filter-aaaa-on-v4", &obj);
3147         INSIST(result == ISC_R_SUCCESS);
3148         if (cfg_obj_isboolean(obj)) {
3149                 if (cfg_obj_asboolean(obj))
3150                         view->v4_aaaa = dns_v4_aaaa_filter;
3151                 else
3152                         view->v4_aaaa = dns_v4_aaaa_ok;
3153         } else {
3154                 const char *v4_aaaastr = cfg_obj_asstring(obj);
3155                 if (strcasecmp(v4_aaaastr, "break-dnssec") == 0)
3156                         view->v4_aaaa = dns_v4_aaaa_break_dnssec;
3157                 else
3158                         INSIST(0);
3159         }
3160         CHECK(configure_view_acl(vconfig, config, "filter-aaaa", NULL,
3161                                  actx, ns_g_mctx, &view->v4_aaaa_acl));
3162 #endif
3163
3164         obj = NULL;
3165         result = ns_config_get(maps, "dnssec-enable", &obj);
3166         INSIST(result == ISC_R_SUCCESS);
3167         view->enablednssec = cfg_obj_asboolean(obj);
3168
3169         obj = NULL;
3170         result = ns_config_get(optionmaps, "dnssec-lookaside", &obj);
3171         if (result == ISC_R_SUCCESS) {
3172                 /* If set to "auto", use the version from the defaults */
3173                 const cfg_obj_t *dlvobj;
3174                 const char *dom;
3175                 dlvobj = cfg_listelt_value(cfg_list_first(obj));
3176                 dom = cfg_obj_asstring(cfg_tuple_get(dlvobj, "domain"));
3177                 if (cfg_obj_isvoid(cfg_tuple_get(dlvobj, "trust-anchor"))) {
3178                         /* If "no", skip; if "auto", use global default */
3179                         if (!strcasecmp(dom, "no"))
3180                                 result = ISC_R_NOTFOUND;
3181                         else if (!strcasecmp(dom, "auto")) {
3182                                 auto_dlv = ISC_TRUE;
3183                                 obj = NULL;
3184                                 result = cfg_map_get(ns_g_defaults,
3185                                                      "dnssec-lookaside", &obj);
3186                         }
3187                 }
3188         }
3189
3190         if (result == ISC_R_SUCCESS) {
3191                 for (element = cfg_list_first(obj);
3192                      element != NULL;
3193                      element = cfg_list_next(element))
3194                 {
3195                         const char *str;
3196                         isc_buffer_t b;
3197                         dns_name_t *dlv;
3198
3199                         obj = cfg_listelt_value(element);
3200                         str = cfg_obj_asstring(cfg_tuple_get(obj,
3201                                                              "trust-anchor"));
3202                         isc_buffer_constinit(&b, str, strlen(str));
3203                         isc_buffer_add(&b, strlen(str));
3204                         dlv = dns_fixedname_name(&view->dlv_fixed);
3205                         CHECK(dns_name_fromtext(dlv, &b, dns_rootname,
3206                                                 DNS_NAME_DOWNCASE, NULL));
3207                         view->dlv = dns_fixedname_name(&view->dlv_fixed);
3208                 }
3209         } else
3210                 view->dlv = NULL;
3211
3212         /*
3213          * For now, there is only one kind of trusted keys, the
3214          * "security roots".
3215          */
3216         CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
3217                                         auto_dlv, auto_root, mctx));
3218         dns_resolver_resetmustbesecure(view->resolver);
3219         obj = NULL;
3220         result = ns_config_get(maps, "dnssec-must-be-secure", &obj);
3221         if (result == ISC_R_SUCCESS)
3222                 CHECK(mustbesecure(obj, view->resolver));
3223
3224         obj = NULL;
3225         result = ns_config_get(maps, "preferred-glue", &obj);
3226         if (result == ISC_R_SUCCESS) {
3227                 str = cfg_obj_asstring(obj);
3228                 if (strcasecmp(str, "a") == 0)
3229                         view->preferred_glue = dns_rdatatype_a;
3230                 else if (strcasecmp(str, "aaaa") == 0)
3231                         view->preferred_glue = dns_rdatatype_aaaa;
3232                 else
3233                         view->preferred_glue = 0;
3234         } else
3235                 view->preferred_glue = 0;
3236
3237         obj = NULL;
3238         result = ns_config_get(maps, "root-delegation-only", &obj);
3239         if (result == ISC_R_SUCCESS) {
3240                 dns_view_setrootdelonly(view, ISC_TRUE);
3241                 if (!cfg_obj_isvoid(obj)) {
3242                         dns_fixedname_t fixed;
3243                         dns_name_t *name;
3244                         isc_buffer_t b;
3245                         const char *str;
3246                         const cfg_obj_t *exclude;
3247
3248                         dns_fixedname_init(&fixed);
3249                         name = dns_fixedname_name(&fixed);
3250                         for (element = cfg_list_first(obj);
3251                              element != NULL;
3252                              element = cfg_list_next(element)) {
3253                                 exclude = cfg_listelt_value(element);
3254                                 str = cfg_obj_asstring(exclude);
3255                                 isc_buffer_constinit(&b, str, strlen(str));
3256                                 isc_buffer_add(&b, strlen(str));
3257                                 CHECK(dns_name_fromtext(name, &b, dns_rootname,
3258                                                         0, NULL));
3259                                 CHECK(dns_view_excludedelegationonly(view,
3260                                                                      name));
3261                         }
3262                 }
3263         } else
3264                 dns_view_setrootdelonly(view, ISC_FALSE);
3265
3266         /*
3267          * Setup automatic empty zones.  If recursion is off then
3268          * they are disabled by default.
3269          */
3270         obj = NULL;
3271         (void)ns_config_get(maps, "empty-zones-enable", &obj);
3272         (void)ns_config_get(maps, "disable-empty-zone", &disablelist);
3273         if (obj == NULL && disablelist == NULL &&
3274             view->rdclass == dns_rdataclass_in) {
3275                 empty_zones_enable = view->recursion;
3276         } else if (view->rdclass == dns_rdataclass_in) {
3277                 if (obj != NULL)
3278                         empty_zones_enable = cfg_obj_asboolean(obj);
3279                 else
3280                         empty_zones_enable = view->recursion;
3281         } else {
3282                 empty_zones_enable = ISC_FALSE;
3283         }
3284         if (empty_zones_enable && !lwresd_g_useresolvconf) {
3285                 const char *empty;
3286                 int empty_zone = 0;
3287                 dns_fixedname_t fixed;
3288                 dns_name_t *name;
3289                 isc_buffer_t buffer;
3290                 const char *str;
3291                 char server[DNS_NAME_FORMATSIZE + 1];
3292                 char contact[DNS_NAME_FORMATSIZE + 1];
3293                 const char *empty_dbtype[4] =
3294                                     { "_builtin", "empty", NULL, NULL };
3295                 int empty_dbtypec = 4;
3296                 dns_zonestat_level_t statlevel;
3297
3298                 dns_fixedname_init(&fixed);
3299                 name = dns_fixedname_name(&fixed);
3300
3301                 obj = NULL;
3302                 result = ns_config_get(maps, "empty-server", &obj);
3303                 if (result == ISC_R_SUCCESS) {
3304                         str = cfg_obj_asstring(obj);
3305                         isc_buffer_constinit(&buffer, str, strlen(str));
3306                         isc_buffer_add(&buffer, strlen(str));
3307                         CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
3308                                                 NULL));
3309                         isc_buffer_init(&buffer, server, sizeof(server) - 1);
3310                         CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
3311                         server[isc_buffer_usedlength(&buffer)] = 0;
3312                         empty_dbtype[2] = server;
3313                 } else
3314                         empty_dbtype[2] = "@";
3315
3316                 obj = NULL;
3317                 result = ns_config_get(maps, "empty-contact", &obj);
3318                 if (result == ISC_R_SUCCESS) {
3319                         str = cfg_obj_asstring(obj);
3320                         isc_buffer_constinit(&buffer, str, strlen(str));
3321                         isc_buffer_add(&buffer, strlen(str));
3322                         CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
3323                                                 NULL));
3324                         isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
3325                         CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
3326                         contact[isc_buffer_usedlength(&buffer)] = 0;
3327                         empty_dbtype[3] = contact;
3328                 } else
3329                         empty_dbtype[3] = ".";
3330
3331                 obj = NULL;
3332                 result = ns_config_get(maps, "zone-statistics", &obj);
3333                 INSIST(result == ISC_R_SUCCESS);
3334                 if (cfg_obj_isboolean(obj)) {
3335                         if (cfg_obj_asboolean(obj))
3336                                 statlevel = dns_zonestat_full;
3337                         else
3338                                 statlevel = dns_zonestat_terse; /* XXX */
3339                 } else {
3340                         const char *levelstr = cfg_obj_asstring(obj);
3341                         if (strcasecmp(levelstr, "full") == 0)
3342                                 statlevel = dns_zonestat_full;
3343                         else if (strcasecmp(levelstr, "terse") == 0)
3344                                 statlevel = dns_zonestat_terse;
3345                         else if (strcasecmp(levelstr, "none") == 0)
3346                                 statlevel = dns_zonestat_none;
3347                         else
3348                                 INSIST(0);
3349                 }
3350
3351                 for (empty = empty_zones[empty_zone];
3352                      empty != NULL;
3353                      empty = empty_zones[++empty_zone])
3354                 {
3355                         dns_forwarders_t *forwarders = NULL;
3356                         dns_view_t *pview = NULL;
3357
3358                         isc_buffer_constinit(&buffer, empty, strlen(empty));
3359                         isc_buffer_add(&buffer, strlen(empty));
3360                         /*
3361                          * Look for zone on drop list.
3362                          */
3363                         CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
3364                                                 NULL));
3365                         if (disablelist != NULL &&
3366                             on_disable_list(disablelist, name))
3367                                 continue;
3368
3369                         /*
3370                          * This zone already exists.
3371                          */
3372                         (void)dns_view_findzone(view, name, &zone);
3373                         if (zone != NULL) {
3374                                 dns_zone_detach(&zone);
3375                                 continue;
3376                         }
3377
3378                         /*
3379                          * If we would forward this name don't add a
3380                          * empty zone for it.
3381                          */
3382                         result = dns_fwdtable_find(view->fwdtable, name,
3383                                                    &forwarders);
3384                         if (result == ISC_R_SUCCESS &&
3385                             forwarders->fwdpolicy == dns_fwdpolicy_only)
3386                                 continue;
3387
3388                         /*
3389                          * See if we can re-use a existing zone.
3390                          */
3391                         result = dns_viewlist_find(&ns_g_server->viewlist,
3392                                                    view->name, view->rdclass,
3393                                                    &pview);
3394                         if (result != ISC_R_NOTFOUND &&
3395                             result != ISC_R_SUCCESS)
3396                                 goto cleanup;
3397
3398                         if (pview != NULL) {
3399                                 (void)dns_view_findzone(pview, name, &zone);
3400                                 dns_view_detach(&pview);
3401                         }
3402
3403                         CHECK(create_empty_zone(zone, name, view, zonelist,
3404                                                 empty_dbtype, empty_dbtypec,
3405                                                 statlevel));
3406                         if (zone != NULL)
3407                                 dns_zone_detach(&zone);
3408                 }
3409         }
3410
3411 #ifdef USE_RRL
3412         obj = NULL;
3413         result = ns_config_get(maps, "rate-limit", &obj);
3414         if (result == ISC_R_SUCCESS) {
3415                 result = configure_rrl(view, config, obj);
3416                 if (result != ISC_R_SUCCESS)
3417                         goto cleanup;
3418         }
3419 #endif /* USE_RRL */
3420
3421         result = ISC_R_SUCCESS;
3422
3423  cleanup:
3424         if (clients != NULL)
3425                 dns_acl_detach(&clients);
3426         if (mapped != NULL)
3427                 dns_acl_detach(&mapped);
3428         if (excluded != NULL)
3429                 dns_acl_detach(&excluded);
3430         if (ring != NULL)
3431                 dns_tsigkeyring_detach(&ring);
3432         if (zone != NULL)
3433                 dns_zone_detach(&zone);
3434         if (dispatch4 != NULL)
3435                 dns_dispatch_detach(&dispatch4);
3436         if (dispatch6 != NULL)
3437                 dns_dispatch_detach(&dispatch6);
3438         if (resstats != NULL)
3439                 isc_stats_detach(&resstats);
3440         if (resquerystats != NULL)
3441                 dns_stats_detach(&resquerystats);
3442         if (order != NULL)
3443                 dns_order_detach(&order);
3444         if (cmctx != NULL)
3445                 isc_mem_detach(&cmctx);
3446         if (hmctx != NULL)
3447                 isc_mem_detach(&hmctx);
3448
3449         if (cache != NULL)
3450                 dns_cache_detach(&cache);
3451
3452         return (result);
3453 }
3454
3455 static isc_result_t
3456 configure_hints(dns_view_t *view, const char *filename) {
3457         isc_result_t result;
3458         dns_db_t *db;
3459
3460         db = NULL;
3461         result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
3462         if (result == ISC_R_SUCCESS) {
3463                 dns_view_sethints(view, db);
3464                 dns_db_detach(&db);
3465         }
3466
3467         return (result);
3468 }
3469
3470 static isc_result_t
3471 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
3472                      const cfg_obj_t *alternates)
3473 {
3474         const cfg_obj_t *portobj;
3475         const cfg_obj_t *addresses;
3476         const cfg_listelt_t *element;
3477         isc_result_t result = ISC_R_SUCCESS;
3478         in_port_t port;
3479
3480         /*
3481          * Determine which port to send requests to.
3482          */
3483         if (ns_g_lwresdonly && ns_g_port != 0)
3484                 port = ns_g_port;
3485         else
3486                 CHECKM(ns_config_getport(config, &port), "port");
3487
3488         if (alternates != NULL) {
3489                 portobj = cfg_tuple_get(alternates, "port");
3490                 if (cfg_obj_isuint32(portobj)) {
3491                         isc_uint32_t val = cfg_obj_asuint32(portobj);
3492                         if (val > ISC_UINT16_MAX) {
3493                                 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
3494                                             "port '%u' out of range", val);
3495                                 return (ISC_R_RANGE);
3496                         }
3497                         port = (in_port_t) val;
3498                 }
3499         }
3500
3501         addresses = NULL;
3502         if (alternates != NULL)
3503                 addresses = cfg_tuple_get(alternates, "addresses");
3504
3505         for (element = cfg_list_first(addresses);
3506              element != NULL;
3507              element = cfg_list_next(element))
3508         {
3509                 const cfg_obj_t *alternate = cfg_listelt_value(element);
3510                 isc_sockaddr_t sa;
3511
3512                 if (!cfg_obj_issockaddr(alternate)) {
3513                         dns_fixedname_t fixed;
3514                         dns_name_t *name;
3515                         const char *str = cfg_obj_asstring(cfg_tuple_get(
3516                                                            alternate, "name"));
3517                         isc_buffer_t buffer;
3518                         in_port_t myport = port;
3519
3520                         isc_buffer_constinit(&buffer, str, strlen(str));
3521                         isc_buffer_add(&buffer, strlen(str));
3522                         dns_fixedname_init(&fixed);
3523                         name = dns_fixedname_name(&fixed);
3524                         CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
3525                                                 NULL));
3526
3527                         portobj = cfg_tuple_get(alternate, "port");
3528                         if (cfg_obj_isuint32(portobj)) {
3529                                 isc_uint32_t val = cfg_obj_asuint32(portobj);
3530                                 if (val > ISC_UINT16_MAX) {
3531                                         cfg_obj_log(portobj, ns_g_lctx,
3532                                                     ISC_LOG_ERROR,
3533                                                     "port '%u' out of range",
3534                                                      val);
3535                                         return (ISC_R_RANGE);
3536                                 }
3537                                 myport = (in_port_t) val;
3538                         }
3539                         CHECK(dns_resolver_addalternate(view->resolver, NULL,
3540                                                         name, myport));
3541                         continue;
3542                 }
3543
3544                 sa = *cfg_obj_assockaddr(alternate);
3545                 if (isc_sockaddr_getport(&sa) == 0)
3546                         isc_sockaddr_setport(&sa, port);
3547                 CHECK(dns_resolver_addalternate(view->resolver, &sa,
3548                                                 NULL, 0));
3549         }
3550
3551  cleanup:
3552         return (result);
3553 }
3554
3555 static isc_result_t
3556 configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
3557                   const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype)
3558 {
3559         const cfg_obj_t *portobj;
3560         const cfg_obj_t *faddresses;
3561         const cfg_listelt_t *element;
3562         dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
3563         isc_sockaddrlist_t addresses;
3564         isc_sockaddr_t *sa;
3565         isc_result_t result;
3566         in_port_t port;
3567
3568         ISC_LIST_INIT(addresses);
3569
3570         /*
3571          * Determine which port to send forwarded requests to.
3572          */
3573         if (ns_g_lwresdonly && ns_g_port != 0)
3574                 port = ns_g_port;
3575         else
3576                 CHECKM(ns_config_getport(config, &port), "port");
3577
3578         if (forwarders != NULL) {
3579                 portobj = cfg_tuple_get(forwarders, "port");
3580                 if (cfg_obj_isuint32(portobj)) {
3581                         isc_uint32_t val = cfg_obj_asuint32(portobj);
3582                         if (val > ISC_UINT16_MAX) {
3583                                 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
3584                                             "port '%u' out of range", val);
3585                                 return (ISC_R_RANGE);
3586                         }
3587                         port = (in_port_t) val;
3588                 }
3589         }
3590
3591         faddresses = NULL;
3592         if (forwarders != NULL)
3593                 faddresses = cfg_tuple_get(forwarders, "addresses");
3594
3595         for (element = cfg_list_first(faddresses);
3596              element != NULL;
3597              element = cfg_list_next(element))
3598         {
3599                 const cfg_obj_t *forwarder = cfg_listelt_value(element);
3600                 sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t));
3601                 if (sa == NULL) {
3602                         result = ISC_R_NOMEMORY;
3603                         goto cleanup;
3604                 }
3605                 *sa = *cfg_obj_assockaddr(forwarder);
3606                 if (isc_sockaddr_getport(sa) == 0)
3607                         isc_sockaddr_setport(sa, port);
3608                 ISC_LINK_INIT(sa, link);
3609                 ISC_LIST_APPEND(addresses, sa, link);
3610         }
3611
3612         if (ISC_LIST_EMPTY(addresses)) {
3613                 if (forwardtype != NULL)
3614                         cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
3615                                     "no forwarders seen; disabling "
3616                                     "forwarding");
3617                 fwdpolicy = dns_fwdpolicy_none;
3618         } else {
3619                 if (forwardtype == NULL)
3620                         fwdpolicy = dns_fwdpolicy_first;
3621                 else {
3622                         const char *forwardstr = cfg_obj_asstring(forwardtype);
3623                         if (strcasecmp(forwardstr, "first") == 0)
3624                                 fwdpolicy = dns_fwdpolicy_first;
3625                         else if (strcasecmp(forwardstr, "only") == 0)
3626                                 fwdpolicy = dns_fwdpolicy_only;
3627                         else
3628                                 INSIST(0);
3629                 }
3630         }
3631
3632         result = dns_fwdtable_add(view->fwdtable, origin, &addresses,
3633                                   fwdpolicy);
3634         if (result != ISC_R_SUCCESS) {
3635                 char namebuf[DNS_NAME_FORMATSIZE];
3636                 dns_name_format(origin, namebuf, sizeof(namebuf));
3637                 cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
3638                             "could not set up forwarding for domain '%s': %s",
3639                             namebuf, isc_result_totext(result));
3640                 goto cleanup;
3641         }
3642
3643         result = ISC_R_SUCCESS;
3644
3645  cleanup:
3646
3647         while (!ISC_LIST_EMPTY(addresses)) {
3648                 sa = ISC_LIST_HEAD(addresses);
3649                 ISC_LIST_UNLINK(addresses, sa, link);
3650                 isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t));
3651         }
3652
3653         return (result);
3654 }
3655
3656 static isc_result_t
3657 get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
3658              dns_rdataclass_t *classp)
3659 {
3660         isc_result_t result = ISC_R_SUCCESS;
3661         const char *viewname;
3662         dns_rdataclass_t viewclass;
3663
3664         REQUIRE(namep != NULL && *namep == NULL);
3665         REQUIRE(classp != NULL);
3666
3667         if (vconfig != NULL) {
3668                 const cfg_obj_t *classobj = NULL;
3669
3670                 viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
3671                 classobj = cfg_tuple_get(vconfig, "class");
3672                 result = ns_config_getclass(classobj, dns_rdataclass_in,
3673                                             &viewclass);
3674         } else {
3675                 viewname = "_default";
3676                 viewclass = dns_rdataclass_in;
3677         }
3678
3679         *namep = viewname;
3680         *classp = viewclass;
3681
3682         return (result);
3683 }
3684
3685 /*
3686  * Find a view based on its configuration info and attach to it.
3687  *
3688  * If 'vconfig' is NULL, attach to the default view.
3689  */
3690 static isc_result_t
3691 find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
3692           dns_view_t **viewp)
3693 {
3694         isc_result_t result;
3695         const char *viewname = NULL;
3696         dns_rdataclass_t viewclass;
3697         dns_view_t *view = NULL;
3698
3699         result = get_viewinfo(vconfig, &viewname, &viewclass);
3700         if (result != ISC_R_SUCCESS)
3701                 return (result);
3702
3703         result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
3704         if (result != ISC_R_SUCCESS)
3705                 return (result);
3706
3707         *viewp = view;
3708         return (ISC_R_SUCCESS);
3709 }
3710
3711 /*
3712  * Create a new view and add it to the list.
3713  *
3714  * If 'vconfig' is NULL, create the default view.
3715  *
3716  * The view created is attached to '*viewp'.
3717  */
3718 static isc_result_t
3719 create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
3720             dns_view_t **viewp)
3721 {
3722         isc_result_t result;
3723         const char *viewname = NULL;
3724         dns_rdataclass_t viewclass;
3725         dns_view_t *view = NULL;
3726
3727         result = get_viewinfo(vconfig, &viewname, &viewclass);
3728         if (result != ISC_R_SUCCESS)
3729                 return (result);
3730
3731         result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
3732         if (result == ISC_R_SUCCESS)
3733                 return (ISC_R_EXISTS);
3734         if (result != ISC_R_NOTFOUND)
3735                 return (result);
3736         INSIST(view == NULL);
3737
3738         result = dns_view_create(ns_g_mctx, viewclass, viewname, &view);
3739         if (result != ISC_R_SUCCESS)
3740                 return (result);
3741
3742         ISC_LIST_APPEND(*viewlist, view, link);
3743         dns_view_attach(view, viewp);
3744         return (ISC_R_SUCCESS);
3745 }
3746
3747 /*
3748  * Configure or reconfigure a zone.
3749  */
3750 static isc_result_t
3751 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
3752                const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
3753                cfg_aclconfctx_t *aclconf, isc_boolean_t added)
3754 {
3755         dns_view_t *pview = NULL;       /* Production view */
3756         dns_zone_t *zone = NULL;        /* New or reused zone */
3757         dns_zone_t *raw = NULL;         /* New or reused raw zone */
3758         dns_zone_t *dupzone = NULL;
3759         const cfg_obj_t *options = NULL;
3760         const cfg_obj_t *zoptions = NULL;
3761         const cfg_obj_t *typeobj = NULL;
3762         const cfg_obj_t *forwarders = NULL;
3763         const cfg_obj_t *forwardtype = NULL;
3764         const cfg_obj_t *only = NULL;
3765         const cfg_obj_t *signing = NULL;
3766         isc_result_t result;
3767         isc_result_t tresult;
3768         isc_buffer_t buffer;
3769         dns_fixedname_t fixorigin;
3770         dns_name_t *origin;
3771         const char *zname;
3772         dns_rdataclass_t zclass;
3773         const char *ztypestr;
3774         isc_boolean_t is_rpz;
3775         dns_rpz_zone_t *rpz;
3776
3777         options = NULL;
3778         (void)cfg_map_get(config, "options", &options);
3779
3780         zoptions = cfg_tuple_get(zconfig, "options");
3781
3782         /*
3783          * Get the zone origin as a dns_name_t.
3784          */
3785         zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
3786         isc_buffer_constinit(&buffer, zname, strlen(zname));
3787         isc_buffer_add(&buffer, strlen(zname));
3788         dns_fixedname_init(&fixorigin);
3789         CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin),
3790                                 &buffer, dns_rootname, 0, NULL));
3791         origin = dns_fixedname_name(&fixorigin);
3792
3793         CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
3794                                  view->rdclass, &zclass));
3795         if (zclass != view->rdclass) {
3796                 const char *vname = NULL;
3797                 if (vconfig != NULL)
3798                         vname = cfg_obj_asstring(cfg_tuple_get(vconfig,
3799                                                                "name"));
3800                 else
3801                         vname = "<default view>";
3802
3803                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3804                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3805                               "zone '%s': wrong class for view '%s'",
3806                               zname, vname);
3807                 result = ISC_R_FAILURE;
3808                 goto cleanup;
3809         }
3810
3811         (void)cfg_map_get(zoptions, "type", &typeobj);
3812         if (typeobj == NULL) {
3813                 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
3814                             "zone '%s' 'type' not specified", zname);
3815                 return (ISC_R_FAILURE);
3816         }
3817         ztypestr = cfg_obj_asstring(typeobj);
3818
3819         /*
3820          * "hints zones" aren't zones.  If we've got one,
3821          * configure it and return.
3822          */
3823         if (strcasecmp(ztypestr, "hint") == 0) {
3824                 const cfg_obj_t *fileobj = NULL;
3825                 if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
3826                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3827                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3828                                       "zone '%s': 'file' not specified",
3829                                       zname);
3830                         result = ISC_R_FAILURE;
3831                         goto cleanup;
3832                 }
3833                 if (dns_name_equal(origin, dns_rootname)) {
3834                         const char *hintsfile = cfg_obj_asstring(fileobj);
3835
3836                         result = configure_hints(view, hintsfile);
3837                         if (result != ISC_R_SUCCESS) {
3838                                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3839                                               NS_LOGMODULE_SERVER,
3840                                               ISC_LOG_ERROR,
3841                                               "could not configure root hints "
3842                                               "from '%s': %s", hintsfile,
3843                                               isc_result_totext(result));
3844                                 goto cleanup;
3845                         }
3846                         /*
3847                          * Hint zones may also refer to delegation only points.
3848                          */
3849                         only = NULL;
3850                         tresult = cfg_map_get(zoptions, "delegation-only",
3851                                               &only);
3852                         if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
3853                                 CHECK(dns_view_adddelegationonly(view, origin));
3854                 } else {
3855                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3856                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
3857                                       "ignoring non-root hint zone '%s'",
3858                                       zname);
3859                         result = ISC_R_SUCCESS;
3860                 }
3861                 /* Skip ordinary zone processing. */
3862                 goto cleanup;
3863         }
3864
3865         /*
3866          * "forward zones" aren't zones either.  Translate this syntax into
3867          * the appropriate selective forwarding configuration and return.
3868          */
3869         if (strcasecmp(ztypestr, "forward") == 0) {
3870                 forwardtype = NULL;
3871                 forwarders = NULL;
3872
3873                 (void)cfg_map_get(zoptions, "forward", &forwardtype);
3874                 (void)cfg_map_get(zoptions, "forwarders", &forwarders);
3875                 result = configure_forward(config, view, origin, forwarders,
3876                                            forwardtype);
3877                 goto cleanup;
3878         }
3879
3880         /*
3881          * "delegation-only zones" aren't zones either.
3882          */
3883         if (strcasecmp(ztypestr, "delegation-only") == 0) {
3884                 result = dns_view_adddelegationonly(view, origin);
3885                 goto cleanup;
3886         }
3887
3888         /*
3889          * Redirect zones only require minimal configuration.
3890          */
3891         if (strcasecmp(ztypestr, "redirect") == 0) {
3892                 if (view->redirect != NULL) {
3893                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
3894                                     "redirect zone already exists");
3895                         result = ISC_R_EXISTS;
3896                         goto cleanup;
3897                 }
3898                 result = dns_viewlist_find(&ns_g_server->viewlist, view->name,
3899                                            view->rdclass, &pview);
3900                 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
3901                         goto cleanup;
3902                 if (pview != NULL && pview->redirect != NULL) {
3903                         dns_zone_attach(pview->redirect, &zone);
3904                         dns_zone_setview(zone, view);
3905                 } else {
3906                         CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr,
3907                                                      &zone));
3908                         CHECK(dns_zone_setorigin(zone, origin));
3909                         dns_zone_setview(zone, view);
3910                         CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr,
3911                                                      zone));
3912                         dns_zone_setstats(zone, ns_g_server->zonestats);
3913                 }
3914                 CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf,
3915                                         zone, NULL));
3916                 dns_zone_attach(zone, &view->redirect);
3917                 goto cleanup;
3918         }
3919
3920         /*
3921          * Check for duplicates in the new zone table.
3922          */
3923         result = dns_view_findzone(view, origin, &dupzone);
3924         if (result == ISC_R_SUCCESS) {
3925                 /*
3926                  * We already have this zone!
3927                  */
3928                 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
3929                             "zone '%s' already exists", zname);
3930                 dns_zone_detach(&dupzone);
3931                 result = ISC_R_EXISTS;
3932                 goto cleanup;
3933         }
3934         INSIST(dupzone == NULL);
3935
3936         /*
3937          * Note whether this is a response policy zone.
3938          */
3939         is_rpz = ISC_FALSE;
3940         for (rpz = ISC_LIST_HEAD(view->rpz_zones);
3941              rpz != NULL;
3942              rpz = ISC_LIST_NEXT(rpz, link))
3943         {
3944                 if (dns_name_equal(&rpz->origin, origin)) {
3945                         is_rpz = ISC_TRUE;
3946                         rpz->defined = ISC_TRUE;
3947                         break;
3948                 }
3949         }
3950
3951         /*
3952          * See if we can reuse an existing zone.  This is
3953          * only possible if all of these are true:
3954          *   - The zone's view exists
3955          *   - A zone with the right name exists in the view
3956          *   - The zone is compatible with the config
3957          *     options (e.g., an existing master zone cannot
3958          *     be reused if the options specify a slave zone)
3959          *   - The zone was and is or was not and is not a policy zone
3960          */
3961         result = dns_viewlist_find(&ns_g_server->viewlist, view->name,
3962                                    view->rdclass, &pview);
3963         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
3964                 goto cleanup;
3965         if (pview != NULL)
3966                 result = dns_view_findzone(pview, origin, &zone);
3967         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
3968                 goto cleanup;
3969
3970         if (zone != NULL && !ns_zone_reusable(zone, zconfig))
3971                 dns_zone_detach(&zone);
3972
3973         if (zone != NULL && is_rpz != dns_zone_get_rpz(zone))
3974                 dns_zone_detach(&zone);
3975
3976         if (zone != NULL) {
3977                 /*
3978                  * We found a reusable zone.  Make it use the
3979                  * new view.
3980                  */
3981                 dns_zone_setview(zone, view);
3982                 if (view->acache != NULL)
3983                         dns_zone_setacache(zone, view->acache);
3984         } else {
3985                 /*
3986                  * We cannot reuse an existing zone, we have
3987                  * to create a new one.
3988                  */
3989                 CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
3990                 CHECK(dns_zone_setorigin(zone, origin));
3991                 dns_zone_setview(zone, view);
3992                 if (view->acache != NULL)
3993                         dns_zone_setacache(zone, view->acache);
3994                 CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
3995                 dns_zone_setstats(zone, ns_g_server->zonestats);
3996         }
3997
3998         if (is_rpz) {
3999                 result = dns_zone_rpz_enable(zone);
4000                 if (result != ISC_R_SUCCESS) {
4001                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4002                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4003                                       "zone '%s': incompatible"
4004                                       " masterfile-format or database"
4005                                       " for a response policy zone",
4006                                       zname);
4007                         goto cleanup;
4008                 }
4009         }
4010
4011         /*
4012          * If the zone contains a 'forwarders' statement, configure
4013          * selective forwarding.
4014          */
4015         forwarders = NULL;
4016         if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS)
4017         {
4018                 forwardtype = NULL;
4019                 (void)cfg_map_get(zoptions, "forward", &forwardtype);
4020                 CHECK(configure_forward(config, view, origin, forwarders,
4021                                         forwardtype));
4022         }
4023
4024         /*
4025          * Stub and forward zones may also refer to delegation only points.
4026          */
4027         only = NULL;
4028         if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS)
4029         {
4030                 if (cfg_obj_asboolean(only))
4031                         CHECK(dns_view_adddelegationonly(view, origin));
4032         }
4033
4034         /*
4035          * Mark whether the zone was originally added at runtime or not
4036          */
4037         dns_zone_setadded(zone, added);
4038
4039         signing = NULL;
4040         if ((strcasecmp(ztypestr, "master") == 0 ||
4041              strcasecmp(ztypestr, "slave") == 0) &&
4042             cfg_map_get(zoptions, "inline-signing", &signing) == ISC_R_SUCCESS &&
4043             cfg_obj_asboolean(signing))
4044         {
4045                 dns_zone_getraw(zone, &raw);
4046                 if (raw == NULL) {
4047                         CHECK(dns_zone_create(&raw, mctx));
4048                         CHECK(dns_zone_setorigin(raw, origin));
4049                         dns_zone_setview(raw, view);
4050                         if (view->acache != NULL)
4051                                 dns_zone_setacache(raw, view->acache);
4052                         dns_zone_setstats(raw, ns_g_server->zonestats);
4053                         CHECK(dns_zone_link(zone, raw));
4054                 }
4055         }
4056
4057         /*
4058          * Configure the zone.
4059          */
4060         CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone, raw));
4061
4062         /*
4063          * Add the zone to its view in the new view list.
4064          */
4065         CHECK(dns_view_addzone(view, zone));
4066
4067         /*
4068          * Ensure that zone keys are reloaded on reconfig
4069          */
4070         if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0)
4071                 dns_zone_rekey(zone, ISC_FALSE);
4072
4073  cleanup:
4074         if (zone != NULL)
4075                 dns_zone_detach(&zone);
4076         if (raw != NULL)
4077                 dns_zone_detach(&raw);
4078         if (pview != NULL)
4079                 dns_view_detach(&pview);
4080
4081         return (result);
4082 }
4083
4084 /*
4085  * Configure built-in zone for storing managed-key data.
4086  */
4087
4088 #define KEYZONE "managed-keys.bind"
4089 #define MKEYS ".mkeys"
4090
4091 static isc_result_t
4092 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
4093         isc_result_t result;
4094         dns_view_t *pview = NULL;
4095         dns_zone_t *zone = NULL;
4096         dns_acl_t *none = NULL;
4097         char filename[PATH_MAX];
4098         char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(MKEYS)];
4099         int n;
4100
4101         REQUIRE(view != NULL);
4102
4103         /* See if we can re-use an existing keydata zone. */
4104         result = dns_viewlist_find(&ns_g_server->viewlist,
4105                                    view->name, view->rdclass,
4106                                    &pview);
4107         if (result != ISC_R_NOTFOUND &&
4108             result != ISC_R_SUCCESS)
4109                 return (result);
4110
4111         if (pview != NULL && pview->managed_keys != NULL) {
4112                 dns_zone_attach(pview->managed_keys, &view->managed_keys);
4113                 dns_zone_setview(pview->managed_keys, view);
4114                 dns_view_detach(&pview);
4115                 dns_zone_synckeyzone(view->managed_keys);
4116                 return (ISC_R_SUCCESS);
4117         }
4118
4119         /* No existing keydata zone was found; create one */
4120         CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
4121         CHECK(dns_zone_setorigin(zone, dns_rootname));
4122
4123         isc_sha256_data((void *)view->name, strlen(view->name), buffer);
4124         strcat(buffer, MKEYS);
4125         n = snprintf(filename, sizeof(filename), "%s%s%s",
4126                      directory ? directory : "", directory ? "/" : "",
4127                      strcmp(view->name, "_default") == 0 ? KEYZONE : buffer);
4128         if (n < 0 || (size_t)n >= sizeof(filename)) {
4129                 result = (n < 0) ? ISC_R_FAILURE : ISC_R_NOSPACE;
4130                 goto cleanup;
4131         }
4132         CHECK(dns_zone_setfile(zone, filename));
4133
4134         dns_zone_setview(zone, view);
4135         dns_zone_settype(zone, dns_zone_key);
4136         dns_zone_setclass(zone, view->rdclass);
4137
4138         CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
4139
4140         if (view->acache != NULL)
4141                 dns_zone_setacache(zone, view->acache);
4142
4143         CHECK(dns_acl_none(mctx, &none));
4144         dns_zone_setqueryacl(zone, none);
4145         dns_zone_setqueryonacl(zone, none);
4146         dns_acl_detach(&none);
4147
4148         dns_zone_setdialup(zone, dns_dialuptype_no);
4149         dns_zone_setnotifytype(zone, dns_notifytype_no);
4150         dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
4151         dns_zone_setjournalsize(zone, 0);
4152
4153         dns_zone_setstats(zone, ns_g_server->zonestats);
4154         CHECK(setquerystats(zone, mctx, dns_zonestat_none));
4155
4156         if (view->managed_keys != NULL)
4157                 dns_zone_detach(&view->managed_keys);
4158         dns_zone_attach(zone, &view->managed_keys);
4159
4160         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4161                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4162                       "set up managed keys zone for view %s, file '%s'",
4163                       view->name, filename);
4164
4165 cleanup:
4166         if (zone != NULL)
4167                 dns_zone_detach(&zone);
4168         if (none != NULL)
4169                 dns_acl_detach(&none);
4170
4171         return (result);
4172 }
4173
4174 /*
4175  * Configure a single server quota.
4176  */
4177 static void
4178 configure_server_quota(const cfg_obj_t **maps, const char *name,
4179                        isc_quota_t *quota)
4180 {
4181         const cfg_obj_t *obj = NULL;
4182         isc_result_t result;
4183
4184         result = ns_config_get(maps, name, &obj);
4185         INSIST(result == ISC_R_SUCCESS);
4186         isc_quota_max(quota, cfg_obj_asuint32(obj));
4187 }
4188
4189 /*
4190  * This function is called as soon as the 'directory' statement has been
4191  * parsed.  This can be extended to support other options if necessary.
4192  */
4193 static isc_result_t
4194 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
4195         isc_result_t result;
4196         const char *directory;
4197
4198         REQUIRE(strcasecmp("directory", clausename) == 0);
4199
4200         UNUSED(arg);
4201         UNUSED(clausename);
4202
4203         /*
4204          * Change directory.
4205          */
4206         directory = cfg_obj_asstring(obj);
4207
4208         if (! isc_file_ischdiridempotent(directory))
4209                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
4210                             "option 'directory' contains relative path '%s'",
4211                             directory);
4212
4213         result = isc_dir_chdir(directory);
4214         if (result != ISC_R_SUCCESS) {
4215                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
4216                             "change directory to '%s' failed: %s",
4217                             directory, isc_result_totext(result));
4218                 return (result);
4219         }
4220
4221         return (ISC_R_SUCCESS);
4222 }
4223
4224 static void
4225 scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
4226         isc_boolean_t match_mapped = server->aclenv.match_mapped;
4227
4228         ns_interfacemgr_scan(server->interfacemgr, verbose);
4229         /*
4230          * Update the "localhost" and "localnets" ACLs to match the
4231          * current set of network interfaces.
4232          */
4233         dns_aclenv_copy(&server->aclenv,
4234                         ns_interfacemgr_getaclenv(server->interfacemgr));
4235
4236         server->aclenv.match_mapped = match_mapped;
4237 }
4238
4239 static isc_result_t
4240 add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr,
4241               isc_boolean_t wcardport_ok)
4242 {
4243         ns_listenelt_t *lelt = NULL;
4244         dns_acl_t *src_acl = NULL;
4245         isc_result_t result;
4246         isc_sockaddr_t any_sa6;
4247         isc_netaddr_t netaddr;
4248
4249         REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
4250
4251         isc_sockaddr_any6(&any_sa6);
4252         if (!isc_sockaddr_equal(&any_sa6, addr) &&
4253             (wcardport_ok || isc_sockaddr_getport(addr) != 0)) {
4254                 isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr);
4255
4256                 result = dns_acl_create(mctx, 0, &src_acl);
4257                 if (result != ISC_R_SUCCESS)
4258                         return (result);
4259
4260                 result = dns_iptable_addprefix(src_acl->iptable,
4261                                                &netaddr, 128, ISC_TRUE);
4262                 if (result != ISC_R_SUCCESS)
4263                         goto clean;
4264
4265                 result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr),
4266                                              src_acl, &lelt);
4267                 if (result != ISC_R_SUCCESS)
4268                         goto clean;
4269                 ISC_LIST_APPEND(list->elts, lelt, link);
4270         }
4271
4272         return (ISC_R_SUCCESS);
4273
4274  clean:
4275         INSIST(lelt == NULL);
4276         dns_acl_detach(&src_acl);
4277
4278         return (result);
4279 }
4280
4281 /*
4282  * Make a list of xxx-source addresses and call ns_interfacemgr_adjust()
4283  * to update the listening interfaces accordingly.
4284  * We currently only consider IPv6, because this only affects IPv6 wildcard
4285  * sockets.
4286  */
4287 static void
4288 adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
4289         isc_result_t result;
4290         ns_listenlist_t *list = NULL;
4291         dns_view_t *view;
4292         dns_zone_t *zone, *next;
4293         isc_sockaddr_t addr, *addrp;
4294
4295         result = ns_listenlist_create(mctx, &list);
4296         if (result != ISC_R_SUCCESS)
4297                 return;
4298
4299         for (view = ISC_LIST_HEAD(server->viewlist);
4300              view != NULL;
4301              view = ISC_LIST_NEXT(view, link)) {
4302                 dns_dispatch_t *dispatch6;
4303
4304                 dispatch6 = dns_resolver_dispatchv6(view->resolver);
4305                 if (dispatch6 == NULL)
4306                         continue;
4307                 result = dns_dispatch_getlocaladdress(dispatch6, &addr);
4308                 if (result != ISC_R_SUCCESS)
4309                         goto fail;
4310
4311                 /*
4312                  * We always add non-wildcard address regardless of whether
4313                  * the port is 'any' (the fourth arg is TRUE): if the port is
4314                  * specific, we need to add it since it may conflict with a
4315                  * listening interface; if it's zero, we'll dynamically open
4316                  * query ports, and some of them may override an existing
4317                  * wildcard IPv6 port.
4318                  */
4319                 result = add_listenelt(mctx, list, &addr, ISC_TRUE);
4320                 if (result != ISC_R_SUCCESS)
4321                         goto fail;
4322         }
4323
4324         zone = NULL;
4325         for (result = dns_zone_first(server->zonemgr, &zone);
4326              result == ISC_R_SUCCESS;
4327              next = NULL, result = dns_zone_next(zone, &next), zone = next) {
4328                 dns_view_t *zoneview;
4329
4330                 /*
4331                  * At this point the zone list may contain a stale zone
4332                  * just removed from the configuration.  To see the validity,
4333                  * check if the corresponding view is in our current view list.
4334                  * There may also be old zones that are still in the process
4335                  * of shutting down and have detached from their old view
4336                  * (zoneview == NULL).
4337                  */
4338                 zoneview = dns_zone_getview(zone);
4339                 if (zoneview == NULL)
4340                         continue;
4341                 for (view = ISC_LIST_HEAD(server->viewlist);
4342                      view != NULL && view != zoneview;
4343                      view = ISC_LIST_NEXT(view, link))
4344                         ;
4345                 if (view == NULL)
4346                         continue;
4347
4348                 addrp = dns_zone_getnotifysrc6(zone);
4349                 result = add_listenelt(mctx, list, addrp, ISC_FALSE);
4350                 if (result != ISC_R_SUCCESS)
4351                         goto fail;
4352
4353                 addrp = dns_zone_getxfrsource6(zone);
4354                 result = add_listenelt(mctx, list, addrp, ISC_FALSE);
4355                 if (result != ISC_R_SUCCESS)
4356                         goto fail;
4357         }
4358
4359         ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE);
4360
4361  clean:
4362         ns_listenlist_detach(&list);
4363         return;
4364
4365  fail:
4366         /*
4367          * Even when we failed the procedure, most of other interfaces
4368          * should work correctly.  We therefore just warn it.
4369          */
4370         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4371                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
4372                       "could not adjust the listen-on list; "
4373                       "some interfaces may not work");
4374         goto clean;
4375 }
4376
4377 /*
4378  * This event callback is invoked to do periodic network
4379  * interface scanning.
4380  */
4381 static void
4382 interface_timer_tick(isc_task_t *task, isc_event_t *event) {
4383         isc_result_t result;
4384         ns_server_t *server = (ns_server_t *) event->ev_arg;
4385         INSIST(task == server->task);
4386         UNUSED(task);
4387         isc_event_free(&event);
4388         /*
4389          * XXX should scan interfaces unlocked and get exclusive access
4390          * only to replace ACLs.
4391          */
4392         result = isc_task_beginexclusive(server->task);
4393         RUNTIME_CHECK(result == ISC_R_SUCCESS);
4394         scan_interfaces(server, ISC_FALSE);
4395         isc_task_endexclusive(server->task);
4396 }
4397
4398 static void
4399 heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
4400         ns_server_t *server = (ns_server_t *) event->ev_arg;
4401         dns_view_t *view;
4402
4403         UNUSED(task);
4404         isc_event_free(&event);
4405         view = ISC_LIST_HEAD(server->viewlist);
4406         while (view != NULL) {
4407                 dns_view_dialup(view);
4408                 view = ISC_LIST_NEXT(view, link);
4409         }
4410 }
4411
4412 static void
4413 pps_timer_tick(isc_task_t *task, isc_event_t *event) {
4414         static unsigned int oldrequests = 0;
4415         unsigned int requests = ns_client_requests;
4416
4417         UNUSED(task);
4418         isc_event_free(&event);
4419
4420         /*
4421          * Don't worry about wrapping as the overflow result will be right.
4422          */
4423         dns_pps = (requests - oldrequests) / 1200;
4424         oldrequests = requests;
4425 }
4426
4427 /*
4428  * Replace the current value of '*field', a dynamically allocated
4429  * string or NULL, with a dynamically allocated copy of the
4430  * null-terminated string pointed to by 'value', or NULL.
4431  */
4432 static isc_result_t
4433 setstring(ns_server_t *server, char **field, const char *value) {
4434         char *copy;
4435
4436         if (value != NULL) {
4437                 copy = isc_mem_strdup(server->mctx, value);
4438                 if (copy == NULL)
4439                         return (ISC_R_NOMEMORY);
4440         } else {
4441                 copy = NULL;
4442         }
4443
4444         if (*field != NULL)
4445                 isc_mem_free(server->mctx, *field);
4446
4447         *field = copy;
4448         return (ISC_R_SUCCESS);
4449 }
4450
4451 /*
4452  * Replace the current value of '*field', a dynamically allocated
4453  * string or NULL, with another dynamically allocated string
4454  * or NULL if whether 'obj' is a string or void value, respectively.
4455  */
4456 static isc_result_t
4457 setoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) {
4458         if (cfg_obj_isvoid(obj))
4459                 return (setstring(server, field, NULL));
4460         else
4461                 return (setstring(server, field, cfg_obj_asstring(obj)));
4462 }
4463
4464 static void
4465 set_limit(const cfg_obj_t **maps, const char *configname,
4466           const char *description, isc_resource_t resourceid,
4467           isc_resourcevalue_t defaultvalue)
4468 {
4469         const cfg_obj_t *obj = NULL;
4470         const char *resource;
4471         isc_resourcevalue_t value;
4472         isc_result_t result;
4473
4474         if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS)
4475                 return;
4476
4477         if (cfg_obj_isstring(obj)) {
4478                 resource = cfg_obj_asstring(obj);
4479                 if (strcasecmp(resource, "unlimited") == 0)
4480                         value = ISC_RESOURCE_UNLIMITED;
4481                 else {
4482                         INSIST(strcasecmp(resource, "default") == 0);
4483                         value = defaultvalue;
4484                 }
4485         } else
4486                 value = cfg_obj_asuint64(obj);
4487
4488         result = isc_resource_setlimit(resourceid, value);
4489         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
4490                       result == ISC_R_SUCCESS ?
4491                         ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
4492                       "set maximum %s to %" ISC_PRINT_QUADFORMAT "u: %s",
4493                       description, value, isc_result_totext(result));
4494 }
4495
4496 #define SETLIMIT(cfgvar, resource, description) \
4497         set_limit(maps, cfgvar, description, isc_resource_ ## resource, \
4498                   ns_g_init ## resource)
4499
4500 static void
4501 set_limits(const cfg_obj_t **maps) {
4502         SETLIMIT("stacksize", stacksize, "stack size");
4503         SETLIMIT("datasize", datasize, "data size");
4504         SETLIMIT("coresize", coresize, "core size");
4505         SETLIMIT("files", openfiles, "open files");
4506 }
4507
4508 static void
4509 portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
4510                  isc_boolean_t positive)
4511 {
4512         const cfg_listelt_t *element;
4513
4514         for (element = cfg_list_first(ports);
4515              element != NULL;
4516              element = cfg_list_next(element)) {
4517                 const cfg_obj_t *obj = cfg_listelt_value(element);
4518
4519                 if (cfg_obj_isuint32(obj)) {
4520                         in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
4521
4522                         if (positive)
4523                                 isc_portset_add(portset, port);
4524                         else
4525                                 isc_portset_remove(portset, port);
4526                 } else {
4527                         const cfg_obj_t *obj_loport, *obj_hiport;
4528                         in_port_t loport, hiport;
4529
4530                         obj_loport = cfg_tuple_get(obj, "loport");
4531                         loport = (in_port_t)cfg_obj_asuint32(obj_loport);
4532                         obj_hiport = cfg_tuple_get(obj, "hiport");
4533                         hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
4534
4535                         if (positive)
4536                                 isc_portset_addrange(portset, loport, hiport);
4537                         else {
4538                                 isc_portset_removerange(portset, loport,
4539                                                         hiport);
4540                         }
4541                 }
4542         }
4543 }
4544
4545 static isc_result_t
4546 removed(dns_zone_t *zone, void *uap) {
4547         const char *type;
4548
4549         if (dns_zone_getview(zone) != uap)
4550                 return (ISC_R_SUCCESS);
4551
4552         switch (dns_zone_gettype(zone)) {
4553         case dns_zone_master:
4554                 type = "master";
4555                 break;
4556         case dns_zone_slave:
4557                 type = "slave";
4558                 break;
4559         case dns_zone_stub:
4560                 type = "stub";
4561                 break;
4562         case dns_zone_redirect:
4563                 type = "redirect";
4564                 break;
4565         default:
4566                 type = "other";
4567                 break;
4568         }
4569         dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type);
4570         return (ISC_R_SUCCESS);
4571 }
4572
4573 static void
4574 cleanup_session_key(ns_server_t *server, isc_mem_t *mctx) {
4575         if (server->session_keyfile != NULL) {
4576                 isc_file_remove(server->session_keyfile);
4577                 isc_mem_free(mctx, server->session_keyfile);
4578                 server->session_keyfile = NULL;
4579         }
4580
4581         if (server->session_keyname != NULL) {
4582                 if (dns_name_dynamic(server->session_keyname))
4583                         dns_name_free(server->session_keyname, mctx);
4584                 isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
4585                 server->session_keyname = NULL;
4586         }
4587
4588         if (server->sessionkey != NULL)
4589                 dns_tsigkey_detach(&server->sessionkey);
4590
4591         server->session_keyalg = DST_ALG_UNKNOWN;
4592         server->session_keybits = 0;
4593 }
4594
4595 static isc_result_t
4596 generate_session_key(const char *filename, const char *keynamestr,
4597                      dns_name_t *keyname, const char *algstr,
4598                      dns_name_t *algname, unsigned int algtype,
4599                      isc_uint16_t bits, isc_mem_t *mctx,
4600                      dns_tsigkey_t **tsigkeyp)
4601 {
4602         isc_result_t result = ISC_R_SUCCESS;
4603         dst_key_t *key = NULL;
4604         isc_buffer_t key_txtbuffer;
4605         isc_buffer_t key_rawbuffer;
4606         char key_txtsecret[256];
4607         char key_rawsecret[64];
4608         isc_region_t key_rawregion;
4609         isc_stdtime_t now;
4610         dns_tsigkey_t *tsigkey = NULL;
4611         FILE *fp = NULL;
4612
4613         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4614                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4615                       "generating session key for dynamic DNS");
4616
4617         /* generate key */
4618         result = dst_key_generate(keyname, algtype, bits, 1, 0,
4619                                   DNS_KEYPROTO_ANY, dns_rdataclass_in,
4620                                   mctx, &key);
4621         if (result != ISC_R_SUCCESS)
4622                 return (result);
4623
4624         /*
4625          * Dump the key to the buffer for later use.  Should be done before
4626          * we transfer the ownership of key to tsigkey.
4627          */
4628         isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
4629         CHECK(dst_key_tobuffer(key, &key_rawbuffer));
4630
4631         isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
4632         isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
4633         CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
4634
4635         /* Store the key in tsigkey. */
4636         isc_stdtime_get(&now);
4637         CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key,
4638                                         ISC_FALSE, NULL, now, now, mctx, NULL,
4639                                         &tsigkey));
4640
4641         /* Dump the key to the key file. */
4642         fp = ns_os_openfile(filename, S_IRUSR|S_IWUSR, ISC_TRUE);
4643         if (fp == NULL) {
4644                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4645                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4646                               "could not create %s", filename);
4647                 result = ISC_R_NOPERM;
4648                 goto cleanup;
4649         }
4650
4651         fprintf(fp, "key \"%s\" {\n"
4652                 "\talgorithm %s;\n"
4653                 "\tsecret \"%.*s\";\n};\n", keynamestr, algstr,
4654                 (int) isc_buffer_usedlength(&key_txtbuffer),
4655                 (char*) isc_buffer_base(&key_txtbuffer));
4656
4657         RUNTIME_CHECK(isc_stdio_flush(fp) == ISC_R_SUCCESS);
4658         RUNTIME_CHECK(isc_stdio_close(fp) == ISC_R_SUCCESS);
4659
4660         dst_key_free(&key);
4661
4662         *tsigkeyp = tsigkey;
4663
4664         return (ISC_R_SUCCESS);
4665
4666   cleanup:
4667         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4668                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
4669                       "failed to generate session key "
4670                       "for dynamic DNS: %s", isc_result_totext(result));
4671         if (tsigkey != NULL)
4672                 dns_tsigkey_detach(&tsigkey);
4673         if (key != NULL)
4674                 dst_key_free(&key);
4675
4676         return (result);
4677 }
4678
4679 static isc_result_t
4680 configure_session_key(const cfg_obj_t **maps, ns_server_t *server,
4681                       isc_mem_t *mctx)
4682 {
4683         const char *keyfile, *keynamestr, *algstr;
4684         unsigned int algtype;
4685         dns_fixedname_t fname;
4686         dns_name_t *keyname, *algname;
4687         isc_buffer_t buffer;
4688         isc_uint16_t bits;
4689         const cfg_obj_t *obj;
4690         isc_boolean_t need_deleteold = ISC_FALSE;
4691         isc_boolean_t need_createnew = ISC_FALSE;
4692         isc_result_t result;
4693
4694         obj = NULL;
4695         result = ns_config_get(maps, "session-keyfile", &obj);
4696         if (result == ISC_R_SUCCESS) {
4697                 if (cfg_obj_isvoid(obj))
4698                         keyfile = NULL; /* disable it */
4699                 else
4700                         keyfile = cfg_obj_asstring(obj);
4701         } else
4702                 keyfile = ns_g_defaultsessionkeyfile;
4703
4704         obj = NULL;
4705         result = ns_config_get(maps, "session-keyname", &obj);
4706         INSIST(result == ISC_R_SUCCESS);
4707         keynamestr = cfg_obj_asstring(obj);
4708         dns_fixedname_init(&fname);
4709         isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
4710         isc_buffer_add(&buffer, strlen(keynamestr));
4711         keyname = dns_fixedname_name(&fname);
4712         result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
4713         if (result != ISC_R_SUCCESS)
4714                 return (result);
4715
4716         obj = NULL;
4717         result = ns_config_get(maps, "session-keyalg", &obj);
4718         INSIST(result == ISC_R_SUCCESS);
4719         algstr = cfg_obj_asstring(obj);
4720         algname = NULL;
4721         result = ns_config_getkeyalgorithm2(algstr, &algname, &algtype, &bits);
4722         if (result != ISC_R_SUCCESS) {
4723                 const char *s = " (keeping current key)";
4724
4725                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "session-keyalg: "
4726                             "unsupported or unknown algorithm '%s'%s",
4727                             algstr,
4728                             server->session_keyfile != NULL ? s : "");
4729                 return (result);
4730         }
4731
4732         /* See if we need to (re)generate a new key. */
4733         if (keyfile == NULL) {
4734                 if (server->session_keyfile != NULL)
4735                         need_deleteold = ISC_TRUE;
4736         } else if (server->session_keyfile == NULL)
4737                 need_createnew = ISC_TRUE;
4738         else if (strcmp(keyfile, server->session_keyfile) != 0 ||
4739                  !dns_name_equal(server->session_keyname, keyname) ||
4740                  server->session_keyalg != algtype ||
4741                  server->session_keybits != bits) {
4742                 need_deleteold = ISC_TRUE;
4743                 need_createnew = ISC_TRUE;
4744         }
4745
4746         if (need_deleteold) {
4747                 INSIST(server->session_keyfile != NULL);
4748                 INSIST(server->session_keyname != NULL);
4749                 INSIST(server->sessionkey != NULL);
4750
4751                 cleanup_session_key(server, mctx);
4752         }
4753
4754         if (need_createnew) {
4755                 INSIST(server->sessionkey == NULL);
4756                 INSIST(server->session_keyfile == NULL);
4757                 INSIST(server->session_keyname == NULL);
4758                 INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
4759                 INSIST(server->session_keybits == 0);
4760
4761                 server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
4762                 if (server->session_keyname == NULL)
4763                         goto cleanup;
4764                 dns_name_init(server->session_keyname, NULL);
4765                 CHECK(dns_name_dup(keyname, mctx, server->session_keyname));
4766
4767                 server->session_keyfile = isc_mem_strdup(mctx, keyfile);
4768                 if (server->session_keyfile == NULL)
4769                         goto cleanup;
4770
4771                 server->session_keyalg = algtype;
4772                 server->session_keybits = bits;
4773
4774                 CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr,
4775                                            algname, algtype, bits, mctx,
4776                                            &server->sessionkey));
4777         }
4778
4779         return (result);
4780
4781   cleanup:
4782         cleanup_session_key(server, mctx);
4783         return (result);
4784 }
4785
4786 static isc_result_t
4787 setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
4788                cfg_parser_t *parser, cfg_aclconfctx_t *actx)
4789 {
4790         isc_result_t result = ISC_R_SUCCESS;
4791         isc_boolean_t allow = ISC_FALSE;
4792         struct cfg_context *nzcfg = NULL;
4793         cfg_parser_t *nzparser = NULL;
4794         cfg_obj_t *nzconfig = NULL;
4795         const cfg_obj_t *maps[4];
4796         const cfg_obj_t *options = NULL, *voptions = NULL;
4797         const cfg_obj_t *nz = NULL;
4798         int i = 0;
4799
4800         REQUIRE (config != NULL);
4801
4802         if (vconfig != NULL)
4803                 voptions = cfg_tuple_get(vconfig, "options");
4804         if (voptions != NULL)
4805                 maps[i++] = voptions;
4806         result = cfg_map_get(config, "options", &options);
4807         if (result == ISC_R_SUCCESS)
4808                 maps[i++] = options;
4809         maps[i++] = ns_g_defaults;
4810         maps[i] = NULL;
4811
4812         result = ns_config_get(maps, "allow-new-zones", &nz);
4813         if (result == ISC_R_SUCCESS)
4814                 allow = cfg_obj_asboolean(nz);
4815
4816         if (!allow) {
4817                 dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
4818                 return (ISC_R_SUCCESS);
4819         }
4820
4821         nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
4822         if (nzcfg == NULL) {
4823                 dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
4824                 return (ISC_R_NOMEMORY);
4825         }
4826
4827         dns_view_setnewzones(view, allow, nzcfg, newzone_cfgctx_destroy);
4828
4829         memset(nzcfg, 0, sizeof(*nzcfg));
4830         isc_mem_attach(view->mctx, &nzcfg->mctx);
4831         cfg_obj_attach(config, &nzcfg->config);
4832         cfg_parser_attach(parser, &nzcfg->parser);
4833         cfg_aclconfctx_attach(actx, &nzcfg->actx);
4834
4835         /*
4836          * Attempt to create a parser and parse the newzones
4837          * file.  If successful, preserve both; otherwise leave
4838          * them NULL.
4839          */
4840         result = cfg_parser_create(view->mctx, ns_g_lctx, &nzparser);
4841         if (result == ISC_R_SUCCESS)
4842                 result = cfg_parse_file(nzparser, view->new_zone_file,
4843                                         &cfg_type_newzones, &nzconfig);
4844         if (result == ISC_R_SUCCESS) {
4845                 cfg_parser_attach(nzparser, &nzcfg->nzparser);
4846                 cfg_obj_attach(nzconfig, &nzcfg->nzconfig);
4847         }
4848
4849         if (nzparser != NULL) {
4850                 if (nzconfig != NULL)
4851                         cfg_obj_destroy(nzparser, &nzconfig);
4852                 cfg_parser_destroy(&nzparser);
4853         }
4854
4855         return (ISC_R_SUCCESS);
4856 }
4857
4858 static int
4859 count_zones(const cfg_obj_t *conf) {
4860         const cfg_obj_t *zonelist = NULL;
4861         const cfg_listelt_t *element;
4862         int n = 0;
4863
4864         REQUIRE(conf != NULL);
4865
4866         cfg_map_get(conf, "zone", &zonelist);
4867         for (element = cfg_list_first(zonelist);
4868              element != NULL;
4869              element = cfg_list_next(element))
4870                 n++;
4871
4872         return (n);
4873 }
4874
4875 static isc_result_t
4876 load_configuration(const char *filename, ns_server_t *server,
4877                    isc_boolean_t first_time)
4878 {
4879         cfg_obj_t *config = NULL, *bindkeys = NULL;
4880         cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
4881         const cfg_listelt_t *element;
4882         const cfg_obj_t *builtin_views;
4883         const cfg_obj_t *maps[3];
4884         const cfg_obj_t *obj;
4885         const cfg_obj_t *options;
4886         const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
4887         const cfg_obj_t *views;
4888         dns_view_t *view = NULL;
4889         dns_view_t *view_next;
4890         dns_viewlist_t tmpviewlist;
4891         dns_viewlist_t viewlist, builtin_viewlist;
4892         in_port_t listen_port, udpport_low, udpport_high;
4893         int i;
4894         int num_zones = 0;
4895         isc_boolean_t exclusive = ISC_FALSE;
4896         isc_interval_t interval;
4897         isc_logconfig_t *logc = NULL;
4898         isc_portset_t *v4portset = NULL;
4899         isc_portset_t *v6portset = NULL;
4900         isc_resourcevalue_t nfiles;
4901         isc_result_t result;
4902         isc_uint32_t heartbeat_interval;
4903         isc_uint32_t interface_interval;
4904         isc_uint32_t reserved;
4905         isc_uint32_t udpsize;
4906         ns_cache_t *nsc;
4907         ns_cachelist_t cachelist, tmpcachelist;
4908         struct cfg_context *nzctx;
4909         unsigned int maxsocks;
4910
4911         ISC_LIST_INIT(viewlist);
4912         ISC_LIST_INIT(builtin_viewlist);
4913         ISC_LIST_INIT(cachelist);
4914
4915         /* Create the ACL configuration context */
4916         if (ns_g_aclconfctx != NULL)
4917                 cfg_aclconfctx_detach(&ns_g_aclconfctx);
4918         CHECK(cfg_aclconfctx_create(ns_g_mctx, &ns_g_aclconfctx));
4919
4920         /*
4921          * Parse the global default pseudo-config file.
4922          */
4923         if (first_time) {
4924                 CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config));
4925                 RUNTIME_CHECK(cfg_map_get(ns_g_config, "options",
4926                                           &ns_g_defaults) == ISC_R_SUCCESS);
4927         }
4928
4929         /*
4930          * Parse the configuration file using the new config code.
4931          */
4932         result = ISC_R_FAILURE;
4933         config = NULL;
4934
4935         /*
4936          * Unless this is lwresd with the -C option, parse the config file.
4937          */
4938         if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) {
4939                 isc_log_write(ns_g_lctx,
4940                               NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
4941                               ISC_LOG_INFO, "loading configuration from '%s'",
4942                               filename);
4943                 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser));
4944                 cfg_parser_setcallback(conf_parser, directory_callback, NULL);
4945                 result = cfg_parse_file(conf_parser, filename,
4946                                         &cfg_type_namedconf, &config);
4947         }
4948
4949         /*
4950          * If this is lwresd with the -C option, or lwresd with no -C or -c
4951          * option where the above parsing failed, parse resolv.conf.
4952          */
4953         if (ns_g_lwresdonly &&
4954             (lwresd_g_useresolvconf ||
4955              (!ns_g_conffileset && result == ISC_R_FILENOTFOUND)))
4956         {
4957                 isc_log_write(ns_g_lctx,
4958                               NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
4959                               ISC_LOG_INFO, "loading configuration from '%s'",
4960                               lwresd_g_resolvconffile);
4961                 if (conf_parser != NULL)
4962                         cfg_parser_destroy(&conf_parser);
4963                 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser));
4964                 result = ns_lwresd_parseeresolvconf(ns_g_mctx, conf_parser,
4965                                                     &config);
4966         }
4967         CHECK(result);
4968
4969         /*
4970          * Check the validity of the configuration.
4971          */
4972         CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx));
4973
4974         /*
4975          * Fill in the maps array, used for resolving defaults.
4976          */
4977         i = 0;
4978         options = NULL;
4979         result = cfg_map_get(config, "options", &options);
4980         if (result == ISC_R_SUCCESS)
4981                 maps[i++] = options;
4982         maps[i++] = ns_g_defaults;
4983         maps[i] = NULL;
4984
4985         /*
4986          * If bind.keys exists, load it.  If "dnssec-lookaside auto"
4987          * is turned on, the keys found there will be used as default
4988          * trust anchors.
4989          */
4990         obj = NULL;
4991         result = ns_config_get(maps, "bindkeys-file", &obj);
4992         INSIST(result == ISC_R_SUCCESS);
4993         CHECKM(setstring(server, &server->bindkeysfile,
4994                cfg_obj_asstring(obj)), "strdup");
4995
4996         if (access(server->bindkeysfile, R_OK) == 0) {
4997                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4998                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4999                               "reading built-in trusted "
5000                               "keys from file '%s'", server->bindkeysfile);
5001
5002                 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx,
5003                                         &bindkeys_parser));
5004
5005                 result = cfg_parse_file(bindkeys_parser, server->bindkeysfile,
5006                                         &cfg_type_bindkeys, &bindkeys);
5007                 CHECK(result);
5008         }
5009
5010         /* Ensure exclusive access to configuration data. */
5011         if (!exclusive) {
5012                 result = isc_task_beginexclusive(server->task);
5013                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
5014                 exclusive = ISC_TRUE;
5015         }
5016
5017         /*
5018          * Set process limits, which (usually) needs to be done as root.
5019          */
5020         set_limits(maps);
5021
5022         /*
5023          * Check if max number of open sockets that the system allows is
5024          * sufficiently large.  Failing this condition is not necessarily fatal,
5025          * but may cause subsequent runtime failures for a busy recursive
5026          * server.
5027          */
5028         result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &maxsocks);
5029         if (result != ISC_R_SUCCESS)
5030                 maxsocks = 0;
5031         result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles);
5032         if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) {
5033                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5034                               NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
5035                               "max open files (%" ISC_PRINT_QUADFORMAT "u)"
5036                               " is smaller than max sockets (%u)",
5037                               nfiles, maxsocks);
5038         }
5039
5040         /*
5041          * Set the number of socket reserved for TCP, stdio etc.
5042          */
5043         obj = NULL;
5044         result = ns_config_get(maps, "reserved-sockets", &obj);
5045         INSIST(result == ISC_R_SUCCESS);
5046         reserved = cfg_obj_asuint32(obj);
5047         if (maxsocks != 0) {
5048                 if (maxsocks < 128U)                    /* Prevent underflow. */
5049                         reserved = 0;
5050                 else if (reserved > maxsocks - 128U)    /* Minimum UDP space. */
5051                         reserved = maxsocks - 128;
5052         }
5053         /* Minimum TCP/stdio space. */
5054         if (reserved < 128U)
5055                 reserved = 128;
5056         if (reserved + 128U > maxsocks && maxsocks != 0) {
5057                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5058                               NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
5059                               "less than 128 UDP sockets available after "
5060                               "applying 'reserved-sockets' and 'maxsockets'");
5061         }
5062         isc__socketmgr_setreserved(ns_g_socketmgr, reserved);
5063
5064         /*
5065          * Configure various server options.
5066          */
5067         configure_server_quota(maps, "transfers-out", &server->xfroutquota);
5068         configure_server_quota(maps, "tcp-clients", &server->tcpquota);
5069         configure_server_quota(maps, "recursive-clients",
5070                                &server->recursionquota);
5071         if (server->recursionquota.max > 1000)
5072                 isc_quota_soft(&server->recursionquota,
5073                                server->recursionquota.max - 100);
5074         else
5075                 isc_quota_soft(&server->recursionquota, 0);
5076
5077         CHECK(configure_view_acl(NULL, config, "blackhole", NULL,
5078                                  ns_g_aclconfctx, ns_g_mctx,
5079                                  &server->blackholeacl));
5080         if (server->blackholeacl != NULL)
5081                 dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
5082                                              server->blackholeacl);
5083
5084         obj = NULL;
5085         result = ns_config_get(maps, "match-mapped-addresses", &obj);
5086         INSIST(result == ISC_R_SUCCESS);
5087         server->aclenv.match_mapped = cfg_obj_asboolean(obj);
5088
5089         CHECKM(ns_statschannels_configure(ns_g_server, config, ns_g_aclconfctx),
5090                "configuring statistics server(s)");
5091
5092         /*
5093          * Configure sets of UDP query source ports.
5094          */
5095         CHECKM(isc_portset_create(ns_g_mctx, &v4portset),
5096                "creating UDP port set");
5097         CHECKM(isc_portset_create(ns_g_mctx, &v6portset),
5098                "creating UDP port set");
5099
5100         usev4ports = NULL;
5101         usev6ports = NULL;
5102         avoidv4ports = NULL;
5103         avoidv6ports = NULL;
5104
5105         (void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports);
5106         if (usev4ports != NULL)
5107                 portset_fromconf(v4portset, usev4ports, ISC_TRUE);
5108         else {
5109                 CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
5110                                                &udpport_high),
5111                        "get the default UDP/IPv4 port range");
5112                 if (udpport_low == udpport_high)
5113                         isc_portset_add(v4portset, udpport_low);
5114                 else {
5115                         isc_portset_addrange(v4portset, udpport_low,
5116                                              udpport_high);
5117                 }
5118                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5119                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5120                               "using default UDP/IPv4 port range: [%d, %d]",
5121                               udpport_low, udpport_high);
5122         }
5123         (void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
5124         if (avoidv4ports != NULL)
5125                 portset_fromconf(v4portset, avoidv4ports, ISC_FALSE);
5126
5127         (void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports);
5128         if (usev6ports != NULL)
5129                 portset_fromconf(v6portset, usev6ports, ISC_TRUE);
5130         else {
5131                 CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
5132                                                &udpport_high),
5133                        "get the default UDP/IPv6 port range");
5134                 if (udpport_low == udpport_high)
5135                         isc_portset_add(v6portset, udpport_low);
5136                 else {
5137                         isc_portset_addrange(v6portset, udpport_low,
5138                                              udpport_high);
5139                 }
5140                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5141                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5142                               "using default UDP/IPv6 port range: [%d, %d]",
5143                               udpport_low, udpport_high);
5144         }
5145         (void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
5146         if (avoidv6ports != NULL)
5147                 portset_fromconf(v6portset, avoidv6ports, ISC_FALSE);
5148
5149         dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset);
5150
5151         /*
5152          * Set the EDNS UDP size when we don't match a view.
5153          */
5154         obj = NULL;
5155         result = ns_config_get(maps, "edns-udp-size", &obj);
5156         INSIST(result == ISC_R_SUCCESS);
5157         udpsize = cfg_obj_asuint32(obj);
5158         if (udpsize < 512)
5159                 udpsize = 512;
5160         if (udpsize > 4096)
5161                 udpsize = 4096;
5162         ns_g_udpsize = (isc_uint16_t)udpsize;
5163
5164         /*
5165          * Configure the zone manager.
5166          */
5167         obj = NULL;
5168         result = ns_config_get(maps, "transfers-in", &obj);
5169         INSIST(result == ISC_R_SUCCESS);
5170         dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
5171
5172         obj = NULL;
5173         result = ns_config_get(maps, "transfers-per-ns", &obj);
5174         INSIST(result == ISC_R_SUCCESS);
5175         dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
5176
5177         obj = NULL;
5178         result = ns_config_get(maps, "serial-query-rate", &obj);
5179         INSIST(result == ISC_R_SUCCESS);
5180         dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
5181
5182         /*
5183          * Determine which port to use for listening for incoming connections.
5184          */
5185         if (ns_g_port != 0)
5186                 listen_port = ns_g_port;
5187         else
5188                 CHECKM(ns_config_getport(config, &listen_port), "port");
5189
5190         /*
5191          * Find the listen queue depth.
5192          */
5193         obj = NULL;
5194         result = ns_config_get(maps, "tcp-listen-queue", &obj);
5195         INSIST(result == ISC_R_SUCCESS);
5196         ns_g_listen = cfg_obj_asuint32(obj);
5197         if ((ns_g_listen > 0) && (ns_g_listen < 10))
5198                 ns_g_listen = 10;
5199
5200         /*
5201          * Configure the interface manager according to the "listen-on"
5202          * statement.
5203          */
5204         {
5205                 const cfg_obj_t *clistenon = NULL;
5206                 ns_listenlist_t *listenon = NULL;
5207
5208                 clistenon = NULL;
5209                 /*
5210                  * Even though listen-on is present in the default
5211                  * configuration, we can't use it here, since it isn't
5212                  * used if we're in lwresd mode.  This way is easier.
5213                  */
5214                 if (options != NULL)
5215                         (void)cfg_map_get(options, "listen-on", &clistenon);
5216                 if (clistenon != NULL) {
5217                         /* check return code? */
5218                         (void)ns_listenlist_fromconfig(clistenon, config,
5219                                                        ns_g_aclconfctx,
5220                                                        ns_g_mctx, &listenon);
5221                 } else if (!ns_g_lwresdonly) {
5222                         /*
5223                          * Not specified, use default.
5224                          */
5225                         CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
5226                                                     ISC_TRUE, &listenon));
5227                 }
5228                 if (listenon != NULL) {
5229                         ns_interfacemgr_setlistenon4(server->interfacemgr,
5230                                                      listenon);
5231                         ns_listenlist_detach(&listenon);
5232                 }
5233         }
5234         /*
5235          * Ditto for IPv6.
5236          */
5237         {
5238                 const cfg_obj_t *clistenon = NULL;
5239                 ns_listenlist_t *listenon = NULL;
5240
5241                 if (options != NULL)
5242                         (void)cfg_map_get(options, "listen-on-v6", &clistenon);
5243                 if (clistenon != NULL) {
5244                         /* check return code? */
5245                         (void)ns_listenlist_fromconfig(clistenon, config,
5246                                                        ns_g_aclconfctx,
5247                                                        ns_g_mctx, &listenon);
5248                 } else if (!ns_g_lwresdonly) {
5249                         isc_boolean_t enable;
5250                         /*
5251                          * Not specified, use default.
5252                          */
5253                         enable = ISC_TF(isc_net_probeipv4() != ISC_R_SUCCESS);
5254                         CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
5255                                                     enable, &listenon));
5256                 }
5257                 if (listenon != NULL) {
5258                         ns_interfacemgr_setlistenon6(server->interfacemgr,
5259                                                      listenon);
5260                         ns_listenlist_detach(&listenon);
5261                 }
5262         }
5263
5264         /*
5265          * Rescan the interface list to pick up changes in the
5266          * listen-on option.  It's important that we do this before we try
5267          * to configure the query source, since the dispatcher we use might
5268          * be shared with an interface.
5269          */
5270         scan_interfaces(server, ISC_TRUE);
5271
5272         /*
5273          * Arrange for further interface scanning to occur periodically
5274          * as specified by the "interface-interval" option.
5275          */
5276         obj = NULL;
5277         result = ns_config_get(maps, "interface-interval", &obj);
5278         INSIST(result == ISC_R_SUCCESS);
5279         interface_interval = cfg_obj_asuint32(obj) * 60;
5280         if (interface_interval == 0) {
5281                 CHECK(isc_timer_reset(server->interface_timer,
5282                                       isc_timertype_inactive,
5283                                       NULL, NULL, ISC_TRUE));
5284         } else if (server->interface_interval != interface_interval) {
5285                 isc_interval_set(&interval, interface_interval, 0);
5286                 CHECK(isc_timer_reset(server->interface_timer,
5287                                       isc_timertype_ticker,
5288                                       NULL, &interval, ISC_FALSE));
5289         }
5290         server->interface_interval = interface_interval;
5291
5292         /*
5293          * Configure the dialup heartbeat timer.
5294          */
5295         obj = NULL;
5296         result = ns_config_get(maps, "heartbeat-interval", &obj);
5297         INSIST(result == ISC_R_SUCCESS);
5298         heartbeat_interval = cfg_obj_asuint32(obj) * 60;
5299         if (heartbeat_interval == 0) {
5300                 CHECK(isc_timer_reset(server->heartbeat_timer,
5301                                       isc_timertype_inactive,
5302                                       NULL, NULL, ISC_TRUE));
5303         } else if (server->heartbeat_interval != heartbeat_interval) {
5304                 isc_interval_set(&interval, heartbeat_interval, 0);
5305                 CHECK(isc_timer_reset(server->heartbeat_timer,
5306                                       isc_timertype_ticker,
5307                                       NULL, &interval, ISC_FALSE));
5308         }
5309         server->heartbeat_interval = heartbeat_interval;
5310
5311         isc_interval_set(&interval, 1200, 0);
5312         CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
5313                               &interval, ISC_FALSE));
5314
5315         /*
5316          * Write the PID file.
5317          */
5318         obj = NULL;
5319         if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS)
5320                 if (cfg_obj_isvoid(obj))
5321                         ns_os_writepidfile(NULL, first_time);
5322                 else
5323                         ns_os_writepidfile(cfg_obj_asstring(obj), first_time);
5324         else if (ns_g_lwresdonly)
5325                 ns_os_writepidfile(lwresd_g_defaultpidfile, first_time);
5326         else
5327                 ns_os_writepidfile(ns_g_defaultpidfile, first_time);
5328
5329         /*
5330          * Configure the server-wide session key.  This must be done before
5331          * configure views because zone configuration may need to know
5332          * session-keyname.
5333          *
5334          * Failure of session key generation isn't fatal at this time; if it
5335          * turns out that a session key is really needed but doesn't exist,
5336          * we'll treat it as a fatal error then.
5337          */
5338         (void)configure_session_key(maps, server, ns_g_mctx);
5339
5340         views = NULL;
5341         (void)cfg_map_get(config, "view", &views);
5342
5343         /*
5344          * Create the views and count all the configured zones in
5345          * order to correctly size the zone manager's task table.
5346          * (We only count zones for configured views; the built-in
5347          * "bind" view can be ignored as it only adds a negligible
5348          * number of zones.)
5349          *
5350          * If we're allowing new zones, we need to be able to find the
5351          * new zone file and count those as well.  So we setup the new
5352          * zone configuration context, but otherwise view configuration
5353          * waits until after the zone manager's task list has been sized.
5354          */
5355         for (element = cfg_list_first(views);
5356              element != NULL;
5357              element = cfg_list_next(element))
5358         {
5359                 cfg_obj_t *vconfig = cfg_listelt_value(element);
5360                 const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
5361                 view = NULL;
5362
5363                 CHECK(create_view(vconfig, &viewlist, &view));
5364                 INSIST(view != NULL);
5365
5366                 num_zones += count_zones(voptions);
5367                 CHECK(setup_newzones(view, config, vconfig, conf_parser,
5368                                      ns_g_aclconfctx));
5369
5370                 nzctx = view->new_zone_config;
5371                 if (nzctx != NULL && nzctx->nzconfig != NULL)
5372                         num_zones += count_zones(nzctx->nzconfig);
5373
5374                 dns_view_detach(&view);
5375         }
5376
5377         /*
5378          * If there were no explicit views then we do the default
5379          * view here.
5380          */
5381         if (views == NULL) {
5382                 CHECK(create_view(NULL, &viewlist, &view));
5383                 INSIST(view != NULL);
5384
5385                 num_zones = count_zones(config);
5386
5387                 CHECK(setup_newzones(view, config, NULL,  conf_parser,
5388                                      ns_g_aclconfctx));
5389
5390                 nzctx = view->new_zone_config;
5391                 if (nzctx != NULL && nzctx->nzconfig != NULL)
5392                         num_zones += count_zones(nzctx->nzconfig);
5393
5394                 dns_view_detach(&view);
5395         }
5396
5397         /*
5398          * Zones have been counted; set the zone manager task pool size.
5399          */
5400         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5401                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5402                       "sizing zone task pool based on %d zones", num_zones);
5403         CHECK(dns_zonemgr_setsize(ns_g_server->zonemgr, num_zones));
5404
5405         /*
5406          * Configure and freeze all explicit views.  Explicit
5407          * views that have zones were already created at parsing
5408          * time, but views with no zones must be created here.
5409          */
5410         for (element = cfg_list_first(views);
5411              element != NULL;
5412              element = cfg_list_next(element))
5413         {
5414                 cfg_obj_t *vconfig = cfg_listelt_value(element);
5415
5416                 view = NULL;
5417                 CHECK(find_view(vconfig, &viewlist, &view));
5418                 CHECK(configure_view(view, config, vconfig,
5419                                      &cachelist, bindkeys, ns_g_mctx,
5420                                      ns_g_aclconfctx, ISC_TRUE));
5421                 dns_view_freeze(view);
5422                 dns_view_detach(&view);
5423         }
5424
5425         /*
5426          * Make sure we have a default view if and only if there
5427          * were no explicit views.
5428          */
5429         if (views == NULL) {
5430                 view = NULL;
5431                 CHECK(find_view(NULL, &viewlist, &view));
5432                 CHECK(configure_view(view, config, NULL,
5433                                      &cachelist, bindkeys,
5434                                      ns_g_mctx, ns_g_aclconfctx, ISC_TRUE));
5435                 dns_view_freeze(view);
5436                 dns_view_detach(&view);
5437         }
5438
5439         /*
5440          * Create (or recreate) the built-in views.
5441          */
5442         builtin_views = NULL;
5443         RUNTIME_CHECK(cfg_map_get(ns_g_config, "view",
5444                                   &builtin_views) == ISC_R_SUCCESS);
5445         for (element = cfg_list_first(builtin_views);
5446              element != NULL;
5447              element = cfg_list_next(element))
5448         {
5449                 cfg_obj_t *vconfig = cfg_listelt_value(element);
5450
5451                 CHECK(create_view(vconfig, &builtin_viewlist, &view));
5452                 CHECK(configure_view(view, config, vconfig,
5453                                      &cachelist, bindkeys,
5454                                      ns_g_mctx, ns_g_aclconfctx, ISC_FALSE));
5455                 dns_view_freeze(view);
5456                 dns_view_detach(&view);
5457                 view = NULL;
5458         }
5459
5460         /* Now combine the two viewlists into one */
5461         ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
5462
5463         /* Swap our new view list with the production one. */
5464         tmpviewlist = server->viewlist;
5465         server->viewlist = viewlist;
5466         viewlist = tmpviewlist;
5467
5468         /* Make the view list available to each of the views */
5469         view = ISC_LIST_HEAD(server->viewlist);
5470         while (view != NULL) {
5471                 view->viewlist = &server->viewlist;
5472                 view = ISC_LIST_NEXT(view, link);
5473         }
5474
5475         /* Swap our new cache list with the production one. */
5476         tmpcachelist = server->cachelist;
5477         server->cachelist = cachelist;
5478         cachelist = tmpcachelist;
5479
5480         /* Load the TKEY information from the configuration. */
5481         if (options != NULL) {
5482                 dns_tkeyctx_t *t = NULL;
5483                 CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy,
5484                                              &t),
5485                        "configuring TKEY");
5486                 if (server->tkeyctx != NULL)
5487                         dns_tkeyctx_destroy(&server->tkeyctx);
5488                 server->tkeyctx = t;
5489         }
5490
5491         /*
5492          * Bind the control port(s).
5493          */
5494         CHECKM(ns_controls_configure(ns_g_server->controls, config,
5495                                      ns_g_aclconfctx),
5496                "binding control channel(s)");
5497
5498         /*
5499          * Bind the lwresd port(s).
5500          */
5501         CHECKM(ns_lwresd_configure(ns_g_mctx, config),
5502                "binding lightweight resolver ports");
5503
5504         /*
5505          * Open the source of entropy.
5506          */
5507         if (first_time) {
5508                 obj = NULL;
5509                 result = ns_config_get(maps, "random-device", &obj);
5510                 if (result != ISC_R_SUCCESS) {
5511                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5512                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5513                                       "no source of entropy found");
5514                 } else {
5515                         const char *randomdev = cfg_obj_asstring(obj);
5516                         result = isc_entropy_createfilesource(ns_g_entropy,
5517                                                               randomdev);
5518                         if (result != ISC_R_SUCCESS)
5519                                 isc_log_write(ns_g_lctx,
5520                                               NS_LOGCATEGORY_GENERAL,
5521                                               NS_LOGMODULE_SERVER,
5522                                               ISC_LOG_INFO,
5523                                               "could not open entropy source "
5524                                               "%s: %s",
5525                                               randomdev,
5526                                               isc_result_totext(result));
5527 #ifdef PATH_RANDOMDEV
5528                         if (ns_g_fallbackentropy != NULL) {
5529                                 if (result != ISC_R_SUCCESS) {
5530                                         isc_log_write(ns_g_lctx,
5531                                                       NS_LOGCATEGORY_GENERAL,
5532                                                       NS_LOGMODULE_SERVER,
5533                                                       ISC_LOG_INFO,
5534                                                       "using pre-chroot entropy source "
5535                                                       "%s",
5536                                                       PATH_RANDOMDEV);
5537                                         isc_entropy_detach(&ns_g_entropy);
5538                                         isc_entropy_attach(ns_g_fallbackentropy,
5539                                                            &ns_g_entropy);
5540                                 }
5541                                 isc_entropy_detach(&ns_g_fallbackentropy);
5542                         }
5543 #endif
5544                 }
5545         }
5546
5547         /*
5548          * Relinquish root privileges.
5549          */
5550         if (first_time)
5551                 ns_os_changeuser();
5552
5553         /*
5554          * Check that the working directory is writable.
5555          */
5556         if (access(".", W_OK) != 0) {
5557                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5558                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
5559                               "the working directory is not writable");
5560         }
5561
5562         /*
5563          * Configure the logging system.
5564          *
5565          * Do this after changing UID to make sure that any log
5566          * files specified in named.conf get created by the
5567          * unprivileged user, not root.
5568          */
5569         if (ns_g_logstderr) {
5570                 const cfg_obj_t *logobj = NULL;
5571
5572                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5573                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
5574                               "not using config file logging "
5575                               "statement for logging due to "
5576                               "-g option");
5577
5578                 (void)cfg_map_get(config, "logging", &logobj);
5579                 if (logobj != NULL) {
5580                         result = ns_log_configure(NULL, logobj);
5581                         if (result != ISC_R_SUCCESS) {
5582                                 isc_log_write(ns_g_lctx,
5583                                               NS_LOGCATEGORY_GENERAL,
5584                                               NS_LOGMODULE_SERVER,
5585                                               ISC_LOG_ERROR,
5586                                               "checking logging configuration "
5587                                               "failed: %s",
5588                                               isc_result_totext(result));
5589                                 goto cleanup;
5590                         }
5591                 }
5592         } else {
5593                 const cfg_obj_t *logobj = NULL;
5594
5595                 CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
5596                        "creating new logging configuration");
5597
5598                 logobj = NULL;
5599                 (void)cfg_map_get(config, "logging", &logobj);
5600                 if (logobj != NULL) {
5601                         CHECKM(ns_log_configure(logc, logobj),
5602                                "configuring logging");
5603                 } else {
5604                         CHECKM(ns_log_setdefaultchannels(logc),
5605                                "setting up default logging channels");
5606                         CHECKM(ns_log_setunmatchedcategory(logc),
5607                                "setting up default 'category unmatched'");
5608                         CHECKM(ns_log_setdefaultcategory(logc),
5609                                "setting up default 'category default'");
5610                 }
5611
5612                 CHECKM(isc_logconfig_use(ns_g_lctx, logc),
5613                        "installing logging configuration");
5614                 logc = NULL;
5615
5616                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
5617                               NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
5618                               "now using logging configuration from "
5619                               "config file");
5620         }
5621
5622         /*
5623          * Set the default value of the query logging flag depending
5624          * whether a "queries" category has been defined.  This is
5625          * a disgusting hack, but we need to do this for BIND 8
5626          * compatibility.
5627          */
5628         if (first_time) {
5629                 const cfg_obj_t *logobj = NULL;
5630                 const cfg_obj_t *categories = NULL;
5631
5632                 obj = NULL;
5633                 if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
5634                         server->log_queries = cfg_obj_asboolean(obj);
5635                 } else {
5636
5637                         (void)cfg_map_get(config, "logging", &logobj);
5638                         if (logobj != NULL)
5639                                 (void)cfg_map_get(logobj, "category",
5640                                                   &categories);
5641                         if (categories != NULL) {
5642                                 const cfg_listelt_t *element;
5643                                 for (element = cfg_list_first(categories);
5644                                      element != NULL;
5645                                      element = cfg_list_next(element))
5646                                 {
5647                                         const cfg_obj_t *catobj;
5648                                         const char *str;
5649
5650                                         obj = cfg_listelt_value(element);
5651                                         catobj = cfg_tuple_get(obj, "name");
5652                                         str = cfg_obj_asstring(catobj);
5653                                         if (strcasecmp(str, "queries") == 0)
5654                                                 server->log_queries = ISC_TRUE;
5655                                 }
5656                         }
5657                 }
5658         }
5659
5660
5661         obj = NULL;
5662         if (options != NULL &&
5663             cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
5664                 ns_g_memstatistics = cfg_obj_asboolean(obj);
5665         else
5666                 ns_g_memstatistics =
5667                         ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
5668
5669         obj = NULL;
5670         if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
5671                 ns_main_setmemstats(cfg_obj_asstring(obj));
5672         else if (ns_g_memstatistics)
5673                 ns_main_setmemstats("named.memstats");
5674         else
5675                 ns_main_setmemstats(NULL);
5676
5677         obj = NULL;
5678         result = ns_config_get(maps, "statistics-file", &obj);
5679         INSIST(result == ISC_R_SUCCESS);
5680         CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
5681                "strdup");
5682
5683         obj = NULL;
5684         result = ns_config_get(maps, "dump-file", &obj);
5685         INSIST(result == ISC_R_SUCCESS);
5686         CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
5687                "strdup");
5688
5689         obj = NULL;
5690         result = ns_config_get(maps, "secroots-file", &obj);
5691         INSIST(result == ISC_R_SUCCESS);
5692         CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)),
5693                "strdup");
5694
5695         obj = NULL;
5696         result = ns_config_get(maps, "recursing-file", &obj);
5697         INSIST(result == ISC_R_SUCCESS);
5698         CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
5699                "strdup");
5700
5701         obj = NULL;
5702         result = ns_config_get(maps, "version", &obj);
5703         if (result == ISC_R_SUCCESS) {
5704                 CHECKM(setoptstring(server, &server->version, obj), "strdup");
5705                 server->version_set = ISC_TRUE;
5706         } else {
5707                 server->version_set = ISC_FALSE;
5708         }
5709
5710         obj = NULL;
5711         result = ns_config_get(maps, "hostname", &obj);
5712         if (result == ISC_R_SUCCESS) {
5713                 CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
5714                 server->hostname_set = ISC_TRUE;
5715         } else {
5716                 server->hostname_set = ISC_FALSE;
5717         }
5718
5719         obj = NULL;
5720         result = ns_config_get(maps, "server-id", &obj);
5721         server->server_usehostname = ISC_FALSE;
5722         if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
5723                 /* The parser translates "hostname" to ISC_TRUE */
5724                 server->server_usehostname = cfg_obj_asboolean(obj);
5725                 result = setstring(server, &server->server_id, NULL);
5726                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
5727         } else if (result == ISC_R_SUCCESS) {
5728                 /* Found a quoted string */
5729                 CHECKM(setoptstring(server, &server->server_id, obj), "strdup");
5730         } else {
5731                 result = setstring(server, &server->server_id, NULL);
5732                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
5733         }
5734
5735         obj = NULL;
5736         result = ns_config_get(maps, "flush-zones-on-shutdown", &obj);
5737         if (result == ISC_R_SUCCESS) {
5738                 server->flushonshutdown = cfg_obj_asboolean(obj);
5739         } else {
5740                 server->flushonshutdown = ISC_FALSE;
5741         }
5742
5743         result = ISC_R_SUCCESS;
5744
5745  cleanup:
5746         if (logc != NULL)
5747                 isc_logconfig_destroy(&logc);
5748
5749         if (v4portset != NULL)
5750                 isc_portset_destroy(ns_g_mctx, &v4portset);
5751
5752         if (v6portset != NULL)
5753                 isc_portset_destroy(ns_g_mctx, &v6portset);
5754
5755         if (conf_parser != NULL) {
5756                 if (config != NULL)
5757                         cfg_obj_destroy(conf_parser, &config);
5758                 cfg_parser_destroy(&conf_parser);
5759         }
5760
5761         if (bindkeys_parser != NULL) {
5762                 if (bindkeys  != NULL)
5763                         cfg_obj_destroy(bindkeys_parser, &bindkeys);
5764                 cfg_parser_destroy(&bindkeys_parser);
5765         }
5766
5767         if (view != NULL)
5768                 dns_view_detach(&view);
5769
5770         /*
5771          * This cleans up either the old production view list
5772          * or our temporary list depending on whether they
5773          * were swapped above or not.
5774          */
5775         for (view = ISC_LIST_HEAD(viewlist);
5776              view != NULL;
5777              view = view_next) {
5778                 view_next = ISC_LIST_NEXT(view, link);
5779                 ISC_LIST_UNLINK(viewlist, view, link);
5780                 if (result == ISC_R_SUCCESS &&
5781                     strcmp(view->name, "_bind") != 0)
5782                         (void)dns_zt_apply(view->zonetable, ISC_FALSE,
5783                                            removed, view);
5784                 dns_view_detach(&view);
5785         }
5786
5787         /* Same cleanup for cache list. */
5788         while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
5789                 ISC_LIST_UNLINK(cachelist, nsc, link);
5790                 dns_cache_detach(&nsc->cache);
5791                 isc_mem_put(server->mctx, nsc, sizeof(*nsc));
5792         }
5793
5794         /*
5795          * Adjust the listening interfaces in accordance with the source
5796          * addresses specified in views and zones.
5797          */
5798         if (isc_net_probeipv6() == ISC_R_SUCCESS)
5799                 adjust_interfaces(server, ns_g_mctx);
5800
5801         /* Relinquish exclusive access to configuration data. */
5802         if (exclusive)
5803                 isc_task_endexclusive(server->task);
5804
5805         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5806                       ISC_LOG_DEBUG(1), "load_configuration: %s",
5807                       isc_result_totext(result));
5808
5809         return (result);
5810 }
5811
5812 static isc_result_t
5813 view_loaded(void *arg) {
5814         isc_result_t result;
5815         ns_zoneload_t *zl = (ns_zoneload_t *) arg;
5816         ns_server_t *server = zl->server;
5817         unsigned int refs;
5818
5819
5820         /*
5821          * Force zone maintenance.  Do this after loading
5822          * so that we know when we need to force AXFR of
5823          * slave zones whose master files are missing.
5824          *
5825          * We use the zoneload reference counter to let us
5826          * know when all views are finished.
5827          */
5828         isc_refcount_decrement(&zl->refs, &refs);
5829         if (refs != 0)
5830                 return (ISC_R_SUCCESS);
5831
5832         isc_refcount_destroy(&zl->refs);
5833         isc_mem_put(server->mctx, zl, sizeof (*zl));
5834
5835         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5836                       ISC_LOG_NOTICE, "all zones loaded");
5837         CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
5838                    "forcing zone maintenance");
5839
5840         ns_os_started();
5841         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
5842                       ISC_LOG_NOTICE, "running");
5843
5844         return (ISC_R_SUCCESS);
5845 }
5846
5847 static isc_result_t
5848 load_zones(ns_server_t *server, isc_boolean_t init) {
5849         isc_result_t result;
5850         dns_view_t *view;
5851         ns_zoneload_t *zl;
5852         unsigned int refs = 0;
5853
5854         zl = isc_mem_get(server->mctx, sizeof (*zl));
5855         if (zl == NULL)
5856                 return (ISC_R_NOMEMORY);
5857         zl->server = server;
5858
5859         result = isc_task_beginexclusive(server->task);
5860         RUNTIME_CHECK(result == ISC_R_SUCCESS);
5861
5862         isc_refcount_init(&zl->refs, 1);
5863
5864         /*
5865          * Schedule zones to be loaded from disk.
5866          */
5867         for (view = ISC_LIST_HEAD(server->viewlist);
5868              view != NULL;
5869              view = ISC_LIST_NEXT(view, link))
5870         {
5871                 if (view->managed_keys != NULL) {
5872                         result = dns_zone_load(view->managed_keys);
5873                         if (result != ISC_R_SUCCESS &&
5874                             result != DNS_R_UPTODATE &&
5875                             result != DNS_R_CONTINUE)
5876                                 goto cleanup;
5877                 }
5878                 if (view->redirect != NULL) {
5879                         result = dns_zone_load(view->redirect);
5880                         if (result != ISC_R_SUCCESS &&
5881                             result != DNS_R_UPTODATE &&
5882                             result != DNS_R_CONTINUE)
5883                                 goto cleanup;
5884                 }
5885
5886                 /*
5887                  * 'dns_view_asyncload' calls view_loaded if there are no
5888                  * zones.
5889                  */
5890                 isc_refcount_increment(&zl->refs, NULL);
5891                 CHECK(dns_view_asyncload(view, view_loaded, zl));
5892         }
5893
5894  cleanup:
5895         isc_refcount_decrement(&zl->refs, &refs);
5896         if (refs == 0) {
5897                 isc_refcount_destroy(&zl->refs);
5898                 isc_mem_put(server->mctx, zl, sizeof (*zl));
5899         } else if (init) {
5900                 /*
5901                  * Place the task manager into privileged mode.  This
5902                  * ensures that after we leave task-exclusive mode, no
5903                  * other tasks will be able to run except for the ones
5904                  * that are loading zones. (This should only be done during
5905                  * the initial server setup; it isn't necessary during
5906                  * a reload.)
5907                  */
5908                 isc_taskmgr_setmode(ns_g_taskmgr, isc_taskmgrmode_privileged);
5909         }
5910
5911         isc_task_endexclusive(server->task);
5912         return (result);
5913 }
5914
5915 static isc_result_t
5916 load_new_zones(ns_server_t *server, isc_boolean_t stop) {
5917         isc_result_t result;
5918         dns_view_t *view;
5919
5920         result = isc_task_beginexclusive(server->task);
5921         RUNTIME_CHECK(result == ISC_R_SUCCESS);
5922
5923         /*
5924          * Load zone data from disk.
5925          */
5926         for (view = ISC_LIST_HEAD(server->viewlist);
5927              view != NULL;
5928              view = ISC_LIST_NEXT(view, link))
5929         {
5930                 CHECK(dns_view_loadnew(view, stop));
5931
5932                 /* Load managed-keys data */
5933                 if (view->managed_keys != NULL)
5934                         CHECK(dns_zone_loadnew(view->managed_keys));
5935                 if (view->redirect != NULL)
5936                         CHECK(dns_zone_loadnew(view->redirect));
5937         }
5938
5939         /*
5940          * Resume zone XFRs.
5941          */
5942         dns_zonemgr_resumexfrs(server->zonemgr);
5943  cleanup:
5944         isc_task_endexclusive(server->task);
5945         return (result);
5946 }
5947
5948 static void
5949 run_server(isc_task_t *task, isc_event_t *event) {
5950         isc_result_t result;
5951         ns_server_t *server = (ns_server_t *)event->ev_arg;
5952
5953         INSIST(task == server->task);
5954
5955         isc_event_free(&event);
5956
5957         CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy,
5958                                           &ns_g_dispatchmgr),
5959                    "creating dispatch manager");
5960
5961         dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats);
5962
5963         CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
5964                                           ns_g_socketmgr, ns_g_dispatchmgr,
5965                                           &server->interfacemgr),
5966                    "creating interface manager");
5967
5968         CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
5969                                     NULL, NULL, server->task,
5970                                     interface_timer_tick,
5971                                     server, &server->interface_timer),
5972                    "creating interface timer");
5973
5974         CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
5975                                     NULL, NULL, server->task,
5976                                     heartbeat_timer_tick,
5977                                     server, &server->heartbeat_timer),
5978                    "creating heartbeat timer");
5979
5980         CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
5981                                     NULL, NULL, server->task, pps_timer_tick,
5982                                     server, &server->pps_timer),
5983                    "creating pps timer");
5984
5985         CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser),
5986                    "creating default configuration parser");
5987
5988         if (ns_g_lwresdonly)
5989                 CHECKFATAL(load_configuration(lwresd_g_conffile, server,
5990                                               ISC_TRUE),
5991                            "loading configuration");
5992         else
5993                 CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE),
5994                            "loading configuration");
5995
5996         isc_hash_init();
5997
5998         CHECKFATAL(load_zones(server, ISC_TRUE), "loading zones");
5999 }
6000
6001 void
6002 ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) {
6003
6004         REQUIRE(NS_SERVER_VALID(server));
6005
6006         server->flushonshutdown = flush;
6007 }
6008
6009 static void
6010 shutdown_server(isc_task_t *task, isc_event_t *event) {
6011         isc_result_t result;
6012         dns_view_t *view, *view_next;
6013         ns_server_t *server = (ns_server_t *)event->ev_arg;
6014         isc_boolean_t flush = server->flushonshutdown;
6015         ns_cache_t *nsc;
6016
6017         UNUSED(task);
6018         INSIST(task == server->task);
6019
6020         result = isc_task_beginexclusive(server->task);
6021         RUNTIME_CHECK(result == ISC_R_SUCCESS);
6022
6023         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
6024                       ISC_LOG_INFO, "shutting down%s",
6025                       flush ? ": flushing changes" : "");
6026
6027         ns_statschannels_shutdown(server);
6028         ns_controls_shutdown(server->controls);
6029         end_reserved_dispatches(server, ISC_TRUE);
6030         cleanup_session_key(server, server->mctx);
6031
6032         if (ns_g_aclconfctx != NULL)
6033                 cfg_aclconfctx_detach(&ns_g_aclconfctx);
6034
6035         cfg_obj_destroy(ns_g_parser, &ns_g_config);
6036         cfg_parser_destroy(&ns_g_parser);
6037
6038         for (view = ISC_LIST_HEAD(server->viewlist);
6039              view != NULL;
6040              view = view_next) {
6041                 view_next = ISC_LIST_NEXT(view, link);
6042                 ISC_LIST_UNLINK(server->viewlist, view, link);
6043                 if (flush)
6044                         dns_view_flushanddetach(&view);
6045                 else
6046                         dns_view_detach(&view);
6047         }
6048
6049         while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
6050                 ISC_LIST_UNLINK(server->cachelist, nsc, link);
6051                 dns_cache_detach(&nsc->cache);
6052                 isc_mem_put(server->mctx, nsc, sizeof(*nsc));
6053         }
6054
6055         isc_timer_detach(&server->interface_timer);
6056         isc_timer_detach(&server->heartbeat_timer);
6057         isc_timer_detach(&server->pps_timer);
6058
6059         ns_interfacemgr_shutdown(server->interfacemgr);
6060         ns_interfacemgr_detach(&server->interfacemgr);
6061
6062         dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
6063
6064         dns_zonemgr_shutdown(server->zonemgr);
6065
6066         if (ns_g_sessionkey != NULL) {
6067                 dns_tsigkey_detach(&ns_g_sessionkey);
6068                 dns_name_free(&ns_g_sessionkeyname, server->mctx);
6069         }
6070
6071         if (server->blackholeacl != NULL)
6072                 dns_acl_detach(&server->blackholeacl);
6073
6074         dns_db_detach(&server->in_roothints);
6075
6076         isc_task_endexclusive(server->task);
6077
6078         isc_task_detach(&server->task);
6079
6080         isc_event_free(&event);
6081 }
6082
6083 void
6084 ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
6085         isc_result_t result;
6086         ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
6087
6088         if (server == NULL)
6089                 fatal("allocating server object", ISC_R_NOMEMORY);
6090
6091         server->mctx = mctx;
6092         server->task = NULL;
6093
6094         /* Initialize configuration data with default values. */
6095
6096         result = isc_quota_init(&server->xfroutquota, 10);
6097         RUNTIME_CHECK(result == ISC_R_SUCCESS);
6098         result = isc_quota_init(&server->tcpquota, 10);
6099         RUNTIME_CHECK(result == ISC_R_SUCCESS);
6100         result = isc_quota_init(&server->recursionquota, 100);
6101         RUNTIME_CHECK(result == ISC_R_SUCCESS);
6102
6103         result = dns_aclenv_init(mctx, &server->aclenv);
6104         RUNTIME_CHECK(result == ISC_R_SUCCESS);
6105
6106         /* Initialize server data structures. */
6107         server->zonemgr = NULL;
6108         server->interfacemgr = NULL;
6109         ISC_LIST_INIT(server->viewlist);
6110         server->in_roothints = NULL;
6111         server->blackholeacl = NULL;
6112
6113         CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
6114                                      &server->in_roothints),
6115                    "setting up root hints");
6116
6117         CHECKFATAL(isc_mutex_init(&server->reload_event_lock),
6118                    "initializing reload event lock");
6119         server->reload_event =
6120                 isc_event_allocate(ns_g_mctx, server,
6121                                    NS_EVENT_RELOAD,
6122                                    ns_server_reload,
6123                                    server,
6124                                    sizeof(isc_event_t));
6125         CHECKFATAL(server->reload_event == NULL ?
6126                    ISC_R_NOMEMORY : ISC_R_SUCCESS,
6127                    "allocating reload event");
6128
6129         CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy,
6130                                  ns_g_engine, ISC_ENTROPY_GOODONLY),
6131                    "initializing DST");
6132
6133         server->tkeyctx = NULL;
6134         CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
6135                                       &server->tkeyctx),
6136                    "creating TKEY context");
6137
6138         /*
6139          * Setup the server task, which is responsible for coordinating
6140          * startup and shutdown of the server, as well as all exclusive
6141          * tasks.
6142          */
6143         CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task),
6144                    "creating server task");
6145         isc_task_setname(server->task, "server", server);
6146         isc_taskmgr_setexcltask(ns_g_taskmgr, server->task);
6147         CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
6148                    "isc_task_onshutdown");
6149         CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
6150                    "isc_app_onrun");
6151
6152         server->interface_timer = NULL;
6153         server->heartbeat_timer = NULL;
6154         server->pps_timer = NULL;
6155
6156         server->interface_interval = 0;
6157         server->heartbeat_interval = 0;
6158
6159         CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
6160                                       ns_g_socketmgr, &server->zonemgr),
6161                    "dns_zonemgr_create");
6162         CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000),
6163                    "dns_zonemgr_setsize");
6164
6165         server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
6166         CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
6167                    "isc_mem_strdup");
6168         server->nsstats = NULL;
6169         server->rcvquerystats = NULL;
6170         server->opcodestats = NULL;
6171         server->zonestats = NULL;
6172         server->resolverstats = NULL;
6173         server->sockstats = NULL;
6174         CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
6175                                     isc_sockstatscounter_max),
6176                    "isc_stats_create");
6177         isc_socketmgr_setstats(ns_g_socketmgr, server->sockstats);
6178
6179         server->bindkeysfile = isc_mem_strdup(server->mctx, "bind.keys");
6180         CHECKFATAL(server->bindkeysfile == NULL ? ISC_R_NOMEMORY :
6181                                                   ISC_R_SUCCESS,
6182                    "isc_mem_strdup");
6183
6184         server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
6185         CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
6186                    "isc_mem_strdup");
6187
6188         server->secrootsfile = isc_mem_strdup(server->mctx, "named.secroots");
6189         CHECKFATAL(server->secrootsfile == NULL ? ISC_R_NOMEMORY :
6190                                                   ISC_R_SUCCESS,
6191                    "isc_mem_strdup");
6192
6193         server->recfile = isc_mem_strdup(server->mctx, "named.recursing");
6194         CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
6195                    "isc_mem_strdup");
6196
6197         server->hostname_set = ISC_FALSE;
6198         server->hostname = NULL;
6199         server->version_set = ISC_FALSE;
6200         server->version = NULL;
6201         server->server_usehostname = ISC_FALSE;
6202         server->server_id = NULL;
6203
6204         CHECKFATAL(isc_stats_create(ns_g_mctx, &server->nsstats,
6205                                     dns_nsstatscounter_max),
6206                    "dns_stats_create (server)");
6207
6208         CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx,
6209                                              &server->rcvquerystats),
6210                    "dns_stats_create (rcvquery)");
6211
6212         CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats),
6213                    "dns_stats_create (opcode)");
6214
6215         CHECKFATAL(isc_stats_create(ns_g_mctx, &server->zonestats,
6216                                     dns_zonestatscounter_max),
6217                    "dns_stats_create (zone)");
6218
6219         CHECKFATAL(isc_stats_create(ns_g_mctx, &server->resolverstats,
6220                                     dns_resstatscounter_max),
6221                    "dns_stats_create (resolver)");
6222
6223         server->flushonshutdown = ISC_FALSE;
6224         server->log_queries = ISC_FALSE;
6225
6226         server->controls = NULL;
6227         CHECKFATAL(ns_controls_create(server, &server->controls),
6228                    "ns_controls_create");
6229         server->dispatchgen = 0;
6230         ISC_LIST_INIT(server->dispatches);
6231
6232         ISC_LIST_INIT(server->statschannels);
6233
6234         ISC_LIST_INIT(server->cachelist);
6235
6236         server->sessionkey = NULL;
6237         server->session_keyfile = NULL;
6238         server->session_keyname = NULL;
6239         server->session_keyalg = DST_ALG_UNKNOWN;
6240         server->session_keybits = 0;
6241
6242         server->magic = NS_SERVER_MAGIC;
6243         *serverp = server;
6244 }
6245
6246 void
6247 ns_server_destroy(ns_server_t **serverp) {
6248         ns_server_t *server = *serverp;
6249         REQUIRE(NS_SERVER_VALID(server));
6250
6251         ns_controls_destroy(&server->controls);
6252
6253         isc_stats_detach(&server->nsstats);
6254         dns_stats_detach(&server->rcvquerystats);
6255         dns_stats_detach(&server->opcodestats);
6256         isc_stats_detach(&server->zonestats);
6257         isc_stats_detach(&server->resolverstats);
6258         isc_stats_detach(&server->sockstats);
6259
6260         isc_mem_free(server->mctx, server->statsfile);
6261         isc_mem_free(server->mctx, server->bindkeysfile);
6262         isc_mem_free(server->mctx, server->dumpfile);
6263         isc_mem_free(server->mctx, server->secrootsfile);
6264         isc_mem_free(server->mctx, server->recfile);
6265
6266         if (server->version != NULL)
6267                 isc_mem_free(server->mctx, server->version);
6268         if (server->hostname != NULL)
6269                 isc_mem_free(server->mctx, server->hostname);
6270         if (server->server_id != NULL)
6271                 isc_mem_free(server->mctx, server->server_id);
6272
6273         if (server->zonemgr != NULL)
6274                 dns_zonemgr_detach(&server->zonemgr);
6275
6276         if (server->tkeyctx != NULL)
6277                 dns_tkeyctx_destroy(&server->tkeyctx);
6278
6279         dst_lib_destroy();
6280
6281         isc_event_free(&server->reload_event);
6282
6283         INSIST(ISC_LIST_EMPTY(server->viewlist));
6284         INSIST(ISC_LIST_EMPTY(server->cachelist));
6285
6286         dns_aclenv_destroy(&server->aclenv);
6287
6288         isc_quota_destroy(&server->recursionquota);
6289         isc_quota_destroy(&server->tcpquota);
6290         isc_quota_destroy(&server->xfroutquota);
6291
6292         server->magic = 0;
6293         isc_mem_put(server->mctx, server, sizeof(*server));
6294         *serverp = NULL;
6295 }
6296
6297 static void
6298 fatal(const char *msg, isc_result_t result) {
6299         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
6300                       ISC_LOG_CRITICAL, "%s: %s", msg,
6301                       isc_result_totext(result));
6302         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
6303                       ISC_LOG_CRITICAL, "exiting (due to fatal error)");
6304         exit(1);
6305 }
6306
6307 static void
6308 start_reserved_dispatches(ns_server_t *server) {
6309
6310         REQUIRE(NS_SERVER_VALID(server));
6311
6312         server->dispatchgen++;
6313 }
6314
6315 static void
6316 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) {
6317         ns_dispatch_t *dispatch, *nextdispatch;
6318
6319         REQUIRE(NS_SERVER_VALID(server));
6320
6321         for (dispatch = ISC_LIST_HEAD(server->dispatches);
6322              dispatch != NULL;
6323              dispatch = nextdispatch) {
6324                 nextdispatch = ISC_LIST_NEXT(dispatch, link);
6325                 if (!all && server->dispatchgen == dispatch-> dispatchgen)
6326                         continue;
6327                 ISC_LIST_UNLINK(server->dispatches, dispatch, link);
6328                 dns_dispatch_detach(&dispatch->dispatch);
6329                 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
6330         }
6331 }
6332
6333 void
6334 ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) {
6335         ns_dispatch_t *dispatch;
6336         in_port_t port;
6337         char addrbuf[ISC_SOCKADDR_FORMATSIZE];
6338         isc_result_t result;
6339         unsigned int attrs, attrmask;
6340
6341         REQUIRE(NS_SERVER_VALID(server));
6342
6343         port = isc_sockaddr_getport(addr);
6344         if (port == 0 || port >= 1024)
6345                 return;
6346
6347         for (dispatch = ISC_LIST_HEAD(server->dispatches);
6348              dispatch != NULL;
6349              dispatch = ISC_LIST_NEXT(dispatch, link)) {
6350                 if (isc_sockaddr_equal(&dispatch->addr, addr))
6351                         break;
6352         }
6353         if (dispatch != NULL) {
6354                 dispatch->dispatchgen = server->dispatchgen;
6355                 return;
6356         }
6357
6358         dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
6359         if (dispatch == NULL) {
6360                 result = ISC_R_NOMEMORY;
6361                 goto cleanup;
6362         }
6363
6364         dispatch->addr = *addr;
6365         dispatch->dispatchgen = server->dispatchgen;
6366         dispatch->dispatch = NULL;
6367
6368         attrs = 0;
6369         attrs |= DNS_DISPATCHATTR_UDP;
6370         switch (isc_sockaddr_pf(addr)) {
6371         case AF_INET:
6372                 attrs |= DNS_DISPATCHATTR_IPV4;
6373                 break;
6374         case AF_INET6:
6375                 attrs |= DNS_DISPATCHATTR_IPV6;
6376                 break;
6377         default:
6378                 result = ISC_R_NOTIMPLEMENTED;
6379                 goto cleanup;
6380         }
6381         attrmask = 0;
6382         attrmask |= DNS_DISPATCHATTR_UDP;
6383         attrmask |= DNS_DISPATCHATTR_TCP;
6384         attrmask |= DNS_DISPATCHATTR_IPV4;
6385         attrmask |= DNS_DISPATCHATTR_IPV6;
6386
6387         result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
6388                                      ns_g_taskmgr, &dispatch->addr, 4096,
6389                                      1000, 32768, 16411, 16433,
6390                                      attrs, attrmask, &dispatch->dispatch);
6391         if (result != ISC_R_SUCCESS)
6392                 goto cleanup;
6393
6394         ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
6395
6396         return;
6397
6398  cleanup:
6399         if (dispatch != NULL)
6400                 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
6401         isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
6402         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6403                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
6404                       "unable to create dispatch for reserved port %s: %s",
6405                       addrbuf, isc_result_totext(result));
6406 }
6407
6408
6409 static isc_result_t
6410 loadconfig(ns_server_t *server) {
6411         isc_result_t result;
6412         start_reserved_dispatches(server);
6413         result = load_configuration(ns_g_lwresdonly ?
6414                                     lwresd_g_conffile : ns_g_conffile,
6415                                     server, ISC_FALSE);
6416         if (result == ISC_R_SUCCESS) {
6417                 end_reserved_dispatches(server, ISC_FALSE);
6418                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6419                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6420                               "reloading configuration succeeded");
6421         } else {
6422                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6423                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6424                               "reloading configuration failed: %s",
6425                               isc_result_totext(result));
6426         }
6427         return (result);
6428 }
6429
6430 static isc_result_t
6431 reload(ns_server_t *server) {
6432         isc_result_t result;
6433         CHECK(loadconfig(server));
6434
6435         result = load_zones(server, ISC_FALSE);
6436         if (result == ISC_R_SUCCESS)
6437                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6438                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6439                               "reloading zones succeeded");
6440         else
6441                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6442                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6443                               "reloading zones failed: %s",
6444                               isc_result_totext(result));
6445
6446  cleanup:
6447         return (result);
6448 }
6449
6450 static void
6451 reconfig(ns_server_t *server) {
6452         isc_result_t result;
6453         CHECK(loadconfig(server));
6454
6455         result = load_new_zones(server, ISC_FALSE);
6456         if (result == ISC_R_SUCCESS)
6457                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6458                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6459                               "any newly configured zones are now loaded");
6460         else
6461                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6462                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6463                               "loading new zones failed: %s",
6464                               isc_result_totext(result));
6465
6466  cleanup: ;
6467 }
6468
6469 /*
6470  * Handle a reload event (from SIGHUP).
6471  */
6472 static void
6473 ns_server_reload(isc_task_t *task, isc_event_t *event) {
6474         ns_server_t *server = (ns_server_t *)event->ev_arg;
6475
6476         INSIST(task = server->task);
6477         UNUSED(task);
6478
6479         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6480                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6481                       "received SIGHUP signal to reload zones");
6482         (void)reload(server);
6483
6484         LOCK(&server->reload_event_lock);
6485         INSIST(server->reload_event == NULL);
6486         server->reload_event = event;
6487         UNLOCK(&server->reload_event_lock);
6488 }
6489
6490 void
6491 ns_server_reloadwanted(ns_server_t *server) {
6492         LOCK(&server->reload_event_lock);
6493         if (server->reload_event != NULL)
6494                 isc_task_send(server->task, &server->reload_event);
6495         UNLOCK(&server->reload_event_lock);
6496 }
6497
6498 static char *
6499 next_token(char **stringp, const char *delim) {
6500         char *res;
6501
6502         do {
6503                 res = strsep(stringp, delim);
6504                 if (res == NULL)
6505                         break;
6506         } while (*res == '\0');
6507         return (res);
6508 }
6509
6510 /*
6511  * Find the zone specified in the control channel command 'args',
6512  * if any.  If a zone is specified, point '*zonep' at it, otherwise
6513  * set '*zonep' to NULL.
6514  */
6515 static isc_result_t
6516 zone_from_args(ns_server_t *server, char *args, const char *zonetxt,
6517                dns_zone_t **zonep, const char **zonename,
6518                isc_buffer_t *text, isc_boolean_t skip)
6519 {
6520         char *input, *ptr;
6521         char *classtxt;
6522         const char *viewtxt = NULL;
6523         dns_fixedname_t fname;
6524         dns_name_t *name;
6525         isc_result_t result;
6526         dns_view_t *view = NULL;
6527         dns_rdataclass_t rdclass;
6528         char problem[DNS_NAME_FORMATSIZE + 500] = "";
6529
6530         REQUIRE(zonep != NULL && *zonep == NULL);
6531         REQUIRE(zonename == NULL || *zonename == NULL);
6532
6533         input = args;
6534
6535         if (skip) {
6536                 /* Skip the command name. */
6537                 ptr = next_token(&input, " \t");
6538                 if (ptr == NULL)
6539                         return (ISC_R_UNEXPECTEDEND);
6540         }
6541
6542         /* Look for the zone name. */
6543         if (zonetxt == NULL)
6544                 zonetxt = next_token(&input, " \t");
6545         if (zonetxt == NULL)
6546                 return (ISC_R_SUCCESS);
6547         if (zonename != NULL)
6548                 *zonename = zonetxt;
6549
6550         /* Look for the optional class name. */
6551         classtxt = next_token(&input, " \t");
6552         if (classtxt != NULL) {
6553                 /* Look for the optional view name. */
6554                 viewtxt = next_token(&input, " \t");
6555         }
6556
6557         dns_fixedname_init(&fname);
6558         name = dns_fixedname_name(&fname);
6559         CHECK(dns_name_fromstring(name, zonetxt, 0, NULL));
6560
6561         if (classtxt != NULL) {
6562                 isc_textregion_t r;
6563                 r.base = classtxt;
6564                 r.length = strlen(classtxt);
6565                 CHECK(dns_rdataclass_fromtext(&rdclass, &r));
6566         } else
6567                 rdclass = dns_rdataclass_in;
6568
6569         if (viewtxt == NULL) {
6570                 result = dns_viewlist_findzone(&server->viewlist, name,
6571                                                ISC_TF(classtxt == NULL),
6572                                                rdclass, zonep);
6573                 if (result == ISC_R_NOTFOUND)
6574                         snprintf(problem, sizeof(problem),
6575                                  "no matching zone '%s' in any view",
6576                                  zonetxt);
6577         } else {
6578                 result = dns_viewlist_find(&server->viewlist, viewtxt,
6579                                            rdclass, &view);
6580                 if (result != ISC_R_SUCCESS) {
6581                         snprintf(problem, sizeof(problem),
6582                                  "no matching view '%s'", viewtxt);
6583                         goto report;
6584                 }
6585
6586                 result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
6587                 if (result != ISC_R_SUCCESS)
6588                         snprintf(problem, sizeof(problem),
6589                                  "no matching zone '%s' in view '%s'",
6590                                  zonetxt, viewtxt);
6591         }
6592
6593         /* Partial match? */
6594         if (result != ISC_R_SUCCESS && *zonep != NULL)
6595                 dns_zone_detach(zonep);
6596         if (result == DNS_R_PARTIALMATCH)
6597                 result = ISC_R_NOTFOUND;
6598  report:
6599         if (result != ISC_R_SUCCESS) {
6600                 isc_result_t tresult;
6601
6602                 tresult = putstr(text, problem);
6603                 if (tresult == ISC_R_SUCCESS &&
6604                     isc_buffer_availablelength(text) > 0U)
6605                         isc_buffer_putuint8(text, 0);
6606         }
6607
6608  cleanup:
6609         if (view != NULL)
6610                 dns_view_detach(&view);
6611
6612         return (result);
6613 }
6614
6615 /*
6616  * Act on a "retransfer" command from the command channel.
6617  */
6618 isc_result_t
6619 ns_server_retransfercommand(ns_server_t *server, char *args,
6620                             isc_buffer_t *text)
6621 {
6622         isc_result_t result;
6623         dns_zone_t *zone = NULL;
6624         dns_zone_t *raw = NULL;
6625         dns_zonetype_t type;
6626
6627         result = zone_from_args(server, args, NULL, &zone, NULL,
6628                                 text, ISC_TRUE);
6629         if (result != ISC_R_SUCCESS)
6630                 return (result);
6631         if (zone == NULL)
6632                 return (ISC_R_UNEXPECTEDEND);
6633         dns_zone_getraw(zone, &raw);
6634         if (raw != NULL) {
6635                 dns_zone_detach(&zone);
6636                 dns_zone_attach(raw, &zone);
6637                 dns_zone_detach(&raw);
6638         }
6639         type = dns_zone_gettype(zone);
6640         if (type == dns_zone_slave || type == dns_zone_stub)
6641                 dns_zone_forcereload(zone);
6642         else
6643                 result = ISC_R_NOTFOUND;
6644         dns_zone_detach(&zone);
6645         return (result);
6646 }
6647
6648 /*
6649  * Act on a "reload" command from the command channel.
6650  */
6651 isc_result_t
6652 ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
6653         isc_result_t result;
6654         dns_zone_t *zone = NULL;
6655         dns_zonetype_t type;
6656         const char *msg = NULL;
6657
6658         result = zone_from_args(server, args, NULL, &zone, NULL,
6659                                 text, ISC_TRUE);
6660         if (result != ISC_R_SUCCESS)
6661                 return (result);
6662         if (zone == NULL) {
6663                 result = reload(server);
6664                 if (result == ISC_R_SUCCESS)
6665                         msg = "server reload successful";
6666         } else {
6667                 type = dns_zone_gettype(zone);
6668                 if (type == dns_zone_slave || type == dns_zone_stub) {
6669                         dns_zone_refresh(zone);
6670                         dns_zone_detach(&zone);
6671                         msg = "zone refresh queued";
6672                 } else {
6673                         result = dns_zone_load(zone);
6674                         dns_zone_detach(&zone);
6675                         switch (result) {
6676                         case ISC_R_SUCCESS:
6677                                  msg = "zone reload successful";
6678                                  break;
6679                         case DNS_R_CONTINUE:
6680                                 msg = "zone reload queued";
6681                                 result = ISC_R_SUCCESS;
6682                                 break;
6683                         case DNS_R_UPTODATE:
6684                                 msg = "zone reload up-to-date";
6685                                 result = ISC_R_SUCCESS;
6686                                 break;
6687                         default:
6688                                 /* failure message will be generated by rndc */
6689                                 break;
6690                         }
6691                 }
6692         }
6693         if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
6694                 isc_buffer_putmem(text, (const unsigned char *)msg,
6695                                   strlen(msg) + 1);
6696         return (result);
6697 }
6698
6699 /*
6700  * Act on a "reconfig" command from the command channel.
6701  */
6702 isc_result_t
6703 ns_server_reconfigcommand(ns_server_t *server, char *args) {
6704         UNUSED(args);
6705
6706         reconfig(server);
6707         return (ISC_R_SUCCESS);
6708 }
6709
6710 /*
6711  * Act on a "notify" command from the command channel.
6712  */
6713 isc_result_t
6714 ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) {
6715         isc_result_t result;
6716         dns_zone_t *zone = NULL;
6717         const unsigned char msg[] = "zone notify queued";
6718
6719         result = zone_from_args(server, args, NULL, &zone, NULL,
6720                                 text, ISC_TRUE);
6721         if (result != ISC_R_SUCCESS)
6722                 return (result);
6723         if (zone == NULL)
6724                 return (ISC_R_UNEXPECTEDEND);
6725
6726         dns_zone_notify(zone);
6727         dns_zone_detach(&zone);
6728         if (sizeof(msg) <= isc_buffer_availablelength(text))
6729                 isc_buffer_putmem(text, msg, sizeof(msg));
6730
6731         return (ISC_R_SUCCESS);
6732 }
6733
6734 /*
6735  * Act on a "refresh" command from the command channel.
6736  */
6737 isc_result_t
6738 ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
6739         isc_result_t result;
6740         dns_zone_t *zone = NULL, *raw = NULL;
6741         const unsigned char msg1[] = "zone refresh queued";
6742         const unsigned char msg2[] = "not a slave or stub zone";
6743         dns_zonetype_t type;
6744
6745         result = zone_from_args(server, args, NULL, &zone, NULL,
6746                                 text, ISC_TRUE);
6747         if (result != ISC_R_SUCCESS)
6748                 return (result);
6749         if (zone == NULL)
6750                 return (ISC_R_UNEXPECTEDEND);
6751
6752         dns_zone_getraw(zone, &raw);
6753         if (raw != NULL) {
6754                 dns_zone_detach(&zone);
6755                 dns_zone_attach(raw, &zone);
6756                 dns_zone_detach(&raw);
6757         }
6758
6759         type = dns_zone_gettype(zone);
6760         if (type == dns_zone_slave || type == dns_zone_stub) {
6761                 dns_zone_refresh(zone);
6762                 dns_zone_detach(&zone);
6763                 if (sizeof(msg1) <= isc_buffer_availablelength(text))
6764                         isc_buffer_putmem(text, msg1, sizeof(msg1));
6765                 return (ISC_R_SUCCESS);
6766         }
6767
6768         dns_zone_detach(&zone);
6769         if (sizeof(msg2) <= isc_buffer_availablelength(text))
6770                 isc_buffer_putmem(text, msg2, sizeof(msg2));
6771         return (ISC_R_FAILURE);
6772 }
6773
6774 isc_result_t
6775 ns_server_togglequerylog(ns_server_t *server, char *args) {
6776         isc_boolean_t value;
6777         char *ptr;
6778
6779         /* Skip the command name. */
6780         ptr = next_token(&args, " \t");
6781         if (ptr == NULL)
6782                 return (ISC_R_UNEXPECTEDEND);
6783
6784         ptr = next_token(&args, " \t");
6785         if (ptr == NULL)
6786                 value = server->log_queries ? ISC_FALSE : ISC_TRUE;
6787         else if (strcasecmp(ptr, "yes") == 0 || strcasecmp(ptr, "on") == 0)
6788                 value = ISC_TRUE;
6789         else if (strcasecmp(ptr, "no") == 0 || strcasecmp(ptr, "off") == 0)
6790                 value = ISC_FALSE;
6791         else
6792                 return (ISC_R_NOTFOUND);
6793
6794         if (server->log_queries == value)
6795                 return (ISC_R_SUCCESS);
6796
6797         server->log_queries = value;
6798
6799         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6800                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6801                       "query logging is now %s",
6802                       server->log_queries ? "on" : "off");
6803         return (ISC_R_SUCCESS);
6804 }
6805
6806 static isc_result_t
6807 ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
6808                          cfg_aclconfctx_t *actx,
6809                          isc_mem_t *mctx, ns_listenlist_t **target)
6810 {
6811         isc_result_t result;
6812         const cfg_listelt_t *element;
6813         ns_listenlist_t *dlist = NULL;
6814
6815         REQUIRE(target != NULL && *target == NULL);
6816
6817         result = ns_listenlist_create(mctx, &dlist);
6818         if (result != ISC_R_SUCCESS)
6819                 return (result);
6820
6821         for (element = cfg_list_first(listenlist);
6822              element != NULL;
6823              element = cfg_list_next(element))
6824         {
6825                 ns_listenelt_t *delt = NULL;
6826                 const cfg_obj_t *listener = cfg_listelt_value(element);
6827                 result = ns_listenelt_fromconfig(listener, config, actx,
6828                                                  mctx, &delt);
6829                 if (result != ISC_R_SUCCESS)
6830                         goto cleanup;
6831                 ISC_LIST_APPEND(dlist->elts, delt, link);
6832         }
6833         *target = dlist;
6834         return (ISC_R_SUCCESS);
6835
6836  cleanup:
6837         ns_listenlist_detach(&dlist);
6838         return (result);
6839 }
6840
6841 /*
6842  * Create a listen list from the corresponding configuration
6843  * data structure.
6844  */
6845 static isc_result_t
6846 ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
6847                         cfg_aclconfctx_t *actx,
6848                         isc_mem_t *mctx, ns_listenelt_t **target)
6849 {
6850         isc_result_t result;
6851         const cfg_obj_t *portobj;
6852         in_port_t port;
6853         ns_listenelt_t *delt = NULL;
6854         REQUIRE(target != NULL && *target == NULL);
6855
6856         portobj = cfg_tuple_get(listener, "port");
6857         if (!cfg_obj_isuint32(portobj)) {
6858                 if (ns_g_port != 0) {
6859                         port = ns_g_port;
6860                 } else {
6861                         result = ns_config_getport(config, &port);
6862                         if (result != ISC_R_SUCCESS)
6863                                 return (result);
6864                 }
6865         } else {
6866                 if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
6867                         cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
6868                                     "port value '%u' is out of range",
6869                                     cfg_obj_asuint32(portobj));
6870                         return (ISC_R_RANGE);
6871                 }
6872                 port = (in_port_t)cfg_obj_asuint32(portobj);
6873         }
6874
6875         result = ns_listenelt_create(mctx, port, NULL, &delt);
6876         if (result != ISC_R_SUCCESS)
6877                 return (result);
6878
6879         result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"),
6880                                    config, ns_g_lctx, actx, mctx, 0,
6881                                    &delt->acl);
6882         if (result != ISC_R_SUCCESS) {
6883                 ns_listenelt_destroy(delt);
6884                 return (result);
6885         }
6886         *target = delt;
6887         return (ISC_R_SUCCESS);
6888 }
6889
6890 isc_result_t
6891 ns_server_dumpstats(ns_server_t *server) {
6892         isc_result_t result;
6893         FILE *fp = NULL;
6894
6895         CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
6896                 "could not open statistics dump file", server->statsfile);
6897
6898         result = ns_stats_dump(server, fp);
6899
6900  cleanup:
6901         if (fp != NULL)
6902                 (void)isc_stdio_close(fp);
6903         if (result == ISC_R_SUCCESS)
6904                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6905                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
6906                               "dumpstats complete");
6907         else
6908                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
6909                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
6910                               "dumpstats failed: %s",
6911                               dns_result_totext(result));
6912         return (result);
6913 }
6914
6915 static isc_result_t
6916 add_zone_tolist(dns_zone_t *zone, void *uap) {
6917         struct dumpcontext *dctx = uap;
6918         struct zonelistentry *zle;
6919
6920         zle = isc_mem_get(dctx->mctx, sizeof *zle);
6921         if (zle ==  NULL)
6922                 return (ISC_R_NOMEMORY);
6923         zle->zone = NULL;
6924         dns_zone_attach(zone, &zle->zone);
6925         ISC_LINK_INIT(zle, link);
6926         ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
6927         return (ISC_R_SUCCESS);
6928 }
6929
6930 static isc_result_t
6931 add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
6932         struct viewlistentry *vle;
6933         isc_result_t result = ISC_R_SUCCESS;
6934
6935         /*
6936          * Prevent duplicate views.
6937          */
6938         for (vle = ISC_LIST_HEAD(dctx->viewlist);
6939              vle != NULL;
6940              vle = ISC_LIST_NEXT(vle, link))
6941                 if (vle->view == view)
6942                         return (ISC_R_SUCCESS);
6943
6944         vle = isc_mem_get(dctx->mctx, sizeof *vle);
6945         if (vle == NULL)
6946                 return (ISC_R_NOMEMORY);
6947         vle->view = NULL;
6948         dns_view_attach(view, &vle->view);
6949         ISC_LINK_INIT(vle, link);
6950         ISC_LIST_INIT(vle->zonelist);
6951         ISC_LIST_APPEND(dctx->viewlist, vle, link);
6952         if (dctx->dumpzones)
6953                 result = dns_zt_apply(view->zonetable, ISC_TRUE,
6954                                       add_zone_tolist, dctx);
6955         return (result);
6956 }
6957
6958 static void
6959 dumpcontext_destroy(struct dumpcontext *dctx) {
6960         struct viewlistentry *vle;
6961         struct zonelistentry *zle;
6962
6963         vle = ISC_LIST_HEAD(dctx->viewlist);
6964         while (vle != NULL) {
6965                 ISC_LIST_UNLINK(dctx->viewlist, vle, link);
6966                 zle = ISC_LIST_HEAD(vle->zonelist);
6967                 while (zle != NULL) {
6968                         ISC_LIST_UNLINK(vle->zonelist, zle, link);
6969                         dns_zone_detach(&zle->zone);
6970                         isc_mem_put(dctx->mctx, zle, sizeof *zle);
6971                         zle = ISC_LIST_HEAD(vle->zonelist);
6972                 }
6973                 dns_view_detach(&vle->view);
6974                 isc_mem_put(dctx->mctx, vle, sizeof *vle);
6975                 vle = ISC_LIST_HEAD(dctx->viewlist);
6976         }
6977         if (dctx->version != NULL)
6978                 dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
6979         if (dctx->db != NULL)
6980                 dns_db_detach(&dctx->db);
6981         if (dctx->cache != NULL)
6982                 dns_db_detach(&dctx->cache);
6983         if (dctx->task != NULL)
6984                 isc_task_detach(&dctx->task);
6985         if (dctx->fp != NULL)
6986                 (void)isc_stdio_close(dctx->fp);
6987         if (dctx->mdctx != NULL)
6988                 dns_dumpctx_detach(&dctx->mdctx);
6989         isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
6990 }
6991
6992 static void
6993 dumpdone(void *arg, isc_result_t result) {
6994         struct dumpcontext *dctx = arg;
6995         char buf[1024+32];
6996         const dns_master_style_t *style;
6997
6998         if (result != ISC_R_SUCCESS)
6999                 goto cleanup;
7000         if (dctx->mdctx != NULL)
7001                 dns_dumpctx_detach(&dctx->mdctx);
7002         if (dctx->view == NULL) {
7003                 dctx->view = ISC_LIST_HEAD(dctx->viewlist);
7004                 if (dctx->view == NULL)
7005                         goto done;
7006                 INSIST(dctx->zone == NULL);
7007         } else
7008                 goto resume;
7009  nextview:
7010         fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
7011  resume:
7012         if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
7013                 fprintf(dctx->fp,
7014                         ";\n; Cache of view '%s' is shared as '%s'\n",
7015                         dctx->view->view->name,
7016                         dns_cache_getname(dctx->view->view->cache));
7017         } else if (dctx->zone == NULL && dctx->cache == NULL &&
7018                    dctx->dumpcache)
7019         {
7020                 style = &dns_master_style_cache;
7021                 /* start cache dump */
7022                 if (dctx->view->view->cachedb != NULL)
7023                         dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
7024                 if (dctx->cache != NULL) {
7025                         fprintf(dctx->fp,
7026                                 ";\n; Cache dump of view '%s' (cache %s)\n;\n",
7027                                 dctx->view->view->name,
7028                                 dns_cache_getname(dctx->view->view->cache));
7029                         result = dns_master_dumptostreaminc(dctx->mctx,
7030                                                             dctx->cache, NULL,
7031                                                             style, dctx->fp,
7032                                                             dctx->task,
7033                                                             dumpdone, dctx,
7034                                                             &dctx->mdctx);
7035                         if (result == DNS_R_CONTINUE)
7036                                 return;
7037                         if (result == ISC_R_NOTIMPLEMENTED)
7038                                 fprintf(dctx->fp, "; %s\n",
7039                                         dns_result_totext(result));
7040                         else if (result != ISC_R_SUCCESS)
7041                                 goto cleanup;
7042                 }
7043         }
7044         if (dctx->cache != NULL) {
7045                 dns_adb_dump(dctx->view->view->adb, dctx->fp);
7046                 dns_resolver_printbadcache(dctx->view->view->resolver,
7047                                            dctx->fp);
7048                 dns_db_detach(&dctx->cache);
7049         }
7050         if (dctx->dumpzones) {
7051                 style = &dns_master_style_full;
7052  nextzone:
7053                 if (dctx->version != NULL)
7054                         dns_db_closeversion(dctx->db, &dctx->version,
7055                                             ISC_FALSE);
7056                 if (dctx->db != NULL)
7057                         dns_db_detach(&dctx->db);
7058                 if (dctx->zone == NULL)
7059                         dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
7060                 else
7061                         dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
7062                 if (dctx->zone != NULL) {
7063                         /* start zone dump */
7064                         dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
7065                         fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
7066                         result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
7067                         if (result != ISC_R_SUCCESS) {
7068                                 fprintf(dctx->fp, "; %s\n",
7069                                         dns_result_totext(result));
7070                                 goto nextzone;
7071                         }
7072                         dns_db_currentversion(dctx->db, &dctx->version);
7073                         result = dns_master_dumptostreaminc(dctx->mctx,
7074                                                             dctx->db,
7075                                                             dctx->version,
7076                                                             style, dctx->fp,
7077                                                             dctx->task,
7078                                                             dumpdone, dctx,
7079                                                             &dctx->mdctx);
7080                         if (result == DNS_R_CONTINUE)
7081                                 return;
7082                         if (result == ISC_R_NOTIMPLEMENTED) {
7083                                 fprintf(dctx->fp, "; %s\n",
7084                                         dns_result_totext(result));
7085                                 result = ISC_R_SUCCESS;
7086                                 POST(result);
7087                                 goto nextzone;
7088                         }
7089                         if (result != ISC_R_SUCCESS)
7090                                 goto cleanup;
7091                 }
7092         }
7093         if (dctx->view != NULL)
7094                 dctx->view = ISC_LIST_NEXT(dctx->view, link);
7095         if (dctx->view != NULL)
7096                 goto nextview;
7097  done:
7098         fprintf(dctx->fp, "; Dump complete\n");
7099         result = isc_stdio_flush(dctx->fp);
7100         if (result == ISC_R_SUCCESS)
7101                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7102                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7103                               "dumpdb complete");
7104  cleanup:
7105         if (result != ISC_R_SUCCESS)
7106                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7107                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7108                               "dumpdb failed: %s", dns_result_totext(result));
7109         dumpcontext_destroy(dctx);
7110 }
7111
7112 isc_result_t
7113 ns_server_dumpdb(ns_server_t *server, char *args) {
7114         struct dumpcontext *dctx = NULL;
7115         dns_view_t *view;
7116         isc_result_t result;
7117         char *ptr;
7118         const char *sep;
7119
7120         /* Skip the command name. */
7121         ptr = next_token(&args, " \t");
7122         if (ptr == NULL)
7123                 return (ISC_R_UNEXPECTEDEND);
7124
7125         dctx = isc_mem_get(server->mctx, sizeof(*dctx));
7126         if (dctx == NULL)
7127                 return (ISC_R_NOMEMORY);
7128
7129         dctx->mctx = server->mctx;
7130         dctx->dumpcache = ISC_TRUE;
7131         dctx->dumpzones = ISC_FALSE;
7132         dctx->fp = NULL;
7133         ISC_LIST_INIT(dctx->viewlist);
7134         dctx->view = NULL;
7135         dctx->zone = NULL;
7136         dctx->cache = NULL;
7137         dctx->mdctx = NULL;
7138         dctx->db = NULL;
7139         dctx->cache = NULL;
7140         dctx->task = NULL;
7141         dctx->version = NULL;
7142         isc_task_attach(server->task, &dctx->task);
7143
7144         CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
7145                 "could not open dump file", server->dumpfile);
7146
7147         sep = (args == NULL) ? "" : ": ";
7148         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7149                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7150                       "dumpdb started%s%s", sep, (args != NULL) ? args : "");
7151
7152         ptr = next_token(&args, " \t");
7153         if (ptr != NULL && strcmp(ptr, "-all") == 0) {
7154                 dctx->dumpzones = ISC_TRUE;
7155                 dctx->dumpcache = ISC_TRUE;
7156                 ptr = next_token(&args, " \t");
7157         } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
7158                 dctx->dumpzones = ISC_FALSE;
7159                 dctx->dumpcache = ISC_TRUE;
7160                 ptr = next_token(&args, " \t");
7161         } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
7162                 dctx->dumpzones = ISC_TRUE;
7163                 dctx->dumpcache = ISC_FALSE;
7164                 ptr = next_token(&args, " \t");
7165         }
7166
7167  nextview:
7168         for (view = ISC_LIST_HEAD(server->viewlist);
7169              view != NULL;
7170              view = ISC_LIST_NEXT(view, link))
7171         {
7172                 if (ptr != NULL && strcmp(view->name, ptr) != 0)
7173                         continue;
7174                 CHECK(add_view_tolist(dctx, view));
7175         }
7176         if (ptr != NULL) {
7177                 ptr = next_token(&args, " \t");
7178                 if (ptr != NULL)
7179                         goto nextview;
7180         }
7181         dumpdone(dctx, ISC_R_SUCCESS);
7182         return (ISC_R_SUCCESS);
7183
7184  cleanup:
7185         if (dctx != NULL)
7186                 dumpcontext_destroy(dctx);
7187         return (result);
7188 }
7189
7190 isc_result_t
7191 ns_server_dumpsecroots(ns_server_t *server, char *args) {
7192         dns_view_t *view;
7193         dns_keytable_t *secroots = NULL;
7194         isc_result_t result;
7195         char *ptr;
7196         FILE *fp = NULL;
7197         isc_time_t now;
7198         char tbuf[64];
7199
7200         /* Skip the command name. */
7201         ptr = next_token(&args, " \t");
7202         if (ptr == NULL)
7203                 return (ISC_R_UNEXPECTEDEND);
7204
7205         ptr = next_token(&args, " \t");
7206
7207         CHECKMF(isc_stdio_open(server->secrootsfile, "w", &fp),
7208                 "could not open secroots dump file", server->secrootsfile);
7209         TIME_NOW(&now);
7210         isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
7211         fprintf(fp, "%s\n", tbuf);
7212
7213         do {
7214                 for (view = ISC_LIST_HEAD(server->viewlist);
7215                      view != NULL;
7216                      view = ISC_LIST_NEXT(view, link))
7217                 {
7218                         if (ptr != NULL && strcmp(view->name, ptr) != 0)
7219                                 continue;
7220                         if (secroots != NULL)
7221                                 dns_keytable_detach(&secroots);
7222                         result = dns_view_getsecroots(view, &secroots);
7223                         if (result == ISC_R_NOTFOUND) {
7224                                 result = ISC_R_SUCCESS;
7225                                 continue;
7226                         }
7227                         fprintf(fp, "\n Start view %s\n\n", view->name);
7228                         result = dns_keytable_dump(secroots, fp);
7229                         if (result != ISC_R_SUCCESS)
7230                                 fprintf(fp, " dumpsecroots failed: %s\n",
7231                                         isc_result_totext(result));
7232                 }
7233                 if (ptr != NULL)
7234                         ptr = next_token(&args, " \t");
7235         } while (ptr != NULL);
7236
7237  cleanup:
7238         if (secroots != NULL)
7239                 dns_keytable_detach(&secroots);
7240         if (fp != NULL)
7241                 (void)isc_stdio_close(fp);
7242         if (result == ISC_R_SUCCESS)
7243                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7244                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7245                               "dumpsecroots complete");
7246         else
7247                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7248                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7249                               "dumpsecroots failed: %s",
7250                               dns_result_totext(result));
7251         return (result);
7252 }
7253
7254 isc_result_t
7255 ns_server_dumprecursing(ns_server_t *server) {
7256         FILE *fp = NULL;
7257         isc_result_t result;
7258
7259         CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
7260                 "could not open dump file", server->recfile);
7261         fprintf(fp,";\n; Recursing Queries\n;\n");
7262         ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
7263         fprintf(fp, "; Dump complete\n");
7264
7265  cleanup:
7266         if (fp != NULL)
7267                 result = isc_stdio_close(fp);
7268         if (result == ISC_R_SUCCESS)
7269                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7270                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7271                               "dumprecursing complete");
7272         else
7273                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7274                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7275                               "dumprecursing failed: %s",
7276                               dns_result_totext(result));
7277         return (result);
7278 }
7279
7280 isc_result_t
7281 ns_server_setdebuglevel(ns_server_t *server, char *args) {
7282         char *ptr;
7283         char *levelstr;
7284         char *endp;
7285         long newlevel;
7286
7287         UNUSED(server);
7288
7289         /* Skip the command name. */
7290         ptr = next_token(&args, " \t");
7291         if (ptr == NULL)
7292                 return (ISC_R_UNEXPECTEDEND);
7293
7294         /* Look for the new level name. */
7295         levelstr = next_token(&args, " \t");
7296         if (levelstr == NULL) {
7297                 if (ns_g_debuglevel < 99)
7298                         ns_g_debuglevel++;
7299         } else {
7300                 newlevel = strtol(levelstr, &endp, 10);
7301                 if (*endp != '\0' || newlevel < 0 || newlevel > 99)
7302                         return (ISC_R_RANGE);
7303                 ns_g_debuglevel = (unsigned int)newlevel;
7304         }
7305         isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel);
7306         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7307                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7308                       "debug level is now %d", ns_g_debuglevel);
7309         return (ISC_R_SUCCESS);
7310 }
7311
7312 isc_result_t
7313 ns_server_validation(ns_server_t *server, char *args) {
7314         char *ptr, *viewname;
7315         dns_view_t *view;
7316         isc_boolean_t changed = ISC_FALSE;
7317         isc_result_t result;
7318         isc_boolean_t enable;
7319
7320         /* Skip the command name. */
7321         ptr = next_token(&args, " \t");
7322         if (ptr == NULL)
7323                 return (ISC_R_UNEXPECTEDEND);
7324
7325         /* Find out what we are to do. */
7326         ptr = next_token(&args, " \t");
7327         if (ptr == NULL)
7328                 return (ISC_R_UNEXPECTEDEND);
7329
7330         if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
7331             !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
7332                 enable = ISC_TRUE;
7333         else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
7334                  !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
7335                 enable = ISC_FALSE;
7336         else
7337                 return (DNS_R_SYNTAX);
7338
7339         /* Look for the view name. */
7340         viewname = next_token(&args, " \t");
7341
7342         result = isc_task_beginexclusive(server->task);
7343         RUNTIME_CHECK(result == ISC_R_SUCCESS);
7344         for (view = ISC_LIST_HEAD(server->viewlist);
7345              view != NULL;
7346              view = ISC_LIST_NEXT(view, link))
7347         {
7348                 if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
7349                         continue;
7350                 result = dns_view_flushcache(view);
7351                 if (result != ISC_R_SUCCESS)
7352                         goto out;
7353                 view->enablevalidation = enable;
7354                 changed = ISC_TRUE;
7355         }
7356         if (changed)
7357                 result = ISC_R_SUCCESS;
7358         else
7359                 result = ISC_R_FAILURE;
7360  out:
7361         isc_task_endexclusive(server->task);
7362         return (result);
7363 }
7364
7365 isc_result_t
7366 ns_server_flushcache(ns_server_t *server, char *args) {
7367         char *ptr, *viewname;
7368         dns_view_t *view;
7369         isc_boolean_t flushed;
7370         isc_boolean_t found;
7371         isc_result_t result;
7372         ns_cache_t *nsc;
7373
7374         /* Skip the command name. */
7375         ptr = next_token(&args, " \t");
7376         if (ptr == NULL)
7377                 return (ISC_R_UNEXPECTEDEND);
7378
7379         /* Look for the view name. */
7380         viewname = next_token(&args, " \t");
7381
7382         result = isc_task_beginexclusive(server->task);
7383         RUNTIME_CHECK(result == ISC_R_SUCCESS);
7384         flushed = ISC_TRUE;
7385         found = ISC_FALSE;
7386
7387         /*
7388          * Flushing a cache is tricky when caches are shared by multiple views.
7389          * We first identify which caches should be flushed in the local cache
7390          * list, flush these caches, and then update other views that refer to
7391          * the flushed cache DB.
7392          */
7393         if (viewname != NULL) {
7394                 /*
7395                  * Mark caches that need to be flushed.  This is an O(#view^2)
7396                  * operation in the very worst case, but should be normally
7397                  * much more lightweight because only a few (most typically just
7398                  * one) views will match.
7399                  */
7400                 for (view = ISC_LIST_HEAD(server->viewlist);
7401                      view != NULL;
7402                      view = ISC_LIST_NEXT(view, link))
7403                 {
7404                         if (strcasecmp(viewname, view->name) != 0)
7405                                 continue;
7406                         found = ISC_TRUE;
7407                         for (nsc = ISC_LIST_HEAD(server->cachelist);
7408                              nsc != NULL;
7409                              nsc = ISC_LIST_NEXT(nsc, link)) {
7410                                 if (nsc->cache == view->cache)
7411                                         break;
7412                         }
7413                         INSIST(nsc != NULL);
7414                         nsc->needflush = ISC_TRUE;
7415                 }
7416         } else
7417                 found = ISC_TRUE;
7418
7419         /* Perform flush */
7420         for (nsc = ISC_LIST_HEAD(server->cachelist);
7421              nsc != NULL;
7422              nsc = ISC_LIST_NEXT(nsc, link)) {
7423                 if (viewname != NULL && !nsc->needflush)
7424                         continue;
7425                 nsc->needflush = ISC_TRUE;
7426                 result = dns_view_flushcache2(nsc->primaryview, ISC_FALSE);
7427                 if (result != ISC_R_SUCCESS) {
7428                         flushed = ISC_FALSE;
7429                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7430                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7431                                       "flushing cache in view '%s' failed: %s",
7432                                       nsc->primaryview->name,
7433                                       isc_result_totext(result));
7434                 }
7435         }
7436
7437         /*
7438          * Fix up views that share a flushed cache: let the views update the
7439          * cache DB they're referring to.  This could also be an expensive
7440          * operation, but should typically be marginal: the inner loop is only
7441          * necessary for views that share a cache, and if there are many such
7442          * views the number of shared cache should normally be small.
7443          * A worst case is that we have n views and n/2 caches, each shared by
7444          * two views.  Then this will be a O(n^2/4) operation.
7445          */
7446         for (view = ISC_LIST_HEAD(server->viewlist);
7447              view != NULL;
7448              view = ISC_LIST_NEXT(view, link))
7449         {
7450                 if (!dns_view_iscacheshared(view))
7451                         continue;
7452                 for (nsc = ISC_LIST_HEAD(server->cachelist);
7453                      nsc != NULL;
7454                      nsc = ISC_LIST_NEXT(nsc, link)) {
7455                         if (!nsc->needflush || nsc->cache != view->cache)
7456                                 continue;
7457                         result = dns_view_flushcache2(view, ISC_TRUE);
7458                         if (result != ISC_R_SUCCESS) {
7459                                 flushed = ISC_FALSE;
7460                                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7461                                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7462                                               "fixing cache in view '%s' "
7463                                               "failed: %s", view->name,
7464                                               isc_result_totext(result));
7465                         }
7466                 }
7467         }
7468
7469         /* Cleanup the cache list. */
7470         for (nsc = ISC_LIST_HEAD(server->cachelist);
7471              nsc != NULL;
7472              nsc = ISC_LIST_NEXT(nsc, link)) {
7473                 nsc->needflush = ISC_FALSE;
7474         }
7475
7476         if (flushed && found) {
7477                 if (viewname != NULL)
7478                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7479                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7480                                       "flushing cache in view '%s' succeeded",
7481                                       viewname);
7482                 else
7483                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7484                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7485                                       "flushing caches in all views succeeded");
7486                 result = ISC_R_SUCCESS;
7487         } else {
7488                 if (!found) {
7489                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7490                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7491                                       "flushing cache in view '%s' failed: "
7492                                       "view not found", viewname);
7493                         result = ISC_R_NOTFOUND;
7494                 } else
7495                         result = ISC_R_FAILURE;
7496         }
7497         isc_task_endexclusive(server->task);
7498         return (result);
7499 }
7500
7501 isc_result_t
7502 ns_server_flushnode(ns_server_t *server, char *args, isc_boolean_t tree) {
7503         char *ptr, *target, *viewname;
7504         dns_view_t *view;
7505         isc_boolean_t flushed;
7506         isc_boolean_t found;
7507         isc_result_t result;
7508         isc_buffer_t b;
7509         dns_fixedname_t fixed;
7510         dns_name_t *name;
7511
7512         /* Skip the command name. */
7513         ptr = next_token(&args, " \t");
7514         if (ptr == NULL)
7515                 return (ISC_R_UNEXPECTEDEND);
7516
7517         /* Find the domain name to flush. */
7518         target = next_token(&args, " \t");
7519         if (target == NULL)
7520                 return (ISC_R_UNEXPECTEDEND);
7521
7522         isc_buffer_constinit(&b, target, strlen(target));
7523         isc_buffer_add(&b, strlen(target));
7524         dns_fixedname_init(&fixed);
7525         name = dns_fixedname_name(&fixed);
7526         result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
7527         if (result != ISC_R_SUCCESS)
7528                 return (result);
7529
7530         /* Look for the view name. */
7531         viewname = next_token(&args, " \t");
7532
7533         result = isc_task_beginexclusive(server->task);
7534         RUNTIME_CHECK(result == ISC_R_SUCCESS);
7535         flushed = ISC_TRUE;
7536         found = ISC_FALSE;
7537         for (view = ISC_LIST_HEAD(server->viewlist);
7538              view != NULL;
7539              view = ISC_LIST_NEXT(view, link))
7540         {
7541                 if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
7542                         continue;
7543                 found = ISC_TRUE;
7544                 /*
7545                  * It's a little inefficient to try flushing name for all views
7546                  * if some of the views share a single cache.  But since the
7547                  * operation is lightweight we prefer simplicity here.
7548                  */
7549                 result = dns_view_flushnode(view, name, tree);
7550                 if (result != ISC_R_SUCCESS) {
7551                         flushed = ISC_FALSE;
7552                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7553                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7554                                       "flushing %s '%s' in cache view '%s' "
7555                                       "failed: %s",
7556                                       tree ? "tree" : "name",
7557                                       target, view->name,
7558                                       isc_result_totext(result));
7559                 }
7560         }
7561         if (flushed && found) {
7562                 if (viewname != NULL)
7563                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7564                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7565                                       "flushing %s '%s' in cache view '%s' "
7566                                       "succeeded",
7567                                       tree ? "tree" : "name",
7568                                       target, viewname);
7569                 else
7570                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7571                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7572                                       "flushing %s '%s' in all cache views "
7573                                       "succeeded",
7574                                       tree ? "tree" : "name",
7575                                       target);
7576                 result = ISC_R_SUCCESS;
7577         } else {
7578                 if (!found)
7579                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7580                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
7581                                       "flushing %s '%s' in cache view '%s' "
7582                                       "failed: view not found",
7583                                       tree ? "tree" : "name",
7584                                       target, viewname);
7585                 result = ISC_R_FAILURE;
7586         }
7587         isc_task_endexclusive(server->task);
7588         return (result);
7589 }
7590
7591 isc_result_t
7592 ns_server_status(ns_server_t *server, isc_buffer_t *text) {
7593         int zonecount, xferrunning, xferdeferred, soaqueries;
7594         unsigned int n;
7595         const char *ob = "", *cb = "", *alt = "";
7596
7597         if (ns_g_server->version_set) {
7598                 ob = " (";
7599                 cb = ")";
7600                 if (ns_g_server->version == NULL)
7601                         alt = "version.bind/txt/ch disabled";
7602                 else
7603                         alt = ns_g_server->version;
7604         }
7605         zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
7606         xferrunning = dns_zonemgr_getcount(server->zonemgr,
7607                                            DNS_ZONESTATE_XFERRUNNING);
7608         xferdeferred = dns_zonemgr_getcount(server->zonemgr,
7609                                             DNS_ZONESTATE_XFERDEFERRED);
7610         soaqueries = dns_zonemgr_getcount(server->zonemgr,
7611                                           DNS_ZONESTATE_SOAQUERY);
7612
7613         n = snprintf((char *)isc_buffer_used(text),
7614                      isc_buffer_availablelength(text),
7615                      "version: %s%s%s%s <id:%s>\n"
7616 #ifdef ISC_PLATFORM_USETHREADS
7617                      "CPUs found: %u\n"
7618                      "worker threads: %u\n"
7619                      "UDP listeners per interface: %u\n"
7620 #endif
7621                      "number of zones: %u\n"
7622                      "debug level: %d\n"
7623                      "xfers running: %u\n"
7624                      "xfers deferred: %u\n"
7625                      "soa queries in progress: %u\n"
7626                      "query logging is %s\n"
7627                      "recursive clients: %d/%d/%d\n"
7628                      "tcp clients: %d/%d\n"
7629                      "server is up and running",
7630                      ns_g_version, ob, alt, cb, ns_g_srcid,
7631 #ifdef ISC_PLATFORM_USETHREADS
7632                      ns_g_cpus_detected, ns_g_cpus, ns_g_udpdisp,
7633 #endif
7634                      zonecount, ns_g_debuglevel, xferrunning, xferdeferred,
7635                      soaqueries, server->log_queries ? "ON" : "OFF",
7636                      server->recursionquota.used, server->recursionquota.soft,
7637                      server->recursionquota.max,
7638                      server->tcpquota.used, server->tcpquota.max);
7639         if (n >= isc_buffer_availablelength(text))
7640                 return (ISC_R_NOSPACE);
7641         isc_buffer_add(text, n);
7642         return (ISC_R_SUCCESS);
7643 }
7644
7645 static isc_result_t
7646 delete_keynames(dns_tsig_keyring_t *ring, char *target,
7647                 unsigned int *foundkeys)
7648 {
7649         char namestr[DNS_NAME_FORMATSIZE];
7650         isc_result_t result;
7651         dns_rbtnodechain_t chain;
7652         dns_name_t foundname;
7653         dns_fixedname_t fixedorigin;
7654         dns_name_t *origin;
7655         dns_rbtnode_t *node;
7656         dns_tsigkey_t *tkey;
7657
7658         dns_name_init(&foundname, NULL);
7659         dns_fixedname_init(&fixedorigin);
7660         origin = dns_fixedname_name(&fixedorigin);
7661
7662  again:
7663         dns_rbtnodechain_init(&chain, ring->mctx);
7664         result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
7665                                         origin);
7666         if (result == ISC_R_NOTFOUND) {
7667                 dns_rbtnodechain_invalidate(&chain);
7668                 return (ISC_R_SUCCESS);
7669         }
7670         if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
7671                 dns_rbtnodechain_invalidate(&chain);
7672                 return (result);
7673         }
7674
7675         for (;;) {
7676                 node = NULL;
7677                 dns_rbtnodechain_current(&chain, &foundname, origin, &node);
7678                 tkey = node->data;
7679
7680                 if (tkey != NULL) {
7681                         if (!tkey->generated)
7682                                 goto nextkey;
7683
7684                         dns_name_format(&tkey->name, namestr, sizeof(namestr));
7685                         if (strcmp(namestr, target) == 0) {
7686                                 (*foundkeys)++;
7687                                 dns_rbtnodechain_invalidate(&chain);
7688                                 (void)dns_rbt_deletename(ring->keys,
7689                                                          &tkey->name,
7690                                                          ISC_FALSE);
7691                                 goto again;
7692                         }
7693                 }
7694
7695         nextkey:
7696                 result = dns_rbtnodechain_next(&chain, &foundname, origin);
7697                 if (result == ISC_R_NOMORE)
7698                         break;
7699                 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
7700                         dns_rbtnodechain_invalidate(&chain);
7701                         return (result);
7702                 }
7703         }
7704
7705         return (ISC_R_SUCCESS);
7706 }
7707
7708 isc_result_t
7709 ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text) {
7710         isc_result_t result;
7711         unsigned int n;
7712         dns_view_t *view;
7713         unsigned int foundkeys = 0;
7714         char *target;
7715         char *viewname;
7716
7717         (void)next_token(&command, " \t");  /* skip command name */
7718         target = next_token(&command, " \t");
7719         if (target == NULL)
7720                 return (ISC_R_UNEXPECTEDEND);
7721         viewname = next_token(&command, " \t");
7722
7723         result = isc_task_beginexclusive(server->task);
7724         RUNTIME_CHECK(result == ISC_R_SUCCESS);
7725         for (view = ISC_LIST_HEAD(server->viewlist);
7726              view != NULL;
7727              view = ISC_LIST_NEXT(view, link)) {
7728                 if (viewname == NULL || strcmp(view->name, viewname) == 0) {
7729                         RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
7730                         result = delete_keynames(view->dynamickeys, target,
7731                                                  &foundkeys);
7732                         RWUNLOCK(&view->dynamickeys->lock,
7733                                  isc_rwlocktype_write);
7734                         if (result != ISC_R_SUCCESS) {
7735                                 isc_task_endexclusive(server->task);
7736                                 return (result);
7737                         }
7738                 }
7739         }
7740         isc_task_endexclusive(server->task);
7741
7742         n = snprintf((char *)isc_buffer_used(text),
7743                      isc_buffer_availablelength(text),
7744                      "%d tsig keys deleted.\n", foundkeys);
7745         if (n >= isc_buffer_availablelength(text))
7746                 return (ISC_R_NOSPACE);
7747         isc_buffer_add(text, n);
7748
7749         return (ISC_R_SUCCESS);
7750 }
7751
7752 static isc_result_t
7753 list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text,
7754              unsigned int *foundkeys)
7755 {
7756         char namestr[DNS_NAME_FORMATSIZE];
7757         char creatorstr[DNS_NAME_FORMATSIZE];
7758         isc_result_t result;
7759         dns_rbtnodechain_t chain;
7760         dns_name_t foundname;
7761         dns_fixedname_t fixedorigin;
7762         dns_name_t *origin;
7763         dns_rbtnode_t *node;
7764         dns_tsigkey_t *tkey;
7765         unsigned int n;
7766         const char *viewname;
7767
7768         if (view != NULL)
7769                 viewname = view->name;
7770         else
7771                 viewname = "(global)";
7772
7773         dns_name_init(&foundname, NULL);
7774         dns_fixedname_init(&fixedorigin);
7775         origin = dns_fixedname_name(&fixedorigin);
7776         dns_rbtnodechain_init(&chain, ring->mctx);
7777         result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
7778                                         origin);
7779         if (result == ISC_R_NOTFOUND) {
7780                 dns_rbtnodechain_invalidate(&chain);
7781                 return (ISC_R_SUCCESS);
7782         }
7783         if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
7784                 dns_rbtnodechain_invalidate(&chain);
7785                 return (result);
7786         }
7787
7788         for (;;) {
7789                 node = NULL;
7790                 dns_rbtnodechain_current(&chain, &foundname, origin, &node);
7791                 tkey = node->data;
7792
7793                 if (tkey != NULL) {
7794                         (*foundkeys)++;
7795                         dns_name_format(&tkey->name, namestr, sizeof(namestr));
7796                         if (tkey->generated) {
7797                                 dns_name_format(tkey->creator, creatorstr,
7798                                                 sizeof(creatorstr));
7799                                 n = snprintf((char *)isc_buffer_used(text),
7800                                              isc_buffer_availablelength(text),
7801                                              "view \"%s\"; type \"dynamic\"; key \"%s\"; creator \"%s\";\n",
7802                                              viewname, namestr, creatorstr);
7803                         } else {
7804                                 n = snprintf((char *)isc_buffer_used(text),
7805                                              isc_buffer_availablelength(text),
7806                                              "view \"%s\"; type \"static\"; key \"%s\";\n",
7807                                              viewname, namestr);
7808                         }
7809                         if (n >= isc_buffer_availablelength(text)) {
7810                                 dns_rbtnodechain_invalidate(&chain);
7811                                 return (ISC_R_NOSPACE);
7812                         }
7813                         isc_buffer_add(text, n);
7814                 }
7815                 result = dns_rbtnodechain_next(&chain, &foundname, origin);
7816                 if (result == ISC_R_NOMORE)
7817                         break;
7818                 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
7819                         dns_rbtnodechain_invalidate(&chain);
7820                         return (result);
7821                 }
7822         }
7823
7824         return (ISC_R_SUCCESS);
7825 }
7826
7827 isc_result_t
7828 ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) {
7829         isc_result_t result;
7830         unsigned int n;
7831         dns_view_t *view;
7832         unsigned int foundkeys = 0;
7833
7834         result = isc_task_beginexclusive(server->task);
7835         RUNTIME_CHECK(result == ISC_R_SUCCESS);
7836         for (view = ISC_LIST_HEAD(server->viewlist);
7837              view != NULL;
7838              view = ISC_LIST_NEXT(view, link)) {
7839                 RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
7840                 result = list_keynames(view, view->statickeys, text,
7841                                        &foundkeys);
7842                 RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
7843                 if (result != ISC_R_SUCCESS) {
7844                         isc_task_endexclusive(server->task);
7845                         return (result);
7846                 }
7847                 RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
7848                 result = list_keynames(view, view->dynamickeys, text,
7849                                        &foundkeys);
7850                 RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
7851                 if (result != ISC_R_SUCCESS) {
7852                         isc_task_endexclusive(server->task);
7853                         return (result);
7854                 }
7855         }
7856         isc_task_endexclusive(server->task);
7857
7858         if (foundkeys == 0) {
7859                 n = snprintf((char *)isc_buffer_used(text),
7860                              isc_buffer_availablelength(text),
7861                              "no tsig keys found.\n");
7862                 if (n >= isc_buffer_availablelength(text))
7863                         return (ISC_R_NOSPACE);
7864                 isc_buffer_add(text, n);
7865         }
7866
7867         return (ISC_R_SUCCESS);
7868 }
7869
7870 /*
7871  * Act on a "sign" or "loadkeys" command from the command channel.
7872  */
7873 isc_result_t
7874 ns_server_rekey(ns_server_t *server, char *args, isc_buffer_t *text) {
7875         isc_result_t result;
7876         dns_zone_t *zone = NULL;
7877         dns_zonetype_t type;
7878         isc_uint16_t keyopts;
7879         isc_boolean_t fullsign = ISC_FALSE;
7880
7881         if (strncasecmp(args, NS_COMMAND_SIGN, strlen(NS_COMMAND_SIGN)) == 0)
7882             fullsign = ISC_TRUE;
7883
7884         result = zone_from_args(server, args, NULL, &zone, NULL,
7885                                 text, ISC_TRUE);
7886         if (result != ISC_R_SUCCESS)
7887                 return (result);
7888         if (zone == NULL)
7889                 return (ISC_R_UNEXPECTEDEND);   /* XXX: or do all zones? */
7890
7891         type = dns_zone_gettype(zone);
7892         if (type != dns_zone_master) {
7893                 dns_zone_detach(&zone);
7894                 return (DNS_R_NOTMASTER);
7895         }
7896
7897         keyopts = dns_zone_getkeyopts(zone);
7898
7899         /* "rndc loadkeys" requires "auto-dnssec maintain". */
7900         if ((keyopts & DNS_ZONEKEY_ALLOW) == 0)
7901                 result = ISC_R_NOPERM;
7902         else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign)
7903                 result = ISC_R_NOPERM;
7904         else
7905                 dns_zone_rekey(zone, fullsign);
7906
7907         dns_zone_detach(&zone);
7908         return (result);
7909 }
7910
7911 /*
7912  * Act on a "sync" command from the command channel.
7913 */
7914 static isc_result_t
7915 synczone(dns_zone_t *zone, void *uap) {
7916         isc_boolean_t cleanup = *(isc_boolean_t *)uap;
7917         isc_result_t result;
7918         dns_zone_t *raw = NULL;
7919         char *journal;
7920
7921         dns_zone_getraw(zone, &raw);
7922         if (raw != NULL) {
7923                 synczone(raw, uap);
7924                 dns_zone_detach(&raw);
7925         }
7926
7927         result = dns_zone_flush(zone);
7928         if (result != ISC_R_SUCCESS)
7929                 cleanup = ISC_FALSE;
7930         if (cleanup) {
7931                 journal = dns_zone_getjournal(zone);
7932                 if (journal != NULL)
7933                         (void)isc_file_remove(journal);
7934         }
7935
7936         return (result);
7937 }
7938
7939 isc_result_t
7940 ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text) {
7941         isc_result_t result, tresult;
7942         dns_view_t *view;
7943         dns_zone_t *zone = NULL;
7944         char classstr[DNS_RDATACLASS_FORMATSIZE];
7945         char zonename[DNS_NAME_FORMATSIZE];
7946         const char *vname, *sep, *msg = NULL, *arg;
7947         isc_boolean_t cleanup = ISC_FALSE;
7948
7949         (void) next_token(&args, " \t");
7950
7951         arg = next_token(&args, " \t");
7952         if (arg != NULL &&
7953             (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0)) {
7954                 cleanup = ISC_TRUE;
7955                 arg = next_token(&args, " \t");
7956         }
7957
7958         result = zone_from_args(server, args, arg, &zone, NULL,
7959                                 text, ISC_FALSE);
7960         if (result != ISC_R_SUCCESS)
7961                 return (result);
7962
7963         if (zone == NULL) {
7964                 result = isc_task_beginexclusive(server->task);
7965                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
7966                 tresult = ISC_R_SUCCESS;
7967                 for (view = ISC_LIST_HEAD(server->viewlist);
7968                      view != NULL;
7969                      view = ISC_LIST_NEXT(view, link)) {
7970                         result = dns_zt_apply(view->zonetable, ISC_FALSE,
7971                                               synczone, &cleanup);
7972                         if (result != ISC_R_SUCCESS &&
7973                             tresult == ISC_R_SUCCESS)
7974                                 tresult = result;
7975                 }
7976                 isc_task_endexclusive(server->task);
7977                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
7978                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
7979                               "dumping all zones%s: %s",
7980                               cleanup ? ", removing journal files" : "",
7981                               isc_result_totext(result));
7982                 return (tresult);
7983         }
7984
7985         result = isc_task_beginexclusive(server->task);
7986         RUNTIME_CHECK(result == ISC_R_SUCCESS);
7987         result = synczone(zone, &cleanup);
7988         isc_task_endexclusive(server->task);
7989
7990         if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
7991                 isc_buffer_putmem(text, (const unsigned char *)msg,
7992                                   strlen(msg) + 1);
7993
7994         view = dns_zone_getview(zone);
7995         if (strcmp(view->name, "_default") == 0 ||
7996             strcmp(view->name, "_bind") == 0)
7997         {
7998                 vname = "";
7999                 sep = "";
8000         } else {
8001                 vname = view->name;
8002                 sep = " ";
8003         }
8004         dns_rdataclass_format(dns_zone_getclass(zone), classstr,
8005                               sizeof(classstr));
8006         dns_name_format(dns_zone_getorigin(zone),
8007                         zonename, sizeof(zonename));
8008         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8009                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8010                       "sync: dumping zone '%s/%s'%s%s%s: %s",
8011                       zonename, classstr, sep, vname,
8012                       cleanup ? ", removing journal file" : "",
8013                       isc_result_totext(result));
8014         dns_zone_detach(&zone);
8015         return (result);
8016 }
8017
8018 /*
8019  * Act on a "freeze" or "thaw" command from the command channel.
8020  */
8021 isc_result_t
8022 ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
8023                  isc_buffer_t *text)
8024 {
8025         isc_result_t result, tresult;
8026         dns_zone_t *zone = NULL, *raw = NULL;
8027         dns_zonetype_t type;
8028         char classstr[DNS_RDATACLASS_FORMATSIZE];
8029         char zonename[DNS_NAME_FORMATSIZE];
8030         dns_view_t *view;
8031         const char *vname, *sep;
8032         isc_boolean_t frozen;
8033         const char *msg = NULL;
8034
8035         result = zone_from_args(server, args, NULL, &zone, NULL,
8036                                 text, ISC_TRUE);
8037         if (result != ISC_R_SUCCESS)
8038                 return (result);
8039         if (zone == NULL) {
8040                 result = isc_task_beginexclusive(server->task);
8041                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
8042                 tresult = ISC_R_SUCCESS;
8043                 for (view = ISC_LIST_HEAD(server->viewlist);
8044                      view != NULL;
8045                      view = ISC_LIST_NEXT(view, link)) {
8046                         result = dns_view_freezezones(view, freeze);
8047                         if (result != ISC_R_SUCCESS &&
8048                             tresult == ISC_R_SUCCESS)
8049                                 tresult = result;
8050                 }
8051                 isc_task_endexclusive(server->task);
8052                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8053                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8054                               "%s all zones: %s",
8055                               freeze ? "freezing" : "thawing",
8056                               isc_result_totext(tresult));
8057                 return (tresult);
8058         }
8059         dns_zone_getraw(zone, &raw);
8060         if (raw != NULL) {
8061                 dns_zone_detach(&zone);
8062                 dns_zone_attach(raw, &zone);
8063                 dns_zone_detach(&raw);
8064         }
8065         type = dns_zone_gettype(zone);
8066         if (type != dns_zone_master) {
8067                 dns_zone_detach(&zone);
8068                 return (DNS_R_NOTMASTER);
8069         }
8070
8071         if (freeze && !dns_zone_isdynamic(zone, ISC_TRUE)) {
8072                 dns_zone_detach(&zone);
8073                 return (DNS_R_NOTDYNAMIC);
8074         }
8075
8076         result = isc_task_beginexclusive(server->task);
8077         RUNTIME_CHECK(result == ISC_R_SUCCESS);
8078         frozen = dns_zone_getupdatedisabled(zone);
8079         if (freeze) {
8080                 if (frozen) {
8081                         msg = "WARNING: The zone was already frozen.\n"
8082                               "Someone else may be editing it or "
8083                               "it may still be re-loading.";
8084                         result = DNS_R_FROZEN;
8085                 }
8086                 if (result == ISC_R_SUCCESS) {
8087                         result = dns_zone_flush(zone);
8088                         if (result != ISC_R_SUCCESS)
8089                                 msg = "Flushing the zone updates to "
8090                                       "disk failed.";
8091                 }
8092                 if (result == ISC_R_SUCCESS)
8093                         dns_zone_setupdatedisabled(zone, freeze);
8094         } else {
8095                 if (frozen) {
8096                         result = dns_zone_loadandthaw(zone);
8097                         switch (result) {
8098                         case ISC_R_SUCCESS:
8099                         case DNS_R_UPTODATE:
8100                                 msg = "The zone reload and thaw was "
8101                                       "successful.";
8102                                 result = ISC_R_SUCCESS;
8103                                 break;
8104                         case DNS_R_CONTINUE:
8105                                 msg = "A zone reload and thaw was started.\n"
8106                                       "Check the logs to see the result.";
8107                                 result = ISC_R_SUCCESS;
8108                                 break;
8109                         }
8110                 }
8111         }
8112         isc_task_endexclusive(server->task);
8113
8114         if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
8115                 isc_buffer_putmem(text, (const unsigned char *)msg,
8116                                   strlen(msg) + 1);
8117
8118         view = dns_zone_getview(zone);
8119         if (strcmp(view->name, "_default") == 0 ||
8120             strcmp(view->name, "_bind") == 0)
8121         {
8122                 vname = "";
8123                 sep = "";
8124         } else {
8125                 vname = view->name;
8126                 sep = " ";
8127         }
8128         dns_rdataclass_format(dns_zone_getclass(zone), classstr,
8129                               sizeof(classstr));
8130         dns_name_format(dns_zone_getorigin(zone),
8131                         zonename, sizeof(zonename));
8132         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8133                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8134                       "%s zone '%s/%s'%s%s: %s",
8135                       freeze ? "freezing" : "thawing",
8136                       zonename, classstr, sep, vname,
8137                       isc_result_totext(result));
8138         dns_zone_detach(&zone);
8139         return (result);
8140 }
8141
8142 #ifdef HAVE_LIBSCF
8143 /*
8144  * This function adds a message for rndc to echo if named
8145  * is managed by smf and is also running chroot.
8146  */
8147 isc_result_t
8148 ns_smf_add_message(isc_buffer_t *text) {
8149         unsigned int n;
8150
8151         n = snprintf((char *)isc_buffer_used(text),
8152                 isc_buffer_availablelength(text),
8153                 "use svcadm(1M) to manage named");
8154         if (n >= isc_buffer_availablelength(text))
8155                 return (ISC_R_NOSPACE);
8156         isc_buffer_add(text, n);
8157         return (ISC_R_SUCCESS);
8158 }
8159 #endif /* HAVE_LIBSCF */
8160
8161 /*
8162  * Emit a comment at the top of the nzf file containing the viewname
8163  * Expects the fp to already be open for writing
8164  */
8165 #define HEADER1 "# New zone file for view: "
8166 #define HEADER2 "\n# This file contains configuration for zones added by\n" \
8167                 "# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
8168 isc_result_t
8169 add_comment(FILE *fp, const char *viewname) {
8170         isc_result_t result;
8171         CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
8172         CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
8173         CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
8174  cleanup:
8175         return (result);
8176 }
8177
8178 /*
8179  * Act on an "addzone" command from the command channel.
8180  */
8181 isc_result_t
8182 ns_server_add_zone(ns_server_t *server, char *args) {
8183         isc_result_t         result;
8184         isc_buffer_t         argbuf;
8185         size_t               arglen;
8186         cfg_parser_t        *parser = NULL;
8187         cfg_obj_t           *config = NULL;
8188         const cfg_obj_t     *vconfig = NULL;
8189         const cfg_obj_t     *views = NULL;
8190         const cfg_obj_t     *parms = NULL;
8191         const cfg_obj_t     *obj = NULL;
8192         const cfg_listelt_t *element;
8193         const char          *zonename;
8194         const char          *classname = NULL;
8195         const char          *argp;
8196         const char          *viewname = NULL;
8197         dns_rdataclass_t     rdclass;
8198         dns_view_t          *view = 0;
8199         isc_buffer_t         buf;
8200         dns_fixedname_t      fname;
8201         dns_name_t          *dnsname;
8202         dns_zone_t          *zone = NULL;
8203         FILE                *fp = NULL;
8204         struct cfg_context  *cfg = NULL;
8205         char                namebuf[DNS_NAME_FORMATSIZE];
8206         off_t               offset;
8207
8208         /* Try to parse the argument string */
8209         arglen = strlen(args);
8210         isc_buffer_init(&argbuf, args, (unsigned int)arglen);
8211         isc_buffer_add(&argbuf, strlen(args));
8212         CHECK(cfg_parser_create(server->mctx, ns_g_lctx, &parser));
8213         CHECK(cfg_parse_buffer(parser, &argbuf, &cfg_type_addzoneconf,
8214                                &config));
8215         CHECK(cfg_map_get(config, "addzone", &parms));
8216
8217         zonename = cfg_obj_asstring(cfg_tuple_get(parms, "name"));
8218         isc_buffer_constinit(&buf, zonename, strlen(zonename));
8219         isc_buffer_add(&buf, strlen(zonename));
8220
8221         dns_fixedname_init(&fname);
8222         dnsname = dns_fixedname_name(&fname);
8223         CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, ISC_FALSE, NULL));
8224
8225         /* Make sense of optional class argument */
8226         obj = cfg_tuple_get(parms, "class");
8227         CHECK(ns_config_getclass(obj, dns_rdataclass_in, &rdclass));
8228         if (rdclass != dns_rdataclass_in && obj)
8229                 classname = cfg_obj_asstring(obj);
8230
8231         /* Make sense of optional view argument */
8232         obj = cfg_tuple_get(parms, "view");
8233         if (obj && cfg_obj_isstring(obj))
8234                 viewname = cfg_obj_asstring(obj);
8235         if (viewname == NULL || *viewname == '\0')
8236                 viewname = "_default";
8237         CHECK(dns_viewlist_find(&server->viewlist, viewname, rdclass, &view));
8238
8239         /* Are we accepting new zones? */
8240         if (view->new_zone_file == NULL) {
8241                 result = ISC_R_NOPERM;
8242                 goto cleanup;
8243         }
8244
8245         cfg = (struct cfg_context *) view->new_zone_config;
8246         if (cfg == NULL) {
8247                 result = ISC_R_FAILURE;
8248                 goto cleanup;
8249         }
8250
8251         /* Zone shouldn't already exist */
8252         result = dns_zt_find(view->zonetable, dnsname, 0, NULL, &zone);
8253         if (result == ISC_R_SUCCESS) {
8254                 result = ISC_R_EXISTS;
8255                 goto cleanup;
8256         } else if (result == DNS_R_PARTIALMATCH) {
8257                 /* Create our sub-zone anyway */
8258                 dns_zone_detach(&zone);
8259                 zone = NULL;
8260         }
8261         else if (result != ISC_R_NOTFOUND)
8262                 goto cleanup;
8263
8264         /* Find the view statement */
8265         cfg_map_get(cfg->config, "view", &views);
8266         for (element = cfg_list_first(views);
8267              element != NULL;
8268              element = cfg_list_next(element))
8269         {
8270                 const char *vname;
8271                 vconfig = cfg_listelt_value(element);
8272                 vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
8273                 if (vname && !strcasecmp(vname, viewname))
8274                         break;
8275                 vconfig = NULL;
8276         }
8277
8278         /* Open save file for write configuration */
8279         CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
8280         CHECK(isc_stdio_tell(fp, &offset));
8281         if (offset == 0)
8282                 CHECK(add_comment(fp, view->name));
8283
8284         /* Mark view unfrozen so that zone can be added */
8285         result = isc_task_beginexclusive(server->task);
8286         RUNTIME_CHECK(result == ISC_R_SUCCESS);
8287         dns_view_thaw(view);
8288         result = configure_zone(cfg->config, parms, vconfig,
8289                                 server->mctx, view, cfg->actx, ISC_FALSE);
8290         dns_view_freeze(view);
8291         isc_task_endexclusive(server->task);
8292         if (result != ISC_R_SUCCESS)
8293                 goto cleanup;
8294
8295         /* Is it there yet? */
8296         CHECK(dns_zt_find(view->zonetable, dnsname, 0, NULL, &zone));
8297
8298         /*
8299          * Load the zone from the master file.  If this fails, we'll
8300          * need to undo the configuration we've done already.
8301          */
8302         result = dns_zone_loadnew(zone);
8303         if (result != ISC_R_SUCCESS) {
8304                 dns_db_t *dbp = NULL;
8305
8306                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8307                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8308                               "addzone failed; reverting.");
8309
8310                 /* If the zone loaded partially, unload it */
8311                 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
8312                         dns_db_detach(&dbp);
8313                         dns_zone_unload(zone);
8314                 }
8315
8316                 /* Remove the zone from the zone table */
8317                 dns_zt_unmount(view->zonetable, zone);
8318                 goto cleanup;
8319         }
8320
8321         /* Flag the zone as having been added at runtime */
8322         dns_zone_setadded(zone, ISC_TRUE);
8323
8324         /* Emit the zone name, quoted and escaped */
8325         isc_buffer_init(&buf, namebuf, sizeof(namebuf));
8326         CHECK(dns_name_totext(dnsname, ISC_TRUE, &buf));
8327         isc_buffer_putuint8(&buf, 0);
8328         CHECK(isc_stdio_write("zone \"", 6, 1, fp, NULL));
8329         CHECK(isc_stdio_write(namebuf, strlen(namebuf), 1, fp, NULL));
8330         CHECK(isc_stdio_write("\" ", 2, 1, fp, NULL));
8331
8332         /* Classname, if not default */
8333         if (classname != NULL && *classname != '\0') {
8334                 CHECK(isc_stdio_write(classname, strlen(classname), 1, fp,
8335                                       NULL));
8336                 CHECK(isc_stdio_write(" ", 1, 1, fp, NULL));
8337         }
8338
8339         /* Find beginning of option block from args */
8340         for (argp = args; *argp; argp++, arglen--) {
8341                 if (*argp == '{') {     /* Assume matching '}' */
8342                         /* Add that to our file */
8343                         CHECK(isc_stdio_write(argp, arglen, 1, fp, NULL));
8344
8345                         /* Make sure we end with a LF */
8346                         if (argp[arglen-1] != '\n') {
8347                                 CHECK(isc_stdio_write("\n", 1, 1, fp, NULL));
8348                         }
8349                         break;
8350                 }
8351         }
8352
8353         CHECK(isc_stdio_close(fp));
8354         fp = NULL;
8355         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8356                                   NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8357                                   "zone %s added to view %s via addzone",
8358                                   zonename, viewname);
8359
8360         result = ISC_R_SUCCESS;
8361
8362  cleanup:
8363         if (fp != NULL)
8364                 isc_stdio_close(fp);
8365         if (parser != NULL) {
8366                 if (config != NULL)
8367                         cfg_obj_destroy(parser, &config);
8368                 cfg_parser_destroy(&parser);
8369         }
8370         if (zone != NULL)
8371                 dns_zone_detach(&zone);
8372         if (view != NULL)
8373                 dns_view_detach(&view);
8374
8375         return (result);
8376 }
8377
8378 /*
8379  * Act on a "delzone" command from the command channel.
8380  */
8381 isc_result_t
8382 ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t *text) {
8383         isc_result_t result;
8384         dns_zone_t *zone = NULL;
8385         dns_view_t *view = NULL;
8386         dns_db_t *dbp = NULL;
8387         const char *filename = NULL;
8388         char *tmpname = NULL;
8389         char buf[1024];
8390         const char *zonename = NULL;
8391         size_t znamelen = 0;
8392         FILE *ifp = NULL, *ofp = NULL;
8393         isc_boolean_t inheader = ISC_TRUE;
8394
8395         /* Parse parameters */
8396         CHECK(zone_from_args(server, args, NULL, &zone, &zonename,
8397                              text, ISC_TRUE));
8398
8399         if (zone == NULL) {
8400                 result = ISC_R_UNEXPECTEDEND;
8401                 goto cleanup;
8402         }
8403
8404         /*
8405          * Was this zone originally added at runtime?
8406          * If not, we can't delete it now.
8407          */
8408         if (!dns_zone_getadded(zone)) {
8409                 result = ISC_R_NOPERM;
8410                 goto cleanup;
8411         }
8412
8413         INSIST(zonename != NULL);
8414         znamelen = strlen(zonename);
8415
8416         /* Dig out configuration for this zone */
8417         view = dns_zone_getview(zone);
8418         filename = view->new_zone_file;
8419         if (filename == NULL) {
8420                 /* No adding zones in this view */
8421                 result = ISC_R_FAILURE;
8422                 goto cleanup;
8423         }
8424
8425         /* Rewrite zone list */
8426         result = isc_stdio_open(filename, "r", &ifp);
8427         if (ifp != NULL && result == ISC_R_SUCCESS) {
8428                 char *found = NULL, *p = NULL;
8429                 size_t n;
8430
8431                 /* Create a temporary file */
8432                 CHECK(isc_string_printf(buf, 1023, "%s.%ld", filename,
8433                                         (long)getpid()));
8434                 if (!(tmpname = isc_mem_strdup(server->mctx, buf))) {
8435                         result = ISC_R_NOMEMORY;
8436                         goto cleanup;
8437                 }
8438                 CHECK(isc_stdio_open(tmpname, "w", &ofp));
8439                 CHECK(add_comment(ofp, view->name));
8440
8441                 /* Look for the entry for that zone */
8442                 while (fgets(buf, 1024, ifp)) {
8443                         /* Skip initial comment, if any */
8444                         if (inheader && *buf == '#')
8445                                 continue;
8446                         if (*buf != '#')
8447                                 inheader = ISC_FALSE;
8448
8449                         /*
8450                          * Any other lines not starting with zone, copy
8451                          * them out and continue.
8452                          */
8453                         if (strncasecmp(buf, "zone", 4) != 0) {
8454                                 fputs(buf, ofp);
8455                                 continue;
8456                         }
8457                         p = buf+4;
8458
8459                         /* This is a zone; find its name. */
8460                         while (*p &&
8461                                ((*p == '"') || isspace((unsigned char)*p)))
8462                                 p++;
8463
8464                         /*
8465                          * If it's not the zone we're looking for, copy
8466                          * it out and continue
8467                          */
8468                         if (strncasecmp(p, zonename, znamelen) != 0) {
8469                                 fputs(buf, ofp);
8470                                 continue;
8471                         }
8472
8473                         /*
8474                          * But if it is the zone we want, skip over it
8475                          * so it will be omitted from the new file
8476                          */
8477                         p += znamelen;
8478                         if (isspace((unsigned char)*p) ||
8479                             *p == '"' || *p == '{') {
8480                                 /* This must be the entry */
8481                                 found = p;
8482                                 break;
8483                         }
8484
8485                         /* Copy the rest of the buffer out and continue */
8486                         fputs(buf, ofp);
8487                 }
8488
8489                 /* Skip over an option block (matching # of braces) */
8490                 if (found) {
8491                         int obrace = 0, cbrace = 0;
8492                         for (;;) {
8493                                 while (*p) {
8494                                         if (*p == '{') obrace++;
8495                                         if (*p == '}') cbrace++;
8496                                         p++;
8497                                 }
8498                                 if (obrace && (obrace == cbrace))
8499                                         break;
8500                                 if (!fgets(buf, 1024, ifp))
8501                                         break;
8502                                 p = buf;
8503                         }
8504
8505                         /* Just spool the remainder of the file out */
8506                         result = isc_stdio_read(buf, 1, 1024, ifp, &n);
8507                         while (n > 0U) {
8508                                 if (result == ISC_R_EOF)
8509                                         result = ISC_R_SUCCESS;
8510                                 CHECK(result);
8511                                 isc_stdio_write(buf, 1, n, ofp, NULL);
8512                                 result = isc_stdio_read(buf, 1, 1024, ifp, &n);
8513                         }
8514
8515                         /* Move temporary into place */
8516                         CHECK(isc_file_rename(tmpname, view->new_zone_file));
8517                 } else {
8518                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8519                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
8520                                       "deleted zone %s was missing from "
8521                                       "new zone file", zonename);
8522                         goto cleanup;
8523                 }
8524         }
8525
8526         /* Stop answering for this zone */
8527         if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
8528                 dns_db_detach(&dbp);
8529                 dns_zone_unload(zone);
8530         }
8531
8532         CHECK(dns_zt_unmount(view->zonetable, zone));
8533
8534         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
8535                                   NS_LOGMODULE_SERVER, ISC_LOG_INFO,
8536                                   "zone %s removed via delzone", zonename);
8537
8538         result = ISC_R_SUCCESS;
8539
8540  cleanup:
8541         if (ifp != NULL)
8542                 isc_stdio_close(ifp);
8543         if (ofp != NULL) {
8544                 isc_stdio_close(ofp);
8545                 isc_file_remove(tmpname);
8546         }
8547         if (tmpname != NULL)
8548                 isc_mem_free(server->mctx, tmpname);
8549         if (zone != NULL)
8550                 dns_zone_detach(&zone);
8551
8552         return (result);
8553 }
8554
8555 static void
8556 newzone_cfgctx_destroy(void **cfgp) {
8557         struct cfg_context *cfg;
8558
8559         REQUIRE(cfgp != NULL && *cfgp != NULL);
8560
8561         cfg = *cfgp;
8562
8563         if (cfg->actx != NULL)
8564                 cfg_aclconfctx_detach(&cfg->actx);
8565
8566         if (cfg->parser != NULL) {
8567                 if (cfg->config != NULL)
8568                         cfg_obj_destroy(cfg->parser, &cfg->config);
8569                 cfg_parser_destroy(&cfg->parser);
8570         }
8571         if (cfg->nzparser != NULL) {
8572                 if (cfg->nzconfig != NULL)
8573                         cfg_obj_destroy(cfg->nzparser, &cfg->nzconfig);
8574                 cfg_parser_destroy(&cfg->nzparser);
8575         }
8576
8577         isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
8578         *cfgp = NULL;
8579 }
8580
8581 isc_result_t
8582 ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text) {
8583         isc_result_t result = ISC_R_SUCCESS;
8584         dns_zone_t *zone = NULL;
8585         dns_name_t *origin;
8586         dns_db_t *db = NULL;
8587         dns_dbnode_t *node = NULL;
8588         dns_dbversion_t *version = NULL;
8589         dns_rdatatype_t privatetype;
8590         dns_rdataset_t privset;
8591         isc_boolean_t first = ISC_TRUE;
8592         isc_boolean_t list = ISC_FALSE, clear = ISC_FALSE;
8593         isc_boolean_t chain = ISC_FALSE;
8594         char keystr[DNS_SECALG_FORMATSIZE + 7];
8595         unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0;
8596         unsigned char salt[255];
8597         const char *ptr;
8598         size_t n;
8599
8600         dns_rdataset_init(&privset);
8601
8602         /* Skip the command name. */
8603         ptr = next_token(&args, " \t");
8604         if (ptr == NULL)
8605                 return (ISC_R_UNEXPECTEDEND);
8606
8607         /* Find out what we are to do. */
8608         ptr = next_token(&args, " \t");
8609         if (ptr == NULL)
8610                 return (ISC_R_UNEXPECTEDEND);
8611
8612         if (strcasecmp(ptr, "-list") == 0)
8613                 list = ISC_TRUE;
8614         else if ((strcasecmp(ptr, "-clear") == 0)  ||
8615                  (strcasecmp(ptr, "-clean") == 0)) {
8616                 clear = ISC_TRUE;
8617                 ptr = next_token(&args, " \t");
8618                 if (ptr == NULL)
8619                         return (ISC_R_UNEXPECTEDEND);
8620                 memmove(keystr, ptr, sizeof(keystr));
8621         } else if (strcasecmp(ptr, "-nsec3param") == 0) {
8622                 const char *hashstr, *flagstr, *iterstr;
8623                 char nbuf[512];
8624
8625                 chain = ISC_TRUE;
8626                 hashstr = next_token(&args, " \t");
8627                 if (hashstr == NULL)
8628                         return (ISC_R_UNEXPECTEDEND);
8629
8630                 if (strcasecmp(hashstr, "none") == 0)
8631                         hash = 0;
8632                 else {
8633                         flagstr = next_token(&args, " \t");
8634                         iterstr = next_token(&args, " \t");
8635                         if (flagstr == NULL || iterstr == NULL)
8636                                 return (ISC_R_UNEXPECTEDEND);
8637
8638                         n = snprintf(nbuf, sizeof(nbuf), "%s %s %s",
8639                                      hashstr, flagstr, iterstr);
8640                         if (n == sizeof(nbuf))
8641                                 return (ISC_R_NOSPACE);
8642                         n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter);
8643                         if (n != 3U)
8644                                 return (ISC_R_BADNUMBER);
8645
8646                         if (hash > 0xffU || flags > 0xffU)
8647                                 return (ISC_R_RANGE);
8648
8649                         ptr = next_token(&args, " \t");
8650                         if (ptr == NULL)
8651                                 return (ISC_R_UNEXPECTEDEND);
8652                         if (strcmp(ptr, "-") != 0) {
8653                                 isc_buffer_t buf;
8654
8655                                 isc_buffer_init(&buf, salt, sizeof(salt));
8656                                 CHECK(isc_hex_decodestring(ptr, &buf));
8657                                 saltlen = isc_buffer_usedlength(&buf);
8658                         }
8659                 }
8660         } else
8661                 CHECK(DNS_R_SYNTAX);
8662
8663         CHECK(zone_from_args(server, args, NULL, &zone, NULL,
8664                              text, ISC_FALSE));
8665         if (zone == NULL)
8666                 CHECK(ISC_R_UNEXPECTEDEND);
8667
8668         if (clear) {
8669                 CHECK(dns_zone_keydone(zone, keystr));
8670                 isc_buffer_putstr(text, "request queued");
8671                 isc_buffer_putuint8(text, 0);
8672         } else if (chain) {
8673                 CHECK(dns_zone_setnsec3param(zone, (isc_uint8_t)hash,
8674                                              (isc_uint8_t)flags, iter,
8675                                              (isc_uint8_t)saltlen, salt,
8676                                              ISC_TRUE));
8677                 isc_buffer_putstr(text, "request queued");
8678                 isc_buffer_putuint8(text, 0);
8679         } else if (list) {
8680                 privatetype = dns_zone_getprivatetype(zone);
8681                 origin = dns_zone_getorigin(zone);
8682                 CHECK(dns_zone_getdb(zone, &db));
8683                 CHECK(dns_db_findnode(db, origin, ISC_FALSE, &node));
8684                 dns_db_currentversion(db, &version);
8685
8686                 result = dns_db_findrdataset(db, node, version, privatetype,
8687                                              dns_rdatatype_none, 0,
8688                                              &privset, NULL);
8689                 if (result == ISC_R_NOTFOUND) {
8690                         isc_buffer_putstr(text, "No signing records found");
8691                         isc_buffer_putuint8(text, 0);
8692                         result = ISC_R_SUCCESS;
8693                         goto cleanup;
8694                 }
8695
8696                 for (result = dns_rdataset_first(&privset);
8697                      result == ISC_R_SUCCESS;
8698                      result = dns_rdataset_next(&privset))
8699                 {
8700                         dns_rdata_t priv = DNS_RDATA_INIT;
8701                         char output[BUFSIZ];
8702                         isc_buffer_t buf;
8703
8704                         dns_rdataset_current(&privset, &priv);
8705
8706                         isc_buffer_init(&buf, output, sizeof(output));
8707                         CHECK(dns_private_totext(&priv, &buf));
8708
8709                         if (!first)
8710                                 isc_buffer_putstr(text, "\n");
8711                         first = ISC_FALSE;
8712
8713                         n = snprintf((char *)isc_buffer_used(text),
8714                                      isc_buffer_availablelength(text),
8715                                      "%s", output);
8716                         if (n >= isc_buffer_availablelength(text))
8717                                 CHECK(ISC_R_NOSPACE);
8718
8719                         isc_buffer_add(text, (unsigned int)n);
8720                 }
8721                 if (!first && isc_buffer_availablelength(text) > 0)
8722                         isc_buffer_putuint8(text, 0);
8723
8724                 if (result == ISC_R_NOMORE)
8725                         result = ISC_R_SUCCESS;
8726         }
8727
8728  cleanup:
8729         if (dns_rdataset_isassociated(&privset))
8730                 dns_rdataset_disassociate(&privset);
8731         if (node != NULL)
8732                 dns_db_detachnode(db, &node);
8733         if (version != NULL)
8734                 dns_db_closeversion(db, &version, ISC_FALSE);
8735         if (db != NULL)
8736                 dns_db_detach(&db);
8737         if (zone != NULL)
8738                 dns_zone_detach(&zone);
8739
8740         return (result);
8741 }
8742
8743 static isc_result_t
8744 putstr(isc_buffer_t *b, const char *str) {
8745         size_t l = strlen(str);
8746
8747         /*
8748          * Use >= to leave space for NUL termination.
8749          */
8750         if (l >= isc_buffer_availablelength(b))
8751                 return (ISC_R_NOSPACE);
8752
8753         isc_buffer_putmem(b, (const unsigned char *)str, l);
8754         return (ISC_R_SUCCESS);
8755 }