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