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