server.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 #include <config.h>
00021 
00022 #include <stdlib.h>
00023 #include <unistd.h>
00024 #include <limits.h>
00025 #include <ctype.h>
00026 #include <sys/types.h>
00027 #include <sys/stat.h>
00028 
00029 #include <isc/app.h>
00030 #include <isc/base64.h>
00031 #include <isc/dir.h>
00032 #include <isc/entropy.h>
00033 #include <isc/file.h>
00034 #include <isc/hash.h>
00035 #include <isc/hex.h>
00036 #include <isc/httpd.h>
00037 #include <isc/lex.h>
00038 #include <isc/parseint.h>
00039 #include <isc/portset.h>
00040 #include <isc/print.h>
00041 #include <isc/random.h>
00042 #include <isc/refcount.h>
00043 #include <isc/resource.h>
00044 #include <isc/sha2.h>
00045 #include <isc/socket.h>
00046 #include <isc/stat.h>
00047 #include <isc/stats.h>
00048 #include <isc/stdio.h>
00049 #include <isc/string.h>
00050 #include <isc/task.h>
00051 #include <isc/timer.h>
00052 #include <isc/util.h>
00053 #include <isc/xml.h>
00054 
00055 #ifdef AES_SIT
00056 #include <isc/aes.h>
00057 #else
00058 #include <isc/hmacsha.h>
00059 #endif
00060 
00061 #include <isccfg/grammar.h>
00062 #include <isccfg/namedconf.h>
00063 
00064 #include <bind9/check.h>
00065 
00066 #include <dns/acache.h>
00067 #include <dns/adb.h>
00068 #include <dns/badcache.h>
00069 #include <dns/cache.h>
00070 #include <dns/db.h>
00071 #include <dns/dispatch.h>
00072 #include <dns/dlz.h>
00073 #include <dns/dns64.h>
00074 #include <dns/forward.h>
00075 #include <dns/journal.h>
00076 #include <dns/keytable.h>
00077 #include <dns/keyvalues.h>
00078 #include <dns/lib.h>
00079 #include <dns/master.h>
00080 #include <dns/masterdump.h>
00081 #include <dns/nta.h>
00082 #include <dns/order.h>
00083 #include <dns/peer.h>
00084 #include <dns/portlist.h>
00085 #include <dns/private.h>
00086 #include <dns/rbt.h>
00087 #include <dns/rdataclass.h>
00088 #include <dns/rdatalist.h>
00089 #include <dns/rdataset.h>
00090 #include <dns/rdatastruct.h>
00091 #include <dns/resolver.h>
00092 #include <dns/rootns.h>
00093 #include <dns/rriterator.h>
00094 #include <dns/secalg.h>
00095 #include <dns/soa.h>
00096 #include <dns/stats.h>
00097 #include <dns/tkey.h>
00098 #include <dns/tsig.h>
00099 #include <dns/ttl.h>
00100 #include <dns/view.h>
00101 #include <dns/zone.h>
00102 #include <dns/zt.h>
00103 
00104 #include <dst/dst.h>
00105 #include <dst/result.h>
00106 
00107 #include <named/client.h>
00108 #include <named/config.h>
00109 #include <named/control.h>
00110 #include <named/geoip.h>
00111 #include <named/interfacemgr.h>
00112 #include <named/log.h>
00113 #include <named/logconf.h>
00114 #include <named/lwresd.h>
00115 #include <named/main.h>
00116 #include <named/os.h>
00117 #include <named/server.h>
00118 #include <named/statschannel.h>
00119 #include <named/tkeyconf.h>
00120 #include <named/tsigconf.h>
00121 #include <named/zoneconf.h>
00122 #ifdef HAVE_LIBSCF
00123 #include <named/ns_smf_globals.h>
00124 #include <stdlib.h>
00125 #endif
00126 #ifdef HAVE_GEOIP
00127 #include <named/geoip.h>
00128 #endif /* HAVE_GEOIP */
00129 
00130 #ifndef PATH_MAX
00131 #define PATH_MAX 1024
00132 #endif
00133 
00134 #ifndef SIZE_MAX
00135 #define SIZE_MAX ((size_t)-1)
00136 #endif
00137 
00138 #ifdef TUNE_LARGE
00139 #define RESOLVER_NTASKS 523
00140 #define UDPBUFFERS 32768
00141 #define EXCLBUFFERS 32768
00142 #else
00143 #define RESOLVER_NTASKS 31
00144 #define UDPBUFFERS 1000
00145 #define EXCLBUFFERS 4096
00146 #endif /* TUNE_LARGE */
00147 
00148 /*%
00149  * Check an operation for failure.  Assumes that the function
00150  * using it has a 'result' variable and a 'cleanup' label.
00151  */
00152 #define CHECK(op) \
00153         do { result = (op);                                      \
00154                if (result != ISC_R_SUCCESS) goto cleanup;        \
00155         } while (0)
00156 
00157 #define TCHECK(op) \
00158         do { tresult = (op);                                     \
00159                 if (tresult != ISC_R_SUCCESS) {                  \
00160                         isc_buffer_clear(*text);                 \
00161                         goto cleanup;                            \
00162                 }                                                \
00163         } while (0)
00164 
00165 #define CHECKM(op, msg) \
00166         do { result = (op);                                       \
00167                if (result != ISC_R_SUCCESS) {                     \
00168                         isc_log_write(ns_g_lctx,                  \
00169                                       NS_LOGCATEGORY_GENERAL,     \
00170                                       NS_LOGMODULE_SERVER,        \
00171                                       ISC_LOG_ERROR,              \
00172                                       "%s: %s", msg,              \
00173                                       isc_result_totext(result)); \
00174                         goto cleanup;                             \
00175                 }                                                 \
00176         } while (0)                                               \
00177 
00178 #define CHECKMF(op, msg, file) \
00179         do { result = (op);                                       \
00180                if (result != ISC_R_SUCCESS) {                     \
00181                         isc_log_write(ns_g_lctx,                  \
00182                                       NS_LOGCATEGORY_GENERAL,     \
00183                                       NS_LOGMODULE_SERVER,        \
00184                                       ISC_LOG_ERROR,              \
00185                                       "%s '%s': %s", msg, file,   \
00186                                       isc_result_totext(result)); \
00187                         goto cleanup;                             \
00188                 }                                                 \
00189         } while (0)                                               \
00190 
00191 #define CHECKFATAL(op, msg) \
00192         do { result = (op);                                       \
00193                if (result != ISC_R_SUCCESS)                       \
00194                         fatal(msg, result);                       \
00195         } while (0)                                               \
00196 
00197 /*%
00198  * Maximum ADB size for views that share a cache.  Use this limit to suppress
00199  * the total of memory footprint, which should be the main reason for sharing
00200  * a cache.  Only effective when a finite max-cache-size is specified.
00201  * This is currently defined to be 8MB.
00202  */
00203 #define MAX_ADB_SIZE_FOR_CACHESHARE     8388608U
00204 
00205 struct ns_dispatch {
00206         isc_sockaddr_t                  addr;
00207         unsigned int                    dispatchgen;
00208         dns_dispatch_t                  *dispatch;
00209         ISC_LINK(struct ns_dispatch)    link;
00210 };
00211 
00212 struct ns_cache {
00213         dns_cache_t                     *cache;
00214         dns_view_t                      *primaryview;
00215         isc_boolean_t                   needflush;
00216         isc_boolean_t                   adbsizeadjusted;
00217         ISC_LINK(ns_cache_t)            link;
00218 };
00219 
00220 struct dumpcontext {
00221         isc_mem_t                       *mctx;
00222         isc_boolean_t                   dumpcache;
00223         isc_boolean_t                   dumpzones;
00224         FILE                            *fp;
00225         ISC_LIST(struct viewlistentry)  viewlist;
00226         struct viewlistentry            *view;
00227         struct zonelistentry            *zone;
00228         dns_dumpctx_t                   *mdctx;
00229         dns_db_t                        *db;
00230         dns_db_t                        *cache;
00231         isc_task_t                      *task;
00232         dns_dbversion_t                 *version;
00233 };
00234 
00235 struct viewlistentry {
00236         dns_view_t                      *view;
00237         ISC_LINK(struct viewlistentry)  link;
00238         ISC_LIST(struct zonelistentry)  zonelist;
00239 };
00240 
00241 struct zonelistentry {
00242         dns_zone_t                      *zone;
00243         ISC_LINK(struct zonelistentry)  link;
00244 };
00245 
00246 /*%
00247  * Configuration context to retain for each view that allows
00248  * new zones to be added at runtime.
00249  */
00250 typedef struct ns_cfgctx {
00251         isc_mem_t *                     mctx;
00252         cfg_parser_t *                  conf_parser;
00253         cfg_parser_t *                  add_parser;
00254         cfg_obj_t *                     config;
00255         cfg_obj_t *                     vconfig;
00256         cfg_obj_t *                     nzconfig;
00257         cfg_aclconfctx_t *              actx;
00258 } ns_cfgctx_t;
00259 
00260 /*%
00261  * Holds state information for the initial zone loading process.
00262  * Uses the isc_refcount structure to count the number of views
00263  * with pending zone loads, dereferencing as each view finishes.
00264  */
00265 typedef struct {
00266                 ns_server_t *server;
00267                 isc_refcount_t refs;
00268 } ns_zoneload_t;
00269 
00270 /*
00271  * These zones should not leak onto the Internet.
00272  */
00273 const char *empty_zones[] = {
00274         /* RFC 1918 */
00275         "10.IN-ADDR.ARPA",
00276         "16.172.IN-ADDR.ARPA",
00277         "17.172.IN-ADDR.ARPA",
00278         "18.172.IN-ADDR.ARPA",
00279         "19.172.IN-ADDR.ARPA",
00280         "20.172.IN-ADDR.ARPA",
00281         "21.172.IN-ADDR.ARPA",
00282         "22.172.IN-ADDR.ARPA",
00283         "23.172.IN-ADDR.ARPA",
00284         "24.172.IN-ADDR.ARPA",
00285         "25.172.IN-ADDR.ARPA",
00286         "26.172.IN-ADDR.ARPA",
00287         "27.172.IN-ADDR.ARPA",
00288         "28.172.IN-ADDR.ARPA",
00289         "29.172.IN-ADDR.ARPA",
00290         "30.172.IN-ADDR.ARPA",
00291         "31.172.IN-ADDR.ARPA",
00292         "168.192.IN-ADDR.ARPA",
00293 
00294         /* RFC 6598 */
00295         "64.100.IN-ADDR.ARPA",
00296         "65.100.IN-ADDR.ARPA",
00297         "66.100.IN-ADDR.ARPA",
00298         "67.100.IN-ADDR.ARPA",
00299         "68.100.IN-ADDR.ARPA",
00300         "69.100.IN-ADDR.ARPA",
00301         "70.100.IN-ADDR.ARPA",
00302         "71.100.IN-ADDR.ARPA",
00303         "72.100.IN-ADDR.ARPA",
00304         "73.100.IN-ADDR.ARPA",
00305         "74.100.IN-ADDR.ARPA",
00306         "75.100.IN-ADDR.ARPA",
00307         "76.100.IN-ADDR.ARPA",
00308         "77.100.IN-ADDR.ARPA",
00309         "78.100.IN-ADDR.ARPA",
00310         "79.100.IN-ADDR.ARPA",
00311         "80.100.IN-ADDR.ARPA",
00312         "81.100.IN-ADDR.ARPA",
00313         "82.100.IN-ADDR.ARPA",
00314         "83.100.IN-ADDR.ARPA",
00315         "84.100.IN-ADDR.ARPA",
00316         "85.100.IN-ADDR.ARPA",
00317         "86.100.IN-ADDR.ARPA",
00318         "87.100.IN-ADDR.ARPA",
00319         "88.100.IN-ADDR.ARPA",
00320         "89.100.IN-ADDR.ARPA",
00321         "90.100.IN-ADDR.ARPA",
00322         "91.100.IN-ADDR.ARPA",
00323         "92.100.IN-ADDR.ARPA",
00324         "93.100.IN-ADDR.ARPA",
00325         "94.100.IN-ADDR.ARPA",
00326         "95.100.IN-ADDR.ARPA",
00327         "96.100.IN-ADDR.ARPA",
00328         "97.100.IN-ADDR.ARPA",
00329         "98.100.IN-ADDR.ARPA",
00330         "99.100.IN-ADDR.ARPA",
00331         "100.100.IN-ADDR.ARPA",
00332         "101.100.IN-ADDR.ARPA",
00333         "102.100.IN-ADDR.ARPA",
00334         "103.100.IN-ADDR.ARPA",
00335         "104.100.IN-ADDR.ARPA",
00336         "105.100.IN-ADDR.ARPA",
00337         "106.100.IN-ADDR.ARPA",
00338         "107.100.IN-ADDR.ARPA",
00339         "108.100.IN-ADDR.ARPA",
00340         "109.100.IN-ADDR.ARPA",
00341         "110.100.IN-ADDR.ARPA",
00342         "111.100.IN-ADDR.ARPA",
00343         "112.100.IN-ADDR.ARPA",
00344         "113.100.IN-ADDR.ARPA",
00345         "114.100.IN-ADDR.ARPA",
00346         "115.100.IN-ADDR.ARPA",
00347         "116.100.IN-ADDR.ARPA",
00348         "117.100.IN-ADDR.ARPA",
00349         "118.100.IN-ADDR.ARPA",
00350         "119.100.IN-ADDR.ARPA",
00351         "120.100.IN-ADDR.ARPA",
00352         "121.100.IN-ADDR.ARPA",
00353         "122.100.IN-ADDR.ARPA",
00354         "123.100.IN-ADDR.ARPA",
00355         "124.100.IN-ADDR.ARPA",
00356         "125.100.IN-ADDR.ARPA",
00357         "126.100.IN-ADDR.ARPA",
00358         "127.100.IN-ADDR.ARPA",
00359 
00360         /* RFC 5735 and RFC 5737 */
00361         "0.IN-ADDR.ARPA",       /* THIS NETWORK */
00362         "127.IN-ADDR.ARPA",     /* LOOPBACK */
00363         "254.169.IN-ADDR.ARPA", /* LINK LOCAL */
00364         "2.0.192.IN-ADDR.ARPA", /* TEST NET */
00365         "100.51.198.IN-ADDR.ARPA",      /* TEST NET 2 */
00366         "113.0.203.IN-ADDR.ARPA",       /* TEST NET 3 */
00367         "255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
00368 
00369         /* Local IPv6 Unicast Addresses */
00370         "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",
00371         "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",
00372         /* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
00373         "D.F.IP6.ARPA",
00374         "8.E.F.IP6.ARPA",       /* LINK LOCAL */
00375         "9.E.F.IP6.ARPA",       /* LINK LOCAL */
00376         "A.E.F.IP6.ARPA",       /* LINK LOCAL */
00377         "B.E.F.IP6.ARPA",       /* LINK LOCAL */
00378 
00379         /* Example Prefix, RFC 3849. */
00380         "8.B.D.0.1.0.0.2.IP6.ARPA",
00381 
00382         NULL
00383 };
00384 
00385 ISC_PLATFORM_NORETURN_PRE static void
00386 fatal(const char *msg, isc_result_t result) ISC_PLATFORM_NORETURN_POST;
00387 
00388 static void
00389 ns_server_reload(isc_task_t *task, isc_event_t *event);
00390 
00391 static isc_result_t
00392 ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
00393                         cfg_aclconfctx_t *actx, isc_mem_t *mctx,
00394                         isc_uint16_t family, ns_listenelt_t **target);
00395 static isc_result_t
00396 ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
00397                          cfg_aclconfctx_t *actx, isc_mem_t *mctx,
00398                          isc_uint16_t family, ns_listenlist_t **target);
00399 
00400 static isc_result_t
00401 configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
00402                   const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype);
00403 
00404 static isc_result_t
00405 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
00406                      const cfg_obj_t *alternates);
00407 
00408 static isc_result_t
00409 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
00410                const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
00411                dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
00412                isc_boolean_t added, isc_boolean_t old_rpz_ok,
00413                isc_boolean_t modify);
00414 
00415 static isc_result_t
00416 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
00417 
00418 static void
00419 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
00420 
00421 static void
00422 newzone_cfgctx_destroy(void **cfgp);
00423 
00424 static inline isc_result_t
00425 putstr(isc_buffer_t **b, const char *str);
00426 
00427 static isc_result_t
00428 putmem(isc_buffer_t **b, const char *str, size_t len);
00429 
00430 static isc_result_t
00431 putuint8(isc_buffer_t **b, isc_uint8_t val);
00432 
00433 static inline isc_result_t
00434 putnull(isc_buffer_t **b);
00435 
00436 static isc_result_t
00437 add_comment(FILE *fp, const char *viewname);
00438 
00439 /*%
00440  * Configure a single view ACL at '*aclp'.  Get its configuration from
00441  * 'vconfig' (for per-view configuration) and maybe from 'config'
00442  */
00443 static isc_result_t
00444 configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
00445                    const char *aclname, const char *acltuplename,
00446                    cfg_aclconfctx_t *actx, isc_mem_t *mctx, dns_acl_t **aclp)
00447 {
00448         isc_result_t result;
00449         const cfg_obj_t *maps[3];
00450         const cfg_obj_t *aclobj = NULL;
00451         int i = 0;
00452 
00453         if (*aclp != NULL)
00454                 dns_acl_detach(aclp);
00455         if (vconfig != NULL)
00456                 maps[i++] = cfg_tuple_get(vconfig, "options");
00457         if (config != NULL) {
00458                 const cfg_obj_t *options = NULL;
00459                 (void)cfg_map_get(config, "options", &options);
00460                 if (options != NULL)
00461                         maps[i++] = options;
00462         }
00463         maps[i] = NULL;
00464 
00465         (void)ns_config_get(maps, aclname, &aclobj);
00466         if (aclobj == NULL)
00467                 /*
00468                  * No value available.  *aclp == NULL.
00469                  */
00470                 return (ISC_R_SUCCESS);
00471 
00472         if (acltuplename != NULL) {
00473                 /*
00474                  * If the ACL is given in an optional tuple, retrieve it.
00475                  * The parser should have ensured that a valid object be
00476                  * returned.
00477                  */
00478                 aclobj = cfg_tuple_get(aclobj, acltuplename);
00479         }
00480 
00481         result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
00482                                     actx, mctx, 0, aclp);
00483 
00484         return (result);
00485 }
00486 
00487 /*%
00488  * Configure a sortlist at '*aclp'.  Essentially the same as
00489  * configure_view_acl() except it calls cfg_acl_fromconfig with a
00490  * nest_level value of 2.
00491  */
00492 static isc_result_t
00493 configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
00494                         cfg_aclconfctx_t *actx, isc_mem_t *mctx,
00495                         dns_acl_t **aclp)
00496 {
00497         isc_result_t result;
00498         const cfg_obj_t *maps[3];
00499         const cfg_obj_t *aclobj = NULL;
00500         int i = 0;
00501 
00502         if (*aclp != NULL)
00503                 dns_acl_detach(aclp);
00504         if (vconfig != NULL)
00505                 maps[i++] = cfg_tuple_get(vconfig, "options");
00506         if (config != NULL) {
00507                 const cfg_obj_t *options = NULL;
00508                 (void)cfg_map_get(config, "options", &options);
00509                 if (options != NULL)
00510                         maps[i++] = options;
00511         }
00512         maps[i] = NULL;
00513 
00514         (void)ns_config_get(maps, "sortlist", &aclobj);
00515         if (aclobj == NULL)
00516                 return (ISC_R_SUCCESS);
00517 
00518         /*
00519          * Use a nest level of 3 for the "top level" of the sortlist;
00520          * this means each entry in the top three levels will be stored
00521          * as lists of separate, nested ACLs, rather than merged together
00522          * into IP tables as is usually done with ACLs.
00523          */
00524         result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
00525                                     actx, mctx, 3, aclp);
00526 
00527         return (result);
00528 }
00529 
00530 static isc_result_t
00531 configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
00532                          const char *confname, const char *conftuplename,
00533                          isc_mem_t *mctx, dns_rbt_t **rbtp)
00534 {
00535         isc_result_t result;
00536         const cfg_obj_t *maps[3];
00537         const cfg_obj_t *obj = NULL;
00538         const cfg_listelt_t *element;
00539         int i = 0;
00540         dns_fixedname_t fixed;
00541         dns_name_t *name;
00542         isc_buffer_t b;
00543         const char *str;
00544         const cfg_obj_t *nameobj;
00545 
00546         if (*rbtp != NULL)
00547                 dns_rbt_destroy(rbtp);
00548         if (vconfig != NULL)
00549                 maps[i++] = cfg_tuple_get(vconfig, "options");
00550         if (config != NULL) {
00551                 const cfg_obj_t *options = NULL;
00552                 (void)cfg_map_get(config, "options", &options);
00553                 if (options != NULL)
00554                         maps[i++] = options;
00555         }
00556         maps[i] = NULL;
00557 
00558         (void)ns_config_get(maps, confname, &obj);
00559         if (obj == NULL)
00560                 /*
00561                  * No value available.  *rbtp == NULL.
00562                  */
00563                 return (ISC_R_SUCCESS);
00564 
00565         if (conftuplename != NULL) {
00566                 obj = cfg_tuple_get(obj, conftuplename);
00567                 if (cfg_obj_isvoid(obj))
00568                         return (ISC_R_SUCCESS);
00569         }
00570 
00571         result = dns_rbt_create(mctx, NULL, NULL, rbtp);
00572         if (result != ISC_R_SUCCESS)
00573                 return (result);
00574 
00575         dns_fixedname_init(&fixed);
00576         name = dns_fixedname_name(&fixed);
00577         for (element = cfg_list_first(obj);
00578              element != NULL;
00579              element = cfg_list_next(element)) {
00580                 nameobj = cfg_listelt_value(element);
00581                 str = cfg_obj_asstring(nameobj);
00582                 isc_buffer_constinit(&b, str, strlen(str));
00583                 isc_buffer_add(&b, strlen(str));
00584                 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
00585                 /*
00586                  * We don't need the node data, but need to set dummy data to
00587                  * avoid a partial match with an empty node.  For example, if
00588                  * we have foo.example.com and bar.example.com, we'd get a match
00589                  * for baz.example.com, which is not the expected result.
00590                  * We simply use (void *)1 as the dummy data.
00591                  */
00592                 result = dns_rbt_addname(*rbtp, name, (void *)1);
00593                 if (result != ISC_R_SUCCESS) {
00594                         cfg_obj_log(nameobj, ns_g_lctx, ISC_LOG_ERROR,
00595                                     "failed to add %s for %s: %s",
00596                                     str, confname, isc_result_totext(result));
00597                         goto cleanup;
00598                 }
00599 
00600         }
00601 
00602         return (result);
00603 
00604   cleanup:
00605         dns_rbt_destroy(rbtp);
00606         return (result);
00607 
00608 }
00609 
00610 static isc_result_t
00611 dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key,
00612                   isc_boolean_t managed, dst_key_t **target, isc_mem_t *mctx)
00613 {
00614         dns_rdataclass_t viewclass;
00615         dns_rdata_dnskey_t keystruct;
00616         isc_uint32_t flags, proto, alg;
00617         const char *keystr, *keynamestr;
00618         unsigned char keydata[4096];
00619         isc_buffer_t keydatabuf;
00620         unsigned char rrdata[4096];
00621         isc_buffer_t rrdatabuf;
00622         isc_region_t r;
00623         dns_fixedname_t fkeyname;
00624         dns_name_t *keyname;
00625         isc_buffer_t namebuf;
00626         isc_result_t result;
00627         dst_key_t *dstkey = NULL;
00628 
00629         INSIST(target != NULL && *target == NULL);
00630 
00631         flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
00632         proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
00633         alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
00634         keyname = dns_fixedname_name(&fkeyname);
00635         keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
00636 
00637         if (managed) {
00638                 const char *initmethod;
00639                 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
00640 
00641                 if (strcasecmp(initmethod, "initial-key") != 0) {
00642                         cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
00643                                     "managed key '%s': "
00644                                     "invalid initialization method '%s'",
00645                                     keynamestr, initmethod);
00646                         result = ISC_R_FAILURE;
00647                         goto cleanup;
00648                 }
00649         }
00650 
00651         if (vconfig == NULL)
00652                 viewclass = dns_rdataclass_in;
00653         else {
00654                 const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
00655                 CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
00656                                          &viewclass));
00657         }
00658         keystruct.common.rdclass = viewclass;
00659         keystruct.common.rdtype = dns_rdatatype_dnskey;
00660         /*
00661          * The key data in keystruct is not dynamically allocated.
00662          */
00663         keystruct.mctx = NULL;
00664 
00665         ISC_LINK_INIT(&keystruct.common, link);
00666 
00667         if (flags > 0xffff)
00668                 CHECKM(ISC_R_RANGE, "key flags");
00669         if (proto > 0xff)
00670                 CHECKM(ISC_R_RANGE, "key protocol");
00671         if (alg > 0xff)
00672                 CHECKM(ISC_R_RANGE, "key algorithm");
00673         keystruct.flags = (isc_uint16_t)flags;
00674         keystruct.protocol = (isc_uint8_t)proto;
00675         keystruct.algorithm = (isc_uint8_t)alg;
00676 
00677         isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
00678         isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
00679 
00680         keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
00681         CHECK(isc_base64_decodestring(keystr, &keydatabuf));
00682         isc_buffer_usedregion(&keydatabuf, &r);
00683         keystruct.datalen = r.length;
00684         keystruct.data = r.base;
00685 
00686         if ((keystruct.algorithm == DST_ALG_RSASHA1 ||
00687              keystruct.algorithm == DST_ALG_RSAMD5) &&
00688             r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
00689                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
00690                             "%s key '%s' has a weak exponent",
00691                             managed ? "managed" : "trusted",
00692                             keynamestr);
00693 
00694         CHECK(dns_rdata_fromstruct(NULL,
00695                                    keystruct.common.rdclass,
00696                                    keystruct.common.rdtype,
00697                                    &keystruct, &rrdatabuf));
00698         dns_fixedname_init(&fkeyname);
00699         isc_buffer_constinit(&namebuf, keynamestr, strlen(keynamestr));
00700         isc_buffer_add(&namebuf, strlen(keynamestr));
00701         CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL));
00702         CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
00703                               mctx, &dstkey));
00704 
00705         *target = dstkey;
00706         return (ISC_R_SUCCESS);
00707 
00708  cleanup:
00709         if (result == DST_R_NOCRYPTO) {
00710                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
00711                             "ignoring %s key for '%s': no crypto support",
00712                             managed ? "managed" : "trusted",
00713                             keynamestr);
00714         } else if (result == DST_R_UNSUPPORTEDALG) {
00715                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
00716                             "skipping %s key for '%s': %s",
00717                             managed ? "managed" : "trusted",
00718                             keynamestr, isc_result_totext(result));
00719         } else {
00720                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
00721                             "configuring %s key for '%s': %s",
00722                             managed ? "managed" : "trusted",
00723                             keynamestr, isc_result_totext(result));
00724                 result = ISC_R_FAILURE;
00725         }
00726 
00727         if (dstkey != NULL)
00728                 dst_key_free(&dstkey);
00729 
00730         return (result);
00731 }
00732 
00733 static isc_result_t
00734 load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
00735                dns_view_t *view, isc_boolean_t managed,
00736                dns_name_t *keyname, isc_mem_t *mctx)
00737 {
00738         const cfg_listelt_t *elt, *elt2;
00739         const cfg_obj_t *key, *keylist;
00740         dst_key_t *dstkey = NULL;
00741         isc_result_t result;
00742         dns_keytable_t *secroots = NULL;
00743 
00744         CHECK(dns_view_getsecroots(view, &secroots));
00745 
00746         for (elt = cfg_list_first(keys);
00747              elt != NULL;
00748              elt = cfg_list_next(elt)) {
00749                 keylist = cfg_listelt_value(elt);
00750 
00751                 for (elt2 = cfg_list_first(keylist);
00752                      elt2 != NULL;
00753                      elt2 = cfg_list_next(elt2)) {
00754                         key = cfg_listelt_value(elt2);
00755                         result = dstkey_fromconfig(vconfig, key, managed,
00756                                                    &dstkey, mctx);
00757                         if (result ==  DST_R_UNSUPPORTEDALG) {
00758                                 result = ISC_R_SUCCESS;
00759                                 continue;
00760                         }
00761                         if (result != ISC_R_SUCCESS)
00762                                 goto cleanup;
00763 
00764                         /*
00765                          * If keyname was specified, we only add that key.
00766                          */
00767                         if (keyname != NULL &&
00768                             !dns_name_equal(keyname, dst_key_name(dstkey)))
00769                         {
00770                                 dst_key_free(&dstkey);
00771                                 continue;
00772                         }
00773 
00774                         CHECK(dns_keytable_add(secroots, managed, &dstkey));
00775                 }
00776         }
00777 
00778  cleanup:
00779         if (dstkey != NULL)
00780                 dst_key_free(&dstkey);
00781         if (secroots != NULL)
00782                 dns_keytable_detach(&secroots);
00783         if (result == DST_R_NOCRYPTO)
00784                 result = ISC_R_SUCCESS;
00785         return (result);
00786 }
00787 
00788 /*%
00789  * Configure DNSSEC keys for a view.
00790  *
00791  * The per-view configuration values and the server-global defaults are read
00792  * from 'vconfig' and 'config'.
00793  */
00794 static isc_result_t
00795 configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
00796                           const cfg_obj_t *config, const cfg_obj_t *bindkeys,
00797                           isc_boolean_t auto_dlv, isc_boolean_t auto_root,
00798                           isc_mem_t *mctx)
00799 {
00800         isc_result_t result = ISC_R_SUCCESS;
00801         const cfg_obj_t *view_keys = NULL;
00802         const cfg_obj_t *global_keys = NULL;
00803         const cfg_obj_t *view_managed_keys = NULL;
00804         const cfg_obj_t *global_managed_keys = NULL;
00805         const cfg_obj_t *maps[4];
00806         const cfg_obj_t *voptions = NULL;
00807         const cfg_obj_t *options = NULL;
00808         const cfg_obj_t *obj = NULL;
00809         const char *directory;
00810         int i = 0;
00811 
00812         /* We don't need trust anchors for the _bind view */
00813         if (strcmp(view->name, "_bind") == 0 &&
00814             view->rdclass == dns_rdataclass_chaos) {
00815                 return (ISC_R_SUCCESS);
00816         }
00817 
00818         if (vconfig != NULL) {
00819                 voptions = cfg_tuple_get(vconfig, "options");
00820                 if (voptions != NULL) {
00821                         (void) cfg_map_get(voptions, "trusted-keys",
00822                                            &view_keys);
00823                         (void) cfg_map_get(voptions, "managed-keys",
00824                                            &view_managed_keys);
00825                         maps[i++] = voptions;
00826                 }
00827         }
00828 
00829         if (config != NULL) {
00830                 (void)cfg_map_get(config, "trusted-keys", &global_keys);
00831                 (void)cfg_map_get(config, "managed-keys", &global_managed_keys);
00832                 (void)cfg_map_get(config, "options", &options);
00833                 if (options != NULL) {
00834                         maps[i++] = options;
00835                 }
00836         }
00837 
00838         maps[i++] = ns_g_defaults;
00839         maps[i] = NULL;
00840 
00841         result = dns_view_initsecroots(view, mctx);
00842         if (result != ISC_R_SUCCESS) {
00843                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00844                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
00845                               "couldn't create keytable");
00846                 return (ISC_R_UNEXPECTED);
00847         }
00848 
00849         result = dns_view_initntatable(view, ns_g_taskmgr, ns_g_timermgr);
00850         if (result != ISC_R_SUCCESS) {
00851                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
00852                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
00853                               "couldn't create NTA table");
00854                 return (ISC_R_UNEXPECTED);
00855         }
00856 
00857         if (auto_dlv && view->rdclass == dns_rdataclass_in) {
00858                 const cfg_obj_t *builtin_keys = NULL;
00859                 const cfg_obj_t *builtin_managed_keys = NULL;
00860 
00861                 isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
00862                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
00863                               "using built-in DLV key for view %s",
00864                               view->name);
00865 
00866                 /*
00867                  * If bind.keys exists, it overrides the managed-keys
00868                  * clause hard-coded in ns_g_config.
00869                  */
00870                 if (bindkeys != NULL) {
00871                         (void)cfg_map_get(bindkeys, "trusted-keys",
00872                                           &builtin_keys);
00873                         (void)cfg_map_get(bindkeys, "managed-keys",
00874                                           &builtin_managed_keys);
00875                 } else {
00876                         (void)cfg_map_get(ns_g_config, "trusted-keys",
00877                                           &builtin_keys);
00878                         (void)cfg_map_get(ns_g_config, "managed-keys",
00879                                           &builtin_managed_keys);
00880                 }
00881 
00882                 if (builtin_keys != NULL)
00883                         CHECK(load_view_keys(builtin_keys, vconfig, view,
00884                                              ISC_FALSE, view->dlv, mctx));
00885                 if (builtin_managed_keys != NULL)
00886                         CHECK(load_view_keys(builtin_managed_keys, vconfig,
00887                                              view, ISC_TRUE, view->dlv, mctx));
00888         }
00889 
00890         if (auto_root && view->rdclass == dns_rdataclass_in) {
00891                 const cfg_obj_t *builtin_keys = NULL;
00892                 const cfg_obj_t *builtin_managed_keys = NULL;
00893 
00894                 isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
00895                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
00896                               "using built-in root key for view %s",
00897                               view->name);
00898 
00899                 /*
00900                  * If bind.keys exists, it overrides the managed-keys
00901                  * clause hard-coded in ns_g_config.
00902                  */
00903                 if (bindkeys != NULL) {
00904                         (void)cfg_map_get(bindkeys, "trusted-keys",
00905                                           &builtin_keys);
00906                         (void)cfg_map_get(bindkeys, "managed-keys",
00907                                           &builtin_managed_keys);
00908                 } else {
00909                         (void)cfg_map_get(ns_g_config, "trusted-keys",
00910                                           &builtin_keys);
00911                         (void)cfg_map_get(ns_g_config, "managed-keys",
00912                                           &builtin_managed_keys);
00913                 }
00914 
00915                 if (builtin_keys != NULL)
00916                         CHECK(load_view_keys(builtin_keys, vconfig, view,
00917                                              ISC_FALSE, dns_rootname, mctx));
00918                 if (builtin_managed_keys != NULL)
00919                         CHECK(load_view_keys(builtin_managed_keys, vconfig,
00920                                              view, ISC_TRUE, dns_rootname,
00921                                              mctx));
00922         }
00923 
00924         CHECK(load_view_keys(view_keys, vconfig, view, ISC_FALSE,
00925                              NULL, mctx));
00926         CHECK(load_view_keys(view_managed_keys, vconfig, view, ISC_TRUE,
00927                              NULL, mctx));
00928 
00929         if (view->rdclass == dns_rdataclass_in) {
00930                 CHECK(load_view_keys(global_keys, vconfig, view, ISC_FALSE,
00931                                      NULL, mctx));
00932                 CHECK(load_view_keys(global_managed_keys, vconfig, view,
00933                                      ISC_TRUE, NULL, mctx));
00934         }
00935 
00936         /*
00937          * Add key zone for managed-keys.
00938          */
00939         obj = NULL;
00940         (void)ns_config_get(maps, "managed-keys-directory", &obj);
00941         directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
00942         if (directory != NULL)
00943                 result = isc_file_isdirectory(directory);
00944         if (result != ISC_R_SUCCESS) {
00945                 isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
00946                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
00947                               "invalid managed-keys-directory %s: %s",
00948                               directory, isc_result_totext(result));
00949                 goto cleanup;
00950 
00951         }
00952         CHECK(add_keydata_zone(view, directory, ns_g_mctx));
00953 
00954   cleanup:
00955         return (result);
00956 }
00957 
00958 static isc_result_t
00959 mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
00960         const cfg_listelt_t *element;
00961         const cfg_obj_t *obj;
00962         const char *str;
00963         dns_fixedname_t fixed;
00964         dns_name_t *name;
00965         isc_boolean_t value;
00966         isc_result_t result;
00967         isc_buffer_t b;
00968 
00969         dns_fixedname_init(&fixed);
00970         name = dns_fixedname_name(&fixed);
00971         for (element = cfg_list_first(mbs);
00972              element != NULL;
00973              element = cfg_list_next(element))
00974         {
00975                 obj = cfg_listelt_value(element);
00976                 str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
00977                 isc_buffer_constinit(&b, str, strlen(str));
00978                 isc_buffer_add(&b, strlen(str));
00979                 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
00980                 value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
00981                 CHECK(dns_resolver_setmustbesecure(resolver, name, value));
00982         }
00983 
00984         result = ISC_R_SUCCESS;
00985 
00986  cleanup:
00987         return (result);
00988 }
00989 
00990 /*%
00991  * Get a dispatch appropriate for the resolver of a given view.
00992  */
00993 static isc_result_t
00994 get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
00995                               dns_dispatch_t **dispatchp, isc_dscp_t *dscpp,
00996                               isc_boolean_t is_firstview)
00997 {
00998         isc_result_t result = ISC_R_FAILURE;
00999         dns_dispatch_t *disp;
01000         isc_sockaddr_t sa;
01001         unsigned int attrs, attrmask;
01002         const cfg_obj_t *obj = NULL;
01003         unsigned int maxdispatchbuffers = UDPBUFFERS;
01004         isc_dscp_t dscp = -1;
01005 
01006         switch (af) {
01007         case AF_INET:
01008                 result = ns_config_get(maps, "query-source", &obj);
01009                 INSIST(result == ISC_R_SUCCESS);
01010                 break;
01011         case AF_INET6:
01012                 result = ns_config_get(maps, "query-source-v6", &obj);
01013                 INSIST(result == ISC_R_SUCCESS);
01014                 break;
01015         default:
01016                 INSIST(0);
01017         }
01018 
01019         sa = *(cfg_obj_assockaddr(obj));
01020         INSIST(isc_sockaddr_pf(&sa) == af);
01021 
01022         dscp = cfg_obj_getdscp(obj);
01023         if (dscp != -1 && dscpp != NULL)
01024                 *dscpp = dscp;
01025 
01026         /*
01027          * If we don't support this address family, we're done!
01028          */
01029         switch (af) {
01030         case AF_INET:
01031                 result = isc_net_probeipv4();
01032                 break;
01033         case AF_INET6:
01034                 result = isc_net_probeipv6();
01035                 break;
01036         default:
01037                 INSIST(0);
01038         }
01039         if (result != ISC_R_SUCCESS)
01040                 return (ISC_R_SUCCESS);
01041 
01042         /*
01043          * Try to find a dispatcher that we can share.
01044          */
01045         attrs = 0;
01046         attrs |= DNS_DISPATCHATTR_UDP;
01047         switch (af) {
01048         case AF_INET:
01049                 attrs |= DNS_DISPATCHATTR_IPV4;
01050                 break;
01051         case AF_INET6:
01052                 attrs |= DNS_DISPATCHATTR_IPV6;
01053                 break;
01054         }
01055         if (isc_sockaddr_getport(&sa) == 0) {
01056                 attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
01057                 maxdispatchbuffers = EXCLBUFFERS;
01058         } else {
01059                 INSIST(obj != NULL);
01060                 if (is_firstview) {
01061                         cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO,
01062                                     "using specific query-source port "
01063                                     "suppresses port randomization and can be "
01064                                     "insecure.");
01065                 }
01066         }
01067 
01068         attrmask = 0;
01069         attrmask |= DNS_DISPATCHATTR_UDP;
01070         attrmask |= DNS_DISPATCHATTR_TCP;
01071         attrmask |= DNS_DISPATCHATTR_IPV4;
01072         attrmask |= DNS_DISPATCHATTR_IPV6;
01073 
01074         disp = NULL;
01075         result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
01076                                      ns_g_taskmgr, &sa, 4096,
01077                                      maxdispatchbuffers, 32768, 16411, 16433,
01078                                      attrs, attrmask, &disp);
01079         if (result != ISC_R_SUCCESS) {
01080                 isc_sockaddr_t any;
01081                 char buf[ISC_SOCKADDR_FORMATSIZE];
01082 
01083                 switch (af) {
01084                 case AF_INET:
01085                         isc_sockaddr_any(&any);
01086                         break;
01087                 case AF_INET6:
01088                         isc_sockaddr_any6(&any);
01089                         break;
01090                 }
01091                 if (isc_sockaddr_equal(&sa, &any))
01092                         return (ISC_R_SUCCESS);
01093                 isc_sockaddr_format(&sa, buf, sizeof(buf));
01094                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
01095                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
01096                               "could not get query source dispatcher (%s)",
01097                               buf);
01098                 return (result);
01099         }
01100 
01101         *dispatchp = disp;
01102 
01103         return (ISC_R_SUCCESS);
01104 }
01105 
01106 static isc_result_t
01107 configure_order(dns_order_t *order, const cfg_obj_t *ent) {
01108         dns_rdataclass_t rdclass;
01109         dns_rdatatype_t rdtype;
01110         const cfg_obj_t *obj;
01111         dns_fixedname_t fixed;
01112         unsigned int mode = 0;
01113         const char *str;
01114         isc_buffer_t b;
01115         isc_result_t result;
01116         isc_boolean_t addroot;
01117 
01118         result = ns_config_getclass(cfg_tuple_get(ent, "class"),
01119                                     dns_rdataclass_any, &rdclass);
01120         if (result != ISC_R_SUCCESS)
01121                 return (result);
01122 
01123         result = ns_config_gettype(cfg_tuple_get(ent, "type"),
01124                                    dns_rdatatype_any, &rdtype);
01125         if (result != ISC_R_SUCCESS)
01126                 return (result);
01127 
01128         obj = cfg_tuple_get(ent, "name");
01129         if (cfg_obj_isstring(obj))
01130                 str = cfg_obj_asstring(obj);
01131         else
01132                 str = "*";
01133         addroot = ISC_TF(strcmp(str, "*") == 0);
01134         isc_buffer_constinit(&b, str, strlen(str));
01135         isc_buffer_add(&b, strlen(str));
01136         dns_fixedname_init(&fixed);
01137         result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
01138                                    dns_rootname, 0, NULL);
01139         if (result != ISC_R_SUCCESS)
01140                 return (result);
01141 
01142         obj = cfg_tuple_get(ent, "ordering");
01143         INSIST(cfg_obj_isstring(obj));
01144         str = cfg_obj_asstring(obj);
01145         if (!strcasecmp(str, "fixed"))
01146 #if DNS_RDATASET_FIXED
01147                 mode = DNS_RDATASETATTR_FIXEDORDER;
01148 #else
01149                 mode = 0;
01150 #endif /* DNS_RDATASET_FIXED */
01151         else if (!strcasecmp(str, "random"))
01152                 mode = DNS_RDATASETATTR_RANDOMIZE;
01153         else if (!strcasecmp(str, "cyclic"))
01154                 mode = 0;
01155         else
01156                 INSIST(0);
01157 
01158         /*
01159          * "*" should match everything including the root (BIND 8 compat).
01160          * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
01161          * explicit entry for "." when the name is "*".
01162          */
01163         if (addroot) {
01164                 result = dns_order_add(order, dns_rootname,
01165                                        rdtype, rdclass, mode);
01166                 if (result != ISC_R_SUCCESS)
01167                         return (result);
01168         }
01169 
01170         return (dns_order_add(order, dns_fixedname_name(&fixed),
01171                               rdtype, rdclass, mode));
01172 }
01173 
01174 static isc_result_t
01175 configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
01176         isc_netaddr_t na;
01177         dns_peer_t *peer;
01178         const cfg_obj_t *obj;
01179         const char *str;
01180         isc_result_t result;
01181         unsigned int prefixlen;
01182 
01183         cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
01184 
01185         peer = NULL;
01186         result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
01187         if (result != ISC_R_SUCCESS)
01188                 return (result);
01189 
01190         obj = NULL;
01191         (void)cfg_map_get(cpeer, "bogus", &obj);
01192         if (obj != NULL)
01193                 CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
01194 
01195         obj = NULL;
01196         (void)cfg_map_get(cpeer, "provide-ixfr", &obj);
01197         if (obj != NULL)
01198                 CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
01199 
01200         obj = NULL;
01201         (void)cfg_map_get(cpeer, "request-expire", &obj);
01202         if (obj != NULL)
01203                 CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));
01204 
01205         obj = NULL;
01206         (void)cfg_map_get(cpeer, "request-ixfr", &obj);
01207         if (obj != NULL)
01208                 CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
01209 
01210         obj = NULL;
01211         (void)cfg_map_get(cpeer, "request-nsid", &obj);
01212         if (obj != NULL)
01213                 CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
01214 
01215 #ifdef ISC_PLATFORM_USESIT
01216         obj = NULL;
01217         (void)cfg_map_get(cpeer, "request-sit", &obj);
01218         if (obj != NULL)
01219                 CHECK(dns_peer_setrequestsit(peer, cfg_obj_asboolean(obj)));
01220 #endif
01221 
01222         obj = NULL;
01223         (void)cfg_map_get(cpeer, "edns", &obj);
01224         if (obj != NULL)
01225                 CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
01226 
01227         obj = NULL;
01228         (void)cfg_map_get(cpeer, "edns-udp-size", &obj);
01229         if (obj != NULL) {
01230                 isc_uint32_t udpsize = cfg_obj_asuint32(obj);
01231                 if (udpsize < 512)
01232                         udpsize = 512;
01233                 if (udpsize > 4096)
01234                         udpsize = 4096;
01235                 CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize));
01236         }
01237 
01238         obj = NULL;
01239         (void)cfg_map_get(cpeer, "edns-version", &obj);
01240         if (obj != NULL) {
01241                 isc_uint32_t ednsversion = cfg_obj_asuint32(obj);
01242                 if (ednsversion > 255)
01243                         ednsversion = 255;
01244                 CHECK(dns_peer_setednsversion(peer, (isc_uint8_t)ednsversion));
01245         }
01246 
01247         obj = NULL;
01248         (void)cfg_map_get(cpeer, "max-udp-size", &obj);
01249         if (obj != NULL) {
01250                 isc_uint32_t udpsize = cfg_obj_asuint32(obj);
01251                 if (udpsize < 512)
01252                         udpsize = 512;
01253                 if (udpsize > 4096)
01254                         udpsize = 4096;
01255                 CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize));
01256         }
01257 
01258         obj = NULL;
01259         (void)cfg_map_get(cpeer, "tcp-only", &obj);
01260         if (obj != NULL)
01261                 CHECK(dns_peer_setforcetcp(peer, cfg_obj_asboolean(obj)));
01262 
01263         obj = NULL;
01264         (void)cfg_map_get(cpeer, "transfers", &obj);
01265         if (obj != NULL)
01266                 CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
01267 
01268         obj = NULL;
01269         (void)cfg_map_get(cpeer, "transfer-format", &obj);
01270         if (obj != NULL) {
01271                 str = cfg_obj_asstring(obj);
01272                 if (strcasecmp(str, "many-answers") == 0)
01273                         CHECK(dns_peer_settransferformat(peer,
01274                                                          dns_many_answers));
01275                 else if (strcasecmp(str, "one-answer") == 0)
01276                         CHECK(dns_peer_settransferformat(peer,
01277                                                          dns_one_answer));
01278                 else
01279                         INSIST(0);
01280         }
01281 
01282         obj = NULL;
01283         (void)cfg_map_get(cpeer, "keys", &obj);
01284         if (obj != NULL) {
01285                 result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
01286                 if (result != ISC_R_SUCCESS)
01287                         goto cleanup;
01288         }
01289 
01290         obj = NULL;
01291         if (na.family == AF_INET)
01292                 (void)cfg_map_get(cpeer, "transfer-source", &obj);
01293         else
01294                 (void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
01295         if (obj != NULL) {
01296                 result = dns_peer_settransfersource(peer,
01297                                                     cfg_obj_assockaddr(obj));
01298                 if (result != ISC_R_SUCCESS)
01299                         goto cleanup;
01300                 result = dns_peer_settransferdscp(peer, cfg_obj_getdscp(obj));
01301                 if (result != ISC_R_SUCCESS)
01302                         goto cleanup;
01303                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
01304         }
01305 
01306         obj = NULL;
01307         if (na.family == AF_INET)
01308                 (void)cfg_map_get(cpeer, "notify-source", &obj);
01309         else
01310                 (void)cfg_map_get(cpeer, "notify-source-v6", &obj);
01311         if (obj != NULL) {
01312                 result = dns_peer_setnotifysource(peer,
01313                                                   cfg_obj_assockaddr(obj));
01314                 if (result != ISC_R_SUCCESS)
01315                         goto cleanup;
01316                 result = dns_peer_setnotifydscp(peer, cfg_obj_getdscp(obj));
01317                 if (result != ISC_R_SUCCESS)
01318                         goto cleanup;
01319                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
01320         }
01321 
01322         obj = NULL;
01323         if (na.family == AF_INET)
01324                 (void)cfg_map_get(cpeer, "query-source", &obj);
01325         else
01326                 (void)cfg_map_get(cpeer, "query-source-v6", &obj);
01327         if (obj != NULL) {
01328                 result = dns_peer_setquerysource(peer,
01329                                                  cfg_obj_assockaddr(obj));
01330                 if (result != ISC_R_SUCCESS)
01331                         goto cleanup;
01332                 result = dns_peer_setquerydscp(peer, cfg_obj_getdscp(obj));
01333                 if (result != ISC_R_SUCCESS)
01334                         goto cleanup;
01335                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
01336         }
01337 
01338         *peerp = peer;
01339         return (ISC_R_SUCCESS);
01340 
01341  cleanup:
01342         dns_peer_detach(&peer);
01343         return (result);
01344 }
01345 
01346 static isc_result_t
01347 disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
01348         isc_result_t result;
01349         const cfg_obj_t *algorithms;
01350         const cfg_listelt_t *element;
01351         const char *str;
01352         dns_fixedname_t fixed;
01353         dns_name_t *name;
01354         isc_buffer_t b;
01355 
01356         dns_fixedname_init(&fixed);
01357         name = dns_fixedname_name(&fixed);
01358         str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
01359         isc_buffer_constinit(&b, str, strlen(str));
01360         isc_buffer_add(&b, strlen(str));
01361         CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
01362 
01363         algorithms = cfg_tuple_get(disabled, "algorithms");
01364         for (element = cfg_list_first(algorithms);
01365              element != NULL;
01366              element = cfg_list_next(element))
01367         {
01368                 isc_textregion_t r;
01369                 dns_secalg_t alg;
01370 
01371                 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
01372                 r.length = strlen(r.base);
01373 
01374                 result = dns_secalg_fromtext(&alg, &r);
01375                 if (result != ISC_R_SUCCESS) {
01376                         isc_uint8_t ui;
01377                         result = isc_parse_uint8(&ui, r.base, 10);
01378                         alg = ui;
01379                 }
01380                 if (result != ISC_R_SUCCESS) {
01381                         cfg_obj_log(cfg_listelt_value(element),
01382                                     ns_g_lctx, ISC_LOG_ERROR,
01383                                     "invalid algorithm");
01384                         CHECK(result);
01385                 }
01386                 CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
01387         }
01388  cleanup:
01389         return (result);
01390 }
01391 
01392 static isc_result_t
01393 disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
01394         isc_result_t result;
01395         const cfg_obj_t *digests;
01396         const cfg_listelt_t *element;
01397         const char *str;
01398         dns_fixedname_t fixed;
01399         dns_name_t *name;
01400         isc_buffer_t b;
01401 
01402         dns_fixedname_init(&fixed);
01403         name = dns_fixedname_name(&fixed);
01404         str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
01405         isc_buffer_constinit(&b, str, strlen(str));
01406         isc_buffer_add(&b, strlen(str));
01407         CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
01408 
01409         digests = cfg_tuple_get(disabled, "digests");
01410         for (element = cfg_list_first(digests);
01411              element != NULL;
01412              element = cfg_list_next(element))
01413         {
01414                 isc_textregion_t r;
01415                 dns_dsdigest_t digest;
01416 
01417                 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
01418                 r.length = strlen(r.base);
01419 
01420                 /* disable_ds_digests handles numeric values. */
01421                 result = dns_dsdigest_fromtext(&digest, &r);
01422                 if (result != ISC_R_SUCCESS) {
01423                         cfg_obj_log(cfg_listelt_value(element),
01424                                     ns_g_lctx, ISC_LOG_ERROR,
01425                                     "invalid algorithm");
01426                         CHECK(result);
01427                 }
01428                 CHECK(dns_resolver_disable_ds_digest(resolver, name, digest));
01429         }
01430  cleanup:
01431         return (result);
01432 }
01433 
01434 static isc_boolean_t
01435 on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
01436         const cfg_listelt_t *element;
01437         dns_fixedname_t fixed;
01438         dns_name_t *name;
01439         isc_result_t result;
01440         const cfg_obj_t *value;
01441         const char *str;
01442         isc_buffer_t b;
01443 
01444         dns_fixedname_init(&fixed);
01445         name = dns_fixedname_name(&fixed);
01446 
01447         for (element = cfg_list_first(disablelist);
01448              element != NULL;
01449              element = cfg_list_next(element))
01450         {
01451                 value = cfg_listelt_value(element);
01452                 str = cfg_obj_asstring(value);
01453                 isc_buffer_constinit(&b, str, strlen(str));
01454                 isc_buffer_add(&b, strlen(str));
01455                 result = dns_name_fromtext(name, &b, dns_rootname,
01456                                            0, NULL);
01457                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
01458                 if (dns_name_equal(name, zonename))
01459                         return (ISC_TRUE);
01460         }
01461         return (ISC_FALSE);
01462 }
01463 
01464 static isc_result_t
01465 check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
01466              isc_mem_t *mctx)
01467 {
01468         char **argv = NULL;
01469         unsigned int i;
01470         isc_result_t result = ISC_R_SUCCESS;
01471 
01472         CHECK(dns_zone_getdbtype(zone, &argv, mctx));
01473 
01474         /*
01475          * Check that all the arguments match.
01476          */
01477         for (i = 0; i < dbtypec; i++)
01478                 if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0)
01479                         CHECK(ISC_R_FAILURE);
01480 
01481         /*
01482          * Check that there are not extra arguments.
01483          */
01484         if (i == dbtypec && argv[i] != NULL)
01485                 result = ISC_R_FAILURE;
01486 
01487  cleanup:
01488         isc_mem_free(mctx, argv);
01489         return (result);
01490 }
01491 
01492 static isc_result_t
01493 setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
01494         isc_result_t result;
01495         isc_stats_t *zoneqrystats;
01496 
01497         dns_zone_setstatlevel(zone, level);
01498 
01499         zoneqrystats = NULL;
01500         if (level == dns_zonestat_full) {
01501                 result = isc_stats_create(mctx, &zoneqrystats,
01502                                           dns_nsstatscounter_max);
01503                 if (result != ISC_R_SUCCESS)
01504                         return (result);
01505         }
01506         dns_zone_setrequeststats(zone, zoneqrystats);
01507         if (zoneqrystats != NULL)
01508                 isc_stats_detach(&zoneqrystats);
01509 
01510         return (ISC_R_SUCCESS);
01511 }
01512 
01513 static ns_cache_t *
01514 cachelist_find(ns_cachelist_t *cachelist, const char *cachename) {
01515         ns_cache_t *nsc;
01516 
01517         for (nsc = ISC_LIST_HEAD(*cachelist);
01518              nsc != NULL;
01519              nsc = ISC_LIST_NEXT(nsc, link)) {
01520                 if (strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
01521                         return (nsc);
01522         }
01523 
01524         return (NULL);
01525 }
01526 
01527 static isc_boolean_t
01528 cache_reusable(dns_view_t *originview, dns_view_t *view,
01529                isc_boolean_t new_zero_no_soattl)
01530 {
01531         if (originview->checknames != view->checknames ||
01532             dns_resolver_getzeronosoattl(originview->resolver) !=
01533             new_zero_no_soattl ||
01534             originview->acceptexpired != view->acceptexpired ||
01535             originview->enablevalidation != view->enablevalidation ||
01536             originview->maxcachettl != view->maxcachettl ||
01537             originview->maxncachettl != view->maxncachettl) {
01538                 return (ISC_FALSE);
01539         }
01540 
01541         return (ISC_TRUE);
01542 }
01543 
01544 static isc_boolean_t
01545 cache_sharable(dns_view_t *originview, dns_view_t *view,
01546                isc_boolean_t new_zero_no_soattl,
01547                unsigned int new_cleaning_interval,
01548                isc_uint64_t new_max_cache_size)
01549 {
01550         /*
01551          * If the cache cannot even reused for the same view, it cannot be
01552          * shared with other views.
01553          */
01554         if (!cache_reusable(originview, view, new_zero_no_soattl))
01555                 return (ISC_FALSE);
01556 
01557         /*
01558          * Check other cache related parameters that must be consistent among
01559          * the sharing views.
01560          */
01561         if (dns_cache_getcleaninginterval(originview->cache) !=
01562             new_cleaning_interval ||
01563             dns_cache_getcachesize(originview->cache) != new_max_cache_size) {
01564                 return (ISC_FALSE);
01565         }
01566 
01567         return (ISC_TRUE);
01568 }
01569 
01570 /*
01571  * Callback from DLZ configure when the driver sets up a writeable zone
01572  */
01573 static isc_result_t
01574 dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
01575         dns_name_t *origin = dns_zone_getorigin(zone);
01576         dns_rdataclass_t zclass = view->rdclass;
01577         isc_result_t result;
01578 
01579         result = dns_zonemgr_managezone(ns_g_server->zonemgr, zone);
01580         if (result != ISC_R_SUCCESS)
01581                 return (result);
01582         dns_zone_setstats(zone, ns_g_server->zonestats);
01583 
01584         return (ns_zone_configure_writeable_dlz(dlzdb, zone, zclass, origin));
01585 }
01586 
01587 static isc_result_t
01588 dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
01589               unsigned int prefixlen, const char *server,
01590               const char *contact)
01591 {
01592         char *cp;
01593         char reverse[48+sizeof("ip6.arpa.")];
01594         const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
01595         const char *sep = ": view ";
01596         const char *viewname = view->name;
01597         const unsigned char *s6;
01598         dns_fixedname_t fixed;
01599         dns_name_t *name;
01600         dns_zone_t *zone = NULL;
01601         int dns64_dbtypec = 4;
01602         isc_buffer_t b;
01603         isc_result_t result;
01604 
01605         REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
01606                 prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
01607 
01608         if (!strcmp(viewname, "_default")) {
01609                 sep = "";
01610                 viewname = "";
01611         }
01612 
01613         /*
01614          * Construct the reverse name of the zone.
01615          */
01616         cp = reverse;
01617         s6 = na->type.in6.s6_addr;
01618         while (prefixlen > 0) {
01619                 prefixlen -= 8;
01620                 sprintf(cp, "%x.%x.", s6[prefixlen/8] & 0xf,
01621                         (s6[prefixlen/8] >> 4) & 0xf);
01622                 cp += 4;
01623         }
01624         strcat(cp, "ip6.arpa.");
01625 
01626         /*
01627          * Create the actual zone.
01628          */
01629         if (server != NULL)
01630                 dns64_dbtype[2] = server;
01631         if (contact != NULL)
01632                 dns64_dbtype[3] = contact;
01633         dns_fixedname_init(&fixed);
01634         name = dns_fixedname_name(&fixed);
01635         isc_buffer_constinit(&b, reverse, strlen(reverse));
01636         isc_buffer_add(&b, strlen(reverse));
01637         CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
01638         CHECK(dns_zone_create(&zone, mctx));
01639         CHECK(dns_zone_setorigin(zone, name));
01640         dns_zone_setview(zone, view);
01641         CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
01642         dns_zone_setclass(zone, view->rdclass);
01643         dns_zone_settype(zone, dns_zone_master);
01644         dns_zone_setstats(zone, ns_g_server->zonestats);
01645         CHECK(dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype));
01646         if (view->queryacl != NULL)
01647                 dns_zone_setqueryacl(zone, view->queryacl);
01648         if (view->queryonacl != NULL)
01649                 dns_zone_setqueryonacl(zone, view->queryonacl);
01650         dns_zone_setdialup(zone, dns_dialuptype_no);
01651         dns_zone_setnotifytype(zone, dns_notifytype_no);
01652         dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
01653         CHECK(setquerystats(zone, mctx, dns_zonestat_none));    /* XXXMPA */
01654         CHECK(dns_view_addzone(view, zone));
01655         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
01656                       ISC_LOG_INFO, "dns64 reverse zone%s%s: %s", sep,
01657                       viewname, reverse);
01658 
01659 cleanup:
01660         if (zone != NULL)
01661                 dns_zone_detach(&zone);
01662         return (result);
01663 }
01664 
01665 static isc_result_t
01666 configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
01667                    const char *str, const char *msg)
01668 {
01669         isc_result_t result;
01670 
01671         result = dns_name_fromstring(name, str, DNS_NAME_DOWNCASE, view->mctx);
01672         if (result != ISC_R_SUCCESS)
01673                 cfg_obj_log(obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
01674                             "invalid %s '%s'", msg, str);
01675         return (result);
01676 }
01677 
01678 static isc_result_t
01679 configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
01680                     const char *str, const dns_name_t *origin)
01681 {
01682         isc_result_t result;
01683 
01684         result = dns_name_fromstring2(name, str, origin, DNS_NAME_DOWNCASE,
01685                                       view->mctx);
01686         if (result != ISC_R_SUCCESS)
01687                 cfg_obj_log(obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
01688                             "invalid zone '%s'", str);
01689         return (result);
01690 }
01691 
01692 static isc_result_t
01693 configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
01694                    isc_boolean_t recursive_only_def, dns_ttl_t ttl_def,
01695                    const dns_rpz_zone_t *old, isc_boolean_t *old_rpz_okp)
01696 {
01697         const cfg_obj_t *rpz_obj, *obj;
01698         const char *str;
01699         dns_rpz_zone_t *new;
01700         isc_result_t result;
01701         dns_rpz_num_t rpz_num;
01702 
01703         REQUIRE(old != NULL || !*old_rpz_okp);
01704 
01705         rpz_obj = cfg_listelt_value(element);
01706 
01707         if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
01708                 cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
01709                             "limit of %d response policy zones exceeded",
01710                             DNS_RPZ_MAX_ZONES);
01711                 return (ISC_R_FAILURE);
01712         }
01713 
01714         new = isc_mem_get(view->rpzs->mctx, sizeof(*new));
01715         if (new == NULL) {
01716                 cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
01717                             "no memory for response policy zones");
01718                 return (ISC_R_NOMEMORY);
01719         }
01720 
01721         memset(new, 0, sizeof(*new));
01722         result = isc_refcount_init(&new->refs, 1);
01723         if (result != ISC_R_SUCCESS) {
01724                 isc_mem_put(view->rpzs->mctx, new, sizeof(*new));
01725                 return (result);
01726         }
01727         dns_name_init(&new->origin, NULL);
01728         dns_name_init(&new->client_ip, NULL);
01729         dns_name_init(&new->ip, NULL);
01730         dns_name_init(&new->nsdname, NULL);
01731         dns_name_init(&new->nsip, NULL);
01732         dns_name_init(&new->passthru, NULL);
01733         dns_name_init(&new->drop, NULL);
01734         dns_name_init(&new->tcp_only, NULL);
01735         dns_name_init(&new->cname, NULL);
01736         new->num = view->rpzs->p.num_zones++;
01737         view->rpzs->zones[new->num] = new;
01738 
01739         obj = cfg_tuple_get(rpz_obj, "recursive-only");
01740         if (cfg_obj_isvoid(obj) ? recursive_only_def : cfg_obj_asboolean(obj)) {
01741                 view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(new->num);
01742         } else {
01743                 view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(new->num);
01744         }
01745 
01746         obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
01747         if (cfg_obj_isuint32(obj)) {
01748                 new->max_policy_ttl = cfg_obj_asuint32(obj);
01749         } else {
01750                 new->max_policy_ttl = ttl_def;
01751         }
01752         if (*old_rpz_okp && new->max_policy_ttl != old->max_policy_ttl)
01753                 *old_rpz_okp = ISC_FALSE;
01754 
01755         str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
01756         result = configure_rpz_name(view, rpz_obj, &new->origin, str, "zone");
01757         if (result != ISC_R_SUCCESS)
01758                 return (result);
01759         if (dns_name_equal(&new->origin, dns_rootname)) {
01760                 cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
01761                             "invalid zone name '%s'", str);
01762                 return (DNS_R_EMPTYLABEL);
01763         }
01764         for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones-1; ++rpz_num) {
01765                 if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
01766                                    &new->origin)) {
01767                         cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
01768                                     "duplicate '%s'", str);
01769                         result = DNS_R_DUPLICATE;
01770                         return (result);
01771                 }
01772         }
01773         if (*old_rpz_okp && !dns_name_equal(&old->origin, &new->origin))
01774                 *old_rpz_okp = ISC_FALSE;
01775 
01776         result = configure_rpz_name2(view, rpz_obj, &new->client_ip,
01777                                      DNS_RPZ_CLIENT_IP_ZONE, &new->origin);
01778         if (result != ISC_R_SUCCESS)
01779                 return (result);
01780 
01781         result = configure_rpz_name2(view, rpz_obj, &new->ip,
01782                                      DNS_RPZ_IP_ZONE, &new->origin);
01783         if (result != ISC_R_SUCCESS)
01784                 return (result);
01785 
01786         result = configure_rpz_name2(view, rpz_obj, &new->nsdname,
01787                                      DNS_RPZ_NSDNAME_ZONE, &new->origin);
01788         if (result != ISC_R_SUCCESS)
01789                 return (result);
01790 
01791         result = configure_rpz_name2(view, rpz_obj, &new->nsip,
01792                                      DNS_RPZ_NSIP_ZONE, &new->origin);
01793         if (result != ISC_R_SUCCESS)
01794                 return (result);
01795 
01796         result = configure_rpz_name(view, rpz_obj, &new->passthru,
01797                                     DNS_RPZ_PASSTHRU_NAME, "name");
01798         if (result != ISC_R_SUCCESS)
01799                 return (result);
01800 
01801         result = configure_rpz_name(view, rpz_obj, &new->drop,
01802                                     DNS_RPZ_DROP_NAME, "name");
01803         if (result != ISC_R_SUCCESS)
01804                 return (result);
01805 
01806         result = configure_rpz_name(view, rpz_obj, &new->tcp_only,
01807                                     DNS_RPZ_TCP_ONLY_NAME, "name");
01808         if (result != ISC_R_SUCCESS)
01809                 return (result);
01810 
01811         obj = cfg_tuple_get(rpz_obj, "policy");
01812         if (cfg_obj_isvoid(obj)) {
01813                 new->policy = DNS_RPZ_POLICY_GIVEN;
01814         } else {
01815                 str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
01816                 new->policy = dns_rpz_str2policy(str);
01817                 INSIST(new->policy != DNS_RPZ_POLICY_ERROR);
01818                 if (new->policy == DNS_RPZ_POLICY_CNAME) {
01819                         str = cfg_obj_asstring(cfg_tuple_get(obj, "cname"));
01820                         result = configure_rpz_name(view, rpz_obj, &new->cname,
01821                                                     str, "cname");
01822                         if (result != ISC_R_SUCCESS)
01823                                 return (result);
01824                 }
01825         }
01826         if (*old_rpz_okp && (new->policy != old->policy ||
01827                              !dns_name_equal(&old->cname, &new->cname)))
01828                 *old_rpz_okp = ISC_FALSE;
01829 
01830         return (ISC_R_SUCCESS);
01831 }
01832 
01833 static isc_result_t
01834 configure_rpz(dns_view_t *view, const cfg_obj_t *rpz_obj,
01835               isc_boolean_t *old_rpz_okp)
01836 {
01837         const cfg_listelt_t *zone_element;
01838         const cfg_obj_t *sub_obj;
01839         isc_boolean_t recursive_only_def;
01840         dns_ttl_t ttl_def;
01841         dns_rpz_zones_t *new;
01842         const dns_rpz_zones_t *old;
01843         dns_view_t *pview;
01844         const dns_rpz_zone_t *old_zone;
01845         isc_result_t result;
01846         int i;
01847 
01848         *old_rpz_okp = ISC_FALSE;
01849 
01850         zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list"));
01851         if (zone_element == NULL)
01852                 return (ISC_R_SUCCESS);
01853 
01854         result = dns_rpz_new_zones(&view->rpzs, view->mctx);
01855         if (result != ISC_R_SUCCESS)
01856                 return (result);
01857         new = view->rpzs;
01858 
01859         sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
01860         if (!cfg_obj_isvoid(sub_obj) &&
01861             !cfg_obj_asboolean(sub_obj))
01862                 recursive_only_def = ISC_FALSE;
01863         else
01864                 recursive_only_def = ISC_TRUE;
01865 
01866         sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec");
01867         if (!cfg_obj_isvoid(sub_obj) &&
01868             cfg_obj_asboolean(sub_obj))
01869                 new->p.break_dnssec = ISC_TRUE;
01870         else
01871                 new->p.break_dnssec = ISC_FALSE;
01872 
01873         sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
01874         if (cfg_obj_isuint32(sub_obj))
01875                 ttl_def = cfg_obj_asuint32(sub_obj);
01876         else
01877                 ttl_def = DNS_RPZ_MAX_TTL_DEFAULT;
01878 
01879         sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots");
01880         if (cfg_obj_isuint32(sub_obj))
01881                 new->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1;
01882         else
01883                 new->p.min_ns_labels = 2;
01884 
01885         sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse");
01886         if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj))
01887                 new->p.qname_wait_recurse = ISC_TRUE;
01888         else
01889                 new->p.qname_wait_recurse = ISC_FALSE;
01890 
01891         pview = NULL;
01892         result = dns_viewlist_find(&ns_g_server->viewlist,
01893                                    view->name, view->rdclass, &pview);
01894         if (result == ISC_R_SUCCESS) {
01895                 old = pview->rpzs;
01896         } else {
01897                 old = NULL;
01898         }
01899         if (old == NULL)
01900                 *old_rpz_okp = ISC_FALSE;
01901         else
01902                 *old_rpz_okp = ISC_TRUE;
01903 
01904         for (i = 0;
01905              zone_element != NULL;
01906              ++i, zone_element = cfg_list_next(zone_element)) {
01907                 INSIST(old != NULL || !*old_rpz_okp);
01908                 if (*old_rpz_okp && i < old->p.num_zones) {
01909                         old_zone = old->zones[i];
01910                 } else {
01911                         *old_rpz_okp = ISC_FALSE;
01912                         old_zone = NULL;
01913                 }
01914                 result = configure_rpz_zone(view, zone_element,
01915                                             recursive_only_def, ttl_def,
01916                                             old_zone, old_rpz_okp);
01917                 if (result != ISC_R_SUCCESS) {
01918                         if (pview != NULL)
01919                                 dns_view_detach(&pview);
01920                         return (result);
01921                 }
01922         }
01923 
01924         /*
01925          * If this is a reloading and the parameters and list of policy
01926          * zones are unchanged, then use the same policy data.
01927          * Data for individual zones that must be reloaded will be merged.
01928          */
01929         if (old != NULL && memcmp(&old->p, &new->p, sizeof(new->p)) != 0)
01930                 *old_rpz_okp = ISC_FALSE;
01931         if (*old_rpz_okp) {
01932                 dns_rpz_detach_rpzs(&view->rpzs);
01933                 dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs);
01934         }
01935         if (pview != NULL)
01936                 dns_view_detach(&pview);
01937 
01938         return (ISC_R_SUCCESS);
01939 }
01940 
01941 #define CHECK_RRL(cond, pat, val1, val2)                                \
01942         do {                                                            \
01943                 if (!(cond)) {                                          \
01944                         cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,      \
01945                                     pat, val1, val2);                   \
01946                         result = ISC_R_RANGE;                           \
01947                         goto cleanup;                                   \
01948                     }                                                   \
01949         } while (0)
01950 
01951 #define CHECK_RRL_RATE(rate, def, max_rate, name)                       \
01952         do {                                                            \
01953                 obj = NULL;                                             \
01954                 rrl->rate.str = name;                                   \
01955                 result = cfg_map_get(map, name, &obj);                  \
01956                 if (result == ISC_R_SUCCESS) {                          \
01957                         rrl->rate.r = cfg_obj_asuint32(obj);            \
01958                         CHECK_RRL(rrl->rate.r <= max_rate,              \
01959                                   name" %d > %d",                       \
01960                                   rrl->rate.r, max_rate);               \
01961                 } else {                                                \
01962                         rrl->rate.r = def;                              \
01963                 }                                                       \
01964                 rrl->rate.scaled = rrl->rate.r;                         \
01965         } while (0)
01966 
01967 static isc_result_t
01968 configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
01969         const cfg_obj_t *obj;
01970         dns_rrl_t *rrl;
01971         isc_result_t result;
01972         int min_entries, i, j;
01973 
01974         /*
01975          * Most DNS servers have few clients, but intentinally open
01976          * recursive and authoritative servers often have many.
01977          * So start with a small number of entries unless told otherwise
01978          * to reduce cold-start costs.
01979          */
01980         min_entries = 500;
01981         obj = NULL;
01982         result = cfg_map_get(map, "min-table-size", &obj);
01983         if (result == ISC_R_SUCCESS) {
01984                 min_entries = cfg_obj_asuint32(obj);
01985                 if (min_entries < 1)
01986                         min_entries = 1;
01987         }
01988         result = dns_rrl_init(&rrl, view, min_entries);
01989         if (result != ISC_R_SUCCESS)
01990                 return (result);
01991 
01992         i = ISC_MAX(20000, min_entries);
01993         obj = NULL;
01994         result = cfg_map_get(map, "max-table-size", &obj);
01995         if (result == ISC_R_SUCCESS) {
01996                 i = cfg_obj_asuint32(obj);
01997                 CHECK_RRL(i >= min_entries,
01998                           "max-table-size %d < min-table-size %d",
01999                           i, min_entries);
02000         }
02001         rrl->max_entries = i;
02002 
02003         CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
02004                        "responses-per-second");
02005         CHECK_RRL_RATE(referrals_per_second,
02006                        rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
02007                        "referrals-per-second");
02008         CHECK_RRL_RATE(nodata_per_second,
02009                        rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
02010                        "nodata-per-second");
02011         CHECK_RRL_RATE(nxdomains_per_second,
02012                        rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
02013                        "nxdomains-per-second");
02014         CHECK_RRL_RATE(errors_per_second,
02015                        rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
02016                        "errors-per-second");
02017 
02018         CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE,
02019                        "all-per-second");
02020 
02021         CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP,
02022                        "slip");
02023 
02024         i = 15;
02025         obj = NULL;
02026         result = cfg_map_get(map, "window", &obj);
02027         if (result == ISC_R_SUCCESS) {
02028                 i = cfg_obj_asuint32(obj);
02029                 CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
02030                           "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
02031         }
02032         rrl->window = i;
02033 
02034         i = 0;
02035         obj = NULL;
02036         result = cfg_map_get(map, "qps-scale", &obj);
02037         if (result == ISC_R_SUCCESS) {
02038                 i = cfg_obj_asuint32(obj);
02039                 CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
02040         }
02041         rrl->qps_scale = i;
02042         rrl->qps = 1.0;
02043 
02044         i = 24;
02045         obj = NULL;
02046         result = cfg_map_get(map, "ipv4-prefix-length", &obj);
02047         if (result == ISC_R_SUCCESS) {
02048                 i = cfg_obj_asuint32(obj);
02049                 CHECK_RRL(i >= 8 && i <= 32,
02050                           "invalid 'ipv4-prefix-length %d'%s", i, "");
02051         }
02052         rrl->ipv4_prefixlen = i;
02053         if (i == 32)
02054                 rrl->ipv4_mask = 0xffffffff;
02055         else
02056                 rrl->ipv4_mask = htonl(0xffffffff << (32-i));
02057 
02058         i = 56;
02059         obj = NULL;
02060         result = cfg_map_get(map, "ipv6-prefix-length", &obj);
02061         if (result == ISC_R_SUCCESS) {
02062                 i = cfg_obj_asuint32(obj);
02063                 CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
02064                           "ipv6-prefix-length %d < 16 or > %d",
02065                           i, DNS_RRL_MAX_PREFIX);
02066         }
02067         rrl->ipv6_prefixlen = i;
02068         for (j = 0; j < 4; ++j) {
02069                 if (i <= 0) {
02070                         rrl->ipv6_mask[j] = 0;
02071                 } else if (i < 32) {
02072                         rrl->ipv6_mask[j] = htonl(0xffffffff << (32-i));
02073                 } else {
02074                         rrl->ipv6_mask[j] = 0xffffffff;
02075                 }
02076                 i -= 32;
02077         }
02078 
02079         obj = NULL;
02080         result = cfg_map_get(map, "exempt-clients", &obj);
02081         if (result == ISC_R_SUCCESS) {
02082                 result = cfg_acl_fromconfig(obj, config, ns_g_lctx,
02083                                             ns_g_aclconfctx, ns_g_mctx,
02084                                             0, &rrl->exempt);
02085                 CHECK_RRL(result == ISC_R_SUCCESS,
02086                           "invalid %s%s", "address match list", "");
02087         }
02088 
02089         obj = NULL;
02090         result = cfg_map_get(map, "log-only", &obj);
02091         if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj))
02092                 rrl->log_only = ISC_TRUE;
02093         else
02094                 rrl->log_only = ISC_FALSE;
02095 
02096         return (ISC_R_SUCCESS);
02097 
02098  cleanup:
02099         dns_rrl_view_destroy(view);
02100         return (result);
02101 }
02102 
02103 static isc_result_t
02104 add_soa(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
02105         dns_name_t *origin, dns_name_t *contact)
02106 {
02107         dns_dbnode_t *node = NULL;
02108         dns_rdata_t rdata = DNS_RDATA_INIT;
02109         dns_rdatalist_t rdatalist;
02110         dns_rdataset_t rdataset;
02111         isc_result_t result;
02112         unsigned char buf[DNS_SOA_BUFFERSIZE];
02113 
02114         CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db),
02115                                  0, 28800, 7200, 604800, 86400, buf, &rdata));
02116 
02117         dns_rdatalist_init(&rdatalist);
02118         rdatalist.type = rdata.type;
02119         rdatalist.rdclass = rdata.rdclass;
02120         rdatalist.ttl = 86400;
02121         ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
02122 
02123         dns_rdataset_init(&rdataset);
02124         CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
02125         CHECK(dns_db_findnode(db, name, ISC_TRUE, &node));
02126         CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
02127 
02128  cleanup:
02129         if (node != NULL)
02130                 dns_db_detachnode(db, &node);
02131         return (result);
02132 }
02133 
02134 static isc_result_t
02135 add_ns(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
02136        dns_name_t *nsname)
02137 {
02138         dns_dbnode_t *node = NULL;
02139         dns_rdata_ns_t ns;
02140         dns_rdata_t rdata = DNS_RDATA_INIT;
02141         dns_rdatalist_t rdatalist;
02142         dns_rdataset_t rdataset;
02143         isc_result_t result;
02144         isc_buffer_t b;
02145         unsigned char buf[DNS_NAME_MAXWIRE];
02146 
02147         isc_buffer_init(&b, buf, sizeof(buf));
02148 
02149         ns.common.rdtype = dns_rdatatype_ns;
02150         ns.common.rdclass = dns_db_class(db);
02151         ns.mctx = NULL;
02152         dns_name_init(&ns.name, NULL);
02153         dns_name_clone(nsname, &ns.name);
02154         CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
02155                                    &ns, &b));
02156 
02157         dns_rdatalist_init(&rdatalist);
02158         rdatalist.type = rdata.type;
02159         rdatalist.rdclass = rdata.rdclass;
02160         rdatalist.ttl = 86400;
02161         ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
02162 
02163         dns_rdataset_init(&rdataset);
02164         CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
02165         CHECK(dns_db_findnode(db, name, ISC_TRUE, &node));
02166         CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
02167 
02168  cleanup:
02169         if (node != NULL)
02170                 dns_db_detachnode(db, &node);
02171         return (result);
02172 }
02173 
02174 static isc_result_t
02175 create_empty_zone(dns_zone_t *zone, dns_name_t *name, dns_view_t *view,
02176                   const cfg_obj_t *zonelist, const char **empty_dbtype,
02177                   int empty_dbtypec, dns_zonestat_level_t statlevel)
02178 {
02179         char namebuf[DNS_NAME_FORMATSIZE];
02180         const cfg_listelt_t *element;
02181         const cfg_obj_t *obj;
02182         const cfg_obj_t *zconfig;
02183         const cfg_obj_t *zoptions;
02184         const char *rbt_dbtype[4] = { "rbt" };
02185         const char *sep = ": view ";
02186         const char *str;
02187         const char *viewname = view->name;
02188         dns_db_t *db = NULL;
02189         dns_dbversion_t *version = NULL;
02190         dns_fixedname_t cfixed;
02191         dns_fixedname_t fixed;
02192         dns_fixedname_t nsfixed;
02193         dns_name_t *contact;
02194         dns_name_t *ns;
02195         dns_name_t *zname;
02196         dns_zone_t *myzone = NULL;
02197         int rbt_dbtypec = 1;
02198         isc_result_t result;
02199         dns_namereln_t namereln;
02200         int order;
02201         unsigned int nlabels;
02202 
02203         dns_fixedname_init(&fixed);
02204         zname = dns_fixedname_name(&fixed);
02205         dns_fixedname_init(&nsfixed);
02206         ns = dns_fixedname_name(&nsfixed);
02207         dns_fixedname_init(&cfixed);
02208         contact = dns_fixedname_name(&cfixed);
02209 
02210         /*
02211          * Look for forward "zones" beneath this empty zone and if so
02212          * create a custom db for the empty zone.
02213          */
02214         for (element = cfg_list_first(zonelist);
02215              element != NULL;
02216              element = cfg_list_next(element)) {
02217 
02218                 zconfig = cfg_listelt_value(element);
02219                 str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
02220                 CHECK(dns_name_fromstring(zname, str, 0, NULL));
02221                 namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
02222                 if (namereln != dns_namereln_subdomain)
02223                         continue;
02224 
02225                 zoptions = cfg_tuple_get(zconfig, "options");
02226 
02227                 obj = NULL;
02228                 (void)cfg_map_get(zoptions, "type", &obj);
02229                 if (obj != NULL &&
02230                     strcasecmp(cfg_obj_asstring(obj), "forward") == 0) {
02231                         obj = NULL;
02232                         (void)cfg_map_get(zoptions, "forward", &obj);
02233                         if (obj == NULL)
02234                                 continue;
02235                         if (strcasecmp(cfg_obj_asstring(obj), "only") != 0)
02236                                 continue;
02237                 }
02238                 if (db == NULL) {
02239                         CHECK(dns_db_create(view->mctx, "rbt", name,
02240                                             dns_dbtype_zone, view->rdclass,
02241                                             0, NULL, &db));
02242                         CHECK(dns_db_newversion(db, &version));
02243                         if (strcmp(empty_dbtype[2], "@") == 0)
02244                                 dns_name_clone(name, ns);
02245                         else
02246                                 CHECK(dns_name_fromstring(ns, empty_dbtype[2],
02247                                                           0, NULL));
02248                         CHECK(dns_name_fromstring(contact, empty_dbtype[3],
02249                                                   0, NULL));
02250                         CHECK(add_soa(db, version, name, ns, contact));
02251                         CHECK(add_ns(db, version, name, ns));
02252                 }
02253                 CHECK(add_ns(db, version, zname, dns_rootname));
02254         }
02255 
02256         /*
02257          * Is the existing zone the ok to use?
02258          */
02259         if (zone != NULL) {
02260                 unsigned int typec;
02261                 const char **dbargv;
02262 
02263                 if (db != NULL) {
02264                         typec = rbt_dbtypec;
02265                         dbargv = rbt_dbtype;
02266                 } else {
02267                         typec = empty_dbtypec;
02268                         dbargv = empty_dbtype;
02269                 }
02270 
02271                 result = check_dbtype(zone, typec, dbargv, view->mctx);
02272                 if (result != ISC_R_SUCCESS)
02273                         zone = NULL;
02274 
02275                 if (zone != NULL && dns_zone_gettype(zone) != dns_zone_master)
02276                         zone = NULL;
02277                 if (zone != NULL && dns_zone_getfile(zone) != NULL)
02278                         zone = NULL;
02279                 if (zone != NULL) {
02280                         dns_zone_getraw(zone, &myzone);
02281                         if (myzone != NULL) {
02282                                 dns_zone_detach(&myzone);
02283                                 zone = NULL;
02284                         }
02285                 }
02286         }
02287 
02288         if (zone == NULL) {
02289                 CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &myzone));
02290                 zone = myzone;
02291                 CHECK(dns_zone_setorigin(zone, name));
02292                 CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
02293                 if (db == NULL)
02294                         CHECK(dns_zone_setdbtype(zone, empty_dbtypec,
02295                                                  empty_dbtype));
02296                 dns_zone_setclass(zone, view->rdclass);
02297                 dns_zone_settype(zone, dns_zone_master);
02298                 dns_zone_setstats(zone, ns_g_server->zonestats);
02299         }
02300 
02301         dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, ISC_FALSE);
02302         dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
02303         dns_zone_setnotifytype(zone, dns_notifytype_no);
02304         dns_zone_setdialup(zone, dns_dialuptype_no);
02305         dns_zone_setautomatic(zone, ISC_TRUE);
02306         if (view->queryacl != NULL)
02307                 dns_zone_setqueryacl(zone, view->queryacl);
02308         else
02309                 dns_zone_clearqueryacl(zone);
02310         if (view->queryonacl != NULL)
02311                 dns_zone_setqueryonacl(zone, view->queryonacl);
02312         else
02313                 dns_zone_clearqueryonacl(zone);
02314         dns_zone_clearupdateacl(zone);
02315         if (view->transferacl != NULL)
02316                 dns_zone_setxfracl(zone, view->transferacl);
02317         else
02318                 dns_zone_clearxfracl(zone);
02319 
02320         CHECK(setquerystats(zone, view->mctx, statlevel));
02321         if (db != NULL) {
02322                 dns_db_closeversion(db, &version, ISC_TRUE);
02323                 CHECK(dns_zone_replacedb(zone, db, ISC_FALSE));
02324         }
02325         dns_zone_setview(zone, view);
02326         CHECK(dns_view_addzone(view, zone));
02327 
02328         if (!strcmp(viewname, "_default")) {
02329                 sep = "";
02330                 viewname = "";
02331         }
02332         dns_name_format(name, namebuf, sizeof(namebuf));
02333         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
02334                       ISC_LOG_INFO, "automatic empty zone%s%s: %s",
02335                       sep, viewname, namebuf);
02336 
02337  cleanup:
02338         if (myzone != NULL)
02339                 dns_zone_detach(&myzone);
02340         if (version != NULL)
02341                 dns_db_closeversion(db, &version, ISC_FALSE);
02342         if (db != NULL)
02343                 dns_db_detach(&db);
02344 
02345         INSIST(version == NULL);
02346 
02347         return (result);
02348 }
02349 
02350 /*
02351  * Configure 'view' according to 'vconfig', taking defaults from 'config'
02352  * where values are missing in 'vconfig'.
02353  *
02354  * When configuring the default view, 'vconfig' will be NULL and the
02355  * global defaults in 'config' used exclusively.
02356  */
02357 static isc_result_t
02358 configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
02359                cfg_obj_t *config, cfg_obj_t *vconfig,
02360                ns_cachelist_t *cachelist, const cfg_obj_t *bindkeys,
02361                isc_mem_t *mctx, cfg_aclconfctx_t *actx,
02362                isc_boolean_t need_hints)
02363 {
02364         const cfg_obj_t *maps[4];
02365         const cfg_obj_t *cfgmaps[3];
02366         const cfg_obj_t *optionmaps[3];
02367         const cfg_obj_t *options = NULL;
02368         const cfg_obj_t *voptions = NULL;
02369         const cfg_obj_t *forwardtype;
02370         const cfg_obj_t *forwarders;
02371         const cfg_obj_t *alternates;
02372         const cfg_obj_t *zonelist;
02373         const cfg_obj_t *dlzlist;
02374         const cfg_obj_t *dlz;
02375         unsigned int dlzargc;
02376         char **dlzargv;
02377         const cfg_obj_t *disabled;
02378         const cfg_obj_t *obj;
02379         const cfg_listelt_t *element;
02380         in_port_t port;
02381         dns_cache_t *cache = NULL;
02382         isc_result_t result;
02383         unsigned int cleaning_interval;
02384         size_t max_cache_size;
02385         size_t max_acache_size;
02386         size_t max_adb_size;
02387         isc_uint32_t lame_ttl, fail_ttl;
02388         dns_tsig_keyring_t *ring = NULL;
02389         dns_view_t *pview = NULL;       /* Production view */
02390         isc_mem_t *cmctx = NULL, *hmctx = NULL;
02391         dns_dispatch_t *dispatch4 = NULL;
02392         dns_dispatch_t *dispatch6 = NULL;
02393         isc_boolean_t reused_cache = ISC_FALSE;
02394         isc_boolean_t shared_cache = ISC_FALSE;
02395         int i = 0, j = 0, k = 0;
02396         const char *str;
02397         const char *cachename = NULL;
02398         dns_order_t *order = NULL;
02399         isc_uint32_t udpsize;
02400         isc_uint32_t maxbits;
02401         unsigned int resopts = 0;
02402         dns_zone_t *zone = NULL;
02403         isc_uint32_t max_clients_per_query;
02404         isc_boolean_t empty_zones_enable;
02405         const cfg_obj_t *disablelist = NULL;
02406         isc_stats_t *resstats = NULL;
02407         dns_stats_t *resquerystats = NULL;
02408         isc_boolean_t auto_dlv = ISC_FALSE;
02409         isc_boolean_t auto_root = ISC_FALSE;
02410         ns_cache_t *nsc;
02411         isc_boolean_t zero_no_soattl;
02412         dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
02413         unsigned int query_timeout, ndisp;
02414         ns_cfgctx_t *nzctx;
02415         isc_boolean_t old_rpz_ok = ISC_FALSE;
02416         isc_dscp_t dscp4 = -1, dscp6 = -1;
02417 
02418         REQUIRE(DNS_VIEW_VALID(view));
02419 
02420         if (config != NULL)
02421                 (void)cfg_map_get(config, "options", &options);
02422 
02423         /*
02424          * maps: view options, options, defaults
02425          * cfgmaps: view options, config
02426          * optionmaps: view options, options
02427          */
02428         if (vconfig != NULL) {
02429                 voptions = cfg_tuple_get(vconfig, "options");
02430                 maps[i++] = voptions;
02431                 optionmaps[j++] = voptions;
02432                 cfgmaps[k++] = voptions;
02433         }
02434         if (options != NULL) {
02435                 maps[i++] = options;
02436                 optionmaps[j++] = options;
02437         }
02438 
02439         maps[i++] = ns_g_defaults;
02440         maps[i] = NULL;
02441         optionmaps[j] = NULL;
02442         if (config != NULL)
02443                 cfgmaps[k++] = config;
02444         cfgmaps[k] = NULL;
02445 
02446         /*
02447          * Set the view's port number for outgoing queries.
02448          */
02449         CHECKM(ns_config_getport(config, &port), "port");
02450         dns_view_setdstport(view, port);
02451 
02452         /*
02453          * Create additional cache for this view and zones under the view
02454          * if explicitly enabled.
02455          * XXX950 default to on.
02456          */
02457         obj = NULL;
02458         (void)ns_config_get(maps, "acache-enable", &obj);
02459         if (obj != NULL && cfg_obj_asboolean(obj)) {
02460                 cmctx = NULL;
02461                 CHECK(isc_mem_create(0, 0, &cmctx));
02462                 CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr,
02463                                         ns_g_timermgr));
02464                 isc_mem_setname(cmctx, "acache", NULL);
02465                 isc_mem_detach(&cmctx);
02466         }
02467         if (view->acache != NULL) {
02468                 obj = NULL;
02469                 result = ns_config_get(maps, "acache-cleaning-interval", &obj);
02470                 INSIST(result == ISC_R_SUCCESS);
02471                 dns_acache_setcleaninginterval(view->acache,
02472                                                cfg_obj_asuint32(obj) * 60);
02473 
02474                 obj = NULL;
02475                 result = ns_config_get(maps, "max-acache-size", &obj);
02476                 INSIST(result == ISC_R_SUCCESS);
02477                 if (cfg_obj_isstring(obj)) {
02478                         str = cfg_obj_asstring(obj);
02479                         INSIST(strcasecmp(str, "unlimited") == 0);
02480                         max_acache_size = 0;
02481                 } else {
02482                         isc_resourcevalue_t value;
02483                         value = cfg_obj_asuint64(obj);
02484                         if (value > SIZE_MAX) {
02485                                 cfg_obj_log(obj, ns_g_lctx,
02486                                             ISC_LOG_WARNING,
02487                                             "'max-acache-size "
02488                                             "%" ISC_PRINT_QUADFORMAT "u' "
02489                                             "is too large for this "
02490                                             "system; reducing to %lu",
02491                                             value, (unsigned long)SIZE_MAX);
02492                                 value = SIZE_MAX;
02493                         }
02494                         max_acache_size = (size_t) value;
02495                 }
02496                 dns_acache_setcachesize(view->acache, max_acache_size);
02497         }
02498 
02499         CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, actx,
02500                                  ns_g_mctx, &view->queryacl));
02501         if (view->queryacl == NULL) {
02502                 CHECK(configure_view_acl(NULL, ns_g_config, "allow-query",
02503                                          NULL, actx, ns_g_mctx,
02504                                          &view->queryacl));
02505         }
02506 
02507         /*
02508          * Make the list of response policy zone names for a view that
02509          * is used for real lookups and so cares about hints.
02510          */
02511         obj = NULL;
02512         if (view->rdclass == dns_rdataclass_in && need_hints &&
02513             ns_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS) {
02514                 CHECK(configure_rpz(view, obj, &old_rpz_ok));
02515         }
02516 
02517         /*
02518          * Configure the zones.
02519          */
02520         zonelist = NULL;
02521         if (voptions != NULL)
02522                 (void)cfg_map_get(voptions, "zone", &zonelist);
02523         else
02524                 (void)cfg_map_get(config, "zone", &zonelist);
02525 
02526         /*
02527          * Load zone configuration
02528          */
02529         for (element = cfg_list_first(zonelist);
02530              element != NULL;
02531              element = cfg_list_next(element))
02532         {
02533                 const cfg_obj_t *zconfig = cfg_listelt_value(element);
02534                 CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
02535                                      viewlist, actx, ISC_FALSE, old_rpz_ok,
02536                                      ISC_FALSE));
02537         }
02538 
02539         /*
02540          * Check that a master or slave zone was found for each
02541          * zone named in the response policy statement.
02542          */
02543         if (view->rpzs != NULL) {
02544                 dns_rpz_num_t n;
02545 
02546                 for (n = 0; n < view->rpzs->p.num_zones; ++n)
02547                 {
02548                         if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
02549                                 char namebuf[DNS_NAME_FORMATSIZE];
02550 
02551                                 dns_name_format(&view->rpzs->zones[n]->origin,
02552                                                 namebuf, sizeof(namebuf));
02553                                 cfg_obj_log(obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL,
02554                                             "'%s' is not a master or slave zone",
02555                                             namebuf);
02556                                 result = ISC_R_NOTFOUND;
02557                                 goto cleanup;
02558                         }
02559                 }
02560         }
02561 
02562         /*
02563          * If we're allowing added zones, then load zone configuration
02564          * from the newzone file for zones that were added during previous
02565          * runs.
02566          */
02567         nzctx = view->new_zone_config;
02568         if (nzctx != NULL && nzctx->nzconfig != NULL) {
02569                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
02570                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
02571                               "loading additional zones for view '%s'",
02572                               view->name);
02573 
02574                 zonelist = NULL;
02575                 cfg_map_get(nzctx->nzconfig, "zone", &zonelist);
02576 
02577                 for (element = cfg_list_first(zonelist);
02578                      element != NULL;
02579                      element = cfg_list_next(element))
02580                 {
02581                         const cfg_obj_t *zconfig = cfg_listelt_value(element);
02582                         CHECK(configure_zone(config, zconfig, vconfig,
02583                                              mctx, view, NULL, actx,
02584                                              ISC_TRUE, ISC_FALSE, ISC_FALSE));
02585                 }
02586         }
02587 
02588         /*
02589          * Create Dynamically Loadable Zone driver.
02590          */
02591         dlzlist = NULL;
02592         if (voptions != NULL)
02593                 (void)cfg_map_get(voptions, "dlz", &dlzlist);
02594         else
02595                 (void)cfg_map_get(config, "dlz", &dlzlist);
02596 
02597         for (element = cfg_list_first(dlzlist);
02598              element != NULL;
02599              element = cfg_list_next(element))
02600         {
02601                 dlz = cfg_listelt_value(element);
02602 
02603                 obj = NULL;
02604                 (void)cfg_map_get(dlz, "database", &obj);
02605                 if (obj != NULL) {
02606                         dns_dlzdb_t *dlzdb = NULL;
02607                         const cfg_obj_t *name, *search = NULL;
02608                         char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
02609 
02610                         if (s == NULL) {
02611                                 result = ISC_R_NOMEMORY;
02612                                 goto cleanup;
02613                         }
02614 
02615                         result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv);
02616                         if (result != ISC_R_SUCCESS) {
02617                                 isc_mem_free(mctx, s);
02618                                 goto cleanup;
02619                         }
02620 
02621                         name = cfg_map_getname(dlz);
02622                         result = dns_dlzcreate(mctx, cfg_obj_asstring(name),
02623                                                dlzargv[0], dlzargc, dlzargv,
02624                                                &dlzdb);
02625                         isc_mem_free(mctx, s);
02626                         isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
02627                         if (result != ISC_R_SUCCESS)
02628                                 goto cleanup;
02629 
02630                         /*
02631                          * If the DLZ backend supports configuration,
02632                          * and is searchable, then call its configure
02633                          * method now.  If not searchable, we'll take
02634                          * care of it when we process the zone statement.
02635                          */
02636                         (void)cfg_map_get(dlz, "search", &search);
02637                         if (search == NULL || cfg_obj_asboolean(search)) {
02638                                 dlzdb->search = ISC_TRUE;
02639                                 result = dns_dlzconfigure(view, dlzdb,
02640                                                         dlzconfigure_callback);
02641                                 if (result != ISC_R_SUCCESS)
02642                                         goto cleanup;
02643                                 ISC_LIST_APPEND(view->dlz_searched,
02644                                                 dlzdb, link);
02645                         } else {
02646                                 dlzdb->search = ISC_FALSE;
02647                                 ISC_LIST_APPEND(view->dlz_unsearched,
02648                                                 dlzdb, link);
02649                         }
02650 
02651                 }
02652         }
02653 
02654         /*
02655          * Obtain configuration parameters that affect the decision of whether
02656          * we can reuse/share an existing cache.
02657          */
02658         obj = NULL;
02659         result = ns_config_get(maps, "cleaning-interval", &obj);
02660         INSIST(result == ISC_R_SUCCESS);
02661         cleaning_interval = cfg_obj_asuint32(obj) * 60;
02662 
02663         obj = NULL;
02664         result = ns_config_get(maps, "max-cache-size", &obj);
02665         INSIST(result == ISC_R_SUCCESS);
02666         if (cfg_obj_isstring(obj)) {
02667                 str = cfg_obj_asstring(obj);
02668                 INSIST(strcasecmp(str, "unlimited") == 0);
02669                 max_cache_size = 0;
02670         } else {
02671                 isc_resourcevalue_t value;
02672                 value = cfg_obj_asuint64(obj);
02673                 if (value > SIZE_MAX) {
02674                         cfg_obj_log(obj, ns_g_lctx,
02675                                     ISC_LOG_WARNING,
02676                                     "'max-cache-size "
02677                                     "%" ISC_PRINT_QUADFORMAT "u' "
02678                                     "is too large for this "
02679                                     "system; reducing to %lu",
02680                                     value, (unsigned long)SIZE_MAX);
02681                         value = SIZE_MAX;
02682                 }
02683                 max_cache_size = (size_t) value;
02684         }
02685 
02686         /* Check-names. */
02687         obj = NULL;
02688         result = ns_checknames_get(maps, "response", &obj);
02689         INSIST(result == ISC_R_SUCCESS);
02690 
02691         str = cfg_obj_asstring(obj);
02692         if (strcasecmp(str, "fail") == 0) {
02693                 resopts |= DNS_RESOLVER_CHECKNAMES |
02694                         DNS_RESOLVER_CHECKNAMESFAIL;
02695                 view->checknames = ISC_TRUE;
02696         } else if (strcasecmp(str, "warn") == 0) {
02697                 resopts |= DNS_RESOLVER_CHECKNAMES;
02698                 view->checknames = ISC_FALSE;
02699         } else if (strcasecmp(str, "ignore") == 0) {
02700                 view->checknames = ISC_FALSE;
02701         } else
02702                 INSIST(0);
02703 
02704         obj = NULL;
02705         result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj);
02706         INSIST(result == ISC_R_SUCCESS);
02707         zero_no_soattl = cfg_obj_asboolean(obj);
02708 
02709         obj = NULL;
02710         result = ns_config_get(maps, "dns64", &obj);
02711         if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
02712             strcmp(view->name, "_meta")) {
02713                 isc_netaddr_t na, suffix, *sp;
02714                 unsigned int prefixlen;
02715                 const char *server, *contact;
02716                 const cfg_obj_t *myobj;
02717 
02718                 myobj = NULL;
02719                 result = ns_config_get(maps, "dns64-server", &myobj);
02720                 if (result == ISC_R_SUCCESS)
02721                         server = cfg_obj_asstring(myobj);
02722                 else
02723                         server = NULL;
02724 
02725                 myobj = NULL;
02726                 result = ns_config_get(maps, "dns64-contact", &myobj);
02727                 if (result == ISC_R_SUCCESS)
02728                         contact = cfg_obj_asstring(myobj);
02729                 else
02730                         contact = NULL;
02731 
02732                 for (element = cfg_list_first(obj);
02733                      element != NULL;
02734                      element = cfg_list_next(element))
02735                 {
02736                         const cfg_obj_t *map = cfg_listelt_value(element);
02737                         dns_dns64_t *dns64 = NULL;
02738                         unsigned int dns64options = 0;
02739 
02740                         cfg_obj_asnetprefix(cfg_map_getname(map), &na,
02741                                             &prefixlen);
02742 
02743                         obj = NULL;
02744                         (void)cfg_map_get(map, "suffix", &obj);
02745                         if (obj != NULL) {
02746                                 sp = &suffix;
02747                                 isc_netaddr_fromsockaddr(sp,
02748                                                       cfg_obj_assockaddr(obj));
02749                         } else
02750                                 sp = NULL;
02751 
02752                         clients = mapped = excluded = NULL;
02753                         obj = NULL;
02754                         (void)cfg_map_get(map, "clients", &obj);
02755                         if (obj != NULL) {
02756                                 result = cfg_acl_fromconfig(obj, config,
02757                                                             ns_g_lctx, actx,
02758                                                             mctx, 0, &clients);
02759                                 if (result != ISC_R_SUCCESS)
02760                                         goto cleanup;
02761                         }
02762                         obj = NULL;
02763                         (void)cfg_map_get(map, "mapped", &obj);
02764                         if (obj != NULL) {
02765                                 result = cfg_acl_fromconfig(obj, config,
02766                                                             ns_g_lctx, actx,
02767                                                             mctx, 0, &mapped);
02768                                 if (result != ISC_R_SUCCESS)
02769                                         goto cleanup;
02770                         }
02771                         obj = NULL;
02772                         (void)cfg_map_get(map, "exclude", &obj);
02773                         if (obj != NULL) {
02774                                 result = cfg_acl_fromconfig(obj, config,
02775                                                             ns_g_lctx, actx,
02776                                                             mctx, 0, &excluded);
02777                                 if (result != ISC_R_SUCCESS)
02778                                         goto cleanup;
02779                         }
02780 
02781                         obj = NULL;
02782                         (void)cfg_map_get(map, "recursive-only", &obj);
02783                         if (obj != NULL && cfg_obj_asboolean(obj))
02784                                 dns64options |= DNS_DNS64_RECURSIVE_ONLY;
02785 
02786                         obj = NULL;
02787                         (void)cfg_map_get(map, "break-dnssec", &obj);
02788                         if (obj != NULL && cfg_obj_asboolean(obj))
02789                                 dns64options |= DNS_DNS64_BREAK_DNSSEC;
02790 
02791                         result = dns_dns64_create(mctx, &na, prefixlen, sp,
02792                                                   clients, mapped, excluded,
02793                                                   dns64options, &dns64);
02794                         if (result != ISC_R_SUCCESS)
02795                                 goto cleanup;
02796                         dns_dns64_append(&view->dns64, dns64);
02797                         view->dns64cnt++;
02798                         result = dns64_reverse(view, mctx, &na, prefixlen,
02799                                                server, contact);
02800                         if (result != ISC_R_SUCCESS)
02801                                 goto cleanup;
02802                         if (clients != NULL)
02803                                 dns_acl_detach(&clients);
02804                         if (mapped != NULL)
02805                                 dns_acl_detach(&mapped);
02806                         if (excluded != NULL)
02807                                 dns_acl_detach(&excluded);
02808                 }
02809         }
02810 
02811         obj = NULL;
02812         result = ns_config_get(maps, "dnssec-accept-expired", &obj);
02813         INSIST(result == ISC_R_SUCCESS);
02814         view->acceptexpired = cfg_obj_asboolean(obj);
02815 
02816         obj = NULL;
02817         result = ns_config_get(maps, "dnssec-validation", &obj);
02818         INSIST(result == ISC_R_SUCCESS);
02819         if (cfg_obj_isboolean(obj)) {
02820                 view->enablevalidation = cfg_obj_asboolean(obj);
02821         } else {
02822                 /* If dnssec-validation is not boolean, it must be "auto" */
02823                 view->enablevalidation = ISC_TRUE;
02824                 auto_root = ISC_TRUE;
02825         }
02826 
02827         obj = NULL;
02828         result = ns_config_get(maps, "max-cache-ttl", &obj);
02829         INSIST(result == ISC_R_SUCCESS);
02830         view->maxcachettl = cfg_obj_asuint32(obj);
02831 
02832         obj = NULL;
02833         result = ns_config_get(maps, "max-ncache-ttl", &obj);
02834         INSIST(result == ISC_R_SUCCESS);
02835         view->maxncachettl = cfg_obj_asuint32(obj);
02836         if (view->maxncachettl > 7 * 24 * 3600)
02837                 view->maxncachettl = 7 * 24 * 3600;
02838 
02839         /*
02840          * Configure the view's cache.
02841          *
02842          * First, check to see if there are any attach-cache options.  If yes,
02843          * attempt to lookup an existing cache at attach it to the view.  If
02844          * there is not one, then try to reuse an existing cache if possible;
02845          * otherwise create a new cache.
02846          *
02847          * Note that the ADB is not preserved or shared in either case.
02848          *
02849          * When a matching view is found, the associated statistics are also
02850          * retrieved and reused.
02851          *
02852          * XXX Determining when it is safe to reuse or share a cache is tricky.
02853          * When the view's configuration changes, the cached data may become
02854          * invalid because it reflects our old view of the world.  We check
02855          * some of the configuration parameters that could invalidate the cache
02856          * or otherwise make it unsharable, but there are other configuration
02857          * options that should be checked.  For example, if a view uses a
02858          * forwarder, changes in the forwarder configuration may invalidate
02859          * the cache.  At the moment, it's the administrator's responsibility to
02860          * ensure these configuration options don't invalidate reusing/sharing.
02861          */
02862         obj = NULL;
02863         result = ns_config_get(maps, "attach-cache", &obj);
02864         if (result == ISC_R_SUCCESS)
02865                 cachename = cfg_obj_asstring(obj);
02866         else
02867                 cachename = view->name;
02868         cache = NULL;
02869         nsc = cachelist_find(cachelist, cachename);
02870         if (nsc != NULL) {
02871                 if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
02872                                     cleaning_interval, max_cache_size)) {
02873                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
02874                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
02875                                       "views %s and %s can't share the cache "
02876                                       "due to configuration parameter mismatch",
02877                                       nsc->primaryview->name, view->name);
02878                         result = ISC_R_FAILURE;
02879                         goto cleanup;
02880                 }
02881                 dns_cache_attach(nsc->cache, &cache);
02882                 shared_cache = ISC_TRUE;
02883         } else {
02884                 if (strcmp(cachename, view->name) == 0) {
02885                         result = dns_viewlist_find(&ns_g_server->viewlist,
02886                                                    cachename, view->rdclass,
02887                                                    &pview);
02888                         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
02889                                 goto cleanup;
02890                         if (pview != NULL) {
02891                                 if (!cache_reusable(pview, view,
02892                                                     zero_no_soattl)) {
02893                                         isc_log_write(ns_g_lctx,
02894                                                       NS_LOGCATEGORY_GENERAL,
02895                                                       NS_LOGMODULE_SERVER,
02896                                                       ISC_LOG_DEBUG(1),
02897                                                       "cache cannot be reused "
02898                                                       "for view %s due to "
02899                                                       "configuration parameter "
02900                                                       "mismatch", view->name);
02901                                 } else {
02902                                         INSIST(pview->cache != NULL);
02903                                         isc_log_write(ns_g_lctx,
02904                                                       NS_LOGCATEGORY_GENERAL,
02905                                                       NS_LOGMODULE_SERVER,
02906                                                       ISC_LOG_DEBUG(3),
02907                                                       "reusing existing cache");
02908                                         reused_cache = ISC_TRUE;
02909                                         dns_cache_attach(pview->cache, &cache);
02910                                 }
02911                                 dns_view_getresstats(pview, &resstats);
02912                                 dns_view_getresquerystats(pview,
02913                                                           &resquerystats);
02914                                 dns_view_detach(&pview);
02915                         }
02916                 }
02917                 if (cache == NULL) {
02918                         /*
02919                          * Create a cache with the desired name.  This normally
02920                          * equals the view name, but may also be a forward
02921                          * reference to a view that share the cache with this
02922                          * view but is not yet configured.  If it is not the
02923                          * view name but not a forward reference either, then it
02924                          * is simply a named cache that is not shared.
02925                          *
02926                          * We use two separate memory contexts for the
02927                          * cache, for the main cache memory and the heap
02928                          * memory.
02929                          */
02930                         CHECK(isc_mem_create(0, 0, &cmctx));
02931                         isc_mem_setname(cmctx, "cache", NULL);
02932                         CHECK(isc_mem_create(0, 0, &hmctx));
02933                         isc_mem_setname(hmctx, "cache_heap", NULL);
02934                         CHECK(dns_cache_create3(cmctx, hmctx, ns_g_taskmgr,
02935                                                 ns_g_timermgr, view->rdclass,
02936                                                 cachename, "rbt", 0, NULL,
02937                                                 &cache));
02938                         isc_mem_detach(&cmctx);
02939                         isc_mem_detach(&hmctx);
02940                 }
02941                 nsc = isc_mem_get(mctx, sizeof(*nsc));
02942                 if (nsc == NULL) {
02943                         result = ISC_R_NOMEMORY;
02944                         goto cleanup;
02945                 }
02946                 nsc->cache = NULL;
02947                 dns_cache_attach(cache, &nsc->cache);
02948                 nsc->primaryview = view;
02949                 nsc->needflush = ISC_FALSE;
02950                 nsc->adbsizeadjusted = ISC_FALSE;
02951                 ISC_LINK_INIT(nsc, link);
02952                 ISC_LIST_APPEND(*cachelist, nsc, link);
02953         }
02954         dns_view_setcache2(view, cache, shared_cache);
02955 
02956         /*
02957          * cache-file cannot be inherited if views are present, but this
02958          * should be caught by the configuration checking stage.
02959          */
02960         obj = NULL;
02961         result = ns_config_get(maps, "cache-file", &obj);
02962         if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) {
02963                 CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj)));
02964                 if (!reused_cache && !shared_cache)
02965                         CHECK(dns_cache_load(cache));
02966         }
02967 
02968         dns_cache_setcleaninginterval(cache, cleaning_interval);
02969         dns_cache_setcachesize(cache, max_cache_size);
02970 
02971         dns_cache_detach(&cache);
02972 
02973         /*
02974          * Resolver.
02975          *
02976          * XXXRTH  Hardwired number of tasks.
02977          */
02978         CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4, &dscp4,
02979                                             ISC_TF(ISC_LIST_PREV(view, link)
02980                                                    == NULL)));
02981         CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6, &dscp6,
02982                                             ISC_TF(ISC_LIST_PREV(view, link)
02983                                                    == NULL)));
02984         if (dispatch4 == NULL && dispatch6 == NULL) {
02985                 UNEXPECTED_ERROR(__FILE__, __LINE__,
02986                                  "unable to obtain neither an IPv4 nor"
02987                                  " an IPv6 dispatch");
02988                 result = ISC_R_UNEXPECTED;
02989                 goto cleanup;
02990         }
02991 
02992         if (resstats == NULL) {
02993                 CHECK(isc_stats_create(mctx, &resstats,
02994                                        dns_resstatscounter_max));
02995         }
02996         dns_view_setresstats(view, resstats);
02997         if (resquerystats == NULL)
02998                 CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
02999         dns_view_setresquerystats(view, resquerystats);
03000 
03001         ndisp = 4 * ISC_MIN(ns_g_udpdisp, MAX_UDP_DISPATCH);
03002         CHECK(dns_view_createresolver(view, ns_g_taskmgr, RESOLVER_NTASKS,
03003                                       ndisp, ns_g_socketmgr, ns_g_timermgr,
03004                                       resopts, ns_g_dispatchmgr,
03005                                       dispatch4, dispatch6));
03006 
03007         if (dscp4 == -1)
03008                 dscp4 = ns_g_dscp;
03009         if (dscp6 == -1)
03010                 dscp6 = ns_g_dscp;
03011         if (dscp4 != -1)
03012                 dns_resolver_setquerydscp4(view->resolver, dscp4);
03013         if (dscp6 != -1)
03014                 dns_resolver_setquerydscp6(view->resolver, dscp6);
03015 
03016         /*
03017          * Set the ADB cache size to 1/8th of the max-cache-size or
03018          * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
03019          */
03020         max_adb_size = 0;
03021         if (max_cache_size != 0U) {
03022                 max_adb_size = max_cache_size / 8;
03023                 if (max_adb_size == 0U)
03024                         max_adb_size = 1;       /* Force minimum. */
03025                 if (view != nsc->primaryview &&
03026                     max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE) {
03027                         max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
03028                         if (!nsc->adbsizeadjusted) {
03029                                 dns_adb_setadbsize(nsc->primaryview->adb,
03030                                                    MAX_ADB_SIZE_FOR_CACHESHARE);
03031                                 nsc->adbsizeadjusted = ISC_TRUE;
03032                         }
03033                 }
03034         }
03035         dns_adb_setadbsize(view->adb, max_adb_size);
03036 
03037         /*
03038          * Set resolver's lame-ttl.
03039          */
03040         obj = NULL;
03041         result = ns_config_get(maps, "lame-ttl", &obj);
03042         INSIST(result == ISC_R_SUCCESS);
03043         lame_ttl = cfg_obj_asuint32(obj);
03044         if (lame_ttl > 1800)
03045                 lame_ttl = 1800;
03046         dns_resolver_setlamettl(view->resolver, lame_ttl);
03047 
03048         /*
03049          * Set the resolver's query timeout.
03050          */
03051         obj = NULL;
03052         result = ns_config_get(maps, "resolver-query-timeout", &obj);
03053         INSIST(result == ISC_R_SUCCESS);
03054         query_timeout = cfg_obj_asuint32(obj);
03055         dns_resolver_settimeout(view->resolver, query_timeout);
03056 
03057         /* Specify whether to use 0-TTL for negative response for SOA query */
03058         dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
03059 
03060         /*
03061          * Set the resolver's EDNS UDP size.
03062          */
03063         obj = NULL;
03064         result = ns_config_get(maps, "edns-udp-size", &obj);
03065         INSIST(result == ISC_R_SUCCESS);
03066         udpsize = cfg_obj_asuint32(obj);
03067         if (udpsize < 512)
03068                 udpsize = 512;
03069         if (udpsize > 4096)
03070                 udpsize = 4096;
03071         dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize);
03072 
03073         /*
03074          * Set the maximum UDP response size.
03075          */
03076         obj = NULL;
03077         result = ns_config_get(maps, "max-udp-size", &obj);
03078         INSIST(result == ISC_R_SUCCESS);
03079         udpsize = cfg_obj_asuint32(obj);
03080         if (udpsize < 512)
03081                 udpsize = 512;
03082         if (udpsize > 4096)
03083                 udpsize = 4096;
03084         view->maxudp = udpsize;
03085 
03086 #ifdef ISC_PLATFORM_USESIT
03087         /*
03088          * Set the maximum UDP when a SIT is not provided.
03089          */
03090         obj = NULL;
03091         result = ns_config_get(maps, "nosit-udp-size", &obj);
03092         INSIST(result == ISC_R_SUCCESS);
03093         udpsize = cfg_obj_asuint32(obj);
03094         if (udpsize < 128)
03095                 udpsize = 128;
03096         if (udpsize > view->maxudp)
03097                 udpsize = view->maxudp;
03098         view->situdp = udpsize;
03099 #endif
03100 
03101         /*
03102          * Set the maximum rsa exponent bits.
03103          */
03104         obj = NULL;
03105         result = ns_config_get(maps, "max-rsa-exponent-size", &obj);
03106         INSIST(result == ISC_R_SUCCESS);
03107         maxbits = cfg_obj_asuint32(obj);
03108         if (maxbits != 0 && maxbits < 35)
03109                 maxbits = 35;
03110         if (maxbits > 4096)
03111                 maxbits = 4096;
03112         view->maxbits = maxbits;
03113 
03114         /*
03115          * Set supported DNSSEC algorithms.
03116          */
03117         dns_resolver_reset_algorithms(view->resolver);
03118         disabled = NULL;
03119         (void)ns_config_get(maps, "disable-algorithms", &disabled);
03120         if (disabled != NULL) {
03121                 for (element = cfg_list_first(disabled);
03122                      element != NULL;
03123                      element = cfg_list_next(element))
03124                         CHECK(disable_algorithms(cfg_listelt_value(element),
03125                                                  view->resolver));
03126         }
03127 
03128         /*
03129          * Set supported DS/DLV digest types.
03130          */
03131         dns_resolver_reset_ds_digests(view->resolver);
03132         disabled = NULL;
03133         (void)ns_config_get(maps, "disable-ds-digests", &disabled);
03134         if (disabled != NULL) {
03135                 for (element = cfg_list_first(disabled);
03136                      element != NULL;
03137                      element = cfg_list_next(element))
03138                         CHECK(disable_ds_digests(cfg_listelt_value(element),
03139                                                  view->resolver));
03140         }
03141 
03142         /*
03143          * A global or view "forwarders" option, if present,
03144          * creates an entry for "." in the forwarding table.
03145          */
03146         forwardtype = NULL;
03147         forwarders = NULL;
03148         (void)ns_config_get(maps, "forward", &forwardtype);
03149         (void)ns_config_get(maps, "forwarders", &forwarders);
03150         if (forwarders != NULL)
03151                 CHECK(configure_forward(config, view, dns_rootname,
03152                                         forwarders, forwardtype));
03153 
03154         /*
03155          * Dual Stack Servers.
03156          */
03157         alternates = NULL;
03158         (void)ns_config_get(maps, "dual-stack-servers", &alternates);
03159         if (alternates != NULL)
03160                 CHECK(configure_alternates(config, view, alternates));
03161 
03162         /*
03163          * We have default hints for class IN if we need them.
03164          */
03165         if (view->rdclass == dns_rdataclass_in && view->hints == NULL)
03166                 dns_view_sethints(view, ns_g_server->in_roothints);
03167 
03168         /*
03169          * If we still have no hints, this is a non-IN view with no
03170          * "hints zone" configured.  Issue a warning, except if this
03171          * is a root server.  Root servers never need to consult
03172          * their hints, so it's no point requiring users to configure
03173          * them.
03174          */
03175         if (view->hints == NULL) {
03176                 dns_zone_t *rootzone = NULL;
03177                 (void)dns_view_findzone(view, dns_rootname, &rootzone);
03178                 if (rootzone != NULL) {
03179                         dns_zone_detach(&rootzone);
03180                         need_hints = ISC_FALSE;
03181                 }
03182                 if (need_hints)
03183                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
03184                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
03185                                       "no root hints for view '%s'",
03186                                       view->name);
03187         }
03188 
03189         /*
03190          * Configure the view's TSIG keys.
03191          */
03192         CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
03193         if (ns_g_server->sessionkey != NULL) {
03194                 CHECK(dns_tsigkeyring_add(ring, ns_g_server->session_keyname,
03195                                           ns_g_server->sessionkey));
03196         }
03197         dns_view_setkeyring(view, ring);
03198         dns_tsigkeyring_detach(&ring);
03199 
03200         /*
03201          * See if we can re-use a dynamic key ring.
03202          */
03203         result = dns_viewlist_find(&ns_g_server->viewlist, view->name,
03204                                    view->rdclass, &pview);
03205         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
03206                 goto cleanup;
03207         if (pview != NULL) {
03208                 dns_view_getdynamickeyring(pview, &ring);
03209                 if (ring != NULL)
03210                         dns_view_setdynamickeyring(view, ring);
03211                 dns_tsigkeyring_detach(&ring);
03212                 dns_view_detach(&pview);
03213         } else
03214                 dns_view_restorekeyring(view);
03215 
03216         /*
03217          * Configure the view's peer list.
03218          */
03219         {
03220                 const cfg_obj_t *peers = NULL;
03221                 dns_peerlist_t *newpeers = NULL;
03222 
03223                 (void)ns_config_get(cfgmaps, "server", &peers);
03224                 CHECK(dns_peerlist_new(mctx, &newpeers));
03225                 for (element = cfg_list_first(peers);
03226                      element != NULL;
03227                      element = cfg_list_next(element))
03228                 {
03229                         const cfg_obj_t *cpeer = cfg_listelt_value(element);
03230                         dns_peer_t *peer;
03231 
03232                         CHECK(configure_peer(cpeer, mctx, &peer));
03233                         dns_peerlist_addpeer(newpeers, peer);
03234                         dns_peer_detach(&peer);
03235                 }
03236                 dns_peerlist_detach(&view->peers);
03237                 view->peers = newpeers; /* Transfer ownership. */
03238         }
03239 
03240         /*
03241          *      Configure the views rrset-order.
03242          */
03243         {
03244                 const cfg_obj_t *rrsetorder = NULL;
03245 
03246                 (void)ns_config_get(maps, "rrset-order", &rrsetorder);
03247                 CHECK(dns_order_create(mctx, &order));
03248                 for (element = cfg_list_first(rrsetorder);
03249                      element != NULL;
03250                      element = cfg_list_next(element))
03251                 {
03252                         const cfg_obj_t *ent = cfg_listelt_value(element);
03253 
03254                         CHECK(configure_order(order, ent));
03255                 }
03256                 if (view->order != NULL)
03257                         dns_order_detach(&view->order);
03258                 dns_order_attach(order, &view->order);
03259                 dns_order_detach(&order);
03260         }
03261         /*
03262          * Copy the aclenv object.
03263          */
03264         dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv);
03265 
03266         /*
03267          * Configure the "match-clients" and "match-destinations" ACL.
03268          */
03269         CHECK(configure_view_acl(vconfig, config, "match-clients", NULL, actx,
03270                                  ns_g_mctx, &view->matchclients));
03271         CHECK(configure_view_acl(vconfig, config, "match-destinations", NULL,
03272                                  actx, ns_g_mctx, &view->matchdestinations));
03273 
03274         /*
03275          * Configure the "match-recursive-only" option.
03276          */
03277         obj = NULL;
03278         (void)ns_config_get(maps, "match-recursive-only", &obj);
03279         if (obj != NULL && cfg_obj_asboolean(obj))
03280                 view->matchrecursiveonly = ISC_TRUE;
03281         else
03282                 view->matchrecursiveonly = ISC_FALSE;
03283 
03284         /*
03285          * Configure other configurable data.
03286          */
03287         obj = NULL;
03288         result = ns_config_get(maps, "recursion", &obj);
03289         INSIST(result == ISC_R_SUCCESS);
03290         view->recursion = cfg_obj_asboolean(obj);
03291 
03292         obj = NULL;
03293         result = ns_config_get(maps, "auth-nxdomain", &obj);
03294         INSIST(result == ISC_R_SUCCESS);
03295         view->auth_nxdomain = cfg_obj_asboolean(obj);
03296 
03297         obj = NULL;
03298         result = ns_config_get(maps, "minimal-responses", &obj);
03299         INSIST(result == ISC_R_SUCCESS);
03300         view->minimalresponses = cfg_obj_asboolean(obj);
03301 
03302         obj = NULL;
03303         result = ns_config_get(maps, "transfer-format", &obj);
03304         INSIST(result == ISC_R_SUCCESS);
03305         str = cfg_obj_asstring(obj);
03306         if (strcasecmp(str, "many-answers") == 0)
03307                 view->transfer_format = dns_many_answers;
03308         else if (strcasecmp(str, "one-answer") == 0)
03309                 view->transfer_format = dns_one_answer;
03310         else
03311                 INSIST(0);
03312 
03313         /*
03314          * Set sources where additional data and CNAME/DNAME
03315          * targets for authoritative answers may be found.
03316          */
03317         obj = NULL;
03318         result = ns_config_get(maps, "additional-from-auth", &obj);
03319         INSIST(result == ISC_R_SUCCESS);
03320         view->additionalfromauth = cfg_obj_asboolean(obj);
03321         if (view->recursion && ! view->additionalfromauth) {
03322                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
03323                             "'additional-from-auth no' is only supported "
03324                             "with 'recursion no'");
03325                 view->additionalfromauth = ISC_TRUE;
03326         }
03327 
03328         obj = NULL;
03329         result = ns_config_get(maps, "additional-from-cache", &obj);
03330         INSIST(result == ISC_R_SUCCESS);
03331         view->additionalfromcache = cfg_obj_asboolean(obj);
03332         if (view->recursion && ! view->additionalfromcache) {
03333                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
03334                             "'additional-from-cache no' is only supported "
03335                             "with 'recursion no'");
03336                 view->additionalfromcache = ISC_TRUE;
03337         }
03338 
03339         /*
03340          * Set "allow-query-cache", "allow-query-cache-on",
03341          * "allow-recursion", and "allow-recursion-on" acls if
03342          * configured in named.conf.
03343          */
03344         CHECK(configure_view_acl(vconfig, config, "allow-query-cache", NULL,
03345                                  actx, ns_g_mctx, &view->cacheacl));
03346         CHECK(configure_view_acl(vconfig, config, "allow-query-cache-on", NULL,
03347                                  actx, ns_g_mctx, &view->cacheonacl));
03348         if (view->cacheonacl == NULL)
03349                 CHECK(configure_view_acl(NULL, ns_g_config,
03350                                          "allow-query-cache-on", NULL, actx,
03351                                          ns_g_mctx, &view->cacheonacl));
03352         if (strcmp(view->name, "_bind") != 0) {
03353                 CHECK(configure_view_acl(vconfig, config, "allow-recursion",
03354                                          NULL, actx, ns_g_mctx,
03355                                          &view->recursionacl));
03356                 CHECK(configure_view_acl(vconfig, config, "allow-recursion-on",
03357                                          NULL, actx, ns_g_mctx,
03358                                          &view->recursiononacl));
03359         }
03360 
03361         /*
03362          * "allow-query-cache" inherits from "allow-recursion" if set,
03363          * otherwise from "allow-query" if set.
03364          * "allow-recursion" inherits from "allow-query-cache" if set,
03365          * otherwise from "allow-query" if set.
03366          */
03367         if (view->cacheacl == NULL && view->recursionacl != NULL)
03368                 dns_acl_attach(view->recursionacl, &view->cacheacl);
03369         /*
03370          * XXXEACH: This call to configure_view_acl() is redundant.  We
03371          * are leaving it as it is because we are making a minimal change
03372          * for a patch release.  In the future this should be changed to
03373          * dns_acl_attach(view->queryacl, &view->cacheacl).
03374          */
03375         if (view->cacheacl == NULL && view->recursion)
03376                 CHECK(configure_view_acl(vconfig, config, "allow-query", NULL,
03377                                          actx, ns_g_mctx, &view->cacheacl));
03378         if (view->recursion &&
03379             view->recursionacl == NULL && view->cacheacl != NULL)
03380                 dns_acl_attach(view->cacheacl, &view->recursionacl);
03381 
03382         /*
03383          * Set default "allow-recursion", "allow-recursion-on" and
03384          * "allow-query-cache" acls.
03385          */
03386         if (view->recursionacl == NULL && view->recursion)
03387                 CHECK(configure_view_acl(NULL, ns_g_config,
03388                                          "allow-recursion", NULL,
03389                                          actx, ns_g_mctx,
03390                                          &view->recursionacl));
03391         if (view->recursiononacl == NULL && view->recursion)
03392                 CHECK(configure_view_acl(NULL, ns_g_config,
03393                                          "allow-recursion-on", NULL,
03394                                          actx, ns_g_mctx,
03395                                          &view->recursiononacl));
03396         if (view->cacheacl == NULL) {
03397                 if (view->recursion)
03398                         CHECK(configure_view_acl(NULL, ns_g_config,
03399                                                  "allow-query-cache", NULL,
03400                                                  actx, ns_g_mctx,
03401                                                  &view->cacheacl));
03402                 else
03403                         CHECK(dns_acl_none(mctx, &view->cacheacl));
03404         }
03405 
03406         /*
03407          * Ignore case when compressing responses to the specified
03408          * clients. This causes case not always to be preserved,
03409          * and is needed by some broken clients.
03410          */
03411         CHECK(configure_view_acl(vconfig, config, "no-case-compress", NULL,
03412                                  actx, ns_g_mctx, &view->nocasecompress));
03413 
03414         /*
03415          * Filter setting on addresses in the answer section.
03416          */
03417         CHECK(configure_view_acl(vconfig, config, "deny-answer-addresses",
03418                                  "acl", actx, ns_g_mctx, &view->denyansweracl));
03419         CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
03420                                        "except-from", ns_g_mctx,
03421                                        &view->answeracl_exclude));
03422 
03423         /*
03424          * Filter setting on names (CNAME/DNAME targets) in the answer section.
03425          */
03426         CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
03427                                        "name", ns_g_mctx,
03428                                        &view->denyanswernames));
03429         CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
03430                                        "except-from", ns_g_mctx,
03431                                        &view->answernames_exclude));
03432 
03433         /*
03434          * Configure sortlist, if set
03435          */
03436         CHECK(configure_view_sortlist(vconfig, config, actx, ns_g_mctx,
03437                                       &view->sortlist));
03438 
03439         /*
03440          * Configure default allow-transfer, allow-notify, allow-update
03441          * and allow-update-forwarding ACLs, if set, so they can be
03442          * inherited by zones.
03443          */
03444         if (view->notifyacl == NULL)
03445                 CHECK(configure_view_acl(NULL, ns_g_config,
03446                                          "allow-notify", NULL, actx,
03447                                          ns_g_mctx, &view->notifyacl));
03448         if (view->transferacl == NULL)
03449                 CHECK(configure_view_acl(NULL, ns_g_config,
03450                                          "allow-transfer", NULL, actx,
03451                                          ns_g_mctx, &view->transferacl));
03452         if (view->updateacl == NULL)
03453                 CHECK(configure_view_acl(NULL, ns_g_config,
03454                                          "allow-update", NULL, actx,
03455                                          ns_g_mctx, &view->updateacl));
03456         if (view->upfwdacl == NULL)
03457                 CHECK(configure_view_acl(NULL, ns_g_config,
03458                                          "allow-update-forwarding", NULL, actx,
03459                                          ns_g_mctx, &view->upfwdacl));
03460 
03461         obj = NULL;
03462         result = ns_config_get(maps, "provide-ixfr", &obj);
03463         INSIST(result == ISC_R_SUCCESS);
03464         view->provideixfr = cfg_obj_asboolean(obj);
03465 
03466         obj = NULL;
03467         result = ns_config_get(maps, "request-nsid", &obj);
03468         INSIST(result == ISC_R_SUCCESS);
03469         view->requestnsid = cfg_obj_asboolean(obj);
03470 
03471 #ifdef ISC_PLATFORM_USESIT
03472         obj = NULL;
03473         result = ns_config_get(maps, "request-sit", &obj);
03474         INSIST(result == ISC_R_SUCCESS);
03475         view->requestsit = cfg_obj_asboolean(obj);
03476 #endif
03477 
03478         obj = NULL;
03479         result = ns_config_get(maps, "max-clients-per-query", &obj);
03480         INSIST(result == ISC_R_SUCCESS);
03481         max_clients_per_query = cfg_obj_asuint32(obj);
03482 
03483         obj = NULL;
03484         result = ns_config_get(maps, "clients-per-query", &obj);
03485         INSIST(result == ISC_R_SUCCESS);
03486         dns_resolver_setclientsperquery(view->resolver,
03487                                         cfg_obj_asuint32(obj),
03488                                         max_clients_per_query);
03489 
03490         obj = NULL;
03491         result = ns_config_get(maps, "max-recursion-depth", &obj);
03492         INSIST(result == ISC_R_SUCCESS);
03493         dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
03494 
03495         obj = NULL;
03496         result = ns_config_get(maps, "max-recursion-queries", &obj);
03497         INSIST(result == ISC_R_SUCCESS);
03498         dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
03499 
03500 #ifdef ALLOW_FILTER_AAAA
03501         obj = NULL;
03502         result = ns_config_get(maps, "filter-aaaa-on-v4", &obj);
03503         INSIST(result == ISC_R_SUCCESS);
03504         if (cfg_obj_isboolean(obj)) {
03505                 if (cfg_obj_asboolean(obj))
03506                         view->v4_aaaa = dns_aaaa_filter;
03507                 else
03508                         view->v4_aaaa = dns_aaaa_ok;
03509         } else {
03510                 const char *v4_aaaastr = cfg_obj_asstring(obj);
03511                 if (strcasecmp(v4_aaaastr, "break-dnssec") == 0)
03512                         view->v4_aaaa = dns_aaaa_break_dnssec;
03513                 else
03514                         INSIST(0);
03515         }
03516 
03517         obj = NULL;
03518         result = ns_config_get(maps, "filter-aaaa-on-v6", &obj);
03519         INSIST(result == ISC_R_SUCCESS);
03520         if (cfg_obj_isboolean(obj)) {
03521                 if (cfg_obj_asboolean(obj))
03522                         view->v6_aaaa = dns_aaaa_filter;
03523                 else
03524                         view->v6_aaaa = dns_aaaa_ok;
03525         } else {
03526                 const char *v6_aaaastr = cfg_obj_asstring(obj);
03527                 if (strcasecmp(v6_aaaastr, "break-dnssec") == 0)
03528                         view->v6_aaaa = dns_aaaa_break_dnssec;
03529                 else
03530                         INSIST(0);
03531         }
03532 
03533         CHECK(configure_view_acl(vconfig, config, "filter-aaaa", NULL,
03534                                  actx, ns_g_mctx, &view->aaaa_acl));
03535 #endif
03536         obj = NULL;
03537         result = ns_config_get(maps, "prefetch", &obj);
03538         if (result == ISC_R_SUCCESS) {
03539                 const cfg_obj_t *trigger, *eligible;
03540 
03541                 trigger = cfg_tuple_get(obj, "trigger");
03542                 view->prefetch_trigger = cfg_obj_asuint32(trigger);
03543                 if (view->prefetch_trigger > 10)
03544                         view->prefetch_trigger = 10;
03545                 eligible = cfg_tuple_get(obj, "eligible");
03546                 if (cfg_obj_isvoid(eligible)) {
03547                         int m;
03548                         for (m = 1; maps[m] != NULL; m++) {
03549                                 obj = NULL;
03550                                 result = ns_config_get(&maps[m],
03551                                                        "prefetch", &obj);
03552                                 INSIST(result == ISC_R_SUCCESS);
03553                                 eligible = cfg_tuple_get(obj, "eligible");
03554                                 if (cfg_obj_isuint32(eligible))
03555                                         break;
03556                         }
03557                         INSIST(cfg_obj_isuint32(eligible));
03558                 }
03559                 view->prefetch_eligible = cfg_obj_asuint32(eligible);
03560                 if (view->prefetch_eligible < view->prefetch_trigger + 6)
03561                         view->prefetch_eligible = view->prefetch_trigger + 6;
03562         }
03563 
03564         obj = NULL;
03565         result = ns_config_get(maps, "dnssec-enable", &obj);
03566         INSIST(result == ISC_R_SUCCESS);
03567         view->enablednssec = cfg_obj_asboolean(obj);
03568 
03569         obj = NULL;
03570         result = ns_config_get(optionmaps, "dnssec-lookaside", &obj);
03571         if (result == ISC_R_SUCCESS) {
03572                 /* If set to "auto", use the version from the defaults */
03573                 const cfg_obj_t *dlvobj;
03574                 const char *dom;
03575                 dlvobj = cfg_listelt_value(cfg_list_first(obj));
03576                 dom = cfg_obj_asstring(cfg_tuple_get(dlvobj, "domain"));
03577                 if (cfg_obj_isvoid(cfg_tuple_get(dlvobj, "trust-anchor"))) {
03578                         /* If "no", skip; if "auto", use global default */
03579                         if (!strcasecmp(dom, "no"))
03580                                 result = ISC_R_NOTFOUND;
03581                         else if (!strcasecmp(dom, "auto")) {
03582                                 auto_dlv = ISC_TRUE;
03583                                 obj = NULL;
03584                                 result = cfg_map_get(ns_g_defaults,
03585                                                      "dnssec-lookaside", &obj);
03586                         }
03587                 }
03588         }
03589 
03590         if (result == ISC_R_SUCCESS) {
03591                 for (element = cfg_list_first(obj);
03592                      element != NULL;
03593                      element = cfg_list_next(element))
03594                 {
03595                         dns_name_t *dlv;
03596 
03597                         obj = cfg_listelt_value(element);
03598                         obj = cfg_tuple_get(obj, "trust-anchor");
03599                         dlv = dns_fixedname_name(&view->dlv_fixed);
03600                         CHECK(dns_name_fromstring(dlv, cfg_obj_asstring(obj),
03601                                                   DNS_NAME_DOWNCASE, NULL));
03602                         view->dlv = dns_fixedname_name(&view->dlv_fixed);
03603                 }
03604         } else
03605                 view->dlv = NULL;
03606 
03607         /*
03608          * For now, there is only one kind of trusted keys, the
03609          * "security roots".
03610          */
03611         CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
03612                                         auto_dlv, auto_root, mctx));
03613         dns_resolver_resetmustbesecure(view->resolver);
03614         obj = NULL;
03615         result = ns_config_get(maps, "dnssec-must-be-secure", &obj);
03616         if (result == ISC_R_SUCCESS)
03617                 CHECK(mustbesecure(obj, view->resolver));
03618 
03619         obj = NULL;
03620         result = ns_config_get(maps, "nta-recheck", &obj);
03621         INSIST(result == ISC_R_SUCCESS);
03622         view->nta_recheck = cfg_obj_asuint32(obj);
03623 
03624         obj = NULL;
03625         result = ns_config_get(maps, "nta-lifetime", &obj);
03626         INSIST(result == ISC_R_SUCCESS);
03627         view->nta_lifetime = cfg_obj_asuint32(obj);
03628 
03629         obj = NULL;
03630         result = ns_config_get(maps, "preferred-glue", &obj);
03631         if (result == ISC_R_SUCCESS) {
03632                 str = cfg_obj_asstring(obj);
03633                 if (strcasecmp(str, "a") == 0)
03634                         view->preferred_glue = dns_rdatatype_a;
03635                 else if (strcasecmp(str, "aaaa") == 0)
03636                         view->preferred_glue = dns_rdatatype_aaaa;
03637                 else
03638                         view->preferred_glue = 0;
03639         } else
03640                 view->preferred_glue = 0;
03641 
03642         obj = NULL;
03643         result = ns_config_get(maps, "root-delegation-only", &obj);
03644         if (result == ISC_R_SUCCESS) {
03645                 dns_fixedname_t fixed;
03646                 dns_name_t *name;
03647                 const cfg_obj_t *exclude;
03648 
03649                 dns_view_setrootdelonly(view, ISC_TRUE);
03650 
03651                 dns_fixedname_init(&fixed);
03652                 name = dns_fixedname_name(&fixed);
03653                 for (element = cfg_list_first(obj);
03654                      element != NULL;
03655                      element = cfg_list_next(element)) {
03656                         exclude = cfg_listelt_value(element);
03657                         CHECK(dns_name_fromstring(name,
03658                                                   cfg_obj_asstring(exclude),
03659                                                   0, NULL));
03660                         CHECK(dns_view_excludedelegationonly(view, name));
03661                 }
03662         } else
03663                 dns_view_setrootdelonly(view, ISC_FALSE);
03664 
03665         /*
03666          * Setup automatic empty zones.  If recursion is off then
03667          * they are disabled by default.
03668          */
03669         obj = NULL;
03670         (void)ns_config_get(maps, "empty-zones-enable", &obj);
03671         (void)ns_config_get(maps, "disable-empty-zone", &disablelist);
03672         if (obj == NULL && disablelist == NULL &&
03673             view->rdclass == dns_rdataclass_in) {
03674                 empty_zones_enable = view->recursion;
03675         } else if (view->rdclass == dns_rdataclass_in) {
03676                 if (obj != NULL)
03677                         empty_zones_enable = cfg_obj_asboolean(obj);
03678                 else
03679                         empty_zones_enable = view->recursion;
03680         } else {
03681                 empty_zones_enable = ISC_FALSE;
03682         }
03683 
03684         if (empty_zones_enable && !lwresd_g_useresolvconf) {
03685                 const char *empty;
03686                 int empty_zone = 0;
03687                 dns_fixedname_t fixed;
03688                 dns_name_t *name;
03689                 isc_buffer_t buffer;
03690                 char server[DNS_NAME_FORMATSIZE + 1];
03691                 char contact[DNS_NAME_FORMATSIZE + 1];
03692                 const char *empty_dbtype[4] =
03693                                     { "_builtin", "empty", NULL, NULL };
03694                 int empty_dbtypec = 4;
03695                 dns_zonestat_level_t statlevel;
03696 
03697                 dns_fixedname_init(&fixed);
03698                 name = dns_fixedname_name(&fixed);
03699 
03700                 obj = NULL;
03701                 result = ns_config_get(maps, "empty-server", &obj);
03702                 if (result == ISC_R_SUCCESS) {
03703                         CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
03704                                                   0, NULL));
03705                         isc_buffer_init(&buffer, server, sizeof(server) - 1);
03706                         CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
03707                         server[isc_buffer_usedlength(&buffer)] = 0;
03708                         empty_dbtype[2] = server;
03709                 } else
03710                         empty_dbtype[2] = "@";
03711 
03712                 obj = NULL;
03713                 result = ns_config_get(maps, "empty-contact", &obj);
03714                 if (result == ISC_R_SUCCESS) {
03715                         CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
03716                                                  0, NULL));
03717                         isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
03718                         CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
03719                         contact[isc_buffer_usedlength(&buffer)] = 0;
03720                         empty_dbtype[3] = contact;
03721                 } else
03722                         empty_dbtype[3] = ".";
03723 
03724                 obj = NULL;
03725                 result = ns_config_get(maps, "zone-statistics", &obj);
03726                 INSIST(result == ISC_R_SUCCESS);
03727                 if (cfg_obj_isboolean(obj)) {
03728                         if (cfg_obj_asboolean(obj))
03729                                 statlevel = dns_zonestat_full;
03730                         else
03731                                 statlevel = dns_zonestat_none;
03732                 } else {
03733                         const char *levelstr = cfg_obj_asstring(obj);
03734                         if (strcasecmp(levelstr, "full") == 0)
03735                                 statlevel = dns_zonestat_full;
03736                         else if (strcasecmp(levelstr, "terse") == 0)
03737                                 statlevel = dns_zonestat_terse;
03738                         else if (strcasecmp(levelstr, "none") == 0)
03739                                 statlevel = dns_zonestat_none;
03740                         else
03741                                 INSIST(0);
03742                 }
03743 
03744                 for (empty = empty_zones[empty_zone];
03745                      empty != NULL;
03746                      empty = empty_zones[++empty_zone])
03747                 {
03748                         dns_forwarders_t *dnsforwarders = NULL;
03749 
03750                         /*
03751                          * Look for zone on drop list.
03752                          */
03753                         CHECK(dns_name_fromstring(name, empty, 0, NULL));
03754                         if (disablelist != NULL &&
03755                             on_disable_list(disablelist, name))
03756                                 continue;
03757 
03758                         /*
03759                          * This zone already exists.
03760                          */
03761                         (void)dns_view_findzone(view, name, &zone);
03762                         if (zone != NULL) {
03763                                 dns_zone_detach(&zone);
03764                                 continue;
03765                         }
03766 
03767                         /*
03768                          * If we would forward this name don't add a
03769                          * empty zone for it.
03770                          */
03771                         result = dns_fwdtable_find(view->fwdtable, name,
03772                                                    &dnsforwarders);
03773                         if (result == ISC_R_SUCCESS &&
03774                             dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
03775                                 continue;
03776 
03777                         /*
03778                          * See if we can re-use a existing zone.
03779                          */
03780                         result = dns_viewlist_find(&ns_g_server->viewlist,
03781                                                    view->name, view->rdclass,
03782                                                    &pview);
03783                         if (result != ISC_R_NOTFOUND &&
03784                             result != ISC_R_SUCCESS)
03785                                 goto cleanup;
03786 
03787                         if (pview != NULL) {
03788                                 (void)dns_view_findzone(pview, name, &zone);
03789                                 dns_view_detach(&pview);
03790                         }
03791 
03792                         CHECK(create_empty_zone(zone, name, view, zonelist,
03793                                                 empty_dbtype, empty_dbtypec,
03794                                                 statlevel));
03795                         if (zone != NULL)
03796                                 dns_zone_detach(&zone);
03797                 }
03798         }
03799 
03800         obj = NULL;
03801         result = ns_config_get(maps, "rate-limit", &obj);
03802         if (result == ISC_R_SUCCESS) {
03803                 result = configure_rrl(view, config, obj);
03804                 if (result != ISC_R_SUCCESS)
03805                         goto cleanup;
03806         }
03807 
03808         /*
03809          * Set the servfail-ttl.
03810          */
03811         obj = NULL;
03812         result = ns_config_get(maps, "servfail-ttl", &obj);
03813         INSIST(result == ISC_R_SUCCESS);
03814         fail_ttl  = cfg_obj_asuint32(obj);
03815         if (fail_ttl > 300)
03816                 fail_ttl = 300;
03817         dns_view_setfailttl(view, fail_ttl);
03818 
03819         /*
03820          * Name space to look up redirect information in.
03821          */
03822         obj = NULL;
03823         result = ns_config_get(maps, "nxdomain-redirect", &obj);
03824         if (result == ISC_R_SUCCESS) {
03825                 dns_name_t *name = dns_fixedname_name(&view->redirectfixed);
03826                 CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj), 0,
03827                                           NULL));
03828                 view->redirectzone = name;
03829         } else
03830                 view->redirectzone = NULL;
03831 
03832 
03833         result = ISC_R_SUCCESS;
03834 
03835  cleanup:
03836         if (clients != NULL)
03837                 dns_acl_detach(&clients);
03838         if (mapped != NULL)
03839                 dns_acl_detach(&mapped);
03840         if (excluded != NULL)
03841                 dns_acl_detach(&excluded);
03842         if (ring != NULL)
03843                 dns_tsigkeyring_detach(&ring);
03844         if (zone != NULL)
03845                 dns_zone_detach(&zone);
03846         if (dispatch4 != NULL)
03847                 dns_dispatch_detach(&dispatch4);
03848         if (dispatch6 != NULL)
03849                 dns_dispatch_detach(&dispatch6);
03850         if (resstats != NULL)
03851                 isc_stats_detach(&resstats);
03852         if (resquerystats != NULL)
03853                 dns_stats_detach(&resquerystats);
03854         if (order != NULL)
03855                 dns_order_detach(&order);
03856         if (cmctx != NULL)
03857                 isc_mem_detach(&cmctx);
03858         if (hmctx != NULL)
03859                 isc_mem_detach(&hmctx);
03860 
03861         if (cache != NULL)
03862                 dns_cache_detach(&cache);
03863 
03864         return (result);
03865 }
03866 
03867 static isc_result_t
03868 configure_hints(dns_view_t *view, const char *filename) {
03869         isc_result_t result;
03870         dns_db_t *db;
03871 
03872         db = NULL;
03873         result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
03874         if (result == ISC_R_SUCCESS) {
03875                 dns_view_sethints(view, db);
03876                 dns_db_detach(&db);
03877         }
03878 
03879         return (result);
03880 }
03881 
03882 static isc_result_t
03883 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
03884                      const cfg_obj_t *alternates)
03885 {
03886         const cfg_obj_t *portobj;
03887         const cfg_obj_t *addresses;
03888         const cfg_listelt_t *element;
03889         isc_result_t result = ISC_R_SUCCESS;
03890         in_port_t port;
03891 
03892         /*
03893          * Determine which port to send requests to.
03894          */
03895         if (ns_g_lwresdonly && ns_g_port != 0)
03896                 port = ns_g_port;
03897         else
03898                 CHECKM(ns_config_getport(config, &port), "port");
03899 
03900         if (alternates != NULL) {
03901                 portobj = cfg_tuple_get(alternates, "port");
03902                 if (cfg_obj_isuint32(portobj)) {
03903                         isc_uint32_t val = cfg_obj_asuint32(portobj);
03904                         if (val > ISC_UINT16_MAX) {
03905                                 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
03906                                             "port '%u' out of range", val);
03907                                 return (ISC_R_RANGE);
03908                         }
03909                         port = (in_port_t) val;
03910                 }
03911         }
03912 
03913         addresses = NULL;
03914         if (alternates != NULL)
03915                 addresses = cfg_tuple_get(alternates, "addresses");
03916 
03917         for (element = cfg_list_first(addresses);
03918              element != NULL;
03919              element = cfg_list_next(element))
03920         {
03921                 const cfg_obj_t *alternate = cfg_listelt_value(element);
03922                 isc_sockaddr_t sa;
03923 
03924                 if (!cfg_obj_issockaddr(alternate)) {
03925                         dns_fixedname_t fixed;
03926                         dns_name_t *name;
03927                         const char *str = cfg_obj_asstring(cfg_tuple_get(
03928                                                            alternate, "name"));
03929                         isc_buffer_t buffer;
03930                         in_port_t myport = port;
03931 
03932                         isc_buffer_constinit(&buffer, str, strlen(str));
03933                         isc_buffer_add(&buffer, strlen(str));
03934                         dns_fixedname_init(&fixed);
03935                         name = dns_fixedname_name(&fixed);
03936                         CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
03937                                                 NULL));
03938 
03939                         portobj = cfg_tuple_get(alternate, "port");
03940                         if (cfg_obj_isuint32(portobj)) {
03941                                 isc_uint32_t val = cfg_obj_asuint32(portobj);
03942                                 if (val > ISC_UINT16_MAX) {
03943                                         cfg_obj_log(portobj, ns_g_lctx,
03944                                                     ISC_LOG_ERROR,
03945                                                     "port '%u' out of range",
03946                                                      val);
03947                                         return (ISC_R_RANGE);
03948                                 }
03949                                 myport = (in_port_t) val;
03950                         }
03951                         CHECK(dns_resolver_addalternate(view->resolver, NULL,
03952                                                         name, myport));
03953                         continue;
03954                 }
03955 
03956                 sa = *cfg_obj_assockaddr(alternate);
03957                 if (isc_sockaddr_getport(&sa) == 0)
03958                         isc_sockaddr_setport(&sa, port);
03959                 CHECK(dns_resolver_addalternate(view->resolver, &sa,
03960                                                 NULL, 0));
03961         }
03962 
03963  cleanup:
03964         return (result);
03965 }
03966 
03967 static isc_result_t
03968 configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
03969                   const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype)
03970 {
03971         const cfg_obj_t *portobj, *dscpobj;
03972         const cfg_obj_t *faddresses;
03973         const cfg_listelt_t *element;
03974         dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
03975         dns_forwarderlist_t fwdlist;
03976         dns_forwarder_t *fwd;
03977         isc_result_t result;
03978         in_port_t port;
03979         isc_dscp_t dscp = -1;
03980 
03981         ISC_LIST_INIT(fwdlist);
03982 
03983         /*
03984          * Determine which port to send forwarded requests to.
03985          */
03986         if (ns_g_lwresdonly && ns_g_port != 0)
03987                 port = ns_g_port;
03988         else
03989                 CHECKM(ns_config_getport(config, &port), "port");
03990 
03991         if (forwarders != NULL) {
03992                 portobj = cfg_tuple_get(forwarders, "port");
03993                 if (cfg_obj_isuint32(portobj)) {
03994                         isc_uint32_t val = cfg_obj_asuint32(portobj);
03995                         if (val > ISC_UINT16_MAX) {
03996                                 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
03997                                             "port '%u' out of range", val);
03998                                 return (ISC_R_RANGE);
03999                         }
04000                         port = (in_port_t) val;
04001                 }
04002         }
04003 
04004         /*
04005          * DSCP value for forwarded requests.
04006          */
04007         dscp = ns_g_dscp;
04008         if (forwarders != NULL) {
04009                 dscpobj = cfg_tuple_get(forwarders, "dscp");
04010                 if (cfg_obj_isuint32(dscpobj)) {
04011                         if (cfg_obj_asuint32(dscpobj) > 63) {
04012                                 cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR,
04013                                             "dscp value '%u' is out of range",
04014                                             cfg_obj_asuint32(dscpobj));
04015                                 return (ISC_R_RANGE);
04016                         }
04017                         dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
04018                 }
04019         }
04020 
04021         faddresses = NULL;
04022         if (forwarders != NULL)
04023                 faddresses = cfg_tuple_get(forwarders, "addresses");
04024 
04025         for (element = cfg_list_first(faddresses);
04026              element != NULL;
04027              element = cfg_list_next(element))
04028         {
04029                 const cfg_obj_t *forwarder = cfg_listelt_value(element);
04030                 fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t));
04031                 if (fwd == NULL) {
04032                         result = ISC_R_NOMEMORY;
04033                         goto cleanup;
04034                 }
04035                 fwd->addr = *cfg_obj_assockaddr(forwarder);
04036                 if (isc_sockaddr_getport(&fwd->addr) == 0)
04037                         isc_sockaddr_setport(&fwd->addr, port);
04038                 fwd->dscp = cfg_obj_getdscp(forwarder);
04039                 if (fwd->dscp == -1)
04040                         fwd->dscp = dscp;
04041                 ISC_LINK_INIT(fwd, link);
04042                 ISC_LIST_APPEND(fwdlist, fwd, link);
04043         }
04044 
04045         if (ISC_LIST_EMPTY(fwdlist)) {
04046                 if (forwardtype != NULL)
04047                         cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
04048                                     "no forwarders seen; disabling "
04049                                     "forwarding");
04050                 fwdpolicy = dns_fwdpolicy_none;
04051         } else {
04052                 if (forwardtype == NULL)
04053                         fwdpolicy = dns_fwdpolicy_first;
04054                 else {
04055                         const char *forwardstr = cfg_obj_asstring(forwardtype);
04056                         if (strcasecmp(forwardstr, "first") == 0)
04057                                 fwdpolicy = dns_fwdpolicy_first;
04058                         else if (strcasecmp(forwardstr, "only") == 0)
04059                                 fwdpolicy = dns_fwdpolicy_only;
04060                         else
04061                                 INSIST(0);
04062                 }
04063         }
04064 
04065         result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist,
04066                                      fwdpolicy);
04067         if (result != ISC_R_SUCCESS) {
04068                 char namebuf[DNS_NAME_FORMATSIZE];
04069                 dns_name_format(origin, namebuf, sizeof(namebuf));
04070                 cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
04071                             "could not set up forwarding for domain '%s': %s",
04072                             namebuf, isc_result_totext(result));
04073                 goto cleanup;
04074         }
04075 
04076         result = ISC_R_SUCCESS;
04077 
04078  cleanup:
04079 
04080         while (!ISC_LIST_EMPTY(fwdlist)) {
04081                 fwd = ISC_LIST_HEAD(fwdlist);
04082                 ISC_LIST_UNLINK(fwdlist, fwd, link);
04083                 isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t));
04084         }
04085 
04086         return (result);
04087 }
04088 
04089 static isc_result_t
04090 get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
04091              dns_rdataclass_t *classp)
04092 {
04093         isc_result_t result = ISC_R_SUCCESS;
04094         const char *viewname;
04095         dns_rdataclass_t viewclass;
04096 
04097         REQUIRE(namep != NULL && *namep == NULL);
04098         REQUIRE(classp != NULL);
04099 
04100         if (vconfig != NULL) {
04101                 const cfg_obj_t *classobj = NULL;
04102 
04103                 viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
04104                 classobj = cfg_tuple_get(vconfig, "class");
04105                 result = ns_config_getclass(classobj, dns_rdataclass_in,
04106                                             &viewclass);
04107         } else {
04108                 viewname = "_default";
04109                 viewclass = dns_rdataclass_in;
04110         }
04111 
04112         *namep = viewname;
04113         *classp = viewclass;
04114 
04115         return (result);
04116 }
04117 
04118 /*
04119  * Find a view based on its configuration info and attach to it.
04120  *
04121  * If 'vconfig' is NULL, attach to the default view.
04122  */
04123 static isc_result_t
04124 find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
04125           dns_view_t **viewp)
04126 {
04127         isc_result_t result;
04128         const char *viewname = NULL;
04129         dns_rdataclass_t viewclass;
04130         dns_view_t *view = NULL;
04131 
04132         result = get_viewinfo(vconfig, &viewname, &viewclass);
04133         if (result != ISC_R_SUCCESS)
04134                 return (result);
04135 
04136         result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
04137         if (result != ISC_R_SUCCESS)
04138                 return (result);
04139 
04140         *viewp = view;
04141         return (ISC_R_SUCCESS);
04142 }
04143 
04144 /*
04145  * Create a new view and add it to the list.
04146  *
04147  * If 'vconfig' is NULL, create the default view.
04148  *
04149  * The view created is attached to '*viewp'.
04150  */
04151 static isc_result_t
04152 create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
04153             dns_view_t **viewp)
04154 {
04155         isc_result_t result;
04156         const char *viewname = NULL;
04157         dns_rdataclass_t viewclass;
04158         dns_view_t *view = NULL;
04159 
04160         result = get_viewinfo(vconfig, &viewname, &viewclass);
04161         if (result != ISC_R_SUCCESS)
04162                 return (result);
04163 
04164         result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
04165         if (result == ISC_R_SUCCESS)
04166                 return (ISC_R_EXISTS);
04167         if (result != ISC_R_NOTFOUND)
04168                 return (result);
04169         INSIST(view == NULL);
04170 
04171         result = dns_view_create(ns_g_mctx, viewclass, viewname, &view);
04172         if (result != ISC_R_SUCCESS)
04173                 return (result);
04174 
04175         result = isc_entropy_getdata(ns_g_entropy, view->secret,
04176                                      sizeof(view->secret), NULL, 0);
04177         if (result != ISC_R_SUCCESS) {
04178                 dns_view_detach(&view);
04179                 return (result);
04180         }
04181 
04182 #ifdef HAVE_GEOIP
04183         view->aclenv.geoip = ns_g_geoip;
04184 #endif
04185 
04186         ISC_LIST_APPEND(*viewlist, view, link);
04187         dns_view_attach(view, viewp);
04188         return (ISC_R_SUCCESS);
04189 }
04190 
04191 /*
04192  * Configure or reconfigure a zone.
04193  */
04194 static isc_result_t
04195 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
04196                const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
04197                dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
04198                isc_boolean_t added, isc_boolean_t old_rpz_ok,
04199                isc_boolean_t modify)
04200 {
04201         dns_view_t *pview = NULL;       /* Production view */
04202         dns_zone_t *zone = NULL;        /* New or reused zone */
04203         dns_zone_t *raw = NULL;         /* New or reused raw zone */
04204         dns_zone_t *dupzone = NULL;
04205         const cfg_obj_t *options = NULL;
04206         const cfg_obj_t *zoptions = NULL;
04207         const cfg_obj_t *typeobj = NULL;
04208         const cfg_obj_t *forwarders = NULL;
04209         const cfg_obj_t *forwardtype = NULL;
04210         const cfg_obj_t *only = NULL;
04211         const cfg_obj_t *signing = NULL;
04212         const cfg_obj_t *viewobj = NULL;
04213         isc_result_t result;
04214         isc_result_t tresult;
04215         isc_buffer_t buffer;
04216         dns_fixedname_t fixorigin;
04217         dns_name_t *origin;
04218         const char *zname;
04219         dns_rdataclass_t zclass;
04220         const char *ztypestr;
04221         dns_rpz_num_t rpz_num;
04222 
04223         options = NULL;
04224         (void)cfg_map_get(config, "options", &options);
04225 
04226         zoptions = cfg_tuple_get(zconfig, "options");
04227 
04228         /*
04229          * Get the zone origin as a dns_name_t.
04230          */
04231         zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
04232         isc_buffer_constinit(&buffer, zname, strlen(zname));
04233         isc_buffer_add(&buffer, strlen(zname));
04234         dns_fixedname_init(&fixorigin);
04235         CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin),
04236                                 &buffer, dns_rootname, 0, NULL));
04237         origin = dns_fixedname_name(&fixorigin);
04238 
04239         CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
04240                                  view->rdclass, &zclass));
04241         if (zclass != view->rdclass) {
04242                 const char *vname = NULL;
04243                 if (vconfig != NULL)
04244                         vname = cfg_obj_asstring(cfg_tuple_get(vconfig,
04245                                                                "name"));
04246                 else
04247                         vname = "<default view>";
04248 
04249                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
04250                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
04251                               "zone '%s': wrong class for view '%s'",
04252                               zname, vname);
04253                 result = ISC_R_FAILURE;
04254                 goto cleanup;
04255         }
04256 
04257         (void)cfg_map_get(zoptions, "in-view", &viewobj);
04258         if (viewobj != NULL) {
04259                 const char *inview = cfg_obj_asstring(viewobj);
04260                 dns_view_t *otherview = NULL;
04261 
04262                 if (viewlist == NULL) {
04263                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
04264                                     "'in-view' option is not permitted in "
04265                                     "dynamically added zones");
04266                         result = ISC_R_FAILURE;
04267                         goto cleanup;
04268                 }
04269 
04270                 result = dns_viewlist_find(viewlist, inview, view->rdclass,
04271                                            &otherview);
04272                 if (result != ISC_R_SUCCESS) {
04273                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
04274                                     "view '%s' is not yet defined.", inview);
04275                         result = ISC_R_FAILURE;
04276                         goto cleanup;
04277                 }
04278 
04279                 result = dns_view_findzone(otherview, origin, &zone);
04280                 dns_view_detach(&otherview);
04281                 if (result != ISC_R_SUCCESS) {
04282                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
04283                                     "zone '%s' not defined in view '%s'",
04284                                     zname, inview);
04285                         result = ISC_R_FAILURE;
04286                         goto cleanup;
04287                 }
04288 
04289                 CHECK(dns_view_addzone(view, zone));
04290                 dns_zone_detach(&zone);
04291 
04292                 /*
04293                  * If the zone contains a 'forwarders' statement, configure
04294                  * selective forwarding.  Note: this is not inherited from the
04295                  * other view.
04296                  */
04297                 forwarders = NULL;
04298                 result = cfg_map_get(zoptions, "forwarders", &forwarders);
04299                 if (result == ISC_R_SUCCESS) {
04300                         forwardtype = NULL;
04301                         (void)cfg_map_get(zoptions, "forward", &forwardtype);
04302                         CHECK(configure_forward(config, view, origin,
04303                                                 forwarders, forwardtype));
04304                 }
04305                 result = ISC_R_SUCCESS;
04306                 goto cleanup;
04307         }
04308 
04309         (void)cfg_map_get(zoptions, "type", &typeobj);
04310         if (typeobj == NULL) {
04311                 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
04312                             "zone '%s' 'type' not specified", zname);
04313                 result = ISC_R_FAILURE;
04314                 goto cleanup;
04315         }
04316         ztypestr = cfg_obj_asstring(typeobj);
04317 
04318         /*
04319          * "hints zones" aren't zones.  If we've got one,
04320          * configure it and return.
04321          */
04322         if (strcasecmp(ztypestr, "hint") == 0) {
04323                 const cfg_obj_t *fileobj = NULL;
04324                 if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
04325                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
04326                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
04327                                       "zone '%s': 'file' not specified",
04328                                       zname);
04329                         result = ISC_R_FAILURE;
04330                         goto cleanup;
04331                 }
04332                 if (dns_name_equal(origin, dns_rootname)) {
04333                         const char *hintsfile = cfg_obj_asstring(fileobj);
04334 
04335                         CHECK(configure_hints(view, hintsfile));
04336 
04337                         /*
04338                          * Hint zones may also refer to delegation only points.
04339                          */
04340                         only = NULL;
04341                         tresult = cfg_map_get(zoptions, "delegation-only",
04342                                               &only);
04343                         if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
04344                                 CHECK(dns_view_adddelegationonly(view, origin));
04345                 } else {
04346                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
04347                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
04348                                       "ignoring non-root hint zone '%s'",
04349                                       zname);
04350                         result = ISC_R_SUCCESS;
04351                 }
04352                 /* Skip ordinary zone processing. */
04353                 goto cleanup;
04354         }
04355 
04356         /*
04357          * "forward zones" aren't zones either.  Translate this syntax into
04358          * the appropriate selective forwarding configuration and return.
04359          */
04360         if (strcasecmp(ztypestr, "forward") == 0) {
04361                 forwardtype = NULL;
04362                 forwarders = NULL;
04363 
04364                 (void)cfg_map_get(zoptions, "forward", &forwardtype);
04365                 (void)cfg_map_get(zoptions, "forwarders", &forwarders);
04366                 CHECK(configure_forward(config, view, origin, forwarders,
04367                                         forwardtype));
04368 
04369                 /*
04370                  * Forward zones may also set delegation only.
04371                  */
04372                 only = NULL;
04373                 tresult = cfg_map_get(zoptions, "delegation-only", &only);
04374                 if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
04375                         CHECK(dns_view_adddelegationonly(view, origin));
04376                 goto cleanup;
04377         }
04378 
04379         /*
04380          * "delegation-only zones" aren't zones either.
04381          */
04382         if (strcasecmp(ztypestr, "delegation-only") == 0) {
04383                 result = dns_view_adddelegationonly(view, origin);
04384                 goto cleanup;
04385         }
04386 
04387         /*
04388          * Redirect zones only require minimal configuration.
04389          */
04390         if (strcasecmp(ztypestr, "redirect") == 0) {
04391                 if (view->redirect != NULL) {
04392                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
04393                                     "redirect zone already exists");
04394                         result = ISC_R_EXISTS;
04395                         goto cleanup;
04396                 }
04397                 result = dns_viewlist_find(viewlist, view->name,
04398                                            view->rdclass, &pview);
04399                 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
04400                         goto cleanup;
04401                 if (pview != NULL && pview->redirect != NULL) {
04402                         dns_zone_attach(pview->redirect, &zone);
04403                         dns_zone_setview(zone, view);
04404                 } else {
04405                         CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr,
04406                                                      &zone));
04407                         CHECK(dns_zone_setorigin(zone, origin));
04408                         dns_zone_setview(zone, view);
04409                         CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr,
04410                                                      zone));
04411                         dns_zone_setstats(zone, ns_g_server->zonestats);
04412                 }
04413                 CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf,
04414                                         zone, NULL));
04415                 dns_zone_attach(zone, &view->redirect);
04416                 goto cleanup;
04417         }
04418 
04419         if (!modify) {
04420                 /*
04421                  * Check for duplicates in the new zone table.
04422                  */
04423                 result = dns_view_findzone(view, origin, &dupzone);
04424                 if (result == ISC_R_SUCCESS) {
04425                         /*
04426                          * We already have this zone!
04427                          */
04428                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
04429                                     "zone '%s' already exists", zname);
04430                         dns_zone_detach(&dupzone);
04431                         result = ISC_R_EXISTS;
04432                         goto cleanup;
04433                 }
04434                 INSIST(dupzone == NULL);
04435         }
04436 
04437         /*
04438          * Note whether this is a response policy zone and which one if so.
04439          */
04440         for (rpz_num = 0; ; ++rpz_num) {
04441                 if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones) {
04442                         rpz_num = DNS_RPZ_INVALID_NUM;
04443                         break;
04444                 }
04445                 if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin))
04446                         break;
04447         }
04448 
04449         /*
04450          * See if we can reuse an existing zone.  This is
04451          * only possible if all of these are true:
04452          *   - The zone's view exists
04453          *   - A zone with the right name exists in the view
04454          *   - The zone is compatible with the config
04455          *     options (e.g., an existing master zone cannot
04456          *     be reused if the options specify a slave zone)
04457          *   - The zone was not and is still not a response policy zone
04458          *     or the zone is a policy zone with an unchanged number
04459          *     and we are using the old policy zone summary data.
04460          */
04461         result = dns_viewlist_find(&ns_g_server->viewlist, view->name,
04462                                    view->rdclass, &pview);
04463         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
04464                 goto cleanup;
04465         if (pview != NULL)
04466                 result = dns_view_findzone(pview, origin, &zone);
04467         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
04468                 goto cleanup;
04469 
04470         if (zone != NULL && !ns_zone_reusable(zone, zconfig))
04471                 dns_zone_detach(&zone);
04472 
04473         if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) ||
04474                              (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok)))
04475                 dns_zone_detach(&zone);
04476 
04477         if (zone != NULL) {
04478                 /*
04479                  * We found a reusable zone.  Make it use the
04480                  * new view.
04481                  */
04482                 dns_zone_setview(zone, view);
04483                 if (view->acache != NULL)
04484                         dns_zone_setacache(zone, view->acache);
04485         } else {
04486                 /*
04487                  * We cannot reuse an existing zone, we have
04488                  * to create a new one.
04489                  */
04490                 CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
04491                 CHECK(dns_zone_setorigin(zone, origin));
04492                 dns_zone_setview(zone, view);
04493                 if (view->acache != NULL)
04494                         dns_zone_setacache(zone, view->acache);
04495                 CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
04496                 dns_zone_setstats(zone, ns_g_server->zonestats);
04497         }
04498 
04499         if (rpz_num != DNS_RPZ_INVALID_NUM) {
04500                 result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
04501                 if (result != ISC_R_SUCCESS) {
04502                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
04503                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
04504                                       "zone '%s': incompatible"
04505                                       " masterfile-format or database"
04506                                       " for a response policy zone",
04507                                       zname);
04508                         goto cleanup;
04509                 }
04510         }
04511 
04512         /*
04513          * If the zone contains a 'forwarders' statement, configure
04514          * selective forwarding.
04515          */
04516         forwarders = NULL;
04517         if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS)
04518         {
04519                 forwardtype = NULL;
04520                 (void)cfg_map_get(zoptions, "forward", &forwardtype);
04521                 CHECK(configure_forward(config, view, origin, forwarders,
04522                                         forwardtype));
04523         }
04524 
04525         /*
04526          * Stub and forward zones may also refer to delegation only points.
04527          */
04528         only = NULL;
04529         if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS)
04530         {
04531                 if (cfg_obj_asboolean(only))
04532                         CHECK(dns_view_adddelegationonly(view, origin));
04533         }
04534 
04535         /*
04536          * Mark whether the zone was originally added at runtime or not
04537          */
04538         dns_zone_setadded(zone, added);
04539 
04540         signing = NULL;
04541         if ((strcasecmp(ztypestr, "master") == 0 ||
04542              strcasecmp(ztypestr, "slave") == 0) &&
04543             cfg_map_get(zoptions, "inline-signing", &signing) == ISC_R_SUCCESS &&
04544             cfg_obj_asboolean(signing))
04545         {
04546                 dns_zone_getraw(zone, &raw);
04547                 if (raw == NULL) {
04548                         CHECK(dns_zone_create(&raw, mctx));
04549                         CHECK(dns_zone_setorigin(raw, origin));
04550                         dns_zone_setview(raw, view);
04551                         if (view->acache != NULL)
04552                                 dns_zone_setacache(raw, view->acache);
04553                         dns_zone_setstats(raw, ns_g_server->zonestats);
04554                         CHECK(dns_zone_link(zone, raw));
04555                 }
04556         }
04557 
04558         /*
04559          * Configure the zone.
04560          */
04561         CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone, raw));
04562 
04563         /*
04564          * Add the zone to its view in the new view list.
04565          */
04566         if (!modify)
04567                 CHECK(dns_view_addzone(view, zone));
04568 
04569         /*
04570          * Ensure that zone keys are reloaded on reconfig
04571          */
04572         if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0)
04573                 dns_zone_rekey(zone, ISC_FALSE);
04574 
04575  cleanup:
04576         if (zone != NULL)
04577                 dns_zone_detach(&zone);
04578         if (raw != NULL)
04579                 dns_zone_detach(&raw);
04580         if (pview != NULL)
04581                 dns_view_detach(&pview);
04582 
04583         return (result);
04584 }
04585 
04586 /*
04587  * Configure built-in zone for storing managed-key data.
04588  */
04589 
04590 static isc_result_t
04591 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
04592         isc_result_t result;
04593         dns_view_t *pview = NULL;
04594         dns_zone_t *zone = NULL;
04595         dns_acl_t *none = NULL;
04596         char filename[PATH_MAX];
04597         isc_boolean_t defaultview;
04598 
04599         REQUIRE(view != NULL);
04600 
04601         /* See if we can re-use an existing keydata zone. */
04602         result = dns_viewlist_find(&ns_g_server->viewlist,
04603                                    view->name, view->rdclass,
04604                                    &pview);
04605         if (result != ISC_R_NOTFOUND &&
04606             result != ISC_R_SUCCESS)
04607                 return (result);
04608 
04609         if (pview != NULL && pview->managed_keys != NULL) {
04610                 dns_zone_attach(pview->managed_keys, &view->managed_keys);
04611                 dns_zone_setview(pview->managed_keys, view);
04612                 dns_view_detach(&pview);
04613                 dns_zone_synckeyzone(view->managed_keys);
04614                 return (ISC_R_SUCCESS);
04615         }
04616 
04617         /* No existing keydata zone was found; create one */
04618         CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
04619         CHECK(dns_zone_setorigin(zone, dns_rootname));
04620 
04621         defaultview = ISC_TF(strcmp(view->name, "_default") == 0);
04622         CHECK(isc_file_sanitize(directory,
04623                                 defaultview ? "managed-keys" : view->name,
04624                                 defaultview ? "bind" : "mkeys",
04625                                 filename, sizeof(filename)));
04626         CHECK(dns_zone_setfile(zone, filename));
04627 
04628         dns_zone_setview(zone, view);
04629         dns_zone_settype(zone, dns_zone_key);
04630         dns_zone_setclass(zone, view->rdclass);
04631 
04632         CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
04633 
04634         if (view->acache != NULL)
04635                 dns_zone_setacache(zone, view->acache);
04636 
04637         CHECK(dns_acl_none(mctx, &none));
04638         dns_zone_setqueryacl(zone, none);
04639         dns_zone_setqueryonacl(zone, none);
04640         dns_acl_detach(&none);
04641 
04642         dns_zone_setdialup(zone, dns_dialuptype_no);
04643         dns_zone_setnotifytype(zone, dns_notifytype_no);
04644         dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE);
04645         dns_zone_setjournalsize(zone, 0);
04646 
04647         dns_zone_setstats(zone, ns_g_server->zonestats);
04648         CHECK(setquerystats(zone, mctx, dns_zonestat_none));
04649 
04650         if (view->managed_keys != NULL)
04651                 dns_zone_detach(&view->managed_keys);
04652         dns_zone_attach(zone, &view->managed_keys);
04653 
04654         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
04655                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
04656                       "set up managed keys zone for view %s, file '%s'",
04657                       view->name, filename);
04658 
04659 cleanup:
04660         if (zone != NULL)
04661                 dns_zone_detach(&zone);
04662         if (none != NULL)
04663                 dns_acl_detach(&none);
04664 
04665         return (result);
04666 }
04667 
04668 /*
04669  * Configure a single server quota.
04670  */
04671 static void
04672 configure_server_quota(const cfg_obj_t **maps, const char *name,
04673                        isc_quota_t *quota)
04674 {
04675         const cfg_obj_t *obj = NULL;
04676         isc_result_t result;
04677 
04678         result = ns_config_get(maps, name, &obj);
04679         INSIST(result == ISC_R_SUCCESS);
04680         isc_quota_max(quota, cfg_obj_asuint32(obj));
04681 }
04682 
04683 /*
04684  * This function is called as soon as the 'directory' statement has been
04685  * parsed.  This can be extended to support other options if necessary.
04686  */
04687 static isc_result_t
04688 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
04689         isc_result_t result;
04690         const char *directory;
04691 
04692         REQUIRE(strcasecmp("directory", clausename) == 0);
04693 
04694         UNUSED(arg);
04695         UNUSED(clausename);
04696 
04697         /*
04698          * Change directory.
04699          */
04700         directory = cfg_obj_asstring(obj);
04701 
04702         if (! isc_file_ischdiridempotent(directory))
04703                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
04704                             "option 'directory' contains relative path '%s'",
04705                             directory);
04706 
04707         result = isc_dir_chdir(directory);
04708         if (result != ISC_R_SUCCESS) {
04709                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
04710                             "change directory to '%s' failed: %s",
04711                             directory, isc_result_totext(result));
04712                 return (result);
04713         }
04714 
04715         return (ISC_R_SUCCESS);
04716 }
04717 
04718 static isc_result_t
04719 scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
04720         isc_result_t result;
04721         isc_boolean_t match_mapped = server->aclenv.match_mapped;
04722 #ifdef HAVE_GEOIP
04723         isc_boolean_t use_ecs = server->aclenv.geoip_use_ecs;
04724 #endif
04725 
04726         result = ns_interfacemgr_scan(server->interfacemgr, verbose);
04727         /*
04728          * Update the "localhost" and "localnets" ACLs to match the
04729          * current set of network interfaces.
04730          */
04731         dns_aclenv_copy(&server->aclenv,
04732                         ns_interfacemgr_getaclenv(server->interfacemgr));
04733 
04734         server->aclenv.match_mapped = match_mapped;
04735 #ifdef HAVE_GEOIP
04736         server->aclenv.geoip_use_ecs = use_ecs;
04737 #endif
04738 
04739         return (result);
04740 }
04741 
04742 static isc_result_t
04743 add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr,
04744               isc_dscp_t dscp, isc_boolean_t wcardport_ok)
04745 {
04746         ns_listenelt_t *lelt = NULL;
04747         dns_acl_t *src_acl = NULL;
04748         isc_result_t result;
04749         isc_sockaddr_t any_sa6;
04750         isc_netaddr_t netaddr;
04751 
04752         REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
04753 
04754         isc_sockaddr_any6(&any_sa6);
04755         if (!isc_sockaddr_equal(&any_sa6, addr) &&
04756             (wcardport_ok || isc_sockaddr_getport(addr) != 0)) {
04757                 isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr);
04758 
04759                 result = dns_acl_create(mctx, 0, &src_acl);
04760                 if (result != ISC_R_SUCCESS)
04761                         return (result);
04762 
04763                 result = dns_iptable_addprefix(src_acl->iptable,
04764                                                &netaddr, 128, ISC_TRUE);
04765                 if (result != ISC_R_SUCCESS)
04766                         goto clean;
04767 
04768                 result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr),
04769                                              dscp, src_acl, &lelt);
04770                 if (result != ISC_R_SUCCESS)
04771                         goto clean;
04772                 ISC_LIST_APPEND(list->elts, lelt, link);
04773         }
04774 
04775         return (ISC_R_SUCCESS);
04776 
04777  clean:
04778         INSIST(lelt == NULL);
04779         dns_acl_detach(&src_acl);
04780 
04781         return (result);
04782 }
04783 
04784 /*
04785  * Make a list of xxx-source addresses and call ns_interfacemgr_adjust()
04786  * to update the listening interfaces accordingly.
04787  * We currently only consider IPv6, because this only affects IPv6 wildcard
04788  * sockets.
04789  */
04790 static void
04791 adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
04792         isc_result_t result;
04793         ns_listenlist_t *list = NULL;
04794         dns_view_t *view;
04795         dns_zone_t *zone, *next;
04796         isc_sockaddr_t addr, *addrp;
04797         isc_dscp_t dscp = -1;
04798 
04799         result = ns_listenlist_create(mctx, &list);
04800         if (result != ISC_R_SUCCESS)
04801                 return;
04802 
04803         for (view = ISC_LIST_HEAD(server->viewlist);
04804              view != NULL;
04805              view = ISC_LIST_NEXT(view, link)) {
04806                 dns_dispatch_t *dispatch6;
04807 
04808                 dispatch6 = dns_resolver_dispatchv6(view->resolver);
04809                 if (dispatch6 == NULL)
04810                         continue;
04811                 result = dns_dispatch_getlocaladdress(dispatch6, &addr);
04812                 if (result != ISC_R_SUCCESS)
04813                         goto fail;
04814 
04815                 /*
04816                  * We always add non-wildcard address regardless of whether
04817                  * the port is 'any' (the fourth arg is TRUE): if the port is
04818                  * specific, we need to add it since it may conflict with a
04819                  * listening interface; if it's zero, we'll dynamically open
04820                  * query ports, and some of them may override an existing
04821                  * wildcard IPv6 port.
04822                  */
04823                 /* XXXMPA fix dscp */
04824                 result = add_listenelt(mctx, list, &addr, dscp, ISC_TRUE);
04825                 if (result != ISC_R_SUCCESS)
04826                         goto fail;
04827         }
04828 
04829         zone = NULL;
04830         for (result = dns_zone_first(server->zonemgr, &zone);
04831              result == ISC_R_SUCCESS;
04832              next = NULL, result = dns_zone_next(zone, &next), zone = next) {
04833                 dns_view_t *zoneview;
04834 
04835                 /*
04836                  * At this point the zone list may contain a stale zone
04837                  * just removed from the configuration.  To see the validity,
04838                  * check if the corresponding view is in our current view list.
04839                  * There may also be old zones that are still in the process
04840                  * of shutting down and have detached from their old view
04841                  * (zoneview == NULL).
04842                  */
04843                 zoneview = dns_zone_getview(zone);
04844                 if (zoneview == NULL)
04845                         continue;
04846                 for (view = ISC_LIST_HEAD(server->viewlist);
04847                      view != NULL && view != zoneview;
04848                      view = ISC_LIST_NEXT(view, link))
04849                         ;
04850                 if (view == NULL)
04851                         continue;
04852 
04853                 addrp = dns_zone_getnotifysrc6(zone);
04854                 dscp = dns_zone_getnotifysrc6dscp(zone);
04855                 result = add_listenelt(mctx, list, addrp, dscp, ISC_FALSE);
04856                 if (result != ISC_R_SUCCESS)
04857                         goto fail;
04858 
04859                 addrp = dns_zone_getxfrsource6(zone);
04860                 dscp = dns_zone_getxfrsource6dscp(zone);
04861                 result = add_listenelt(mctx, list, addrp, dscp, ISC_FALSE);
04862                 if (result != ISC_R_SUCCESS)
04863                         goto fail;
04864         }
04865 
04866         ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE);
04867 
04868  clean:
04869         ns_listenlist_detach(&list);
04870         return;
04871 
04872  fail:
04873         /*
04874          * Even when we failed the procedure, most of other interfaces
04875          * should work correctly.  We therefore just warn it.
04876          */
04877         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
04878                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
04879                       "could not adjust the listen-on list; "
04880                       "some interfaces may not work");
04881         goto clean;
04882 }
04883 
04884 /*
04885  * This event callback is invoked to do periodic network interface
04886  * scanning.  It is also called by ns_server_scan_interfaces(),
04887  * invoked by "rndc scan"
04888  */
04889 
04890 static void
04891 interface_timer_tick(isc_task_t *task, isc_event_t *event) {
04892         isc_result_t result;
04893         ns_server_t *server = (ns_server_t *) event->ev_arg;
04894         INSIST(task == server->task);
04895         UNUSED(task);
04896 
04897         isc_event_free(&event);
04898 
04899         /*
04900          * XXX should scan interfaces unlocked and get exclusive access
04901          * only to replace ACLs.
04902          */
04903         result = isc_task_beginexclusive(server->task);
04904         RUNTIME_CHECK(result == ISC_R_SUCCESS);
04905         scan_interfaces(server, ISC_FALSE);
04906         isc_task_endexclusive(server->task);
04907 }
04908 
04909 static void
04910 heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
04911         ns_server_t *server = (ns_server_t *) event->ev_arg;
04912         dns_view_t *view;
04913 
04914         UNUSED(task);
04915         isc_event_free(&event);
04916         view = ISC_LIST_HEAD(server->viewlist);
04917         while (view != NULL) {
04918                 dns_view_dialup(view);
04919                 view = ISC_LIST_NEXT(view, link);
04920         }
04921 }
04922 
04923 static void
04924 pps_timer_tick(isc_task_t *task, isc_event_t *event) {
04925         static unsigned int oldrequests = 0;
04926         unsigned int requests = ns_client_requests;
04927 
04928         UNUSED(task);
04929         isc_event_free(&event);
04930 
04931         /*
04932          * Don't worry about wrapping as the overflow result will be right.
04933          */
04934         dns_pps = (requests - oldrequests) / 1200;
04935         oldrequests = requests;
04936 }
04937 
04938 /*
04939  * Replace the current value of '*field', a dynamically allocated
04940  * string or NULL, with a dynamically allocated copy of the
04941  * null-terminated string pointed to by 'value', or NULL.
04942  */
04943 static isc_result_t
04944 setstring(ns_server_t *server, char **field, const char *value) {
04945         char *copy;
04946 
04947         if (value != NULL) {
04948                 copy = isc_mem_strdup(server->mctx, value);
04949                 if (copy == NULL)
04950                         return (ISC_R_NOMEMORY);
04951         } else {
04952                 copy = NULL;
04953         }
04954 
04955         if (*field != NULL)
04956                 isc_mem_free(server->mctx, *field);
04957 
04958         *field = copy;
04959         return (ISC_R_SUCCESS);
04960 }
04961 
04962 /*
04963  * Replace the current value of '*field', a dynamically allocated
04964  * string or NULL, with another dynamically allocated string
04965  * or NULL if whether 'obj' is a string or void value, respectively.
04966  */
04967 static isc_result_t
04968 setoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) {
04969         if (cfg_obj_isvoid(obj))
04970                 return (setstring(server, field, NULL));
04971         else
04972                 return (setstring(server, field, cfg_obj_asstring(obj)));
04973 }
04974 
04975 static void
04976 set_limit(const cfg_obj_t **maps, const char *configname,
04977           const char *description, isc_resource_t resourceid,
04978           isc_resourcevalue_t defaultvalue)
04979 {
04980         const cfg_obj_t *obj = NULL;
04981         const char *resource;
04982         isc_resourcevalue_t value;
04983         isc_result_t result;
04984 
04985         if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS)
04986                 return;
04987 
04988         if (cfg_obj_isstring(obj)) {
04989                 resource = cfg_obj_asstring(obj);
04990                 if (strcasecmp(resource, "unlimited") == 0)
04991                         value = ISC_RESOURCE_UNLIMITED;
04992                 else {
04993                         INSIST(strcasecmp(resource, "default") == 0);
04994                         value = defaultvalue;
04995                 }
04996         } else
04997                 value = cfg_obj_asuint64(obj);
04998 
04999         result = isc_resource_setlimit(resourceid, value);
05000         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
05001                       result == ISC_R_SUCCESS ?
05002                         ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
05003                       "set maximum %s to %" ISC_PRINT_QUADFORMAT "u: %s",
05004                       description, value, isc_result_totext(result));
05005 }
05006 
05007 #define SETLIMIT(cfgvar, resource, description) \
05008         set_limit(maps, cfgvar, description, isc_resource_ ## resource, \
05009                   ns_g_init ## resource)
05010 
05011 static void
05012 set_limits(const cfg_obj_t **maps) {
05013         SETLIMIT("stacksize", stacksize, "stack size");
05014         SETLIMIT("datasize", datasize, "data size");
05015         SETLIMIT("coresize", coresize, "core size");
05016         SETLIMIT("files", openfiles, "open files");
05017 }
05018 
05019 static void
05020 portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
05021                  isc_boolean_t positive)
05022 {
05023         const cfg_listelt_t *element;
05024 
05025         for (element = cfg_list_first(ports);
05026              element != NULL;
05027              element = cfg_list_next(element)) {
05028                 const cfg_obj_t *obj = cfg_listelt_value(element);
05029 
05030                 if (cfg_obj_isuint32(obj)) {
05031                         in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
05032 
05033                         if (positive)
05034                                 isc_portset_add(portset, port);
05035                         else
05036                                 isc_portset_remove(portset, port);
05037                 } else {
05038                         const cfg_obj_t *obj_loport, *obj_hiport;
05039                         in_port_t loport, hiport;
05040 
05041                         obj_loport = cfg_tuple_get(obj, "loport");
05042                         loport = (in_port_t)cfg_obj_asuint32(obj_loport);
05043                         obj_hiport = cfg_tuple_get(obj, "hiport");
05044                         hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
05045 
05046                         if (positive)
05047                                 isc_portset_addrange(portset, loport, hiport);
05048                         else {
05049                                 isc_portset_removerange(portset, loport,
05050                                                         hiport);
05051                         }
05052                 }
05053         }
05054 }
05055 
05056 static isc_result_t
05057 removed(dns_zone_t *zone, void *uap) {
05058         const char *type;
05059 
05060         if (dns_zone_getview(zone) != uap)
05061                 return (ISC_R_SUCCESS);
05062 
05063         switch (dns_zone_gettype(zone)) {
05064         case dns_zone_master:
05065                 type = "master";
05066                 break;
05067         case dns_zone_slave:
05068                 type = "slave";
05069                 break;
05070         case dns_zone_stub:
05071                 type = "stub";
05072                 break;
05073         case dns_zone_staticstub:
05074                 type = "static-stub";
05075                 break;
05076         case dns_zone_redirect:
05077                 type = "redirect";
05078                 break;
05079         default:
05080                 type = "other";
05081                 break;
05082         }
05083         dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type);
05084         return (ISC_R_SUCCESS);
05085 }
05086 
05087 static void
05088 cleanup_session_key(ns_server_t *server, isc_mem_t *mctx) {
05089         if (server->session_keyfile != NULL) {
05090                 isc_file_remove(server->session_keyfile);
05091                 isc_mem_free(mctx, server->session_keyfile);
05092                 server->session_keyfile = NULL;
05093         }
05094 
05095         if (server->session_keyname != NULL) {
05096                 if (dns_name_dynamic(server->session_keyname))
05097                         dns_name_free(server->session_keyname, mctx);
05098                 isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
05099                 server->session_keyname = NULL;
05100         }
05101 
05102         if (server->sessionkey != NULL)
05103                 dns_tsigkey_detach(&server->sessionkey);
05104 
05105         server->session_keyalg = DST_ALG_UNKNOWN;
05106         server->session_keybits = 0;
05107 }
05108 
05109 static isc_result_t
05110 generate_session_key(const char *filename, const char *keynamestr,
05111                      dns_name_t *keyname, const char *algstr,
05112                      dns_name_t *algname, unsigned int algtype,
05113                      isc_uint16_t bits, isc_mem_t *mctx,
05114                      dns_tsigkey_t **tsigkeyp)
05115 {
05116         isc_result_t result = ISC_R_SUCCESS;
05117         dst_key_t *key = NULL;
05118         isc_buffer_t key_txtbuffer;
05119         isc_buffer_t key_rawbuffer;
05120         char key_txtsecret[256];
05121         char key_rawsecret[64];
05122         isc_region_t key_rawregion;
05123         isc_stdtime_t now;
05124         dns_tsigkey_t *tsigkey = NULL;
05125         FILE *fp = NULL;
05126 
05127         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05128                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
05129                       "generating session key for dynamic DNS");
05130 
05131         /* generate key */
05132         result = dst_key_generate(keyname, algtype, bits, 1, 0,
05133                                   DNS_KEYPROTO_ANY, dns_rdataclass_in,
05134                                   mctx, &key);
05135         if (result != ISC_R_SUCCESS)
05136                 return (result);
05137 
05138         /*
05139          * Dump the key to the buffer for later use.  Should be done before
05140          * we transfer the ownership of key to tsigkey.
05141          */
05142         isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
05143         CHECK(dst_key_tobuffer(key, &key_rawbuffer));
05144 
05145         isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
05146         isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
05147         CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
05148 
05149         /* Store the key in tsigkey. */
05150         isc_stdtime_get(&now);
05151         CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key,
05152                                         ISC_FALSE, NULL, now, now, mctx, NULL,
05153                                         &tsigkey));
05154 
05155         /* Dump the key to the key file. */
05156         fp = ns_os_openfile(filename, S_IRUSR|S_IWUSR, ISC_TRUE);
05157         if (fp == NULL) {
05158                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05159                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
05160                               "could not create %s", filename);
05161                 result = ISC_R_NOPERM;
05162                 goto cleanup;
05163         }
05164 
05165         fprintf(fp, "key \"%s\" {\n"
05166                 "\talgorithm %s;\n"
05167                 "\tsecret \"%.*s\";\n};\n", keynamestr, algstr,
05168                 (int) isc_buffer_usedlength(&key_txtbuffer),
05169                 (char*) isc_buffer_base(&key_txtbuffer));
05170 
05171         CHECK(isc_stdio_flush(fp));
05172         CHECK(isc_stdio_close(fp));
05173 
05174         dst_key_free(&key);
05175 
05176         *tsigkeyp = tsigkey;
05177 
05178         return (ISC_R_SUCCESS);
05179 
05180   cleanup:
05181         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05182                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
05183                       "failed to generate session key "
05184                       "for dynamic DNS: %s", isc_result_totext(result));
05185         if (fp != NULL) {
05186                 (void)isc_stdio_close(fp);
05187                 (void)isc_file_remove(filename);
05188         }
05189         if (tsigkey != NULL)
05190                 dns_tsigkey_detach(&tsigkey);
05191         if (key != NULL)
05192                 dst_key_free(&key);
05193 
05194         return (result);
05195 }
05196 
05197 static isc_result_t
05198 configure_session_key(const cfg_obj_t **maps, ns_server_t *server,
05199                       isc_mem_t *mctx)
05200 {
05201         const char *keyfile, *keynamestr, *algstr;
05202         unsigned int algtype;
05203         dns_fixedname_t fname;
05204         dns_name_t *keyname, *algname;
05205         isc_buffer_t buffer;
05206         isc_uint16_t bits;
05207         const cfg_obj_t *obj;
05208         isc_boolean_t need_deleteold = ISC_FALSE;
05209         isc_boolean_t need_createnew = ISC_FALSE;
05210         isc_result_t result;
05211 
05212         obj = NULL;
05213         result = ns_config_get(maps, "session-keyfile", &obj);
05214         if (result == ISC_R_SUCCESS) {
05215                 if (cfg_obj_isvoid(obj))
05216                         keyfile = NULL; /* disable it */
05217                 else
05218                         keyfile = cfg_obj_asstring(obj);
05219         } else
05220                 keyfile = ns_g_defaultsessionkeyfile;
05221 
05222         obj = NULL;
05223         result = ns_config_get(maps, "session-keyname", &obj);
05224         INSIST(result == ISC_R_SUCCESS);
05225         keynamestr = cfg_obj_asstring(obj);
05226         dns_fixedname_init(&fname);
05227         isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
05228         isc_buffer_add(&buffer, strlen(keynamestr));
05229         keyname = dns_fixedname_name(&fname);
05230         result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
05231         if (result != ISC_R_SUCCESS)
05232                 return (result);
05233 
05234         obj = NULL;
05235         result = ns_config_get(maps, "session-keyalg", &obj);
05236         INSIST(result == ISC_R_SUCCESS);
05237         algstr = cfg_obj_asstring(obj);
05238         algname = NULL;
05239         result = ns_config_getkeyalgorithm2(algstr, &algname, &algtype, &bits);
05240         if (result != ISC_R_SUCCESS) {
05241                 const char *s = " (keeping current key)";
05242 
05243                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "session-keyalg: "
05244                             "unsupported or unknown algorithm '%s'%s",
05245                             algstr,
05246                             server->session_keyfile != NULL ? s : "");
05247                 return (result);
05248         }
05249 
05250         /* See if we need to (re)generate a new key. */
05251         if (keyfile == NULL) {
05252                 if (server->session_keyfile != NULL)
05253                         need_deleteold = ISC_TRUE;
05254         } else if (server->session_keyfile == NULL)
05255                 need_createnew = ISC_TRUE;
05256         else if (strcmp(keyfile, server->session_keyfile) != 0 ||
05257                  !dns_name_equal(server->session_keyname, keyname) ||
05258                  server->session_keyalg != algtype ||
05259                  server->session_keybits != bits) {
05260                 need_deleteold = ISC_TRUE;
05261                 need_createnew = ISC_TRUE;
05262         }
05263 
05264         if (need_deleteold) {
05265                 INSIST(server->session_keyfile != NULL);
05266                 INSIST(server->session_keyname != NULL);
05267                 INSIST(server->sessionkey != NULL);
05268 
05269                 cleanup_session_key(server, mctx);
05270         }
05271 
05272         if (need_createnew) {
05273                 INSIST(server->sessionkey == NULL);
05274                 INSIST(server->session_keyfile == NULL);
05275                 INSIST(server->session_keyname == NULL);
05276                 INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
05277                 INSIST(server->session_keybits == 0);
05278 
05279                 server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
05280                 if (server->session_keyname == NULL)
05281                         goto cleanup;
05282                 dns_name_init(server->session_keyname, NULL);
05283                 CHECK(dns_name_dup(keyname, mctx, server->session_keyname));
05284 
05285                 server->session_keyfile = isc_mem_strdup(mctx, keyfile);
05286                 if (server->session_keyfile == NULL)
05287                         goto cleanup;
05288 
05289                 server->session_keyalg = algtype;
05290                 server->session_keybits = bits;
05291 
05292                 CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr,
05293                                            algname, algtype, bits, mctx,
05294                                            &server->sessionkey));
05295         }
05296 
05297         return (result);
05298 
05299   cleanup:
05300         cleanup_session_key(server, mctx);
05301         return (result);
05302 }
05303 
05304 static isc_result_t
05305 setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
05306                cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx)
05307 {
05308         isc_result_t result = ISC_R_SUCCESS;
05309         isc_boolean_t allow = ISC_FALSE;
05310         ns_cfgctx_t *nzcfg = NULL;
05311         const cfg_obj_t *maps[4];
05312         const cfg_obj_t *options = NULL, *voptions = NULL;
05313         const cfg_obj_t *nz = NULL;
05314         int i = 0;
05315 
05316         REQUIRE (config != NULL);
05317 
05318         if (vconfig != NULL)
05319                 voptions = cfg_tuple_get(vconfig, "options");
05320         if (voptions != NULL)
05321                 maps[i++] = voptions;
05322         result = cfg_map_get(config, "options", &options);
05323         if (result == ISC_R_SUCCESS)
05324                 maps[i++] = options;
05325         maps[i++] = ns_g_defaults;
05326         maps[i] = NULL;
05327 
05328         result = ns_config_get(maps, "allow-new-zones", &nz);
05329         if (result == ISC_R_SUCCESS)
05330                 allow = cfg_obj_asboolean(nz);
05331 
05332         if (!allow) {
05333                 dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
05334                 return (ISC_R_SUCCESS);
05335         }
05336 
05337         nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
05338         if (nzcfg == NULL) {
05339                 dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
05340                 return (ISC_R_NOMEMORY);
05341         }
05342 
05343         memset(nzcfg, 0, sizeof(*nzcfg));
05344 
05345         dns_view_setnewzones(view, allow, nzcfg, newzone_cfgctx_destroy);
05346 
05347         cfg_obj_attach(config, &nzcfg->config);
05348         if (vconfig != NULL)
05349                 cfg_obj_attach(vconfig, &nzcfg->vconfig);
05350 
05351         /*
05352          * We attach the parser that was used for config as well
05353          * as the one that will be used for added zones, to avoid
05354          * a shutdown race later.
05355          */
05356         cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
05357         cfg_parser_attach(ns_g_addparser, &nzcfg->add_parser);
05358         isc_mem_attach(view->mctx, &nzcfg->mctx);
05359         cfg_aclconfctx_attach(actx, &nzcfg->actx);
05360 
05361         /*
05362          * This may be called in multiple views, so we reset
05363          * the parser each time.
05364          */
05365         cfg_parser_reset(ns_g_addparser);
05366         result = cfg_parse_file(ns_g_addparser, view->new_zone_file,
05367                                 &cfg_type_newzones, &nzcfg->nzconfig);
05368 
05369         return (ISC_R_SUCCESS);
05370 }
05371 
05372 static int
05373 count_zones(const cfg_obj_t *conf) {
05374         const cfg_obj_t *zonelist = NULL;
05375         const cfg_listelt_t *element;
05376         int n = 0;
05377 
05378         REQUIRE(conf != NULL);
05379 
05380         cfg_map_get(conf, "zone", &zonelist);
05381         for (element = cfg_list_first(zonelist);
05382              element != NULL;
05383              element = cfg_list_next(element))
05384                 n++;
05385 
05386         return (n);
05387 }
05388 
05389 static isc_result_t
05390 check_lockfile(ns_server_t *server, const cfg_obj_t *config,
05391                isc_boolean_t first_time)
05392 {
05393         isc_result_t result;
05394         const char *filename = NULL;
05395         const cfg_obj_t *maps[3];
05396         const cfg_obj_t *options;
05397         const cfg_obj_t *obj;
05398         int i;
05399 
05400         i = 0;
05401         options = NULL;
05402         result = cfg_map_get(config, "options", &options);
05403         if (result == ISC_R_SUCCESS)
05404                 maps[i++] = options;
05405         maps[i++] = ns_g_defaults;
05406         maps[i] = NULL;
05407 
05408         obj = NULL;
05409         (void) ns_config_get(maps, "lock-file", &obj);
05410 
05411         if (!first_time) {
05412                 if (obj != NULL && !cfg_obj_isstring(obj) &&
05413                     server->lockfile != NULL &&
05414                     strcmp(cfg_obj_asstring(obj), server->lockfile) != 0)
05415                         isc_log_write(ns_g_lctx,
05416                                       NS_LOGCATEGORY_GENERAL,
05417                                       NS_LOGMODULE_SERVER,
05418                                       ISC_LOG_WARNING,
05419                                       "changing 'lock-file' "
05420                                       "has no effect until the "
05421                                       "server is restarted");
05422 
05423                 return (ISC_R_SUCCESS);
05424         }
05425 
05426         if (obj != NULL) {
05427                 if (cfg_obj_isvoid(obj)) {
05428                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05429                                       NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
05430                                       "skipping lock-file check ");
05431                         return (ISC_R_SUCCESS);
05432                 } else if (ns_g_forcelock) {
05433                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05434                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
05435                                       "'lock-file' has no effect "
05436                                       "because the server was run with -X");
05437                         server->lockfile = isc_mem_strdup(server->mctx,
05438                                                           ns_g_defaultlockfile);
05439                 } else {
05440                         filename = cfg_obj_asstring(obj);
05441                         server->lockfile = isc_mem_strdup(server->mctx,
05442                                                           filename);
05443                 }
05444 
05445                 if (server->lockfile == NULL)
05446                         return (ISC_R_NOMEMORY);
05447         }
05448 
05449         if (ns_g_forcelock && ns_g_defaultlockfile != NULL) {
05450                 INSIST(server->lockfile == NULL);
05451                 server->lockfile = isc_mem_strdup(server->mctx,
05452                                                   ns_g_defaultlockfile);
05453         }
05454 
05455         if (server->lockfile == NULL)
05456                 return (ISC_R_SUCCESS);
05457 
05458         if (ns_os_issingleton(server->lockfile))
05459                 return (ISC_R_SUCCESS);
05460 
05461         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05462                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
05463                       "could not lock %s; another named "
05464                       "process may be running", server->lockfile);
05465         return (ISC_R_FAILURE);
05466 }
05467 
05468 static isc_result_t
05469 load_configuration(const char *filename, ns_server_t *server,
05470                    isc_boolean_t first_time)
05471 {
05472         cfg_obj_t *config = NULL, *bindkeys = NULL;
05473         cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
05474         const cfg_listelt_t *element;
05475         const cfg_obj_t *builtin_views;
05476         const cfg_obj_t *maps[3];
05477         const cfg_obj_t *obj;
05478         const cfg_obj_t *options;
05479         const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
05480         const cfg_obj_t *views;
05481         dns_view_t *view = NULL;
05482         dns_view_t *view_next;
05483         dns_viewlist_t tmpviewlist;
05484         dns_viewlist_t viewlist, builtin_viewlist;
05485         in_port_t listen_port, udpport_low, udpport_high;
05486         int i;
05487         int num_zones = 0;
05488         isc_boolean_t exclusive = ISC_FALSE;
05489         isc_interval_t interval;
05490         isc_logconfig_t *logc = NULL;
05491         isc_portset_t *v4portset = NULL;
05492         isc_portset_t *v6portset = NULL;
05493         isc_resourcevalue_t nfiles;
05494         isc_result_t result, tresult;
05495         isc_uint32_t heartbeat_interval;
05496         isc_uint32_t interface_interval;
05497         isc_uint32_t reserved;
05498         isc_uint32_t udpsize;
05499         ns_cache_t *nsc;
05500         ns_cachelist_t cachelist, tmpcachelist;
05501         ns_cfgctx_t *nzctx;
05502         unsigned int maxsocks;
05503 
05504         ISC_LIST_INIT(viewlist);
05505         ISC_LIST_INIT(builtin_viewlist);
05506         ISC_LIST_INIT(cachelist);
05507 
05508         /* Create the ACL configuration context */
05509         if (ns_g_aclconfctx != NULL)
05510                 cfg_aclconfctx_detach(&ns_g_aclconfctx);
05511         CHECK(cfg_aclconfctx_create(ns_g_mctx, &ns_g_aclconfctx));
05512 
05513         /*
05514          * Parse the global default pseudo-config file.
05515          */
05516         if (first_time) {
05517                 CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config));
05518                 RUNTIME_CHECK(cfg_map_get(ns_g_config, "options",
05519                                           &ns_g_defaults) == ISC_R_SUCCESS);
05520         }
05521 
05522         /*
05523          * Parse the configuration file using the new config code.
05524          */
05525         result = ISC_R_FAILURE;
05526         config = NULL;
05527 
05528         /*
05529          * Unless this is lwresd with the -C option, parse the config file.
05530          */
05531         if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) {
05532                 isc_log_write(ns_g_lctx,
05533                               NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
05534                               ISC_LOG_INFO, "loading configuration from '%s'",
05535                               filename);
05536                 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser));
05537                 cfg_parser_setcallback(conf_parser, directory_callback, NULL);
05538                 result = cfg_parse_file(conf_parser, filename,
05539                                         &cfg_type_namedconf, &config);
05540         }
05541 
05542         /*
05543          * If this is lwresd with the -C option, or lwresd with no -C or -c
05544          * option where the above parsing failed, parse resolv.conf.
05545          */
05546         if (ns_g_lwresdonly &&
05547             (lwresd_g_useresolvconf ||
05548              (!ns_g_conffileset && result == ISC_R_FILENOTFOUND)))
05549         {
05550                 isc_log_write(ns_g_lctx,
05551                               NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
05552                               ISC_LOG_INFO, "loading configuration from '%s'",
05553                               lwresd_g_resolvconffile);
05554                 if (conf_parser != NULL)
05555                         cfg_parser_destroy(&conf_parser);
05556                 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &conf_parser));
05557                 result = ns_lwresd_parseeresolvconf(ns_g_mctx, conf_parser,
05558                                                     &config);
05559         }
05560         CHECK(result);
05561 
05562         /*
05563          * Check the validity of the configuration.
05564          */
05565         CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx));
05566 
05567         /*
05568          * Fill in the maps array, used for resolving defaults.
05569          */
05570         i = 0;
05571         options = NULL;
05572         result = cfg_map_get(config, "options", &options);
05573         if (result == ISC_R_SUCCESS)
05574                 maps[i++] = options;
05575         maps[i++] = ns_g_defaults;
05576         maps[i] = NULL;
05577 
05578         /*
05579          * If bind.keys exists, load it.  If "dnssec-validation auto"
05580          * is turned on, the root key found there will be used as a
05581          * default trust anchor, and if "dnssec-lookaside auto" is
05582          * turned on, then the DLV key found there will too.
05583          */
05584         obj = NULL;
05585         result = ns_config_get(maps, "bindkeys-file", &obj);
05586         INSIST(result == ISC_R_SUCCESS);
05587         CHECKM(setstring(server, &server->bindkeysfile,
05588                cfg_obj_asstring(obj)), "strdup");
05589 
05590         if (access(server->bindkeysfile, R_OK) == 0) {
05591                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05592                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
05593                               "reading built-in trusted "
05594                               "keys from file '%s'", server->bindkeysfile);
05595 
05596                 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx,
05597                                         &bindkeys_parser));
05598 
05599                 result = cfg_parse_file(bindkeys_parser, server->bindkeysfile,
05600                                         &cfg_type_bindkeys, &bindkeys);
05601                 CHECK(result);
05602         }
05603 
05604         /* Ensure exclusive access to configuration data. */
05605         if (!exclusive) {
05606                 result = isc_task_beginexclusive(server->task);
05607                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
05608                 exclusive = ISC_TRUE;
05609         }
05610 
05611         /*
05612          * Set process limits, which (usually) needs to be done as root.
05613          */
05614         set_limits(maps);
05615 
05616         /*
05617          * Check the process lockfile.
05618          */
05619         CHECK(check_lockfile(server, config, first_time));
05620 
05621         /*
05622          * Check if max number of open sockets that the system allows is
05623          * sufficiently large.  Failing this condition is not necessarily fatal,
05624          * but may cause subsequent runtime failures for a busy recursive
05625          * server.
05626          */
05627         result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &maxsocks);
05628         if (result != ISC_R_SUCCESS)
05629                 maxsocks = 0;
05630         result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles);
05631         if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) {
05632                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05633                               NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
05634                               "max open files (%" ISC_PRINT_QUADFORMAT "u)"
05635                               " is smaller than max sockets (%u)",
05636                               nfiles, maxsocks);
05637         }
05638 
05639         /*
05640          * Set the number of socket reserved for TCP, stdio etc.
05641          */
05642         obj = NULL;
05643         result = ns_config_get(maps, "reserved-sockets", &obj);
05644         INSIST(result == ISC_R_SUCCESS);
05645         reserved = cfg_obj_asuint32(obj);
05646         if (maxsocks != 0) {
05647                 if (maxsocks < 128U)                    /* Prevent underflow. */
05648                         reserved = 0;
05649                 else if (reserved > maxsocks - 128U)    /* Minimum UDP space. */
05650                         reserved = maxsocks - 128;
05651         }
05652         /* Minimum TCP/stdio space. */
05653         if (reserved < 128U)
05654                 reserved = 128;
05655         if (reserved + 128U > maxsocks && maxsocks != 0) {
05656                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05657                               NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
05658                               "less than 128 UDP sockets available after "
05659                               "applying 'reserved-sockets' and 'maxsockets'");
05660         }
05661         isc__socketmgr_setreserved(ns_g_socketmgr, reserved);
05662 
05663 #ifdef HAVE_GEOIP
05664         /*
05665          * Initialize GeoIP databases from the configured location.
05666          * This should happen before configuring any ACLs, so that we
05667          * know what databases are available and can reject any GeoIP
05668          * ACLs that can't work.
05669          */
05670         obj = NULL;
05671         result = ns_config_get(maps, "geoip-directory", &obj);
05672         if (result == ISC_R_SUCCESS && cfg_obj_isstring(obj)) {
05673                 char *dir;
05674                 DE_CONST(cfg_obj_asstring(obj), dir);
05675                 ns_geoip_load(dir);
05676         } else
05677                 ns_geoip_load(NULL);
05678         ns_g_aclconfctx->geoip = ns_g_geoip;
05679 
05680         obj = NULL;
05681         result = ns_config_get(maps, "geoip-use-ecs", &obj);
05682         INSIST(result == ISC_R_SUCCESS);
05683         ns_g_server->aclenv.geoip_use_ecs = cfg_obj_asboolean(obj);
05684 #endif /* HAVE_GEOIP */
05685 
05686         /*
05687          * Configure various server options.
05688          */
05689         configure_server_quota(maps, "transfers-out", &server->xfroutquota);
05690         configure_server_quota(maps, "tcp-clients", &server->tcpquota);
05691         configure_server_quota(maps, "recursive-clients",
05692                                &server->recursionquota);
05693         if (server->recursionquota.max > 1000)
05694                 isc_quota_soft(&server->recursionquota,
05695                                server->recursionquota.max - 100);
05696         else
05697                 isc_quota_soft(&server->recursionquota, 0);
05698 
05699         CHECK(configure_view_acl(NULL, config, "blackhole", NULL,
05700                                  ns_g_aclconfctx, ns_g_mctx,
05701                                  &server->blackholeacl));
05702         if (server->blackholeacl != NULL)
05703                 dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
05704                                              server->blackholeacl);
05705 
05706         CHECK(configure_view_acl(NULL, config, "keep-response-order", NULL,
05707                                  ns_g_aclconfctx, ns_g_mctx,
05708                                  &server->keepresporder));
05709 
05710         obj = NULL;
05711         result = ns_config_get(maps, "match-mapped-addresses", &obj);
05712         INSIST(result == ISC_R_SUCCESS);
05713         server->aclenv.match_mapped = cfg_obj_asboolean(obj);
05714 
05715         CHECKM(ns_statschannels_configure(ns_g_server, config, ns_g_aclconfctx),
05716                "configuring statistics server(s)");
05717 
05718         /*
05719          * Configure sets of UDP query source ports.
05720          */
05721         CHECKM(isc_portset_create(ns_g_mctx, &v4portset),
05722                "creating UDP port set");
05723         CHECKM(isc_portset_create(ns_g_mctx, &v6portset),
05724                "creating UDP port set");
05725 
05726         usev4ports = NULL;
05727         usev6ports = NULL;
05728         avoidv4ports = NULL;
05729         avoidv6ports = NULL;
05730 
05731         (void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports);
05732         if (usev4ports != NULL)
05733                 portset_fromconf(v4portset, usev4ports, ISC_TRUE);
05734         else {
05735                 CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
05736                                                &udpport_high),
05737                        "get the default UDP/IPv4 port range");
05738                 if (udpport_low == udpport_high)
05739                         isc_portset_add(v4portset, udpport_low);
05740                 else {
05741                         isc_portset_addrange(v4portset, udpport_low,
05742                                              udpport_high);
05743                 }
05744                 if (!ns_g_disable4)
05745                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05746                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
05747                                       "using default UDP/IPv4 port range: "
05748                                       "[%d, %d]", udpport_low, udpport_high);
05749         }
05750         (void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
05751         if (avoidv4ports != NULL)
05752                 portset_fromconf(v4portset, avoidv4ports, ISC_FALSE);
05753 
05754         (void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports);
05755         if (usev6ports != NULL)
05756                 portset_fromconf(v6portset, usev6ports, ISC_TRUE);
05757         else {
05758                 CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
05759                                                &udpport_high),
05760                        "get the default UDP/IPv6 port range");
05761                 if (udpport_low == udpport_high)
05762                         isc_portset_add(v6portset, udpport_low);
05763                 else {
05764                         isc_portset_addrange(v6portset, udpport_low,
05765                                              udpport_high);
05766                 }
05767                 if (!ns_g_disable6)
05768                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05769                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
05770                                       "using default UDP/IPv6 port range: "
05771                                       "[%d, %d]", udpport_low, udpport_high);
05772         }
05773         (void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
05774         if (avoidv6ports != NULL)
05775                 portset_fromconf(v6portset, avoidv6ports, ISC_FALSE);
05776 
05777         dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset);
05778 
05779         /*
05780          * Set the EDNS UDP size when we don't match a view.
05781          */
05782         obj = NULL;
05783         result = ns_config_get(maps, "edns-udp-size", &obj);
05784         INSIST(result == ISC_R_SUCCESS);
05785         udpsize = cfg_obj_asuint32(obj);
05786         if (udpsize < 512)
05787                 udpsize = 512;
05788         if (udpsize > 4096)
05789                 udpsize = 4096;
05790         ns_g_udpsize = (isc_uint16_t)udpsize;
05791 
05792         /*
05793          * Configure the zone manager.
05794          */
05795         obj = NULL;
05796         result = ns_config_get(maps, "transfers-in", &obj);
05797         INSIST(result == ISC_R_SUCCESS);
05798         dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
05799 
05800         obj = NULL;
05801         result = ns_config_get(maps, "transfers-per-ns", &obj);
05802         INSIST(result == ISC_R_SUCCESS);
05803         dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
05804 
05805         obj = NULL;
05806         result = ns_config_get(maps, "notify-rate", &obj);
05807         INSIST(result == ISC_R_SUCCESS);
05808         dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
05809 
05810         obj = NULL;
05811         result = ns_config_get(maps, "startup-notify-rate", &obj);
05812         INSIST(result == ISC_R_SUCCESS);
05813         dns_zonemgr_setstartupnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
05814 
05815         obj = NULL;
05816         result = ns_config_get(maps, "serial-query-rate", &obj);
05817         INSIST(result == ISC_R_SUCCESS);
05818         dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
05819 
05820         /*
05821          * Determine which port to use for listening for incoming connections.
05822          */
05823         if (ns_g_port != 0)
05824                 listen_port = ns_g_port;
05825         else
05826                 CHECKM(ns_config_getport(config, &listen_port), "port");
05827 
05828         /*
05829          * Determing the default DSCP code point.
05830          */
05831         CHECKM(ns_config_getdscp(config, &ns_g_dscp), "dscp");
05832 
05833         /*
05834          * Find the listen queue depth.
05835          */
05836         obj = NULL;
05837         result = ns_config_get(maps, "tcp-listen-queue", &obj);
05838         INSIST(result == ISC_R_SUCCESS);
05839         ns_g_listen = cfg_obj_asuint32(obj);
05840         if ((ns_g_listen > 0) && (ns_g_listen < 10))
05841                 ns_g_listen = 10;
05842 
05843         /*
05844          * Configure the interface manager according to the "listen-on"
05845          * statement.
05846          */
05847         {
05848                 const cfg_obj_t *clistenon = NULL;
05849                 ns_listenlist_t *listenon = NULL;
05850 
05851                 clistenon = NULL;
05852                 /*
05853                  * Even though listen-on is present in the default
05854                  * configuration, we can't use it here, since it isn't
05855                  * used if we're in lwresd mode.  This way is easier.
05856                  */
05857                 if (options != NULL)
05858                         (void)cfg_map_get(options, "listen-on", &clistenon);
05859                 if (clistenon != NULL) {
05860                         /* check return code? */
05861                         (void)ns_listenlist_fromconfig(clistenon, config,
05862                                                        ns_g_aclconfctx,
05863                                                        ns_g_mctx, AF_INET,
05864                                                        &listenon);
05865                 } else if (!ns_g_lwresdonly) {
05866                         /*
05867                          * Not specified, use default.
05868                          */
05869                         CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
05870                                                     -1, ISC_TRUE, &listenon));
05871                 }
05872                 if (listenon != NULL) {
05873                         ns_interfacemgr_setlistenon4(server->interfacemgr,
05874                                                      listenon);
05875                         ns_listenlist_detach(&listenon);
05876                 }
05877         }
05878         /*
05879          * Ditto for IPv6.
05880          */
05881         {
05882                 const cfg_obj_t *clistenon = NULL;
05883                 ns_listenlist_t *listenon = NULL;
05884 
05885                 if (options != NULL)
05886                         (void)cfg_map_get(options, "listen-on-v6", &clistenon);
05887                 if (clistenon != NULL) {
05888                         /* check return code? */
05889                         (void)ns_listenlist_fromconfig(clistenon, config,
05890                                                        ns_g_aclconfctx,
05891                                                        ns_g_mctx, AF_INET6,
05892                                                        &listenon);
05893                 } else if (!ns_g_lwresdonly) {
05894                         /*
05895                          * Not specified, use default.
05896                          */
05897                         CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
05898                                                     -1, ISC_TRUE, &listenon));
05899                 }
05900                 if (listenon != NULL) {
05901                         ns_interfacemgr_setlistenon6(server->interfacemgr,
05902                                                      listenon);
05903                         ns_listenlist_detach(&listenon);
05904                 }
05905         }
05906 
05907         /*
05908          * Rescan the interface list to pick up changes in the
05909          * listen-on option.  It's important that we do this before we try
05910          * to configure the query source, since the dispatcher we use might
05911          * be shared with an interface.
05912          */
05913         result = scan_interfaces(server, ISC_TRUE);
05914 
05915         /*
05916          * Check that named is able to TCP listen on at least one
05917          * interface. Otherwise, another named process could be running
05918          * and we should fail.
05919          */
05920         if (first_time && (result == ISC_R_ADDRINUSE)) {
05921                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
05922                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
05923                               "unable to listen on any configured interfaces");
05924                 result = ISC_R_FAILURE;
05925                 goto cleanup;
05926         }
05927 
05928         /*
05929          * Arrange for further interface scanning to occur periodically
05930          * as specified by the "interface-interval" option.
05931          */
05932         obj = NULL;
05933         result = ns_config_get(maps, "interface-interval", &obj);
05934         INSIST(result == ISC_R_SUCCESS);
05935         interface_interval = cfg_obj_asuint32(obj) * 60;
05936         if (interface_interval == 0) {
05937                 CHECK(isc_timer_reset(server->interface_timer,
05938                                       isc_timertype_inactive,
05939                                       NULL, NULL, ISC_TRUE));
05940         } else if (server->interface_interval != interface_interval) {
05941                 isc_interval_set(&interval, interface_interval, 0);
05942                 CHECK(isc_timer_reset(server->interface_timer,
05943                                       isc_timertype_ticker,
05944                                       NULL, &interval, ISC_FALSE));
05945         }
05946         server->interface_interval = interface_interval;
05947 
05948         /*
05949          * Enable automatic interface scans.
05950          */
05951         obj = NULL;
05952         result = ns_config_get(maps, "automatic-interface-scan", &obj);
05953         INSIST(result == ISC_R_SUCCESS);
05954         server->interface_auto = cfg_obj_asboolean(obj);
05955 
05956         /*
05957          * Configure the dialup heartbeat timer.
05958          */
05959         obj = NULL;
05960         result = ns_config_get(maps, "heartbeat-interval", &obj);
05961         INSIST(result == ISC_R_SUCCESS);
05962         heartbeat_interval = cfg_obj_asuint32(obj) * 60;
05963         if (heartbeat_interval == 0) {
05964                 CHECK(isc_timer_reset(server->heartbeat_timer,
05965                                       isc_timertype_inactive,
05966                                       NULL, NULL, ISC_TRUE));
05967         } else if (server->heartbeat_interval != heartbeat_interval) {
05968                 isc_interval_set(&interval, heartbeat_interval, 0);
05969                 CHECK(isc_timer_reset(server->heartbeat_timer,
05970                                       isc_timertype_ticker,
05971                                       NULL, &interval, ISC_FALSE));
05972         }
05973         server->heartbeat_interval = heartbeat_interval;
05974 
05975         isc_interval_set(&interval, 1200, 0);
05976         CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
05977                               &interval, ISC_FALSE));
05978 
05979         /*
05980          * Write the PID file.
05981          */
05982         obj = NULL;
05983         if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS)
05984                 if (cfg_obj_isvoid(obj))
05985                         ns_os_writepidfile(NULL, first_time);
05986                 else
05987                         ns_os_writepidfile(cfg_obj_asstring(obj), first_time);
05988         else if (ns_g_lwresdonly)
05989                 ns_os_writepidfile(lwresd_g_defaultpidfile, first_time);
05990         else
05991                 ns_os_writepidfile(ns_g_defaultpidfile, first_time);
05992 
05993         /*
05994          * Configure the server-wide session key.  This must be done before
05995          * configure views because zone configuration may need to know
05996          * session-keyname.
05997          *
05998          * Failure of session key generation isn't fatal at this time; if it
05999          * turns out that a session key is really needed but doesn't exist,
06000          * we'll treat it as a fatal error then.
06001          */
06002         (void)configure_session_key(maps, server, ns_g_mctx);
06003 
06004         views = NULL;
06005         (void)cfg_map_get(config, "view", &views);
06006 
06007         /*
06008          * Create the views and count all the configured zones in
06009          * order to correctly size the zone manager's task table.
06010          * (We only count zones for configured views; the built-in
06011          * "bind" view can be ignored as it only adds a negligible
06012          * number of zones.)
06013          *
06014          * If we're allowing new zones, we need to be able to find the
06015          * new zone file and count those as well.  So we setup the new
06016          * zone configuration context, but otherwise view configuration
06017          * waits until after the zone manager's task list has been sized.
06018          */
06019         for (element = cfg_list_first(views);
06020              element != NULL;
06021              element = cfg_list_next(element))
06022         {
06023                 cfg_obj_t *vconfig = cfg_listelt_value(element);
06024                 const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
06025                 view = NULL;
06026 
06027                 CHECK(create_view(vconfig, &viewlist, &view));
06028                 INSIST(view != NULL);
06029 
06030                 num_zones += count_zones(voptions);
06031 
06032                 CHECK(setup_newzones(view, config, vconfig, conf_parser,
06033                                      ns_g_aclconfctx));
06034                 nzctx = view->new_zone_config;
06035                 if (nzctx != NULL && nzctx->nzconfig != NULL)
06036                         num_zones += count_zones(nzctx->nzconfig);
06037 
06038                 dns_view_detach(&view);
06039         }
06040 
06041         /*
06042          * If there were no explicit views then we do the default
06043          * view here.
06044          */
06045         if (views == NULL) {
06046                 CHECK(create_view(NULL, &viewlist, &view));
06047                 INSIST(view != NULL);
06048 
06049                 num_zones = count_zones(config);
06050 
06051                 CHECK(setup_newzones(view, config, NULL, conf_parser,
06052                                      ns_g_aclconfctx));
06053 
06054                 nzctx = view->new_zone_config;
06055                 if (nzctx != NULL && nzctx->nzconfig != NULL)
06056                         num_zones += count_zones(nzctx->nzconfig);
06057 
06058                 dns_view_detach(&view);
06059         }
06060 
06061         /*
06062          * Zones have been counted; set the zone manager task pool size.
06063          */
06064         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
06065                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
06066                       "sizing zone task pool based on %d zones", num_zones);
06067         CHECK(dns_zonemgr_setsize(ns_g_server->zonemgr, num_zones));
06068 
06069         /*
06070          * Configure and freeze all explicit views.  Explicit
06071          * views that have zones were already created at parsing
06072          * time, but views with no zones must be created here.
06073          */
06074         for (element = cfg_list_first(views);
06075              element != NULL;
06076              element = cfg_list_next(element))
06077         {
06078                 cfg_obj_t *vconfig = cfg_listelt_value(element);
06079 
06080                 view = NULL;
06081                 CHECK(find_view(vconfig, &viewlist, &view));
06082                 CHECK(configure_view(view, &viewlist, config, vconfig,
06083                                      &cachelist, bindkeys, ns_g_mctx,
06084                                      ns_g_aclconfctx, ISC_TRUE));
06085                 dns_view_freeze(view);
06086                 dns_view_detach(&view);
06087         }
06088 
06089         /*
06090          * Make sure we have a default view if and only if there
06091          * were no explicit views.
06092          */
06093         if (views == NULL) {
06094                 view = NULL;
06095                 CHECK(find_view(NULL, &viewlist, &view));
06096                 CHECK(configure_view(view, &viewlist, config, NULL,
06097                                      &cachelist, bindkeys,
06098                                      ns_g_mctx, ns_g_aclconfctx, ISC_TRUE));
06099                 dns_view_freeze(view);
06100                 dns_view_detach(&view);
06101         }
06102 
06103         /*
06104          * Create (or recreate) the built-in views.
06105          */
06106         builtin_views = NULL;
06107         RUNTIME_CHECK(cfg_map_get(ns_g_config, "view",
06108                                   &builtin_views) == ISC_R_SUCCESS);
06109         for (element = cfg_list_first(builtin_views);
06110              element != NULL;
06111              element = cfg_list_next(element))
06112         {
06113                 cfg_obj_t *vconfig = cfg_listelt_value(element);
06114 
06115                 CHECK(create_view(vconfig, &builtin_viewlist, &view));
06116                 CHECK(configure_view(view, &viewlist, config, vconfig,
06117                                      &cachelist, bindkeys,
06118                                      ns_g_mctx, ns_g_aclconfctx, ISC_FALSE));
06119                 dns_view_freeze(view);
06120                 dns_view_detach(&view);
06121                 view = NULL;
06122         }
06123 
06124         /* Now combine the two viewlists into one */
06125         ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
06126 
06127         /* Swap our new view list with the production one. */
06128         tmpviewlist = server->viewlist;
06129         server->viewlist = viewlist;
06130         viewlist = tmpviewlist;
06131 
06132         /* Make the view list available to each of the views */
06133         view = ISC_LIST_HEAD(server->viewlist);
06134         while (view != NULL) {
06135                 view->viewlist = &server->viewlist;
06136                 view = ISC_LIST_NEXT(view, link);
06137         }
06138 
06139         /* Swap our new cache list with the production one. */
06140         tmpcachelist = server->cachelist;
06141         server->cachelist = cachelist;
06142         cachelist = tmpcachelist;
06143 
06144         /* Load the TKEY information from the configuration. */
06145         if (options != NULL) {
06146                 dns_tkeyctx_t *t = NULL;
06147                 CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy,
06148                                              &t),
06149                        "configuring TKEY");
06150                 if (server->tkeyctx != NULL)
06151                         dns_tkeyctx_destroy(&server->tkeyctx);
06152                 server->tkeyctx = t;
06153         }
06154 
06155         /*
06156          * Bind the control port(s).
06157          */
06158         CHECKM(ns_controls_configure(ns_g_server->controls, config,
06159                                      ns_g_aclconfctx),
06160                "binding control channel(s)");
06161 
06162         /*
06163          * Bind the lwresd port(s).
06164          */
06165         CHECKM(ns_lwresd_configure(ns_g_mctx, config),
06166                "binding lightweight resolver ports");
06167 
06168         /*
06169          * Open the source of entropy.
06170          */
06171         if (first_time) {
06172                 obj = NULL;
06173                 result = ns_config_get(maps, "random-device", &obj);
06174                 if (result != ISC_R_SUCCESS) {
06175                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
06176                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
06177                                       "no source of entropy found");
06178                 } else {
06179                         const char *randomdev = cfg_obj_asstring(obj);
06180                         result = isc_entropy_createfilesource(ns_g_entropy,
06181                                                               randomdev);
06182                         if (result != ISC_R_SUCCESS)
06183                                 isc_log_write(ns_g_lctx,
06184                                               NS_LOGCATEGORY_GENERAL,
06185                                               NS_LOGMODULE_SERVER,
06186                                               ISC_LOG_INFO,
06187                                               "could not open entropy source "
06188                                               "%s: %s",
06189                                               randomdev,
06190                                               isc_result_totext(result));
06191 #ifdef PATH_RANDOMDEV
06192                         if (ns_g_fallbackentropy != NULL) {
06193                                 if (result != ISC_R_SUCCESS) {
06194                                         isc_log_write(ns_g_lctx,
06195                                                       NS_LOGCATEGORY_GENERAL,
06196                                                       NS_LOGMODULE_SERVER,
06197                                                       ISC_LOG_INFO,
06198                                                       "using pre-chroot entropy source "
06199                                                       "%s",
06200                                                       PATH_RANDOMDEV);
06201                                         isc_entropy_detach(&ns_g_entropy);
06202                                         isc_entropy_attach(ns_g_fallbackentropy,
06203                                                            &ns_g_entropy);
06204                                 }
06205                                 isc_entropy_detach(&ns_g_fallbackentropy);
06206                         }
06207 #endif
06208                 }
06209         }
06210 
06211         /*
06212          * Relinquish root privileges.
06213          */
06214         if (first_time)
06215                 ns_os_changeuser();
06216 
06217         /*
06218          * Check that the working directory is writable.
06219          */
06220         if (access(".", W_OK) != 0) {
06221                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
06222                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
06223                               "the working directory is not writable");
06224         }
06225 
06226         /*
06227          * Configure the logging system.
06228          *
06229          * Do this after changing UID to make sure that any log
06230          * files specified in named.conf get created by the
06231          * unprivileged user, not root.
06232          */
06233         if (ns_g_logstderr) {
06234                 const cfg_obj_t *logobj = NULL;
06235 
06236                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
06237                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
06238                               "not using config file logging "
06239                               "statement for logging due to "
06240                               "-g option");
06241 
06242                 (void)cfg_map_get(config, "logging", &logobj);
06243                 if (logobj != NULL) {
06244                         result = ns_log_configure(NULL, logobj);
06245                         if (result != ISC_R_SUCCESS) {
06246                                 isc_log_write(ns_g_lctx,
06247                                               NS_LOGCATEGORY_GENERAL,
06248                                               NS_LOGMODULE_SERVER,
06249                                               ISC_LOG_ERROR,
06250                                               "checking logging configuration "
06251                                               "failed: %s",
06252                                               isc_result_totext(result));
06253                                 goto cleanup;
06254                         }
06255                 }
06256         } else {
06257                 const cfg_obj_t *logobj = NULL;
06258 
06259                 CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
06260                        "creating new logging configuration");
06261 
06262                 logobj = NULL;
06263                 (void)cfg_map_get(config, "logging", &logobj);
06264                 if (logobj != NULL) {
06265                         CHECKM(ns_log_configure(logc, logobj),
06266                                "configuring logging");
06267                 } else {
06268                         CHECKM(ns_log_setdefaultchannels(logc),
06269                                "setting up default logging channels");
06270                         CHECKM(ns_log_setunmatchedcategory(logc),
06271                                "setting up default 'category unmatched'");
06272                         CHECKM(ns_log_setdefaultcategory(logc),
06273                                "setting up default 'category default'");
06274                 }
06275 
06276                 CHECKM(isc_logconfig_use(ns_g_lctx, logc),
06277                        "installing logging configuration");
06278                 logc = NULL;
06279 
06280                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
06281                               NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
06282                               "now using logging configuration from "
06283                               "config file");
06284         }
06285 
06286         /*
06287          * Set the default value of the query logging flag depending
06288          * whether a "queries" category has been defined.  This is
06289          * a disgusting hack, but we need to do this for BIND 8
06290          * compatibility.
06291          */
06292         if (first_time) {
06293                 const cfg_obj_t *logobj = NULL;
06294                 const cfg_obj_t *categories = NULL;
06295 
06296                 obj = NULL;
06297                 if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
06298                         server->log_queries = cfg_obj_asboolean(obj);
06299                 } else {
06300 
06301                         (void)cfg_map_get(config, "logging", &logobj);
06302                         if (logobj != NULL)
06303                                 (void)cfg_map_get(logobj, "category",
06304                                                   &categories);
06305                         if (categories != NULL) {
06306                                 for (element = cfg_list_first(categories);
06307                                      element != NULL;
06308                                      element = cfg_list_next(element))
06309                                 {
06310                                         const cfg_obj_t *catobj;
06311                                         const char *str;
06312 
06313                                         obj = cfg_listelt_value(element);
06314                                         catobj = cfg_tuple_get(obj, "name");
06315                                         str = cfg_obj_asstring(catobj);
06316                                         if (strcasecmp(str, "queries") == 0)
06317                                                 server->log_queries = ISC_TRUE;
06318                                 }
06319                         }
06320                 }
06321         }
06322 
06323 
06324         obj = NULL;
06325         if (options != NULL &&
06326             cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
06327                 ns_g_memstatistics = cfg_obj_asboolean(obj);
06328         else
06329                 ns_g_memstatistics =
06330                         ISC_TF((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
06331 
06332         obj = NULL;
06333         if (ns_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
06334                 ns_main_setmemstats(cfg_obj_asstring(obj));
06335         else if (ns_g_memstatistics)
06336                 ns_main_setmemstats("named.memstats");
06337         else
06338                 ns_main_setmemstats(NULL);
06339 
06340         obj = NULL;
06341         result = ns_config_get(maps, "statistics-file", &obj);
06342         INSIST(result == ISC_R_SUCCESS);
06343         CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
06344                "strdup");
06345 
06346         obj = NULL;
06347         result = ns_config_get(maps, "dump-file", &obj);
06348         INSIST(result == ISC_R_SUCCESS);
06349         CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
06350                "strdup");
06351 
06352         obj = NULL;
06353         result = ns_config_get(maps, "secroots-file", &obj);
06354         INSIST(result == ISC_R_SUCCESS);
06355         CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)),
06356                "strdup");
06357 
06358         obj = NULL;
06359         result = ns_config_get(maps, "recursing-file", &obj);
06360         INSIST(result == ISC_R_SUCCESS);
06361         CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
06362                "strdup");
06363 
06364         obj = NULL;
06365         result = ns_config_get(maps, "version", &obj);
06366         if (result == ISC_R_SUCCESS) {
06367                 CHECKM(setoptstring(server, &server->version, obj), "strdup");
06368                 server->version_set = ISC_TRUE;
06369         } else {
06370                 server->version_set = ISC_FALSE;
06371         }
06372 
06373         obj = NULL;
06374         result = ns_config_get(maps, "hostname", &obj);
06375         if (result == ISC_R_SUCCESS) {
06376                 CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
06377                 server->hostname_set = ISC_TRUE;
06378         } else {
06379                 server->hostname_set = ISC_FALSE;
06380         }
06381 
06382         obj = NULL;
06383         result = ns_config_get(maps, "server-id", &obj);
06384         server->server_usehostname = ISC_FALSE;
06385         if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
06386                 /* The parser translates "hostname" to ISC_TRUE */
06387                 server->server_usehostname = cfg_obj_asboolean(obj);
06388                 result = setstring(server, &server->server_id, NULL);
06389                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
06390         } else if (result == ISC_R_SUCCESS) {
06391                 /* Found a quoted string */
06392                 CHECKM(setoptstring(server, &server->server_id, obj), "strdup");
06393         } else {
06394                 result = setstring(server, &server->server_id, NULL);
06395                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
06396         }
06397 
06398         obj = NULL;
06399         result = ns_config_get(maps, "flush-zones-on-shutdown", &obj);
06400         if (result == ISC_R_SUCCESS) {
06401                 server->flushonshutdown = cfg_obj_asboolean(obj);
06402         } else {
06403                 server->flushonshutdown = ISC_FALSE;
06404         }
06405 
06406 #ifdef ISC_PLATFORM_USESIT
06407         obj = NULL;
06408         result = ns_config_get(maps, "sit-secret", &obj);
06409         if (result == ISC_R_SUCCESS) {
06410                 isc_buffer_t b;
06411 
06412                 memset(server->secret, 0, sizeof(server->secret));
06413                 isc_buffer_init(&b, server->secret, sizeof(server->secret));
06414                 result = isc_hex_decodestring(cfg_obj_asstring(obj), &b);
06415                 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
06416                         goto cleanup;
06417 #ifdef AES_SIT
06418                 if (isc_buffer_usedlength(&b) != ISC_AES128_KEYLENGTH)
06419                         CHECKM(ISC_R_RANGE,
06420                                "AES sit-secret must be on 128 bits");
06421 #endif
06422 #ifdef HMAC_SHA1_SIT
06423                 if (isc_buffer_usedlength(&b) != ISC_SHA1_DIGESTLENGTH)
06424                         CHECKM(ISC_R_RANGE,
06425                                "SHA1 sit-secret must be on 160 bits");
06426 #endif
06427 #ifdef HMAC_SHA256_SIT
06428                 if (isc_buffer_usedlength(&b) != ISC_SHA256_DIGESTLENGTH)
06429                         CHECKM(ISC_R_RANGE,
06430                                "SHA256 sit-secret must be on 256 bits");
06431 #endif
06432         } else {
06433                 result = isc_entropy_getdata(ns_g_entropy,
06434                                              server->secret,
06435                                              sizeof(server->secret),
06436                                              NULL,
06437                                              0);
06438                 if (result != ISC_R_SUCCESS)
06439                         goto cleanup;
06440         }
06441 #endif
06442 
06443         result = ISC_R_SUCCESS;
06444 
06445  cleanup:
06446         if (logc != NULL)
06447                 isc_logconfig_destroy(&logc);
06448 
06449         if (v4portset != NULL)
06450                 isc_portset_destroy(ns_g_mctx, &v4portset);
06451 
06452         if (v6portset != NULL)
06453                 isc_portset_destroy(ns_g_mctx, &v6portset);
06454 
06455         if (conf_parser != NULL) {
06456                 if (config != NULL)
06457                         cfg_obj_destroy(conf_parser, &config);
06458                 cfg_parser_destroy(&conf_parser);
06459         }
06460 
06461         if (bindkeys_parser != NULL) {
06462                 if (bindkeys != NULL)
06463                         cfg_obj_destroy(bindkeys_parser, &bindkeys);
06464                 cfg_parser_destroy(&bindkeys_parser);
06465         }
06466 
06467         if (view != NULL)
06468                 dns_view_detach(&view);
06469 
06470         ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
06471 
06472         /*
06473          * This cleans up either the old production view list
06474          * or our temporary list depending on whether they
06475          * were swapped above or not.
06476          */
06477         for (view = ISC_LIST_HEAD(viewlist);
06478              view != NULL;
06479              view = view_next) {
06480                 view_next = ISC_LIST_NEXT(view, link);
06481                 ISC_LIST_UNLINK(viewlist, view, link);
06482                 if (result == ISC_R_SUCCESS &&
06483                     strcmp(view->name, "_bind") != 0)
06484                         (void)dns_zt_apply(view->zonetable, ISC_FALSE,
06485                                            removed, view);
06486                 dns_view_detach(&view);
06487         }
06488 
06489         /* Same cleanup for cache list. */
06490         while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
06491                 ISC_LIST_UNLINK(cachelist, nsc, link);
06492                 dns_cache_detach(&nsc->cache);
06493                 isc_mem_put(server->mctx, nsc, sizeof(*nsc));
06494         }
06495 
06496         /*
06497          * Adjust the listening interfaces in accordance with the source
06498          * addresses specified in views and zones.
06499          */
06500         if (isc_net_probeipv6() == ISC_R_SUCCESS)
06501                 adjust_interfaces(server, ns_g_mctx);
06502 
06503         /*
06504          * Record the time of most recent configuration
06505          */
06506         tresult = isc_time_now(&ns_g_configtime);
06507         if (tresult != ISC_R_SUCCESS)
06508                 ns_main_earlyfatal("isc_time_now() failed: %s",
06509                                    isc_result_totext(result));
06510 
06511         /* Relinquish exclusive access to configuration data. */
06512         if (exclusive)
06513                 isc_task_endexclusive(server->task);
06514 
06515         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
06516                       ISC_LOG_DEBUG(1), "load_configuration: %s",
06517                       isc_result_totext(result));
06518 
06519         return (result);
06520 }
06521 
06522 static isc_result_t
06523 view_loaded(void *arg) {
06524         isc_result_t result;
06525         ns_zoneload_t *zl = (ns_zoneload_t *) arg;
06526         ns_server_t *server = zl->server;
06527         unsigned int refs;
06528 
06529 
06530         /*
06531          * Force zone maintenance.  Do this after loading
06532          * so that we know when we need to force AXFR of
06533          * slave zones whose master files are missing.
06534          *
06535          * We use the zoneload reference counter to let us
06536          * know when all views are finished.
06537          */
06538         isc_refcount_decrement(&zl->refs, &refs);
06539         if (refs != 0)
06540                 return (ISC_R_SUCCESS);
06541 
06542         isc_refcount_destroy(&zl->refs);
06543         isc_mem_put(server->mctx, zl, sizeof (*zl));
06544 
06545         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
06546                       ISC_LOG_NOTICE, "all zones loaded");
06547         CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
06548                    "forcing zone maintenance");
06549 
06550         ns_os_started();
06551         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
06552                       ISC_LOG_NOTICE, "running");
06553 
06554         return (ISC_R_SUCCESS);
06555 }
06556 
06557 static isc_result_t
06558 load_zones(ns_server_t *server, isc_boolean_t init) {
06559         isc_result_t result;
06560         dns_view_t *view;
06561         ns_zoneload_t *zl;
06562         unsigned int refs = 0;
06563 
06564         zl = isc_mem_get(server->mctx, sizeof (*zl));
06565         if (zl == NULL)
06566                 return (ISC_R_NOMEMORY);
06567         zl->server = server;
06568 
06569         result = isc_task_beginexclusive(server->task);
06570         RUNTIME_CHECK(result == ISC_R_SUCCESS);
06571 
06572         isc_refcount_init(&zl->refs, 1);
06573 
06574         /*
06575          * Schedule zones to be loaded from disk.
06576          */
06577         for (view = ISC_LIST_HEAD(server->viewlist);
06578              view != NULL;
06579              view = ISC_LIST_NEXT(view, link))
06580         {
06581                 if (view->managed_keys != NULL) {
06582                         result = dns_zone_load(view->managed_keys);
06583                         if (result != ISC_R_SUCCESS &&
06584                             result != DNS_R_UPTODATE &&
06585                             result != DNS_R_CONTINUE)
06586                                 goto cleanup;
06587                 }
06588                 if (view->redirect != NULL) {
06589                         result = dns_zone_load(view->redirect);
06590                         if (result != ISC_R_SUCCESS &&
06591                             result != DNS_R_UPTODATE &&
06592                             result != DNS_R_CONTINUE)
06593                                 goto cleanup;
06594                 }
06595 
06596                 /*
06597                  * 'dns_view_asyncload' calls view_loaded if there are no
06598                  * zones.
06599                  */
06600                 isc_refcount_increment(&zl->refs, NULL);
06601                 CHECK(dns_view_asyncload(view, view_loaded, zl));
06602         }
06603 
06604  cleanup:
06605         isc_refcount_decrement(&zl->refs, &refs);
06606         if (refs == 0) {
06607                 isc_refcount_destroy(&zl->refs);
06608                 isc_mem_put(server->mctx, zl, sizeof (*zl));
06609         } else if (init) {
06610                 /*
06611                  * Place the task manager into privileged mode.  This
06612                  * ensures that after we leave task-exclusive mode, no
06613                  * other tasks will be able to run except for the ones
06614                  * that are loading zones. (This should only be done during
06615                  * the initial server setup; it isn't necessary during
06616                  * a reload.)
06617                  */
06618                 isc_taskmgr_setmode(ns_g_taskmgr, isc_taskmgrmode_privileged);
06619         }
06620 
06621         isc_task_endexclusive(server->task);
06622         return (result);
06623 }
06624 
06625 static isc_result_t
06626 load_new_zones(ns_server_t *server, isc_boolean_t stop) {
06627         isc_result_t result;
06628         dns_view_t *view;
06629 
06630         result = isc_task_beginexclusive(server->task);
06631         RUNTIME_CHECK(result == ISC_R_SUCCESS);
06632 
06633         /*
06634          * Load zone data from disk.
06635          */
06636         for (view = ISC_LIST_HEAD(server->viewlist);
06637              view != NULL;
06638              view = ISC_LIST_NEXT(view, link))
06639         {
06640                 CHECK(dns_view_loadnew(view, stop));
06641 
06642                 /* Load managed-keys data */
06643                 if (view->managed_keys != NULL)
06644                         CHECK(dns_zone_loadnew(view->managed_keys));
06645                 if (view->redirect != NULL)
06646                         CHECK(dns_zone_loadnew(view->redirect));
06647         }
06648 
06649         /*
06650          * Resume zone XFRs.
06651          */
06652         dns_zonemgr_resumexfrs(server->zonemgr);
06653  cleanup:
06654         isc_task_endexclusive(server->task);
06655         return (result);
06656 }
06657 
06658 static void
06659 run_server(isc_task_t *task, isc_event_t *event) {
06660         isc_result_t result;
06661         ns_server_t *server = (ns_server_t *)event->ev_arg;
06662 
06663         INSIST(task == server->task);
06664 
06665         isc_event_free(&event);
06666 
06667         CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy,
06668                                           &ns_g_dispatchmgr),
06669                    "creating dispatch manager");
06670 
06671         dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats);
06672 
06673         CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
06674                                           ns_g_socketmgr, ns_g_dispatchmgr,
06675                                           server->task, &server->interfacemgr),
06676                    "creating interface manager");
06677 
06678         CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
06679                                     NULL, NULL, server->task,
06680                                     interface_timer_tick,
06681                                     server, &server->interface_timer),
06682                    "creating interface timer");
06683 
06684         CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
06685                                     NULL, NULL, server->task,
06686                                     heartbeat_timer_tick,
06687                                     server, &server->heartbeat_timer),
06688                    "creating heartbeat timer");
06689 
06690         CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
06691                                     NULL, NULL, server->task, pps_timer_tick,
06692                                     server, &server->pps_timer),
06693                    "creating pps timer");
06694 
06695         CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser),
06696                    "creating default configuration parser");
06697 
06698         CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_addparser),
06699                    "creating additional configuration parser");
06700 
06701         if (ns_g_lwresdonly)
06702                 CHECKFATAL(load_configuration(lwresd_g_conffile, server,
06703                                               ISC_TRUE),
06704                            "loading configuration");
06705         else
06706                 CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE),
06707                            "loading configuration");
06708 
06709         isc_hash_init();
06710 
06711         CHECKFATAL(load_zones(server, ISC_TRUE), "loading zones");
06712 
06713         (void) ns_server_loadnta(server);
06714 }
06715 
06716 void
06717 ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) {
06718 
06719         REQUIRE(NS_SERVER_VALID(server));
06720 
06721         server->flushonshutdown = flush;
06722 }
06723 
06724 static void
06725 shutdown_server(isc_task_t *task, isc_event_t *event) {
06726         isc_result_t result;
06727         dns_view_t *view, *view_next;
06728         ns_server_t *server = (ns_server_t *)event->ev_arg;
06729         isc_boolean_t flush = server->flushonshutdown;
06730         ns_cache_t *nsc;
06731 
06732         UNUSED(task);
06733         INSIST(task == server->task);
06734 
06735         result = isc_task_beginexclusive(server->task);
06736         RUNTIME_CHECK(result == ISC_R_SUCCESS);
06737 
06738         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
06739                       ISC_LOG_INFO, "shutting down%s",
06740                       flush ? ": flushing changes" : "");
06741 
06742         ns_statschannels_shutdown(server);
06743         ns_controls_shutdown(server->controls);
06744         end_reserved_dispatches(server, ISC_TRUE);
06745         cleanup_session_key(server, server->mctx);
06746 
06747         if (ns_g_aclconfctx != NULL)
06748                 cfg_aclconfctx_detach(&ns_g_aclconfctx);
06749 
06750         cfg_obj_destroy(ns_g_parser, &ns_g_config);
06751         cfg_parser_destroy(&ns_g_parser);
06752         cfg_parser_destroy(&ns_g_addparser);
06753 
06754         (void) ns_server_saventa(server);
06755 
06756         for (view = ISC_LIST_HEAD(server->viewlist);
06757              view != NULL;
06758              view = view_next) {
06759                 view_next = ISC_LIST_NEXT(view, link);
06760                 ISC_LIST_UNLINK(server->viewlist, view, link);
06761                 if (flush)
06762                         dns_view_flushanddetach(&view);
06763                 else
06764                         dns_view_detach(&view);
06765         }
06766 
06767         while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
06768                 ISC_LIST_UNLINK(server->cachelist, nsc, link);
06769                 dns_cache_detach(&nsc->cache);
06770                 isc_mem_put(server->mctx, nsc, sizeof(*nsc));
06771         }
06772 
06773         isc_timer_detach(&server->interface_timer);
06774         isc_timer_detach(&server->heartbeat_timer);
06775         isc_timer_detach(&server->pps_timer);
06776 
06777         ns_interfacemgr_shutdown(server->interfacemgr);
06778         ns_interfacemgr_detach(&server->interfacemgr);
06779 
06780         dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
06781 
06782         dns_zonemgr_shutdown(server->zonemgr);
06783 
06784         if (ns_g_sessionkey != NULL) {
06785                 dns_tsigkey_detach(&ns_g_sessionkey);
06786                 dns_name_free(&ns_g_sessionkeyname, server->mctx);
06787         }
06788 
06789         if (server->keepresporder != NULL)
06790                 dns_acl_detach(&server->keepresporder);
06791 
06792         if (server->blackholeacl != NULL)
06793                 dns_acl_detach(&server->blackholeacl);
06794 
06795 #ifdef HAVE_GEOIP
06796         dns_geoip_shutdown();
06797 #endif
06798 
06799         dns_db_detach(&server->in_roothints);
06800 
06801         isc_task_endexclusive(server->task);
06802 
06803         isc_task_detach(&server->task);
06804 
06805         isc_event_free(&event);
06806 }
06807 
06808 void
06809 ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
06810         isc_result_t result;
06811         ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
06812 
06813         if (server == NULL)
06814                 fatal("allocating server object", ISC_R_NOMEMORY);
06815 
06816         server->mctx = mctx;
06817         server->task = NULL;
06818 
06819         /* Initialize configuration data with default values. */
06820         result = isc_quota_init(&server->xfroutquota, 10);
06821         RUNTIME_CHECK(result == ISC_R_SUCCESS);
06822         result = isc_quota_init(&server->tcpquota, 10);
06823         RUNTIME_CHECK(result == ISC_R_SUCCESS);
06824         result = isc_quota_init(&server->recursionquota, 100);
06825         RUNTIME_CHECK(result == ISC_R_SUCCESS);
06826 
06827 
06828         result = dns_aclenv_init(mctx, &server->aclenv);
06829         RUNTIME_CHECK(result == ISC_R_SUCCESS);
06830 
06831 #ifdef HAVE_GEOIP
06832         /* Initialize GeoIP before using ACL environment */
06833         ns_geoip_init();
06834         server->aclenv.geoip = ns_g_geoip;
06835 #endif
06836 
06837         /* Initialize server data structures. */
06838         server->zonemgr = NULL;
06839         server->interfacemgr = NULL;
06840         ISC_LIST_INIT(server->viewlist);
06841         server->in_roothints = NULL;
06842         server->blackholeacl = NULL;
06843         server->keepresporder = NULL;
06844 
06845         /* Must be first. */
06846         CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy,
06847                                  ns_g_engine, ISC_ENTROPY_GOODONLY),
06848                    "initializing DST");
06849 
06850         CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
06851                                      &server->in_roothints),
06852                    "setting up root hints");
06853 
06854         CHECKFATAL(isc_mutex_init(&server->reload_event_lock),
06855                    "initializing reload event lock");
06856         server->reload_event =
06857                 isc_event_allocate(ns_g_mctx, server,
06858                                    NS_EVENT_RELOAD,
06859                                    ns_server_reload,
06860                                    server,
06861                                    sizeof(isc_event_t));
06862         CHECKFATAL(server->reload_event == NULL ?
06863                    ISC_R_NOMEMORY : ISC_R_SUCCESS,
06864                    "allocating reload event");
06865 
06866         server->tkeyctx = NULL;
06867         CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
06868                                       &server->tkeyctx),
06869                    "creating TKEY context");
06870 
06871         /*
06872          * Setup the server task, which is responsible for coordinating
06873          * startup and shutdown of the server, as well as all exclusive
06874          * tasks.
06875          */
06876         CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task),
06877                    "creating server task");
06878         isc_task_setname(server->task, "server", server);
06879         isc_taskmgr_setexcltask(ns_g_taskmgr, server->task);
06880         CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
06881                    "isc_task_onshutdown");
06882         CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
06883                    "isc_app_onrun");
06884 
06885         server->interface_timer = NULL;
06886         server->heartbeat_timer = NULL;
06887         server->pps_timer = NULL;
06888 
06889         server->interface_interval = 0;
06890         server->heartbeat_interval = 0;
06891 
06892         CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
06893                                       ns_g_socketmgr, &server->zonemgr),
06894                    "dns_zonemgr_create");
06895         CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000),
06896                    "dns_zonemgr_setsize");
06897 
06898         server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
06899         CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
06900                    "isc_mem_strdup");
06901         server->nsstats = NULL;
06902         server->rcvquerystats = NULL;
06903         server->opcodestats = NULL;
06904         server->zonestats = NULL;
06905         server->resolverstats = NULL;
06906         server->sockstats = NULL;
06907         CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
06908                                     isc_sockstatscounter_max),
06909                    "isc_stats_create");
06910         isc_socketmgr_setstats(ns_g_socketmgr, server->sockstats);
06911 
06912         server->bindkeysfile = isc_mem_strdup(server->mctx, "bind.keys");
06913         CHECKFATAL(server->bindkeysfile == NULL ? ISC_R_NOMEMORY :
06914                                                   ISC_R_SUCCESS,
06915                    "isc_mem_strdup");
06916 
06917         server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
06918         CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
06919                    "isc_mem_strdup");
06920 
06921         server->secrootsfile = isc_mem_strdup(server->mctx, "named.secroots");
06922         CHECKFATAL(server->secrootsfile == NULL ? ISC_R_NOMEMORY :
06923                                                   ISC_R_SUCCESS,
06924                    "isc_mem_strdup");
06925 
06926         server->recfile = isc_mem_strdup(server->mctx, "named.recursing");
06927         CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
06928                    "isc_mem_strdup");
06929 
06930         server->hostname_set = ISC_FALSE;
06931         server->hostname = NULL;
06932         server->version_set = ISC_FALSE;
06933         server->version = NULL;
06934         server->server_usehostname = ISC_FALSE;
06935         server->server_id = NULL;
06936 
06937         CHECKFATAL(isc_stats_create(ns_g_mctx, &server->nsstats,
06938                                     dns_nsstatscounter_max),
06939                    "dns_stats_create (server)");
06940 
06941         CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx,
06942                                              &server->rcvquerystats),
06943                    "dns_stats_create (rcvquery)");
06944 
06945         CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats),
06946                    "dns_stats_create (opcode)");
06947 
06948         CHECKFATAL(isc_stats_create(ns_g_mctx, &server->zonestats,
06949                                     dns_zonestatscounter_max),
06950                    "dns_stats_create (zone)");
06951 
06952         CHECKFATAL(isc_stats_create(ns_g_mctx, &server->resolverstats,
06953                                     dns_resstatscounter_max),
06954                    "dns_stats_create (resolver)");
06955 
06956         server->flushonshutdown = ISC_FALSE;
06957         server->log_queries = ISC_FALSE;
06958 
06959         server->controls = NULL;
06960         CHECKFATAL(ns_controls_create(server, &server->controls),
06961                    "ns_controls_create");
06962         server->dispatchgen = 0;
06963         ISC_LIST_INIT(server->dispatches);
06964 
06965         ISC_LIST_INIT(server->statschannels);
06966 
06967         ISC_LIST_INIT(server->cachelist);
06968 
06969         server->sessionkey = NULL;
06970         server->session_keyfile = NULL;
06971         server->session_keyname = NULL;
06972         server->session_keyalg = DST_ALG_UNKNOWN;
06973         server->session_keybits = 0;
06974 
06975         server->lockfile = NULL;
06976 
06977         server->magic = NS_SERVER_MAGIC;
06978         *serverp = server;
06979 }
06980 
06981 void
06982 ns_server_destroy(ns_server_t **serverp) {
06983         ns_server_t *server = *serverp;
06984         REQUIRE(NS_SERVER_VALID(server));
06985 
06986         ns_controls_destroy(&server->controls);
06987 
06988         isc_stats_detach(&server->nsstats);
06989         dns_stats_detach(&server->rcvquerystats);
06990         dns_stats_detach(&server->opcodestats);
06991         isc_stats_detach(&server->zonestats);
06992         isc_stats_detach(&server->resolverstats);
06993         isc_stats_detach(&server->sockstats);
06994 
06995         isc_mem_free(server->mctx, server->statsfile);
06996         isc_mem_free(server->mctx, server->bindkeysfile);
06997         isc_mem_free(server->mctx, server->dumpfile);
06998         isc_mem_free(server->mctx, server->secrootsfile);
06999         isc_mem_free(server->mctx, server->recfile);
07000 
07001         if (server->version != NULL)
07002                 isc_mem_free(server->mctx, server->version);
07003         if (server->hostname != NULL)
07004                 isc_mem_free(server->mctx, server->hostname);
07005         if (server->server_id != NULL)
07006                 isc_mem_free(server->mctx, server->server_id);
07007         if (server->lockfile != NULL)
07008                 isc_mem_free(server->mctx, server->lockfile);
07009 
07010         if (server->zonemgr != NULL)
07011                 dns_zonemgr_detach(&server->zonemgr);
07012 
07013         if (server->tkeyctx != NULL)
07014                 dns_tkeyctx_destroy(&server->tkeyctx);
07015 
07016         dst_lib_destroy();
07017 
07018         isc_event_free(&server->reload_event);
07019 
07020         INSIST(ISC_LIST_EMPTY(server->viewlist));
07021         INSIST(ISC_LIST_EMPTY(server->cachelist));
07022 
07023         dns_aclenv_destroy(&server->aclenv);
07024 
07025         isc_quota_destroy(&server->recursionquota);
07026         isc_quota_destroy(&server->tcpquota);
07027         isc_quota_destroy(&server->xfroutquota);
07028 
07029         server->magic = 0;
07030         isc_mem_put(server->mctx, server, sizeof(*server));
07031         *serverp = NULL;
07032 }
07033 
07034 static void
07035 fatal(const char *msg, isc_result_t result) {
07036         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
07037                       ISC_LOG_CRITICAL, "%s: %s", msg,
07038                       isc_result_totext(result));
07039         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
07040                       ISC_LOG_CRITICAL, "exiting (due to fatal error)");
07041         ns_os_shutdown();
07042         exit(1);
07043 }
07044 
07045 static void
07046 start_reserved_dispatches(ns_server_t *server) {
07047 
07048         REQUIRE(NS_SERVER_VALID(server));
07049 
07050         server->dispatchgen++;
07051 }
07052 
07053 static void
07054 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) {
07055         ns_dispatch_t *dispatch, *nextdispatch;
07056 
07057         REQUIRE(NS_SERVER_VALID(server));
07058 
07059         for (dispatch = ISC_LIST_HEAD(server->dispatches);
07060              dispatch != NULL;
07061              dispatch = nextdispatch) {
07062                 nextdispatch = ISC_LIST_NEXT(dispatch, link);
07063                 if (!all && server->dispatchgen == dispatch-> dispatchgen)
07064                         continue;
07065                 ISC_LIST_UNLINK(server->dispatches, dispatch, link);
07066                 dns_dispatch_detach(&dispatch->dispatch);
07067                 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
07068         }
07069 }
07070 
07071 void
07072 ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) {
07073         ns_dispatch_t *dispatch;
07074         in_port_t port;
07075         char addrbuf[ISC_SOCKADDR_FORMATSIZE];
07076         isc_result_t result;
07077         unsigned int attrs, attrmask;
07078 
07079         REQUIRE(NS_SERVER_VALID(server));
07080 
07081         port = isc_sockaddr_getport(addr);
07082         if (port == 0 || port >= 1024)
07083                 return;
07084 
07085         for (dispatch = ISC_LIST_HEAD(server->dispatches);
07086              dispatch != NULL;
07087              dispatch = ISC_LIST_NEXT(dispatch, link)) {
07088                 if (isc_sockaddr_equal(&dispatch->addr, addr))
07089                         break;
07090         }
07091         if (dispatch != NULL) {
07092                 dispatch->dispatchgen = server->dispatchgen;
07093                 return;
07094         }
07095 
07096         dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
07097         if (dispatch == NULL) {
07098                 result = ISC_R_NOMEMORY;
07099                 goto cleanup;
07100         }
07101 
07102         dispatch->addr = *addr;
07103         dispatch->dispatchgen = server->dispatchgen;
07104         dispatch->dispatch = NULL;
07105 
07106         attrs = 0;
07107         attrs |= DNS_DISPATCHATTR_UDP;
07108         switch (isc_sockaddr_pf(addr)) {
07109         case AF_INET:
07110                 attrs |= DNS_DISPATCHATTR_IPV4;
07111                 break;
07112         case AF_INET6:
07113                 attrs |= DNS_DISPATCHATTR_IPV6;
07114                 break;
07115         default:
07116                 result = ISC_R_NOTIMPLEMENTED;
07117                 goto cleanup;
07118         }
07119         attrmask = 0;
07120         attrmask |= DNS_DISPATCHATTR_UDP;
07121         attrmask |= DNS_DISPATCHATTR_TCP;
07122         attrmask |= DNS_DISPATCHATTR_IPV4;
07123         attrmask |= DNS_DISPATCHATTR_IPV6;
07124 
07125         result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
07126                                      ns_g_taskmgr, &dispatch->addr, 4096,
07127                                      UDPBUFFERS, 32768, 16411, 16433,
07128                                      attrs, attrmask, &dispatch->dispatch);
07129         if (result != ISC_R_SUCCESS)
07130                 goto cleanup;
07131 
07132         ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
07133 
07134         return;
07135 
07136  cleanup:
07137         if (dispatch != NULL)
07138                 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
07139         isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
07140         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07141                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
07142                       "unable to create dispatch for reserved port %s: %s",
07143                       addrbuf, isc_result_totext(result));
07144 }
07145 
07146 
07147 static isc_result_t
07148 loadconfig(ns_server_t *server) {
07149         isc_result_t result;
07150         start_reserved_dispatches(server);
07151         result = load_configuration(ns_g_lwresdonly ?
07152                                     lwresd_g_conffile : ns_g_conffile,
07153                                     server, ISC_FALSE);
07154         if (result == ISC_R_SUCCESS) {
07155                 end_reserved_dispatches(server, ISC_FALSE);
07156                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07157                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
07158                               "reloading configuration succeeded");
07159         } else {
07160                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07161                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
07162                               "reloading configuration failed: %s",
07163                               isc_result_totext(result));
07164         }
07165 
07166         return (result);
07167 }
07168 
07169 static isc_result_t
07170 reload(ns_server_t *server) {
07171         isc_result_t result;
07172         CHECK(loadconfig(server));
07173 
07174         result = load_zones(server, ISC_FALSE);
07175         if (result == ISC_R_SUCCESS)
07176                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07177                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
07178                               "reloading zones succeeded");
07179         else
07180                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07181                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
07182                               "reloading zones failed: %s",
07183                               isc_result_totext(result));
07184 
07185  cleanup:
07186         return (result);
07187 }
07188 
07189 static void
07190 reconfig(ns_server_t *server) {
07191         isc_result_t result;
07192         CHECK(loadconfig(server));
07193 
07194         result = load_new_zones(server, ISC_FALSE);
07195         if (result == ISC_R_SUCCESS)
07196                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07197                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
07198                               "any newly configured zones are now loaded");
07199         else
07200                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07201                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
07202                               "loading new zones failed: %s",
07203                               isc_result_totext(result));
07204 
07205  cleanup: ;
07206 }
07207 
07208 /*
07209  * Handle a reload event (from SIGHUP).
07210  */
07211 static void
07212 ns_server_reload(isc_task_t *task, isc_event_t *event) {
07213         ns_server_t *server = (ns_server_t *)event->ev_arg;
07214 
07215         INSIST(task = server->task);
07216         UNUSED(task);
07217 
07218         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07219                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
07220                       "received SIGHUP signal to reload zones");
07221         (void)reload(server);
07222 
07223         LOCK(&server->reload_event_lock);
07224         INSIST(server->reload_event == NULL);
07225         server->reload_event = event;
07226         UNLOCK(&server->reload_event_lock);
07227 }
07228 
07229 void
07230 ns_server_reloadwanted(ns_server_t *server) {
07231         LOCK(&server->reload_event_lock);
07232         if (server->reload_event != NULL)
07233                 isc_task_send(server->task, &server->reload_event);
07234         UNLOCK(&server->reload_event_lock);
07235 }
07236 
07237 void
07238 ns_server_scan_interfaces(ns_server_t *server) {
07239         isc_result_t result;
07240 
07241         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07242                       NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
07243                       "automatic interface rescan");
07244 
07245         result = isc_task_beginexclusive(server->task);
07246         RUNTIME_CHECK(result == ISC_R_SUCCESS);
07247         scan_interfaces(server, ISC_TRUE);
07248         isc_task_endexclusive(server->task);
07249 }
07250 
07251 static char *
07252 next_token(char **stringp, const char *delim) {
07253         char *res;
07254 
07255         do {
07256                 res = strsep(stringp, delim);
07257                 if (res == NULL)
07258                         break;
07259         } while (*res == '\0');
07260         return (res);
07261 }
07262 
07263 /*
07264  * Find the zone specified in the control channel command 'args',
07265  * if any.  If a zone is specified, point '*zonep' at it, otherwise
07266  * set '*zonep' to NULL.
07267  *
07268  * If 'zonetxt' is set, the caller has already pulled a token
07269  * off the command line that is to be used as the zone name.  (This
07270  * is done when it's necessary to check for an optional argument
07271  * before the zone name, as in "rndc sync [-clean] zone".)
07272  */
07273 static isc_result_t
07274 zone_from_args(ns_server_t *server, char *args, const char *zonetxt,
07275                dns_zone_t **zonep, const char **zonename,
07276                isc_buffer_t **text, isc_boolean_t skip)
07277 {
07278         char *input, *ptr;
07279         char *classtxt;
07280         const char *viewtxt = NULL;
07281         dns_fixedname_t fname;
07282         dns_name_t *name;
07283         isc_result_t result;
07284         dns_view_t *view = NULL;
07285         dns_rdataclass_t rdclass;
07286         char problem[DNS_NAME_FORMATSIZE + 500] = "";
07287 
07288         REQUIRE(zonep != NULL && *zonep == NULL);
07289         REQUIRE(zonename == NULL || *zonename == NULL);
07290 
07291         input = args;
07292 
07293         if (skip) {
07294                 /* Skip the command name. */
07295                 ptr = next_token(&input, " \t");
07296                 if (ptr == NULL)
07297                         return (ISC_R_UNEXPECTEDEND);
07298         }
07299 
07300         /* Look for the zone name. */
07301         if (zonetxt == NULL)
07302                 zonetxt = next_token(&input, " \t");
07303         if (zonetxt == NULL)
07304                 return (ISC_R_SUCCESS);
07305         if (zonename != NULL)
07306                 *zonename = zonetxt;
07307 
07308         /* Look for the optional class name. */
07309         classtxt = next_token(&input, " \t");
07310         if (classtxt != NULL) {
07311                 /* Look for the optional view name. */
07312                 viewtxt = next_token(&input, " \t");
07313         }
07314 
07315         dns_fixedname_init(&fname);
07316         name = dns_fixedname_name(&fname);
07317         CHECK(dns_name_fromstring(name, zonetxt, 0, NULL));
07318 
07319         if (classtxt != NULL) {
07320                 isc_textregion_t r;
07321                 r.base = classtxt;
07322                 r.length = strlen(classtxt);
07323                 CHECK(dns_rdataclass_fromtext(&rdclass, &r));
07324         } else
07325                 rdclass = dns_rdataclass_in;
07326 
07327         if (viewtxt == NULL) {
07328                 result = dns_viewlist_findzone(&server->viewlist, name,
07329                                                ISC_TF(classtxt == NULL),
07330                                                rdclass, zonep);
07331                 if (result == ISC_R_NOTFOUND)
07332                         snprintf(problem, sizeof(problem),
07333                                  "no matching zone '%s' in any view",
07334                                  zonetxt);
07335                 else if (result == ISC_R_MULTIPLE)
07336                         snprintf(problem, sizeof(problem),
07337                                  "zone '%s' was found in multiple views",
07338                                  zonetxt);
07339         } else {
07340                 result = dns_viewlist_find(&server->viewlist, viewtxt,
07341                                            rdclass, &view);
07342                 if (result != ISC_R_SUCCESS) {
07343                         snprintf(problem, sizeof(problem),
07344                                  "no matching view '%s'", viewtxt);
07345                         goto report;
07346                 }
07347 
07348                 result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
07349                 if (result != ISC_R_SUCCESS)
07350                         snprintf(problem, sizeof(problem),
07351                                  "no matching zone '%s' in view '%s'",
07352                                  zonetxt, viewtxt);
07353         }
07354 
07355         /* Partial match? */
07356         if (result != ISC_R_SUCCESS && *zonep != NULL)
07357                 dns_zone_detach(zonep);
07358         if (result == DNS_R_PARTIALMATCH)
07359                 result = ISC_R_NOTFOUND;
07360  report:
07361         if (result != ISC_R_SUCCESS) {
07362                 isc_result_t tresult;
07363 
07364                 tresult = putstr(text, problem);
07365                 if (tresult == ISC_R_SUCCESS)
07366                         (void) putnull(text);
07367         }
07368 
07369  cleanup:
07370         if (view != NULL)
07371                 dns_view_detach(&view);
07372 
07373         return (result);
07374 }
07375 
07376 /*
07377  * Act on a "retransfer" command from the command channel.
07378  */
07379 isc_result_t
07380 ns_server_retransfercommand(ns_server_t *server, char *args,
07381                             isc_buffer_t **text)
07382 {
07383         isc_result_t result;
07384         dns_zone_t *zone = NULL;
07385         dns_zone_t *raw = NULL;
07386         dns_zonetype_t type;
07387 
07388         result = zone_from_args(server, args, NULL, &zone, NULL,
07389                                 text, ISC_TRUE);
07390         if (result != ISC_R_SUCCESS)
07391                 return (result);
07392         if (zone == NULL)
07393                 return (ISC_R_UNEXPECTEDEND);
07394         dns_zone_getraw(zone, &raw);
07395         if (raw != NULL) {
07396                 dns_zone_detach(&zone);
07397                 dns_zone_attach(raw, &zone);
07398                 dns_zone_detach(&raw);
07399         }
07400         type = dns_zone_gettype(zone);
07401         if (type == dns_zone_slave || type == dns_zone_stub)
07402                 dns_zone_forcereload(zone);
07403         else
07404                 result = ISC_R_NOTFOUND;
07405         dns_zone_detach(&zone);
07406         return (result);
07407 }
07408 
07409 /*
07410  * Act on a "reload" command from the command channel.
07411  */
07412 isc_result_t
07413 ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t **text) {
07414         isc_result_t result;
07415         dns_zone_t *zone = NULL;
07416         dns_zonetype_t type;
07417         const char *msg = NULL;
07418 
07419         result = zone_from_args(server, args, NULL, &zone, NULL,
07420                                 text, ISC_TRUE);
07421         if (result != ISC_R_SUCCESS)
07422                 return (result);
07423         if (zone == NULL) {
07424                 result = reload(server);
07425                 if (result == ISC_R_SUCCESS)
07426                         msg = "server reload successful";
07427         } else {
07428                 type = dns_zone_gettype(zone);
07429                 if (type == dns_zone_slave || type == dns_zone_stub) {
07430                         dns_zone_refresh(zone);
07431                         dns_zone_detach(&zone);
07432                         msg = "zone refresh queued";
07433                 } else {
07434                         result = dns_zone_load(zone);
07435                         dns_zone_detach(&zone);
07436                         switch (result) {
07437                         case ISC_R_SUCCESS:
07438                                  msg = "zone reload successful";
07439                                  break;
07440                         case DNS_R_CONTINUE:
07441                                 msg = "zone reload queued";
07442                                 result = ISC_R_SUCCESS;
07443                                 break;
07444                         case DNS_R_UPTODATE:
07445                                 msg = "zone reload up-to-date";
07446                                 result = ISC_R_SUCCESS;
07447                                 break;
07448                         default:
07449                                 /* failure message will be generated by rndc */
07450                                 break;
07451                         }
07452                 }
07453         }
07454         if (msg != NULL) {
07455                 (void) putstr(text, msg);
07456                 (void) putnull(text);
07457         }
07458         return (result);
07459 }
07460 
07461 /*
07462  * Act on a "reconfig" command from the command channel.
07463  */
07464 isc_result_t
07465 ns_server_reconfigcommand(ns_server_t *server, char *args) {
07466         UNUSED(args);
07467 
07468         reconfig(server);
07469         return (ISC_R_SUCCESS);
07470 }
07471 
07472 /*
07473  * Act on a "notify" command from the command channel.
07474  */
07475 isc_result_t
07476 ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t **text) {
07477         isc_result_t result;
07478         dns_zone_t *zone = NULL;
07479         const char msg[] = "zone notify queued";
07480 
07481         result = zone_from_args(server, args, NULL, &zone, NULL,
07482                                 text, ISC_TRUE);
07483         if (result != ISC_R_SUCCESS)
07484                 return (result);
07485         if (zone == NULL)
07486                 return (ISC_R_UNEXPECTEDEND);
07487 
07488         dns_zone_notify(zone);
07489         dns_zone_detach(&zone);
07490         (void) putstr(text, msg);
07491         (void) putnull(text);
07492 
07493         return (ISC_R_SUCCESS);
07494 }
07495 
07496 /*
07497  * Act on a "refresh" command from the command channel.
07498  */
07499 isc_result_t
07500 ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t **text)
07501 {
07502         isc_result_t result;
07503         dns_zone_t *zone = NULL, *raw = NULL;
07504         const char msg1[] = "zone refresh queued";
07505         const char msg2[] = "not a slave or stub zone";
07506         dns_zonetype_t type;
07507 
07508         result = zone_from_args(server, args, NULL, &zone, NULL,
07509                                 text, ISC_TRUE);
07510         if (result != ISC_R_SUCCESS)
07511                 return (result);
07512         if (zone == NULL)
07513                 return (ISC_R_UNEXPECTEDEND);
07514 
07515         dns_zone_getraw(zone, &raw);
07516         if (raw != NULL) {
07517                 dns_zone_detach(&zone);
07518                 dns_zone_attach(raw, &zone);
07519                 dns_zone_detach(&raw);
07520         }
07521 
07522         type = dns_zone_gettype(zone);
07523         if (type == dns_zone_slave || type == dns_zone_stub) {
07524                 dns_zone_refresh(zone);
07525                 dns_zone_detach(&zone);
07526                 (void) putstr(text, msg1);
07527                 (void) putnull(text);
07528                 return (ISC_R_SUCCESS);
07529         }
07530 
07531         dns_zone_detach(&zone);
07532         (void) putstr(text, msg2);
07533         (void) putnull(text);
07534         return (ISC_R_FAILURE);
07535 }
07536 
07537 isc_result_t
07538 ns_server_togglequerylog(ns_server_t *server, char *args) {
07539         isc_boolean_t value;
07540         char *ptr;
07541 
07542         /* Skip the command name. */
07543         ptr = next_token(&args, " \t");
07544         if (ptr == NULL)
07545                 return (ISC_R_UNEXPECTEDEND);
07546 
07547         ptr = next_token(&args, " \t");
07548         if (ptr == NULL)
07549                 value = server->log_queries ? ISC_FALSE : ISC_TRUE;
07550         else if (strcasecmp(ptr, "yes") == 0 || strcasecmp(ptr, "on") == 0)
07551                 value = ISC_TRUE;
07552         else if (strcasecmp(ptr, "no") == 0 || strcasecmp(ptr, "off") == 0)
07553                 value = ISC_FALSE;
07554         else
07555                 return (ISC_R_NOTFOUND);
07556 
07557         if (server->log_queries == value)
07558                 return (ISC_R_SUCCESS);
07559 
07560         server->log_queries = value;
07561 
07562         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07563                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
07564                       "query logging is now %s",
07565                       server->log_queries ? "on" : "off");
07566         return (ISC_R_SUCCESS);
07567 }
07568 
07569 static isc_result_t
07570 ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
07571                          cfg_aclconfctx_t *actx, isc_mem_t *mctx,
07572                          isc_uint16_t family, ns_listenlist_t **target)
07573 {
07574         isc_result_t result;
07575         const cfg_listelt_t *element;
07576         ns_listenlist_t *dlist = NULL;
07577 
07578         REQUIRE(target != NULL && *target == NULL);
07579 
07580         result = ns_listenlist_create(mctx, &dlist);
07581         if (result != ISC_R_SUCCESS)
07582                 return (result);
07583 
07584         for (element = cfg_list_first(listenlist);
07585              element != NULL;
07586              element = cfg_list_next(element))
07587         {
07588                 ns_listenelt_t *delt = NULL;
07589                 const cfg_obj_t *listener = cfg_listelt_value(element);
07590                 result = ns_listenelt_fromconfig(listener, config, actx,
07591                                                  mctx, family, &delt);
07592                 if (result != ISC_R_SUCCESS)
07593                         goto cleanup;
07594                 ISC_LIST_APPEND(dlist->elts, delt, link);
07595         }
07596         *target = dlist;
07597         return (ISC_R_SUCCESS);
07598 
07599  cleanup:
07600         ns_listenlist_detach(&dlist);
07601         return (result);
07602 }
07603 
07604 /*
07605  * Create a listen list from the corresponding configuration
07606  * data structure.
07607  */
07608 static isc_result_t
07609 ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
07610                         cfg_aclconfctx_t *actx, isc_mem_t *mctx,
07611                         isc_uint16_t family, ns_listenelt_t **target)
07612 {
07613         isc_result_t result;
07614         const cfg_obj_t *portobj, *dscpobj;
07615         in_port_t port;
07616         isc_dscp_t dscp = -1;
07617         ns_listenelt_t *delt = NULL;
07618         REQUIRE(target != NULL && *target == NULL);
07619 
07620         portobj = cfg_tuple_get(listener, "port");
07621         if (!cfg_obj_isuint32(portobj)) {
07622                 if (ns_g_port != 0) {
07623                         port = ns_g_port;
07624                 } else {
07625                         result = ns_config_getport(config, &port);
07626                         if (result != ISC_R_SUCCESS)
07627                                 return (result);
07628                 }
07629         } else {
07630                 if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
07631                         cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
07632                                     "port value '%u' is out of range",
07633                                     cfg_obj_asuint32(portobj));
07634                         return (ISC_R_RANGE);
07635                 }
07636                 port = (in_port_t)cfg_obj_asuint32(portobj);
07637         }
07638 
07639         dscpobj = cfg_tuple_get(listener, "dscp");
07640         if (!cfg_obj_isuint32(dscpobj))
07641                 dscp = ns_g_dscp;
07642         else {
07643                 if (cfg_obj_asuint32(dscpobj) > 63) {
07644                         cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR,
07645                                     "dscp value '%u' is out of range",
07646                                     cfg_obj_asuint32(dscpobj));
07647                         return (ISC_R_RANGE);
07648                 }
07649                 dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
07650         }
07651 
07652         result = ns_listenelt_create(mctx, port, dscp, NULL, &delt);
07653         if (result != ISC_R_SUCCESS)
07654                 return (result);
07655 
07656         result = cfg_acl_fromconfig2(cfg_tuple_get(listener, "acl"),
07657                                      config, ns_g_lctx, actx, mctx, 0,
07658                                      family, &delt->acl);
07659         if (result != ISC_R_SUCCESS) {
07660                 ns_listenelt_destroy(delt);
07661                 return (result);
07662         }
07663         *target = delt;
07664         return (ISC_R_SUCCESS);
07665 }
07666 
07667 isc_result_t
07668 ns_server_dumpstats(ns_server_t *server) {
07669         isc_result_t result;
07670         FILE *fp = NULL;
07671 
07672         CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
07673                 "could not open statistics dump file", server->statsfile);
07674 
07675         result = ns_stats_dump(server, fp);
07676 
07677  cleanup:
07678         if (fp != NULL)
07679                 (void)isc_stdio_close(fp);
07680         if (result == ISC_R_SUCCESS)
07681                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07682                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
07683                               "dumpstats complete");
07684         else
07685                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07686                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
07687                               "dumpstats failed: %s",
07688                               dns_result_totext(result));
07689         return (result);
07690 }
07691 
07692 static isc_result_t
07693 add_zone_tolist(dns_zone_t *zone, void *uap) {
07694         struct dumpcontext *dctx = uap;
07695         struct zonelistentry *zle;
07696 
07697         zle = isc_mem_get(dctx->mctx, sizeof *zle);
07698         if (zle ==  NULL)
07699                 return (ISC_R_NOMEMORY);
07700         zle->zone = NULL;
07701         dns_zone_attach(zone, &zle->zone);
07702         ISC_LINK_INIT(zle, link);
07703         ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
07704         return (ISC_R_SUCCESS);
07705 }
07706 
07707 static isc_result_t
07708 add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
07709         struct viewlistentry *vle;
07710         isc_result_t result = ISC_R_SUCCESS;
07711 
07712         /*
07713          * Prevent duplicate views.
07714          */
07715         for (vle = ISC_LIST_HEAD(dctx->viewlist);
07716              vle != NULL;
07717              vle = ISC_LIST_NEXT(vle, link))
07718                 if (vle->view == view)
07719                         return (ISC_R_SUCCESS);
07720 
07721         vle = isc_mem_get(dctx->mctx, sizeof *vle);
07722         if (vle == NULL)
07723                 return (ISC_R_NOMEMORY);
07724         vle->view = NULL;
07725         dns_view_attach(view, &vle->view);
07726         ISC_LINK_INIT(vle, link);
07727         ISC_LIST_INIT(vle->zonelist);
07728         ISC_LIST_APPEND(dctx->viewlist, vle, link);
07729         if (dctx->dumpzones)
07730                 result = dns_zt_apply(view->zonetable, ISC_TRUE,
07731                                       add_zone_tolist, dctx);
07732         return (result);
07733 }
07734 
07735 static void
07736 dumpcontext_destroy(struct dumpcontext *dctx) {
07737         struct viewlistentry *vle;
07738         struct zonelistentry *zle;
07739 
07740         vle = ISC_LIST_HEAD(dctx->viewlist);
07741         while (vle != NULL) {
07742                 ISC_LIST_UNLINK(dctx->viewlist, vle, link);
07743                 zle = ISC_LIST_HEAD(vle->zonelist);
07744                 while (zle != NULL) {
07745                         ISC_LIST_UNLINK(vle->zonelist, zle, link);
07746                         dns_zone_detach(&zle->zone);
07747                         isc_mem_put(dctx->mctx, zle, sizeof *zle);
07748                         zle = ISC_LIST_HEAD(vle->zonelist);
07749                 }
07750                 dns_view_detach(&vle->view);
07751                 isc_mem_put(dctx->mctx, vle, sizeof *vle);
07752                 vle = ISC_LIST_HEAD(dctx->viewlist);
07753         }
07754         if (dctx->version != NULL)
07755                 dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
07756         if (dctx->db != NULL)
07757                 dns_db_detach(&dctx->db);
07758         if (dctx->cache != NULL)
07759                 dns_db_detach(&dctx->cache);
07760         if (dctx->task != NULL)
07761                 isc_task_detach(&dctx->task);
07762         if (dctx->fp != NULL)
07763                 (void)isc_stdio_close(dctx->fp);
07764         if (dctx->mdctx != NULL)
07765                 dns_dumpctx_detach(&dctx->mdctx);
07766         isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
07767 }
07768 
07769 static void
07770 dumpdone(void *arg, isc_result_t result) {
07771         struct dumpcontext *dctx = arg;
07772         char buf[1024+32];
07773         const dns_master_style_t *style;
07774 
07775         if (result != ISC_R_SUCCESS)
07776                 goto cleanup;
07777         if (dctx->mdctx != NULL)
07778                 dns_dumpctx_detach(&dctx->mdctx);
07779         if (dctx->view == NULL) {
07780                 dctx->view = ISC_LIST_HEAD(dctx->viewlist);
07781                 if (dctx->view == NULL)
07782                         goto done;
07783                 INSIST(dctx->zone == NULL);
07784         } else
07785                 goto resume;
07786  nextview:
07787         fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
07788  resume:
07789         if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
07790                 fprintf(dctx->fp,
07791                         ";\n; Cache of view '%s' is shared as '%s'\n",
07792                         dctx->view->view->name,
07793                         dns_cache_getname(dctx->view->view->cache));
07794         } else if (dctx->zone == NULL && dctx->cache == NULL &&
07795                    dctx->dumpcache)
07796         {
07797                 style = &dns_master_style_cache;
07798                 /* start cache dump */
07799                 if (dctx->view->view->cachedb != NULL)
07800                         dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
07801                 if (dctx->cache != NULL) {
07802                         fprintf(dctx->fp,
07803                                 ";\n; Cache dump of view '%s' (cache %s)\n;\n",
07804                                 dctx->view->view->name,
07805                                 dns_cache_getname(dctx->view->view->cache));
07806                         result = dns_master_dumptostreaminc(dctx->mctx,
07807                                                             dctx->cache, NULL,
07808                                                             style, dctx->fp,
07809                                                             dctx->task,
07810                                                             dumpdone, dctx,
07811                                                             &dctx->mdctx);
07812                         if (result == DNS_R_CONTINUE)
07813                                 return;
07814                         if (result == ISC_R_NOTIMPLEMENTED)
07815                                 fprintf(dctx->fp, "; %s\n",
07816                                         dns_result_totext(result));
07817                         else if (result != ISC_R_SUCCESS)
07818                                 goto cleanup;
07819                 }
07820         }
07821         if (dctx->cache != NULL) {
07822                 dns_adb_dump(dctx->view->view->adb, dctx->fp);
07823                 dns_resolver_printbadcache(dctx->view->view->resolver,
07824                                            dctx->fp);
07825                 dns_badcache_print(dctx->view->view->failcache,
07826                                    "SERVFAIL cache", dctx->fp);
07827                 dns_db_detach(&dctx->cache);
07828         }
07829         if (dctx->dumpzones) {
07830                 style = &dns_master_style_full;
07831  nextzone:
07832                 if (dctx->version != NULL)
07833                         dns_db_closeversion(dctx->db, &dctx->version,
07834                                             ISC_FALSE);
07835                 if (dctx->db != NULL)
07836                         dns_db_detach(&dctx->db);
07837                 if (dctx->zone == NULL)
07838                         dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
07839                 else
07840                         dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
07841                 if (dctx->zone != NULL) {
07842                         /* start zone dump */
07843                         dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
07844                         fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
07845                         result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
07846                         if (result != ISC_R_SUCCESS) {
07847                                 fprintf(dctx->fp, "; %s\n",
07848                                         dns_result_totext(result));
07849                                 goto nextzone;
07850                         }
07851                         dns_db_currentversion(dctx->db, &dctx->version);
07852                         result = dns_master_dumptostreaminc(dctx->mctx,
07853                                                             dctx->db,
07854                                                             dctx->version,
07855                                                             style, dctx->fp,
07856                                                             dctx->task,
07857                                                             dumpdone, dctx,
07858                                                             &dctx->mdctx);
07859                         if (result == DNS_R_CONTINUE)
07860                                 return;
07861                         if (result == ISC_R_NOTIMPLEMENTED) {
07862                                 fprintf(dctx->fp, "; %s\n",
07863                                         dns_result_totext(result));
07864                                 result = ISC_R_SUCCESS;
07865                                 POST(result);
07866                                 goto nextzone;
07867                         }
07868                         if (result != ISC_R_SUCCESS)
07869                                 goto cleanup;
07870                 }
07871         }
07872         if (dctx->view != NULL)
07873                 dctx->view = ISC_LIST_NEXT(dctx->view, link);
07874         if (dctx->view != NULL)
07875                 goto nextview;
07876  done:
07877         fprintf(dctx->fp, "; Dump complete\n");
07878         result = isc_stdio_flush(dctx->fp);
07879         if (result == ISC_R_SUCCESS)
07880                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07881                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
07882                               "dumpdb complete");
07883  cleanup:
07884         if (result != ISC_R_SUCCESS)
07885                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07886                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
07887                               "dumpdb failed: %s", dns_result_totext(result));
07888         dumpcontext_destroy(dctx);
07889 }
07890 
07891 isc_result_t
07892 ns_server_dumpdb(ns_server_t *server, char *args) {
07893         struct dumpcontext *dctx = NULL;
07894         dns_view_t *view;
07895         isc_result_t result;
07896         char *ptr;
07897         const char *sep;
07898 
07899         /* Skip the command name. */
07900         ptr = next_token(&args, " \t");
07901         if (ptr == NULL)
07902                 return (ISC_R_UNEXPECTEDEND);
07903 
07904         dctx = isc_mem_get(server->mctx, sizeof(*dctx));
07905         if (dctx == NULL)
07906                 return (ISC_R_NOMEMORY);
07907 
07908         dctx->mctx = server->mctx;
07909         dctx->dumpcache = ISC_TRUE;
07910         dctx->dumpzones = ISC_FALSE;
07911         dctx->fp = NULL;
07912         ISC_LIST_INIT(dctx->viewlist);
07913         dctx->view = NULL;
07914         dctx->zone = NULL;
07915         dctx->cache = NULL;
07916         dctx->mdctx = NULL;
07917         dctx->db = NULL;
07918         dctx->cache = NULL;
07919         dctx->task = NULL;
07920         dctx->version = NULL;
07921         isc_task_attach(server->task, &dctx->task);
07922 
07923         CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
07924                 "could not open dump file", server->dumpfile);
07925 
07926         sep = (args == NULL) ? "" : ": ";
07927         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
07928                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
07929                       "dumpdb started%s%s", sep, (args != NULL) ? args : "");
07930 
07931         ptr = next_token(&args, " \t");
07932         if (ptr != NULL && strcmp(ptr, "-all") == 0) {
07933                 dctx->dumpzones = ISC_TRUE;
07934                 dctx->dumpcache = ISC_TRUE;
07935                 ptr = next_token(&args, " \t");
07936         } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
07937                 dctx->dumpzones = ISC_FALSE;
07938                 dctx->dumpcache = ISC_TRUE;
07939                 ptr = next_token(&args, " \t");
07940         } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
07941                 dctx->dumpzones = ISC_TRUE;
07942                 dctx->dumpcache = ISC_FALSE;
07943                 ptr = next_token(&args, " \t");
07944         }
07945 
07946  nextview:
07947         for (view = ISC_LIST_HEAD(server->viewlist);
07948              view != NULL;
07949              view = ISC_LIST_NEXT(view, link))
07950         {
07951                 if (ptr != NULL && strcmp(view->name, ptr) != 0)
07952                         continue;
07953                 CHECK(add_view_tolist(dctx, view));
07954         }
07955         if (ptr != NULL) {
07956                 ptr = next_token(&args, " \t");
07957                 if (ptr != NULL)
07958                         goto nextview;
07959         }
07960         dumpdone(dctx, ISC_R_SUCCESS);
07961         return (ISC_R_SUCCESS);
07962 
07963  cleanup:
07964         if (dctx != NULL)
07965                 dumpcontext_destroy(dctx);
07966         return (result);
07967 }
07968 
07969 isc_result_t
07970 ns_server_dumpsecroots(ns_server_t *server, char *args, isc_buffer_t **text) {
07971         dns_view_t *view;
07972         dns_keytable_t *secroots = NULL;
07973         dns_ntatable_t *ntatable = NULL;
07974         isc_result_t result;
07975         char *ptr;
07976         FILE *fp = NULL;
07977         isc_time_t now;
07978         char tbuf[64];
07979 
07980         /* Skip the command name. */
07981         ptr = next_token(&args, " \t");
07982         if (ptr == NULL)
07983                 return (ISC_R_UNEXPECTEDEND);
07984 
07985         /* "-" here means print the output instead of dumping to file */
07986         ptr = next_token(&args, " \t");
07987         if (ptr != NULL && strcmp(ptr, "-") == 0)
07988                 ptr = next_token(&args, " \t");
07989         else {
07990                 result = isc_stdio_open(server->secrootsfile, "w", &fp);
07991                 if (result != ISC_R_SUCCESS) {
07992                         (void) putstr(text, "could not open ");
07993                         (void) putstr(text, server->secrootsfile);
07994                         CHECKMF(result, "could not open secroots dump file",
07995                                 server->secrootsfile);
07996                 }
07997         }
07998 
07999         TIME_NOW(&now);
08000         isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
08001         CHECK(putstr(text, "secure roots as of "));
08002         CHECK(putstr(text, tbuf));
08003         CHECK(putstr(text, ":\n"));
08004 
08005         do {
08006                 for (view = ISC_LIST_HEAD(server->viewlist);
08007                      view != NULL;
08008                      view = ISC_LIST_NEXT(view, link))
08009                 {
08010                         if (ptr != NULL && strcmp(view->name, ptr) != 0)
08011                                 continue;
08012                         if (secroots != NULL)
08013                                 dns_keytable_detach(&secroots);
08014                         result = dns_view_getsecroots(view, &secroots);
08015                         if (result == ISC_R_NOTFOUND) {
08016                                 result = ISC_R_SUCCESS;
08017                                 continue;
08018                         }
08019                         CHECK(putstr(text, "\n Start view "));
08020                         CHECK(putstr(text, view->name));
08021                         CHECK(putstr(text, "\n   Secure roots:\n\n"));
08022                         CHECK(dns_keytable_totext(secroots, text));
08023 
08024                         if (ntatable != NULL)
08025                                 dns_ntatable_detach(&ntatable);
08026                         result = dns_view_getntatable(view, &ntatable);
08027                         if (result == ISC_R_NOTFOUND) {
08028                                 result = ISC_R_SUCCESS;
08029                                 continue;
08030                         }
08031                         CHECK(putstr(text, "\n   Negative trust anchors:\n\n"));
08032                         CHECK(dns_ntatable_totext(ntatable, text));
08033                 }
08034                 if (ptr != NULL)
08035                         ptr = next_token(&args, " \t");
08036         } while (ptr != NULL);
08037 
08038  cleanup:
08039         if (isc_buffer_usedlength(*text) > 0) {
08040                 if (fp != NULL)
08041                         (void)putstr(text, "\n");
08042                 else
08043                         (void)putnull(text);
08044         }
08045         if (secroots != NULL)
08046                 dns_keytable_detach(&secroots);
08047         if (ntatable != NULL)
08048                 dns_ntatable_detach(&ntatable);
08049         if (fp != NULL) {
08050                 fprintf(fp, "%.*s", (int) isc_buffer_usedlength(*text),
08051                         (char *) isc_buffer_base(*text));
08052                 isc_buffer_clear(*text);
08053                 (void)isc_stdio_close(fp);
08054         }
08055         if (result == ISC_R_SUCCESS)
08056                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08057                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
08058                               "dumpsecroots complete");
08059         else
08060                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08061                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
08062                               "dumpsecroots failed: %s",
08063                               dns_result_totext(result));
08064         return (result);
08065 }
08066 
08067 isc_result_t
08068 ns_server_dumprecursing(ns_server_t *server) {
08069         FILE *fp = NULL;
08070         isc_result_t result;
08071 
08072         CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
08073                 "could not open dump file", server->recfile);
08074         fprintf(fp,";\n; Recursing Queries\n;\n");
08075         ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
08076         fprintf(fp, "; Dump complete\n");
08077 
08078  cleanup:
08079         if (fp != NULL)
08080                 result = isc_stdio_close(fp);
08081         if (result == ISC_R_SUCCESS)
08082                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08083                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
08084                               "dumprecursing complete");
08085         else
08086                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08087                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
08088                               "dumprecursing failed: %s",
08089                               dns_result_totext(result));
08090         return (result);
08091 }
08092 
08093 isc_result_t
08094 ns_server_setdebuglevel(ns_server_t *server, char *args) {
08095         char *ptr;
08096         char *levelstr;
08097         char *endp;
08098         long newlevel;
08099 
08100         UNUSED(server);
08101 
08102         /* Skip the command name. */
08103         ptr = next_token(&args, " \t");
08104         if (ptr == NULL)
08105                 return (ISC_R_UNEXPECTEDEND);
08106 
08107         /* Look for the new level name. */
08108         levelstr = next_token(&args, " \t");
08109         if (levelstr == NULL) {
08110                 if (ns_g_debuglevel < 99)
08111                         ns_g_debuglevel++;
08112         } else {
08113                 newlevel = strtol(levelstr, &endp, 10);
08114                 if (*endp != '\0' || newlevel < 0 || newlevel > 99)
08115                         return (ISC_R_RANGE);
08116                 ns_g_debuglevel = (unsigned int)newlevel;
08117         }
08118         isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel);
08119         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08120                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
08121                       "debug level is now %d", ns_g_debuglevel);
08122         return (ISC_R_SUCCESS);
08123 }
08124 
08125 isc_result_t
08126 ns_server_validation(ns_server_t *server, char *args, isc_buffer_t **text) {
08127         char *ptr, *viewname;
08128         dns_view_t *view;
08129         isc_boolean_t changed = ISC_FALSE;
08130         isc_result_t result;
08131         isc_boolean_t enable = ISC_TRUE, set = ISC_TRUE, first = ISC_TRUE;
08132 
08133         /* Skip the command name. */
08134         ptr = next_token(&args, " \t");
08135         if (ptr == NULL)
08136                 return (ISC_R_UNEXPECTEDEND);
08137 
08138         /* Find out what we are to do. */
08139         ptr = next_token(&args, " \t");
08140         if (ptr == NULL)
08141                 return (ISC_R_UNEXPECTEDEND);
08142 
08143         if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
08144             !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
08145                 enable = ISC_TRUE;
08146         else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
08147                  !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
08148                 enable = ISC_FALSE;
08149         else if (!strcasecmp(ptr, "check"))
08150                 set = ISC_FALSE;
08151         else
08152                 return (DNS_R_SYNTAX);
08153 
08154         /* Look for the view name. */
08155         viewname = next_token(&args, " \t");
08156 
08157         result = isc_task_beginexclusive(server->task);
08158         RUNTIME_CHECK(result == ISC_R_SUCCESS);
08159         for (view = ISC_LIST_HEAD(server->viewlist);
08160              view != NULL;
08161              view = ISC_LIST_NEXT(view, link))
08162         {
08163                 if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
08164                         continue;
08165                 CHECK(dns_view_flushcache(view));
08166 
08167                 if (set) {
08168                         view->enablevalidation = enable;
08169                         changed = ISC_TRUE;
08170                 } else {
08171                         if (!first)
08172                                 CHECK(putstr(text, "\n"));
08173                         CHECK(putstr(text, "DNSSEC validation is "));
08174                         CHECK(putstr(text, view->enablevalidation
08175                                             ? "enabled" : "disabled"));
08176                         CHECK(putstr(text, " (view "));
08177                         CHECK(putstr(text, view->name));
08178                         CHECK(putstr(text, ")"));
08179                         CHECK(putnull(text));
08180                         first = ISC_FALSE;
08181                 }
08182         }
08183 
08184         if (!set)
08185                 result = ISC_R_SUCCESS;
08186         else if (changed)
08187                 result = ISC_R_SUCCESS;
08188         else
08189                 result = ISC_R_FAILURE;
08190  cleanup:
08191         isc_task_endexclusive(server->task);
08192         return (result);
08193 }
08194 
08195 isc_result_t
08196 ns_server_flushcache(ns_server_t *server, char *args) {
08197         char *ptr, *viewname;
08198         dns_view_t *view;
08199         isc_boolean_t flushed;
08200         isc_boolean_t found;
08201         isc_result_t result;
08202         ns_cache_t *nsc;
08203 
08204         /* Skip the command name. */
08205         ptr = next_token(&args, " \t");
08206         if (ptr == NULL)
08207                 return (ISC_R_UNEXPECTEDEND);
08208 
08209         /* Look for the view name. */
08210         viewname = next_token(&args, " \t");
08211 
08212         result = isc_task_beginexclusive(server->task);
08213         RUNTIME_CHECK(result == ISC_R_SUCCESS);
08214         flushed = ISC_TRUE;
08215         found = ISC_FALSE;
08216 
08217         /*
08218          * Flushing a cache is tricky when caches are shared by multiple views.
08219          * We first identify which caches should be flushed in the local cache
08220          * list, flush these caches, and then update other views that refer to
08221          * the flushed cache DB.
08222          */
08223         if (viewname != NULL) {
08224                 /*
08225                  * Mark caches that need to be flushed.  This is an O(#view^2)
08226                  * operation in the very worst case, but should be normally
08227                  * much more lightweight because only a few (most typically just
08228                  * one) views will match.
08229                  */
08230                 for (view = ISC_LIST_HEAD(server->viewlist);
08231                      view != NULL;
08232                      view = ISC_LIST_NEXT(view, link))
08233                 {
08234                         if (strcasecmp(viewname, view->name) != 0)
08235                                 continue;
08236                         found = ISC_TRUE;
08237                         for (nsc = ISC_LIST_HEAD(server->cachelist);
08238                              nsc != NULL;
08239                              nsc = ISC_LIST_NEXT(nsc, link)) {
08240                                 if (nsc->cache == view->cache)
08241                                         break;
08242                         }
08243                         INSIST(nsc != NULL);
08244                         nsc->needflush = ISC_TRUE;
08245                 }
08246         } else
08247                 found = ISC_TRUE;
08248 
08249         /* Perform flush */
08250         for (nsc = ISC_LIST_HEAD(server->cachelist);
08251              nsc != NULL;
08252              nsc = ISC_LIST_NEXT(nsc, link)) {
08253                 if (viewname != NULL && !nsc->needflush)
08254                         continue;
08255                 nsc->needflush = ISC_TRUE;
08256                 result = dns_view_flushcache2(nsc->primaryview, ISC_FALSE);
08257                 if (result != ISC_R_SUCCESS) {
08258                         flushed = ISC_FALSE;
08259                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08260                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
08261                                       "flushing cache in view '%s' failed: %s",
08262                                       nsc->primaryview->name,
08263                                       isc_result_totext(result));
08264                 }
08265         }
08266 
08267         /*
08268          * Fix up views that share a flushed cache: let the views update the
08269          * cache DB they're referring to.  This could also be an expensive
08270          * operation, but should typically be marginal: the inner loop is only
08271          * necessary for views that share a cache, and if there are many such
08272          * views the number of shared cache should normally be small.
08273          * A worst case is that we have n views and n/2 caches, each shared by
08274          * two views.  Then this will be a O(n^2/4) operation.
08275          */
08276         for (view = ISC_LIST_HEAD(server->viewlist);
08277              view != NULL;
08278              view = ISC_LIST_NEXT(view, link))
08279         {
08280                 if (!dns_view_iscacheshared(view))
08281                         continue;
08282                 for (nsc = ISC_LIST_HEAD(server->cachelist);
08283                      nsc != NULL;
08284                      nsc = ISC_LIST_NEXT(nsc, link)) {
08285                         if (!nsc->needflush || nsc->cache != view->cache)
08286                                 continue;
08287                         result = dns_view_flushcache2(view, ISC_TRUE);
08288                         if (result != ISC_R_SUCCESS) {
08289                                 flushed = ISC_FALSE;
08290                                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08291                                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
08292                                               "fixing cache in view '%s' "
08293                                               "failed: %s", view->name,
08294                                               isc_result_totext(result));
08295                         }
08296                 }
08297         }
08298 
08299         /* Cleanup the cache list. */
08300         for (nsc = ISC_LIST_HEAD(server->cachelist);
08301              nsc != NULL;
08302              nsc = ISC_LIST_NEXT(nsc, link)) {
08303                 nsc->needflush = ISC_FALSE;
08304         }
08305 
08306         if (flushed && found) {
08307                 if (viewname != NULL)
08308                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08309                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
08310                                       "flushing cache in view '%s' succeeded",
08311                                       viewname);
08312                 else
08313                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08314                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
08315                                       "flushing caches in all views succeeded");
08316                 result = ISC_R_SUCCESS;
08317         } else {
08318                 if (!found) {
08319                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08320                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
08321                                       "flushing cache in view '%s' failed: "
08322                                       "view not found", viewname);
08323                         result = ISC_R_NOTFOUND;
08324                 } else
08325                         result = ISC_R_FAILURE;
08326         }
08327         isc_task_endexclusive(server->task);
08328         return (result);
08329 }
08330 
08331 isc_result_t
08332 ns_server_flushnode(ns_server_t *server, char *args, isc_boolean_t tree) {
08333         char *target, *viewname;
08334         dns_view_t *view;
08335         isc_boolean_t flushed;
08336         isc_boolean_t found;
08337         isc_result_t result;
08338         isc_buffer_t b;
08339         dns_fixedname_t fixed;
08340         dns_name_t *name;
08341 
08342         /* Skip the command name. */
08343         target = next_token(&args, " \t");
08344         if (target == NULL)
08345                 return (ISC_R_UNEXPECTEDEND);
08346 
08347         /* Find the domain name to flush. */
08348         target = next_token(&args, " \t");
08349         if (target == NULL)
08350                 return (ISC_R_UNEXPECTEDEND);
08351 
08352         isc_buffer_constinit(&b, target, strlen(target));
08353         isc_buffer_add(&b, strlen(target));
08354         dns_fixedname_init(&fixed);
08355         name = dns_fixedname_name(&fixed);
08356         result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
08357         if (result != ISC_R_SUCCESS)
08358                 return (result);
08359 
08360         /* Look for the view name. */
08361         viewname = next_token(&args, " \t");
08362 
08363         result = isc_task_beginexclusive(server->task);
08364         RUNTIME_CHECK(result == ISC_R_SUCCESS);
08365         flushed = ISC_TRUE;
08366         found = ISC_FALSE;
08367         for (view = ISC_LIST_HEAD(server->viewlist);
08368              view != NULL;
08369              view = ISC_LIST_NEXT(view, link))
08370         {
08371                 if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
08372                         continue;
08373                 found = ISC_TRUE;
08374                 /*
08375                  * It's a little inefficient to try flushing name for all views
08376                  * if some of the views share a single cache.  But since the
08377                  * operation is lightweight we prefer simplicity here.
08378                  */
08379                 result = dns_view_flushnode(view, name, tree);
08380                 if (result != ISC_R_SUCCESS) {
08381                         flushed = ISC_FALSE;
08382                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08383                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
08384                                       "flushing %s '%s' in cache view '%s' "
08385                                       "failed: %s",
08386                                       tree ? "tree" : "name",
08387                                       target, view->name,
08388                                       isc_result_totext(result));
08389                 }
08390         }
08391         if (flushed && found) {
08392                 if (viewname != NULL)
08393                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08394                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
08395                                       "flushing %s '%s' in cache view '%s' "
08396                                       "succeeded",
08397                                       tree ? "tree" : "name",
08398                                       target, viewname);
08399                 else
08400                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08401                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
08402                                       "flushing %s '%s' in all cache views "
08403                                       "succeeded",
08404                                       tree ? "tree" : "name",
08405                                       target);
08406                 result = ISC_R_SUCCESS;
08407         } else {
08408                 if (!found)
08409                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08410                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
08411                                       "flushing %s '%s' in cache view '%s' "
08412                                       "failed: view not found",
08413                                       tree ? "tree" : "name",
08414                                       target, viewname);
08415                 result = ISC_R_FAILURE;
08416         }
08417         isc_task_endexclusive(server->task);
08418         return (result);
08419 }
08420 
08421 isc_result_t
08422 ns_server_status(ns_server_t *server, isc_buffer_t **text) {
08423         isc_result_t result;
08424         unsigned int zonecount, xferrunning, xferdeferred, soaqueries;
08425         unsigned int automatic;
08426         const char *ob = "", *cb = "", *alt = "";
08427         char boottime[ISC_FORMATHTTPTIMESTAMP_SIZE];
08428         char configtime[ISC_FORMATHTTPTIMESTAMP_SIZE];
08429         char line[1024];
08430 
08431         if (ns_g_server->version_set) {
08432                 ob = " (";
08433                 cb = ")";
08434                 if (ns_g_server->version == NULL)
08435                         alt = "version.bind/txt/ch disabled";
08436                 else
08437                         alt = ns_g_server->version;
08438         }
08439         zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
08440         xferrunning = dns_zonemgr_getcount(server->zonemgr,
08441                                            DNS_ZONESTATE_XFERRUNNING);
08442         xferdeferred = dns_zonemgr_getcount(server->zonemgr,
08443                                             DNS_ZONESTATE_XFERDEFERRED);
08444         soaqueries = dns_zonemgr_getcount(server->zonemgr,
08445                                           DNS_ZONESTATE_SOAQUERY);
08446         automatic = dns_zonemgr_getcount(server->zonemgr,
08447                                          DNS_ZONESTATE_AUTOMATIC);
08448 
08449         isc_time_formathttptimestamp(&ns_g_boottime, boottime,
08450                                      sizeof(boottime));
08451         isc_time_formathttptimestamp(&ns_g_configtime, configtime,
08452                                      sizeof(configtime));
08453 
08454         snprintf(line, sizeof(line), "version: %s %s%s%s <id:%s>%s%s%s\n",
08455                  ns_g_product, ns_g_version,
08456                  (*ns_g_description != '\0') ? " " : "",
08457                  ns_g_description, ns_g_srcid, ob, alt, cb);
08458         CHECK(putstr(text, line));
08459 
08460         snprintf(line, sizeof(line), "boot time: %s\n", boottime);
08461         CHECK(putstr(text, line));
08462 
08463         snprintf(line, sizeof(line), "last configured: %s\n", configtime);
08464         CHECK(putstr(text, line));
08465 
08466 #ifdef ISC_PLATFORM_USETHREADS
08467         snprintf(line, sizeof(line), "CPUs found: %u\n", ns_g_cpus_detected);
08468         CHECK(putstr(text, line));
08469 
08470         snprintf(line, sizeof(line), "worker threads: %u\n", ns_g_cpus);
08471         CHECK(putstr(text, line));
08472 
08473         snprintf(line, sizeof(line), "UDP listeners per interface: %u\n",
08474                  ns_g_udpdisp);
08475         CHECK(putstr(text, line));
08476 #else
08477         snprintf(line, sizeof(line), "CPUs found: N/A (threads disabled)\n");
08478         CHECK(putstr(text, line));
08479 #endif
08480 
08481         snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n",
08482                      zonecount, automatic);
08483         CHECK(putstr(text, line));
08484 
08485         snprintf(line, sizeof(line), "debug level: %d\n", ns_g_debuglevel);
08486         CHECK(putstr(text, line));
08487 
08488         snprintf(line, sizeof(line), "xfers running: %u\n", xferrunning);
08489         CHECK(putstr(text, line));
08490 
08491         snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred);
08492         CHECK(putstr(text, line));
08493 
08494         snprintf(line, sizeof(line), "soa queries in progress: %u\n",
08495                      soaqueries);
08496         CHECK(putstr(text, line));
08497 
08498         snprintf(line, sizeof(line), "query logging is %s\n",
08499                      server->log_queries ? "ON" : "OFF");
08500         CHECK(putstr(text, line));
08501 
08502         snprintf(line, sizeof(line), "recursive clients: %d/%d/%d\n",
08503                      server->recursionquota.used, server->recursionquota.soft,
08504                      server->recursionquota.max);
08505         CHECK(putstr(text, line));
08506 
08507         snprintf(line, sizeof(line), "tcp clients: %d/%d\n",
08508                      server->tcpquota.used, server->tcpquota.max);
08509         CHECK(putstr(text, line));
08510 
08511         CHECK(putstr(text, "server is up and running"));
08512         CHECK(putnull(text));
08513 
08514         return (ISC_R_SUCCESS);
08515  cleanup:
08516         return (result);
08517 }
08518 
08519 isc_result_t
08520 ns_server_testgen(char *args, isc_buffer_t **text) {
08521         isc_result_t result;
08522         char *ptr;
08523         unsigned long count;
08524         unsigned long i;
08525         const unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
08526 
08527         /* Skip the command name. */
08528         ptr = next_token(&args, " \t");
08529         if (ptr == NULL)
08530                 return (ISC_R_UNEXPECTEDEND);
08531 
08532         ptr = next_token(&args, " \t");
08533         if (ptr == NULL)
08534                 count = 26;
08535         else
08536                 count = strtoul(ptr, NULL, 10);
08537 
08538         CHECK(isc_buffer_reserve(text, count));
08539         for (i = 0; i < count; i++)
08540                 CHECK(putuint8(text, chars[i % (sizeof(chars) - 1)]));
08541 
08542         CHECK(putnull(text));
08543 
08544  cleanup:
08545         return (result);
08546 }
08547 
08548 static isc_result_t
08549 delete_keynames(dns_tsig_keyring_t *ring, char *target,
08550                 unsigned int *foundkeys)
08551 {
08552         char namestr[DNS_NAME_FORMATSIZE];
08553         isc_result_t result;
08554         dns_rbtnodechain_t chain;
08555         dns_name_t foundname;
08556         dns_fixedname_t fixedorigin;
08557         dns_name_t *origin;
08558         dns_rbtnode_t *node;
08559         dns_tsigkey_t *tkey;
08560 
08561         dns_name_init(&foundname, NULL);
08562         dns_fixedname_init(&fixedorigin);
08563         origin = dns_fixedname_name(&fixedorigin);
08564 
08565  again:
08566         dns_rbtnodechain_init(&chain, ring->mctx);
08567         result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
08568                                         origin);
08569         if (result == ISC_R_NOTFOUND) {
08570                 dns_rbtnodechain_invalidate(&chain);
08571                 return (ISC_R_SUCCESS);
08572         }
08573         if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
08574                 dns_rbtnodechain_invalidate(&chain);
08575                 return (result);
08576         }
08577 
08578         for (;;) {
08579                 node = NULL;
08580                 dns_rbtnodechain_current(&chain, &foundname, origin, &node);
08581                 tkey = node->data;
08582 
08583                 if (tkey != NULL) {
08584                         if (!tkey->generated)
08585                                 goto nextkey;
08586 
08587                         dns_name_format(&tkey->name, namestr, sizeof(namestr));
08588                         if (strcmp(namestr, target) == 0) {
08589                                 (*foundkeys)++;
08590                                 dns_rbtnodechain_invalidate(&chain);
08591                                 (void)dns_rbt_deletename(ring->keys,
08592                                                          &tkey->name,
08593                                                          ISC_FALSE);
08594                                 goto again;
08595                         }
08596                 }
08597 
08598         nextkey:
08599                 result = dns_rbtnodechain_next(&chain, &foundname, origin);
08600                 if (result == ISC_R_NOMORE)
08601                         break;
08602                 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
08603                         dns_rbtnodechain_invalidate(&chain);
08604                         return (result);
08605                 }
08606         }
08607 
08608         return (ISC_R_SUCCESS);
08609 }
08610 
08611 isc_result_t
08612 ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t **text) {
08613         isc_result_t result;
08614         dns_view_t *view;
08615         unsigned int foundkeys = 0;
08616         char *target, *viewname;
08617         char fbuf[16];
08618 
08619         (void)next_token(&command, " \t");  /* skip command name */
08620         target = next_token(&command, " \t");
08621         if (target == NULL)
08622                 return (ISC_R_UNEXPECTEDEND);
08623         viewname = next_token(&command, " \t");
08624 
08625         result = isc_task_beginexclusive(server->task);
08626         RUNTIME_CHECK(result == ISC_R_SUCCESS);
08627         for (view = ISC_LIST_HEAD(server->viewlist);
08628              view != NULL;
08629              view = ISC_LIST_NEXT(view, link)) {
08630                 if (viewname == NULL || strcmp(view->name, viewname) == 0) {
08631                         RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
08632                         result = delete_keynames(view->dynamickeys, target,
08633                                                  &foundkeys);
08634                         RWUNLOCK(&view->dynamickeys->lock,
08635                                  isc_rwlocktype_write);
08636                         if (result != ISC_R_SUCCESS) {
08637                                 isc_task_endexclusive(server->task);
08638                                 return (result);
08639                         }
08640                 }
08641         }
08642         isc_task_endexclusive(server->task);
08643 
08644         snprintf(fbuf, sizeof(fbuf), "%d", foundkeys);
08645 
08646         CHECK(putstr(text, fbuf));
08647         CHECK(putstr(text, " tsig keys deleted."));
08648         CHECK(putnull(text));
08649 
08650  cleanup:
08651         return (result);
08652 }
08653 
08654 static isc_result_t
08655 list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t **text,
08656               unsigned int *foundkeys)
08657 {
08658         char namestr[DNS_NAME_FORMATSIZE];
08659         char creatorstr[DNS_NAME_FORMATSIZE];
08660         isc_result_t result;
08661         dns_rbtnodechain_t chain;
08662         dns_name_t foundname;
08663         dns_fixedname_t fixedorigin;
08664         dns_name_t *origin;
08665         dns_rbtnode_t *node;
08666         dns_tsigkey_t *tkey;
08667         const char *viewname;
08668 
08669         if (view != NULL)
08670                 viewname = view->name;
08671         else
08672                 viewname = "(global)";
08673 
08674         dns_name_init(&foundname, NULL);
08675         dns_fixedname_init(&fixedorigin);
08676         origin = dns_fixedname_name(&fixedorigin);
08677         dns_rbtnodechain_init(&chain, ring->mctx);
08678         result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
08679                                         origin);
08680         if (result == ISC_R_NOTFOUND) {
08681                 dns_rbtnodechain_invalidate(&chain);
08682                 return (ISC_R_SUCCESS);
08683         }
08684         if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
08685                 dns_rbtnodechain_invalidate(&chain);
08686                 return (result);
08687         }
08688 
08689         for (;;) {
08690                 node = NULL;
08691                 dns_rbtnodechain_current(&chain, &foundname, origin, &node);
08692                 tkey = node->data;
08693 
08694                 if (tkey != NULL) {
08695                         dns_name_format(&tkey->name, namestr, sizeof(namestr));
08696                         if (tkey->generated) {
08697                                 dns_name_format(tkey->creator, creatorstr,
08698                                                 sizeof(creatorstr));
08699                                 if (*foundkeys != 0)
08700                                         CHECK(putstr(text, "\n"));
08701                                 CHECK(putstr(text, "view \""));
08702                                 CHECK(putstr(text, viewname));
08703                                 CHECK(putstr(text,
08704                                              "\"; type \"dynamic\"; key \""));
08705                                 CHECK(putstr(text, namestr));
08706                                 CHECK(putstr(text, "\"; creator \""));
08707                                 CHECK(putstr(text, creatorstr));
08708                                 CHECK(putstr(text, "\";"));
08709                         } else {
08710                                 if (*foundkeys != 0)
08711                                         CHECK(putstr(text, "\n"));
08712                                 CHECK(putstr(text, "view \""));
08713                                 CHECK(putstr(text, viewname));
08714                                 CHECK(putstr(text,
08715                                              "\"; type \"static\"; key \""));
08716                                 CHECK(putstr(text, namestr));
08717                                 CHECK(putstr(text, "\";"));
08718                         }
08719                         (*foundkeys)++;
08720                 }
08721                 result = dns_rbtnodechain_next(&chain, &foundname, origin);
08722                 if (result == ISC_R_NOMORE || result == DNS_R_NEWORIGIN)
08723                         break;
08724         }
08725 
08726         return (ISC_R_SUCCESS);
08727  cleanup:
08728         dns_rbtnodechain_invalidate(&chain);
08729         return (result);
08730 }
08731 
08732 isc_result_t
08733 ns_server_tsiglist(ns_server_t *server, isc_buffer_t **text) {
08734         isc_result_t result;
08735         dns_view_t *view;
08736         unsigned int foundkeys = 0;
08737 
08738         result = isc_task_beginexclusive(server->task);
08739         RUNTIME_CHECK(result == ISC_R_SUCCESS);
08740         for (view = ISC_LIST_HEAD(server->viewlist);
08741              view != NULL;
08742              view = ISC_LIST_NEXT(view, link)) {
08743                 RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
08744                 result = list_keynames(view, view->statickeys, text,
08745                                        &foundkeys);
08746                 RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
08747                 if (result != ISC_R_SUCCESS) {
08748                         isc_task_endexclusive(server->task);
08749                         return (result);
08750                 }
08751                 RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
08752                 result = list_keynames(view, view->dynamickeys, text,
08753                                        &foundkeys);
08754                 RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
08755                 if (result != ISC_R_SUCCESS) {
08756                         isc_task_endexclusive(server->task);
08757                         return (result);
08758                 }
08759         }
08760         isc_task_endexclusive(server->task);
08761 
08762         if (foundkeys == 0)
08763                 CHECK(putstr(text, "no tsig keys found."));
08764 
08765         if (isc_buffer_usedlength(*text) > 0)
08766                 CHECK(putnull(text));
08767 
08768  cleanup:
08769         return (result);
08770 }
08771 
08772 /*
08773  * Act on a "sign" or "loadkeys" command from the command channel.
08774  */
08775 isc_result_t
08776 ns_server_rekey(ns_server_t *server, char *args, isc_buffer_t **text) {
08777         isc_result_t result;
08778         dns_zone_t *zone = NULL;
08779         dns_zonetype_t type;
08780         isc_uint16_t keyopts;
08781         isc_boolean_t fullsign = ISC_FALSE;
08782 
08783         if (strncasecmp(args, NS_COMMAND_SIGN, strlen(NS_COMMAND_SIGN)) == 0)
08784             fullsign = ISC_TRUE;
08785 
08786         result = zone_from_args(server, args, NULL, &zone, NULL,
08787                                 text, ISC_TRUE);
08788         if (result != ISC_R_SUCCESS)
08789                 return (result);
08790         if (zone == NULL)
08791                 return (ISC_R_UNEXPECTEDEND);   /* XXX: or do all zones? */
08792 
08793         type = dns_zone_gettype(zone);
08794         if (type != dns_zone_master) {
08795                 dns_zone_detach(&zone);
08796                 return (DNS_R_NOTMASTER);
08797         }
08798 
08799         keyopts = dns_zone_getkeyopts(zone);
08800 
08801         /* "rndc loadkeys" requires "auto-dnssec maintain". */
08802         if ((keyopts & DNS_ZONEKEY_ALLOW) == 0)
08803                 result = ISC_R_NOPERM;
08804         else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign)
08805                 result = ISC_R_NOPERM;
08806         else
08807                 dns_zone_rekey(zone, fullsign);
08808 
08809         dns_zone_detach(&zone);
08810         return (result);
08811 }
08812 
08813 /*
08814  * Act on a "sync" command from the command channel.
08815 */
08816 static isc_result_t
08817 synczone(dns_zone_t *zone, void *uap) {
08818         isc_boolean_t cleanup = *(isc_boolean_t *)uap;
08819         isc_result_t result;
08820         dns_zone_t *raw = NULL;
08821         char *journal;
08822 
08823         dns_zone_getraw(zone, &raw);
08824         if (raw != NULL) {
08825                 synczone(raw, uap);
08826                 dns_zone_detach(&raw);
08827         }
08828 
08829         result = dns_zone_flush(zone);
08830         if (result != ISC_R_SUCCESS)
08831                 cleanup = ISC_FALSE;
08832         if (cleanup) {
08833                 journal = dns_zone_getjournal(zone);
08834                 if (journal != NULL)
08835                         (void)isc_file_remove(journal);
08836         }
08837 
08838         return (result);
08839 }
08840 
08841 isc_result_t
08842 ns_server_sync(ns_server_t *server, char *args, isc_buffer_t **text) {
08843         isc_result_t result, tresult;
08844         dns_view_t *view;
08845         dns_zone_t *zone = NULL;
08846         char classstr[DNS_RDATACLASS_FORMATSIZE];
08847         char zonename[DNS_NAME_FORMATSIZE];
08848         const char *vname, *sep, *arg;
08849         isc_boolean_t cleanup = ISC_FALSE;
08850 
08851         (void) next_token(&args, " \t");
08852 
08853         arg = next_token(&args, " \t");
08854         if (arg != NULL &&
08855             (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0)) {
08856                 cleanup = ISC_TRUE;
08857                 arg = next_token(&args, " \t");
08858         }
08859 
08860         result = zone_from_args(server, args, arg, &zone, NULL,
08861                                 text, ISC_FALSE);
08862         if (result != ISC_R_SUCCESS)
08863                 return (result);
08864 
08865         if (zone == NULL) {
08866                 result = isc_task_beginexclusive(server->task);
08867                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
08868                 tresult = ISC_R_SUCCESS;
08869                 for (view = ISC_LIST_HEAD(server->viewlist);
08870                      view != NULL;
08871                      view = ISC_LIST_NEXT(view, link)) {
08872                         result = dns_zt_apply(view->zonetable, ISC_FALSE,
08873                                               synczone, &cleanup);
08874                         if (result != ISC_R_SUCCESS &&
08875                             tresult == ISC_R_SUCCESS)
08876                                 tresult = result;
08877                 }
08878                 isc_task_endexclusive(server->task);
08879                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08880                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
08881                               "dumping all zones%s: %s",
08882                               cleanup ? ", removing journal files" : "",
08883                               isc_result_totext(result));
08884                 return (tresult);
08885         }
08886 
08887         result = isc_task_beginexclusive(server->task);
08888         RUNTIME_CHECK(result == ISC_R_SUCCESS);
08889         result = synczone(zone, &cleanup);
08890         isc_task_endexclusive(server->task);
08891 
08892         view = dns_zone_getview(zone);
08893         if (strcmp(view->name, "_default") == 0 ||
08894             strcmp(view->name, "_bind") == 0)
08895         {
08896                 vname = "";
08897                 sep = "";
08898         } else {
08899                 vname = view->name;
08900                 sep = " ";
08901         }
08902         dns_rdataclass_format(dns_zone_getclass(zone), classstr,
08903                               sizeof(classstr));
08904         dns_name_format(dns_zone_getorigin(zone),
08905                         zonename, sizeof(zonename));
08906         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08907                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
08908                       "sync: dumping zone '%s/%s'%s%s%s: %s",
08909                       zonename, classstr, sep, vname,
08910                       cleanup ? ", removing journal file" : "",
08911                       isc_result_totext(result));
08912         dns_zone_detach(&zone);
08913         return (result);
08914 }
08915 
08916 /*
08917  * Act on a "freeze" or "thaw" command from the command channel.
08918  */
08919 isc_result_t
08920 ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
08921                  isc_buffer_t **text)
08922 {
08923         isc_result_t result, tresult;
08924         dns_zone_t *zone = NULL, *raw = NULL;
08925         dns_zonetype_t type;
08926         char classstr[DNS_RDATACLASS_FORMATSIZE];
08927         char zonename[DNS_NAME_FORMATSIZE];
08928         dns_view_t *view;
08929         const char *vname, *sep;
08930         isc_boolean_t frozen;
08931         const char *msg = NULL;
08932 
08933         result = zone_from_args(server, args, NULL, &zone, NULL,
08934                                 text, ISC_TRUE);
08935         if (result != ISC_R_SUCCESS)
08936                 return (result);
08937         if (zone == NULL) {
08938                 result = isc_task_beginexclusive(server->task);
08939                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
08940                 tresult = ISC_R_SUCCESS;
08941                 for (view = ISC_LIST_HEAD(server->viewlist);
08942                      view != NULL;
08943                      view = ISC_LIST_NEXT(view, link)) {
08944                         result = dns_view_freezezones(view, freeze);
08945                         if (result != ISC_R_SUCCESS &&
08946                             tresult == ISC_R_SUCCESS)
08947                                 tresult = result;
08948                 }
08949                 isc_task_endexclusive(server->task);
08950                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
08951                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
08952                               "%s all zones: %s",
08953                               freeze ? "freezing" : "thawing",
08954                               isc_result_totext(tresult));
08955                 return (tresult);
08956         }
08957         dns_zone_getraw(zone, &raw);
08958         if (raw != NULL) {
08959                 dns_zone_detach(&zone);
08960                 dns_zone_attach(raw, &zone);
08961                 dns_zone_detach(&raw);
08962         }
08963         type = dns_zone_gettype(zone);
08964         if (type != dns_zone_master) {
08965                 dns_zone_detach(&zone);
08966                 return (DNS_R_NOTMASTER);
08967         }
08968 
08969         if (freeze && !dns_zone_isdynamic(zone, ISC_TRUE)) {
08970                 dns_zone_detach(&zone);
08971                 return (DNS_R_NOTDYNAMIC);
08972         }
08973 
08974         result = isc_task_beginexclusive(server->task);
08975         RUNTIME_CHECK(result == ISC_R_SUCCESS);
08976         frozen = dns_zone_getupdatedisabled(zone);
08977         if (freeze) {
08978                 if (frozen) {
08979                         msg = "WARNING: The zone was already frozen.\n"
08980                               "Someone else may be editing it or "
08981                               "it may still be re-loading.";
08982                         result = DNS_R_FROZEN;
08983                 }
08984                 if (result == ISC_R_SUCCESS) {
08985                         result = dns_zone_flush(zone);
08986                         if (result != ISC_R_SUCCESS)
08987                                 msg = "Flushing the zone updates to "
08988                                       "disk failed.";
08989                 }
08990                 if (result == ISC_R_SUCCESS)
08991                         dns_zone_setupdatedisabled(zone, freeze);
08992         } else {
08993                 if (frozen) {
08994                         result = dns_zone_loadandthaw(zone);
08995                         switch (result) {
08996                         case ISC_R_SUCCESS:
08997                         case DNS_R_UPTODATE:
08998                                 msg = "The zone reload and thaw was "
08999                                       "successful.";
09000                                 result = ISC_R_SUCCESS;
09001                                 break;
09002                         case DNS_R_CONTINUE:
09003                                 msg = "A zone reload and thaw was started.\n"
09004                                       "Check the logs to see the result.";
09005                                 result = ISC_R_SUCCESS;
09006                                 break;
09007                         }
09008                 }
09009         }
09010         isc_task_endexclusive(server->task);
09011 
09012         if (msg != NULL) {
09013                 (void) putstr(text, msg);
09014                 (void) putnull(text);
09015         }
09016 
09017         view = dns_zone_getview(zone);
09018         if (strcmp(view->name, "_default") == 0 ||
09019             strcmp(view->name, "_bind") == 0)
09020         {
09021                 vname = "";
09022                 sep = "";
09023         } else {
09024                 vname = view->name;
09025                 sep = " ";
09026         }
09027         dns_rdataclass_format(dns_zone_getclass(zone), classstr,
09028                               sizeof(classstr));
09029         dns_name_format(dns_zone_getorigin(zone),
09030                         zonename, sizeof(zonename));
09031         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
09032                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
09033                       "%s zone '%s/%s'%s%s: %s",
09034                       freeze ? "freezing" : "thawing",
09035                       zonename, classstr, sep, vname,
09036                       isc_result_totext(result));
09037         dns_zone_detach(&zone);
09038         return (result);
09039 }
09040 
09041 #ifdef HAVE_LIBSCF
09042 /*
09043  * This function adds a message for rndc to echo if named
09044  * is managed by smf and is also running chroot.
09045  */
09046 isc_result_t
09047 ns_smf_add_message(isc_buffer_t **text) {
09048         return (putstr(text, "use svcadm(1M) to manage named"));
09049 }
09050 #endif /* HAVE_LIBSCF */
09051 
09052 /*
09053  * Emit a comment at the top of the nzf file containing the viewname
09054  * Expects the fp to already be open for writing
09055  */
09056 #define HEADER1 "# New zone file for view: "
09057 #define HEADER2 "\n# This file contains configuration for zones added by\n" \
09058                 "# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
09059 static isc_result_t
09060 add_comment(FILE *fp, const char *viewname) {
09061         isc_result_t result;
09062         CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
09063         CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
09064         CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
09065  cleanup:
09066         return (result);
09067 }
09068 
09069 static isc_result_t
09070 nzf_remove(const char *nzfile, const char *viewname, const char *zonename) {
09071         isc_result_t result;
09072         FILE *ifp = NULL, *ofp = NULL;
09073         size_t znamelen = 0;
09074         char tmp[1024], buf[1024];
09075         isc_boolean_t inheader = ISC_TRUE;
09076 
09077         znamelen = strlen(zonename);
09078 
09079         /* Rewrite zone list */
09080         result = isc_stdio_open(nzfile, "r", &ifp);
09081         if (ifp != NULL && result == ISC_R_SUCCESS) {
09082                 char *found = NULL, *p = NULL;
09083                 size_t n;
09084 
09085                 /* Create a temporary file */
09086                 CHECK(isc_file_template("", "nzf-XXXXXXXX", tmp, sizeof(tmp)));
09087                 CHECK(isc_file_openunique(tmp, &ofp));
09088                 CHECK(add_comment(ofp, viewname));
09089 
09090                 /* Look for the entry for that zone */
09091                 while (fgets(buf, 1024, ifp)) {
09092                         /* Skip initial comment, if any */
09093                         if (inheader && *buf == '#')
09094                                 continue;
09095                         if (*buf != '#')
09096                                 inheader = ISC_FALSE;
09097 
09098                         /*
09099                          * Any other lines not starting with zone, copy
09100                          * them out and continue.
09101                          */
09102                         if (strncasecmp(buf, "zone", 4) != 0) {
09103                                 fputs(buf, ofp);
09104                                 continue;
09105                         }
09106                         p = buf+4;
09107 
09108                         /* This is a zone; find its name. */
09109                         while (*p &&
09110                                ((*p == '"') || isspace((unsigned char)*p)))
09111                                 p++;
09112 
09113                         /*
09114                          * If it's not the zone we're looking for, copy
09115                          * it out and continue
09116                          */
09117                         if (strncasecmp(p, zonename, znamelen) != 0) {
09118                                 fputs(buf, ofp);
09119                                 continue;
09120                         }
09121 
09122                         /*
09123                          * But if it is the zone we want, skip over it
09124                          * so it will be omitted from the new file
09125                          */
09126                         p += znamelen;
09127                         if (isspace((unsigned char)*p) ||
09128                             *p == '"' || *p == '{') {
09129                                 /* This must be the entry */
09130                                 found = p;
09131                                 break;
09132                         }
09133 
09134                         /* Copy the buffer out and continue */
09135                         fputs(buf, ofp);
09136                 }
09137 
09138                 /* Skip over an option block (matching # of braces) */
09139                 if (found) {
09140                         int openbrace = 0, closebrace = 0;
09141                         for (;;) {
09142                                 while (*p) {
09143                                         if (*p == '{') openbrace++;
09144                                         if (*p == '}') closebrace++;
09145                                         p++;
09146                                 }
09147                                 if (openbrace && (openbrace == closebrace))
09148                                         break;
09149                                 if (!fgets(buf, 1024, ifp))
09150                                         break;
09151                                 p = buf;
09152                         }
09153 
09154                         /* Just spool the remainder of the file out */
09155                         result = isc_stdio_read(buf, 1, 1024, ifp, &n);
09156                         while (n > 0U) {
09157                                 if (result == ISC_R_EOF)
09158                                         result = ISC_R_SUCCESS;
09159                                 CHECK(result);
09160                                 isc_stdio_write(buf, 1, n, ofp, NULL);
09161                                 result = isc_stdio_read(buf, 1, 1024, ifp, &n);
09162                         }
09163 
09164                         /*
09165                          * Close files before overwriting the nzfile
09166                          * with the temporary file as it's necessary on
09167                          * some platforms (win32).
09168                          */
09169                         (void) isc_stdio_close(ifp);
09170                         ifp = NULL;
09171                         (void) isc_stdio_close(ofp);
09172                         ofp = NULL;
09173 
09174                         /* Move temporary into place */
09175                         CHECK(isc_file_rename(tmp, nzfile));
09176                 } else {
09177                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
09178                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
09179                                       "deleted zone %s was missing from "
09180                                       "new zone file", zonename);
09181                         goto cleanup;
09182                 }
09183         }
09184 
09185  cleanup:
09186         if (ifp != NULL)
09187                 (void) isc_stdio_close(ifp);
09188         if (ofp != NULL)
09189                 (void) isc_stdio_close(ofp);
09190 
09191         return (result);
09192 }
09193 
09194 static void
09195 dumpzone(void *arg, const char *buf, int len) {
09196         FILE *fp = arg;
09197 
09198         isc_stdio_write(buf, len, 1, fp, NULL);
09199 }
09200 
09201 static isc_result_t
09202 nzf_append(FILE *fp, const char *viewname, const cfg_obj_t *zconfig) {
09203         isc_result_t result;
09204         off_t offset;
09205 
09206         CHECK(isc_stdio_seek(fp, 0, SEEK_END));
09207 
09208         CHECK(isc_stdio_tell(fp, &offset));
09209         if (offset == 0)
09210                 CHECK(add_comment(fp, viewname));
09211 
09212         CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
09213         cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
09214         CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
09215 
09216  cleanup:
09217         return (result);
09218 }
09219 
09220 static isc_result_t
09221 newzone_parse(ns_server_t *server, char *args, dns_view_t **viewp,
09222               cfg_obj_t **zoneconfp, const cfg_obj_t **zoneobjp)
09223 {
09224         isc_result_t result;
09225         isc_buffer_t argbuf;
09226         cfg_obj_t *zoneconf = NULL;
09227         const cfg_obj_t *zlist = NULL;
09228         const cfg_obj_t *zoneobj = NULL;
09229         const cfg_obj_t *obj = NULL;
09230         const char *viewname = NULL;
09231         dns_rdataclass_t rdclass;
09232         dns_view_t *view = NULL;
09233 
09234         REQUIRE(viewp != NULL && *viewp == NULL);
09235 
09236         /* Try to parse the argument string */
09237         isc_buffer_init(&argbuf, args, (unsigned int) strlen(args));
09238         isc_buffer_add(&argbuf, strlen(args));
09239 
09240         /*
09241          * Convert the "addzone" or "modzone" to just "zone", for
09242          * the benefit of the parser
09243          */
09244         isc_buffer_forward(&argbuf, 3);
09245 
09246         cfg_parser_reset(ns_g_addparser);
09247         CHECK(cfg_parse_buffer(ns_g_addparser, &argbuf,
09248                                &cfg_type_addzoneconf, &zoneconf));
09249         CHECK(cfg_map_get(zoneconf, "zone", &zlist));
09250         if (! cfg_obj_islist(zlist))
09251                 CHECK(ISC_R_FAILURE);
09252 
09253         /* For now we only support adding one zone at a time */
09254         zoneobj = cfg_listelt_value(cfg_list_first(zlist));
09255 
09256         /* Make sense of optional class argument */
09257         obj = cfg_tuple_get(zoneobj, "class");
09258         CHECK(ns_config_getclass(obj, dns_rdataclass_in, &rdclass));
09259 
09260         /* Make sense of optional view argument */
09261         obj = cfg_tuple_get(zoneobj, "view");
09262         if (obj && cfg_obj_isstring(obj))
09263                 viewname = cfg_obj_asstring(obj);
09264         if (viewname == NULL || *viewname == '\0')
09265                 viewname = "_default";
09266         CHECK(dns_viewlist_find(&server->viewlist, viewname, rdclass, &view));
09267 
09268         *viewp = view;
09269         *zoneobjp = zoneobj;
09270         *zoneconfp = zoneconf;
09271 
09272         return (ISC_R_SUCCESS);
09273 
09274  cleanup:
09275         if (zoneconf != NULL)
09276                 cfg_obj_destroy(ns_g_addparser, &zoneconf);
09277         if (view != NULL)
09278                 dns_view_detach(&view);
09279 
09280         return (result);
09281 }
09282 
09283 static isc_result_t
09284 delete_zoneconf(cfg_parser_t *pctx, const cfg_obj_t *config,
09285                 const char *zname)
09286 {
09287         const cfg_listelt_t *elt = NULL;
09288         const cfg_obj_t *zl = NULL;
09289         cfg_list_t *list;
09290 
09291         REQUIRE(pctx != NULL);
09292         REQUIRE(config != NULL);
09293         REQUIRE(zname != NULL);
09294 
09295         cfg_map_get(config, "zone", &zl);
09296 
09297         if (! cfg_obj_islist(zl))
09298                 return (ISC_R_FAILURE);
09299         DE_CONST(&zl->value.list, list);
09300 
09301         for (elt = ISC_LIST_HEAD(*list);
09302              elt != NULL;
09303              elt = ISC_LIST_NEXT(elt, link))
09304         {
09305                 const cfg_obj_t *zconf = cfg_listelt_value(elt);
09306                 const char *zn;
09307                 cfg_listelt_t *e;
09308 
09309                 zn = cfg_obj_asstring(cfg_tuple_get(zconf, "name"));
09310                 if (strcasecmp(zname, zn) != 0)
09311                         continue;
09312 
09313                 DE_CONST(elt, e);
09314                 ISC_LIST_UNLINK(*list, e, link);
09315                 cfg_obj_destroy(pctx, &e->obj);
09316                 isc_mem_put(pctx->mctx, e, sizeof(*e));
09317                 return (ISC_R_SUCCESS);
09318         }
09319 
09320         return (ISC_R_NOTFOUND);
09321 }
09322 
09323 static isc_result_t
09324 do_addzone(ns_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
09325            dns_name_t *name, cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj,
09326            isc_buffer_t **text)
09327 {
09328         isc_result_t result, tresult;
09329         dns_zone_t *zone = NULL;
09330         FILE *fp = NULL;
09331 
09332         /* Zone shouldn't already exist */
09333         result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
09334         if (result == ISC_R_SUCCESS) {
09335                 result = ISC_R_EXISTS;
09336                 goto cleanup;
09337         } else if (result == DNS_R_PARTIALMATCH) {
09338                 /* Create our sub-zone anyway */
09339                 dns_zone_detach(&zone);
09340                 zone = NULL;
09341         } else if (result != ISC_R_NOTFOUND)
09342                 goto cleanup;
09343 
09344         /* Make sure we can open the configuration save file */
09345         result = isc_stdio_open(view->new_zone_file, "a", &fp);
09346         if (result != ISC_R_SUCCESS) {
09347                 TCHECK(putstr(text, "unable to open '"));
09348                 TCHECK(putstr(text, view->new_zone_file));
09349                 TCHECK(putstr(text, "': "));
09350                 TCHECK(putstr(text, isc_result_totext(result)));
09351                 goto cleanup;
09352         }
09353 
09354         /* Mark view unfrozen so that zone can be added */
09355         result = isc_task_beginexclusive(server->task);
09356         RUNTIME_CHECK(result == ISC_R_SUCCESS);
09357         dns_view_thaw(view);
09358         result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
09359                                 server->mctx, view, NULL, cfg->actx,
09360                                 ISC_TRUE, ISC_FALSE, ISC_FALSE);
09361         dns_view_freeze(view);
09362         isc_task_endexclusive(server->task);
09363         if (result != ISC_R_SUCCESS) {
09364                 TCHECK(putstr(text, "configure_zone failed: "));
09365                 TCHECK(putstr(text, isc_result_totext(result)));
09366                 goto cleanup;
09367         }
09368 
09369         /* Is it there yet? */
09370         CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone));
09371 
09372         /*
09373          * If there wasn't a previous newzone config, just save the one
09374          * we've created. If there was a previous one, merge the new
09375          * zone into it.
09376          */
09377         if (cfg->nzconfig == NULL)
09378                 cfg_obj_attach(zoneconf, &cfg->nzconfig);
09379         else {
09380                 cfg_obj_t *z;
09381                 DE_CONST(zoneobj, z);
09382                 CHECK(cfg_parser_mapadd(cfg->add_parser,
09383                                         cfg->nzconfig, z, "zone"));
09384         }
09385 
09386         /*
09387          * Load the zone from the master file.  If this fails, we'll
09388          * need to undo the configuration we've done already.
09389          */
09390         result = dns_zone_loadnew(zone);
09391         if (result != ISC_R_SUCCESS) {
09392                 dns_db_t *dbp = NULL;
09393 
09394                 TCHECK(putstr(text, "dns_zone_loadnew failed: "));
09395                 TCHECK(putstr(text, isc_result_totext(result)));
09396 
09397                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
09398                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
09399                               "addzone failed; reverting.");
09400 
09401                 /* If the zone loaded partially, unload it */
09402                 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
09403                         dns_db_detach(&dbp);
09404                         dns_zone_unload(zone);
09405                 }
09406 
09407                 /* Remove the zone from the zone table */
09408                 dns_zt_unmount(view->zonetable, zone);
09409                 goto cleanup;
09410         }
09411 
09412         /* Flag the zone as having been added at runtime */
09413         dns_zone_setadded(zone, ISC_TRUE);
09414 
09415         /* Emit the zone configuration */
09416         nzf_append(fp, view->name, zoneobj);
09417         result = ISC_R_SUCCESS;
09418 
09419  cleanup:
09420         if (fp != NULL)
09421                 (void) isc_stdio_close(fp);
09422         if (zone != NULL)
09423                 dns_zone_detach(&zone);
09424 
09425         return (result);
09426 }
09427 
09428 static isc_result_t
09429 do_modzone(ns_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
09430            dns_name_t *name, const char *zname, const cfg_obj_t *zoneobj,
09431            isc_buffer_t **text)
09432 {
09433         isc_result_t result, tresult;
09434         dns_zone_t *zone = NULL;
09435         isc_boolean_t added;
09436         FILE *fp = NULL;
09437         cfg_obj_t *z;
09438 
09439         /* Zone must already exist */
09440         result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
09441         if (result != ISC_R_SUCCESS)
09442                 goto cleanup;
09443 
09444         added = dns_zone_getadded(zone);
09445         dns_zone_detach(&zone);
09446 
09447         /* Make sure we can open the configuration save file */
09448         result = isc_stdio_open(view->new_zone_file, "a", &fp);
09449         if (result != ISC_R_SUCCESS) {
09450                 TCHECK(putstr(text, "unable to open '"));
09451                 TCHECK(putstr(text, view->new_zone_file));
09452                 TCHECK(putstr(text, "': "));
09453                 TCHECK(putstr(text, isc_result_totext(result)));
09454                 goto cleanup;
09455         }
09456         isc_stdio_close(fp);
09457         fp = NULL;
09458 
09459         cfg = (ns_cfgctx_t *) view->new_zone_config;
09460         if (cfg == NULL) {
09461                 TCHECK(putstr(text, "new zone config is not set"));
09462                 CHECK(ISC_R_FAILURE);
09463         }
09464 
09465         /* Reconfigure the zone */
09466         result = isc_task_beginexclusive(server->task);
09467         RUNTIME_CHECK(result == ISC_R_SUCCESS);
09468         dns_view_thaw(view);
09469         result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
09470                                 server->mctx, view, NULL, cfg->actx,
09471                                 ISC_TRUE, ISC_FALSE, ISC_TRUE);
09472         dns_view_freeze(view);
09473         isc_task_endexclusive(server->task);
09474         if (result != ISC_R_SUCCESS) {
09475                 TCHECK(putstr(text, "configure_zone failed: "));
09476                 TCHECK(putstr(text, isc_result_totext(result)));
09477                 goto cleanup;
09478         }
09479 
09480         /* Is it there yet? */
09481         CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone));
09482 
09483         /* Remove old zone from configuration (and NZF file if applicable) */
09484         if (added) {
09485                 delete_zoneconf(cfg->add_parser, cfg->nzconfig, zname);
09486                 nzf_remove(view->new_zone_file, view->name, zname);
09487         } else {
09488                 if (cfg->vconfig == NULL)
09489                         delete_zoneconf(cfg->conf_parser, cfg->config, zname);
09490                 else {
09491                         const cfg_obj_t *voptions =
09492                                 cfg_tuple_get(cfg->vconfig, "options");
09493                         delete_zoneconf(cfg->conf_parser, voptions, zname);
09494                 }
09495         }
09496 
09497         /* Load the zone from the master file if it needs reloading. */
09498         result = dns_zone_loadnew(zone);
09499         if (result != ISC_R_SUCCESS) {
09500                 dns_db_t *dbp = NULL;
09501 
09502                 TCHECK(putstr(text, "failed to load zone '"));
09503                 TCHECK(putstr(text, zname));
09504                 TCHECK(putstr(text, "': "));
09505                 TCHECK(putstr(text, isc_result_totext(result)));
09506                 TCHECK(putstr(text, "\nThe zone is no longer being served. "));
09507                 TCHECK(putstr(text, "Use 'rndc addzone' to correct\n"));
09508                 TCHECK(putstr(text, "the problem and restore service."));
09509 
09510                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
09511                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
09512                               "modzone failed; removing zone.");
09513 
09514                 /* If the zone loaded partially, unload it */
09515                 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
09516                         dns_db_detach(&dbp);
09517                         dns_zone_unload(zone);
09518                 }
09519 
09520                 /* Remove the zone from the zone table */
09521                 dns_zt_unmount(view->zonetable, zone);
09522                 goto cleanup;
09523         }
09524 
09525         /* Store the new zone configuration; also in NZF if applicable */
09526         DE_CONST(zoneobj, z);
09527         CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzconfig, z, "zone"));
09528 
09529         if (added) {
09530                 CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
09531                 nzf_append(fp, view->name, zoneobj);
09532                 (void) isc_stdio_close(fp);
09533                 fp = NULL;
09534 
09535                 TCHECK(putstr(text, "zone '"));
09536                 TCHECK(putstr(text, zname));
09537                 TCHECK(putstr(text, "' reconfigured."));
09538         } else {
09539                 TCHECK(putstr(text, "zone '"));
09540                 TCHECK(putstr(text, zname));
09541                 TCHECK(putstr(text, "' must also be reconfigured in\n"));
09542                 TCHECK(putstr(text, "named.conf to make changes permanent."));
09543         }
09544 
09545  cleanup:
09546         if (fp != NULL)
09547                 isc_stdio_close(fp);
09548         if (zone != NULL)
09549                 dns_zone_detach(&zone);
09550 
09551         return (result);
09552 }
09553 
09554 /*
09555  * Act on an "addzone" or "modzone" command from the command channel.
09556  */
09557 isc_result_t
09558 ns_server_changezone(ns_server_t *server, char *args, isc_buffer_t **text) {
09559         isc_result_t result;
09560         isc_boolean_t addzone;
09561         ns_cfgctx_t *cfg = NULL;
09562         cfg_obj_t *zoneconf = NULL;
09563         const cfg_obj_t *zoneobj = NULL;
09564         const char *zonename;
09565         dns_view_t *view = NULL;
09566         isc_buffer_t buf;
09567         dns_fixedname_t fname;
09568         dns_name_t *dnsname;
09569 
09570         if (strncasecmp(args, "add", 3) == 0)
09571                 addzone = ISC_TRUE;
09572         else
09573                 addzone = ISC_FALSE;
09574 
09575         CHECK(newzone_parse(server, args, &view, &zoneconf, &zoneobj));
09576 
09577         /* Are we accepting new zones in this view? */
09578         if (view->new_zone_file == NULL) {
09579                 result = ISC_R_NOPERM;
09580                 goto cleanup;
09581         }
09582 
09583         cfg = (ns_cfgctx_t *) view->new_zone_config;
09584         if (cfg == NULL) {
09585                 result = ISC_R_FAILURE;
09586                 goto cleanup;
09587         }
09588 
09589         zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name"));
09590         isc_buffer_constinit(&buf, zonename, strlen(zonename));
09591         isc_buffer_add(&buf, strlen(zonename));
09592 
09593         dns_fixedname_init(&fname);
09594         dnsname = dns_fixedname_name(&fname);
09595         CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, ISC_FALSE, NULL));
09596 
09597         if (addzone)
09598                 CHECK(do_addzone(server, cfg, view, dnsname, zoneconf,
09599                                  zoneobj, text));
09600         else
09601                 CHECK(do_modzone(server, cfg, view, dnsname, zonename,
09602                                  zoneobj, text));
09603 
09604         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
09605                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
09606                       "%s zone %s in view %s via %s",
09607                       addzone ? "added" : "updated",
09608                       zonename, view->name,
09609                       addzone ? NS_COMMAND_ADDZONE : NS_COMMAND_MODZONE);
09610 
09611         /* Changing a zone counts as reconfiguration */
09612         CHECK(isc_time_now(&ns_g_configtime));
09613 
09614  cleanup:
09615         if (isc_buffer_usedlength(*text) > 0)
09616                 (void) putnull(text);
09617         if (zoneconf != NULL)
09618                 cfg_obj_destroy(ns_g_addparser, &zoneconf);
09619         if (view != NULL)
09620                 dns_view_detach(&view);
09621 
09622         return (result);
09623 }
09624 
09625 static isc_boolean_t
09626 inuse(const char* file, isc_boolean_t first, isc_buffer_t **text) {
09627         if (file != NULL && isc_file_exists(file)) {
09628                 if (first)
09629                         (void) putstr(text,
09630                                       "The following files were in use "
09631                                       "and may now be removed:\n");
09632                 else
09633                         (void) putstr(text, "\n");
09634                 (void) putstr(text, file);
09635                 (void) putnull(text);
09636                 return (ISC_FALSE);
09637         }
09638         return (first);
09639 }
09640 
09641 /*
09642  * Act on a "delzone" command from the command channel.
09643  */
09644 isc_result_t
09645 ns_server_delzone(ns_server_t *server, char *args, isc_buffer_t **text) {
09646         isc_result_t result, tresult;
09647         ns_cfgctx_t *cfg = NULL;
09648         dns_zone_t *zone = NULL;
09649         dns_zone_t *raw = NULL;
09650         dns_zone_t *mayberaw;
09651         dns_view_t *view = NULL;
09652         dns_db_t *dbp = NULL;
09653         const char *zonename = NULL;
09654         isc_boolean_t exclusive = ISC_FALSE;
09655         isc_boolean_t cleanup = ISC_FALSE;
09656         const char *file, *arg;
09657         isc_boolean_t added;
09658 
09659         /* Skip the command name. */
09660         arg = next_token(&args, " \t");
09661         if (arg == NULL)
09662                 return (ISC_R_UNEXPECTEDEND);
09663 
09664         /* Find out what we are to do. */
09665         arg = next_token(&args, " \t");
09666         if (arg == NULL)
09667                 return (ISC_R_UNEXPECTEDEND);
09668 
09669         if (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0) {
09670                 cleanup = ISC_TRUE;
09671                 arg = next_token(&args, " \t");
09672         }
09673 
09674         CHECK(zone_from_args(server, args, arg, &zone, &zonename,
09675                              text, ISC_FALSE));
09676         if (zone == NULL) {
09677                 result = ISC_R_UNEXPECTEDEND;
09678                 goto cleanup;
09679         }
09680 
09681         INSIST(zonename != NULL);
09682 
09683         result = isc_task_beginexclusive(server->task);
09684         RUNTIME_CHECK(result == ISC_R_SUCCESS);
09685         exclusive = ISC_TRUE;
09686 
09687         /* Dig out configuration for this zone */
09688         view = dns_zone_getview(zone);
09689         cfg = (ns_cfgctx_t *) view->new_zone_config;
09690 
09691         /* Remove the zone from the new_zone_file if applicable */
09692         added = dns_zone_getadded(zone);
09693         if (added) {
09694                 if (view->new_zone_file != NULL)
09695                         nzf_remove(view->new_zone_file, view->name, zonename);
09696                 if (cfg != NULL)
09697                         delete_zoneconf(cfg->add_parser, cfg->nzconfig,
09698                                         zonename);
09699         } else if (cfg != NULL) {
09700                 if (cfg->vconfig != NULL) {
09701                         const cfg_obj_t *voptions =
09702                                 cfg_tuple_get(cfg->vconfig, "options");
09703                         delete_zoneconf(cfg->conf_parser, voptions,
09704                                         zonename);
09705                 } else {
09706                         delete_zoneconf(cfg->conf_parser, cfg->config,
09707                                         zonename);
09708                 }
09709         }
09710 
09711         /* Stop answering for this zone */
09712         if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
09713                 dns_db_detach(&dbp);
09714                 dns_zone_unload(zone);
09715         }
09716 
09717         /* Remove the zone from the new_zone_file if applicable */
09718         added = dns_zone_getadded(zone);
09719         if (added && view->new_zone_file != NULL)
09720                 CHECK(nzf_remove(view->new_zone_file, view->name, zonename));
09721 
09722         /* Clean up stub / slave zone files */
09723         dns_zone_getraw(zone, &raw);
09724         mayberaw = (raw != NULL) ? raw : zone;
09725 
09726         if (!added) {
09727                 TCHECK(putstr(text, "zone '"));
09728                 TCHECK(putstr(text, zonename));
09729                 TCHECK(putstr(text, "' is no longer loaded.\n"));
09730                 TCHECK(putstr(text, "To keep it from returning "));
09731                 TCHECK(putstr(text, "when the server is restarted, it\n"));
09732                 TCHECK(putstr(text, "must also be removed from named.conf."));
09733         } else if (cleanup) {
09734                 file = dns_zone_getfile(mayberaw);
09735                 isc_file_remove(file);
09736 
09737                 file = dns_zone_getjournal(mayberaw);
09738                 isc_file_remove(file);
09739 
09740                 if (zone != mayberaw) {
09741                         file = dns_zone_getfile(zone);
09742                         isc_file_remove(file);
09743 
09744                         file = dns_zone_getjournal(zone);
09745                         isc_file_remove(file);
09746                 }
09747                 TCHECK(putstr(text, "zone '"));
09748                 TCHECK(putstr(text, zonename));
09749                 TCHECK(putstr(text, "' and associated files were deleted."));
09750         } else if (dns_zone_gettype(mayberaw) == dns_zone_slave ||
09751                    dns_zone_gettype(mayberaw) == dns_zone_stub)
09752         {
09753                 isc_boolean_t first;
09754 
09755                 TCHECK(putstr(text, "zone '"));
09756                 TCHECK(putstr(text, zonename));
09757                 TCHECK(putstr(text, "' was deleted.\n"));
09758 
09759                 file = dns_zone_getfile(mayberaw);
09760                 first = inuse(file, ISC_TRUE, text);
09761 
09762                 file = dns_zone_getjournal(mayberaw);
09763                 first = inuse(file, first, text);
09764 
09765                 if (zone != mayberaw) {
09766                         file = dns_zone_getfile(zone);
09767                         first = inuse(file, first, text);
09768 
09769                         file = dns_zone_getjournal(zone);
09770                         (void) inuse(file, first, text);
09771                 }
09772         }
09773 
09774         CHECK(dns_zt_unmount(view->zonetable, zone));
09775 
09776         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
09777                                   NS_LOGMODULE_SERVER, ISC_LOG_INFO,
09778                                   "zone %s removed via delzone", zonename);
09779 
09780         /* Removing a zone counts as reconfiguration */
09781         CHECK(isc_time_now(&ns_g_configtime));
09782 
09783         result = ISC_R_SUCCESS;
09784 
09785  cleanup:
09786         if (isc_buffer_usedlength(*text) > 0)
09787                 (void) putnull(text);
09788         if (raw != NULL)
09789                 dns_zone_detach(&raw);
09790         if (exclusive)
09791                 isc_task_endexclusive(server->task);
09792         if (zone != NULL)
09793                 dns_zone_detach(&zone);
09794 
09795         return (result);
09796 }
09797 
09798 /*
09799  * Act on a "showzone" command from the command channel.
09800  */
09801 static const cfg_obj_t *
09802 find_name_in_list_from_map(const cfg_obj_t *config,
09803                            const char *map_key_for_list,
09804                            const char *name)
09805 {
09806         const cfg_obj_t *list = NULL;
09807         const cfg_listelt_t *element;
09808         const cfg_obj_t *result = NULL;
09809 
09810         cfg_map_get(config, map_key_for_list, &list);
09811         for (element = cfg_list_first(list);
09812              element != NULL;
09813              element = cfg_list_next(element))
09814         {
09815                 const char *vname;
09816                 result = cfg_listelt_value(element);
09817                 INSIST(result != NULL);
09818                 vname = cfg_obj_asstring(cfg_tuple_get(result, "name"));
09819                 if (vname != NULL && !strcasecmp(vname, name))
09820                         break;
09821                 result = NULL;
09822         }
09823 
09824         return (result);
09825 }
09826 
09827 static void
09828 emitzone(void *arg, const char *buf, int len) {
09829         isc_buffer_t **tpp = arg;
09830         putmem(tpp, buf, len);
09831 }
09832 
09833 isc_result_t
09834 ns_server_showzone(ns_server_t *server, char *args, isc_buffer_t **text) {
09835         isc_result_t result;
09836         const cfg_obj_t *vconfig = NULL, *zconfig = NULL;
09837         const char *zonename = NULL;
09838         const cfg_obj_t *map;
09839         dns_view_t *view = NULL;
09840         dns_zone_t *zone = NULL;
09841         ns_cfgctx_t *cfg = NULL;
09842         isc_boolean_t exclusive = ISC_FALSE;
09843 
09844         /* Parse parameters */
09845         CHECK(zone_from_args(server, args, NULL, &zone, &zonename,
09846                              text, ISC_TRUE));
09847         if (zone == NULL) {
09848                 result = ISC_R_UNEXPECTEDEND;
09849                 goto cleanup;
09850         }
09851 
09852         view = dns_zone_getview(zone);
09853         dns_zone_detach(&zone);
09854 
09855         cfg = (ns_cfgctx_t *) view->new_zone_config;
09856         if (cfg == NULL) {
09857                 result = ISC_R_FAILURE;
09858                 goto cleanup;
09859         }
09860 
09861         result = isc_task_beginexclusive(server->task);
09862         RUNTIME_CHECK(result == ISC_R_SUCCESS);
09863         exclusive = ISC_TRUE;
09864 
09865         /* Find the view statement */
09866         vconfig = find_name_in_list_from_map(cfg->config, "view", view->name);
09867 
09868         /* Find the zone statement */
09869         if (vconfig != NULL)
09870                 map = cfg_tuple_get(vconfig, "options");
09871         else
09872                 map = cfg->config;
09873 
09874         zconfig = find_name_in_list_from_map(map, "zone", zonename);
09875         if (zconfig == NULL)
09876                 zconfig = find_name_in_list_from_map(cfg->nzconfig,
09877                                                      "zone", zonename);
09878         if (zconfig == NULL)
09879                 CHECK(ISC_R_NOTFOUND);
09880 
09881         putstr(text, "zone ");
09882         cfg_printx(zconfig, CFG_PRINTER_ONELINE, emitzone, text);
09883         putstr(text, ";");
09884 
09885         result = ISC_R_SUCCESS;
09886 
09887  cleanup:
09888         if (isc_buffer_usedlength(*text) > 0)
09889                 (void) putnull(text);
09890         if (exclusive)
09891                 isc_task_endexclusive(server->task);
09892 
09893         return (result);
09894 }
09895 
09896 static void
09897 newzone_cfgctx_destroy(void **cfgp) {
09898         ns_cfgctx_t *cfg;
09899 
09900         REQUIRE(cfgp != NULL && *cfgp != NULL);
09901 
09902         cfg = *cfgp;
09903 
09904         if (cfg->conf_parser != NULL) {
09905                 if (cfg->config != NULL)
09906                         cfg_obj_destroy(cfg->conf_parser, &cfg->config);
09907                 if (cfg->vconfig != NULL)
09908                         cfg_obj_destroy(cfg->conf_parser, &cfg->vconfig);
09909                 cfg_parser_destroy(&cfg->conf_parser);
09910         }
09911         if (cfg->add_parser != NULL) {
09912                 if (cfg->nzconfig != NULL)
09913                         cfg_obj_destroy(cfg->add_parser, &cfg->nzconfig);
09914                 cfg_parser_destroy(&cfg->add_parser);
09915         }
09916 
09917         if (cfg->actx != NULL)
09918                 cfg_aclconfctx_detach(&cfg->actx);
09919 
09920         isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
09921         *cfgp = NULL;
09922 }
09923 
09924 static isc_result_t
09925 generate_salt(unsigned char *salt, size_t saltlen) {
09926         int i, n;
09927         union {
09928                 unsigned char rnd[256];
09929                 isc_uint32_t rnd32[64];
09930         } rnd;
09931         unsigned char text[512 + 1];
09932         isc_region_t r;
09933         isc_buffer_t buf;
09934         isc_result_t result;
09935 
09936         if (saltlen > 256U)
09937                 return (ISC_R_RANGE);
09938 
09939         n = (int) (saltlen + sizeof(isc_uint32_t) - 1) / sizeof(isc_uint32_t);
09940         for (i = 0; i < n; i++)
09941                 isc_random_get(&rnd.rnd32[i]);
09942 
09943         memmove(salt, rnd.rnd, saltlen);
09944 
09945         r.base = rnd.rnd;
09946         r.length = (unsigned int) saltlen;
09947 
09948         isc_buffer_init(&buf, text, sizeof(text));
09949         result = isc_hex_totext(&r, 2, "", &buf);
09950         RUNTIME_CHECK(result == ISC_R_SUCCESS);
09951         text[saltlen * 2] = 0;
09952 
09953         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
09954                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
09955                       "generated salt: %s", text);
09956 
09957         return (ISC_R_SUCCESS);
09958 }
09959 
09960 isc_result_t
09961 ns_server_signing(ns_server_t *server, char *args, isc_buffer_t **text) {
09962         isc_result_t result = ISC_R_SUCCESS;
09963         dns_zone_t *zone = NULL;
09964         dns_name_t *origin;
09965         dns_db_t *db = NULL;
09966         dns_dbnode_t *node = NULL;
09967         dns_dbversion_t *version = NULL;
09968         dns_rdatatype_t privatetype;
09969         dns_rdataset_t privset;
09970         isc_boolean_t first = ISC_TRUE;
09971         isc_boolean_t list = ISC_FALSE, clear = ISC_FALSE;
09972         isc_boolean_t chain = ISC_FALSE;
09973         isc_boolean_t setserial = ISC_FALSE;
09974         isc_uint32_t serial = 0;
09975         char keystr[DNS_SECALG_FORMATSIZE + 7]; /* <5-digit keyid>/<alg> */
09976         unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0;
09977         unsigned char salt[255];
09978         const char *ptr;
09979         size_t n;
09980 
09981         dns_rdataset_init(&privset);
09982 
09983         /* Skip the command name. */
09984         ptr = next_token(&args, " \t");
09985         if (ptr == NULL)
09986                 return (ISC_R_UNEXPECTEDEND);
09987 
09988         /* Find out what we are to do. */
09989         ptr = next_token(&args, " \t");
09990         if (ptr == NULL)
09991                 return (ISC_R_UNEXPECTEDEND);
09992 
09993         if (strcasecmp(ptr, "-list") == 0)
09994                 list = ISC_TRUE;
09995         else if ((strcasecmp(ptr, "-clear") == 0)  ||
09996                  (strcasecmp(ptr, "-clean") == 0)) {
09997                 clear = ISC_TRUE;
09998                 ptr = next_token(&args, " \t");
09999                 if (ptr == NULL)
10000                         return (ISC_R_UNEXPECTEDEND);
10001                 strlcpy(keystr, ptr, sizeof(keystr));
10002         } else if (strcasecmp(ptr, "-nsec3param") == 0) {
10003                 const char *hashstr, *flagstr, *iterstr;
10004                 char nbuf[512];
10005 
10006                 chain = ISC_TRUE;
10007                 hashstr = next_token(&args, " \t");
10008                 if (hashstr == NULL)
10009                         return (ISC_R_UNEXPECTEDEND);
10010 
10011                 if (strcasecmp(hashstr, "none") == 0)
10012                         hash = 0;
10013                 else {
10014                         flagstr = next_token(&args, " \t");
10015                         iterstr = next_token(&args, " \t");
10016                         if (flagstr == NULL || iterstr == NULL)
10017                                 return (ISC_R_UNEXPECTEDEND);
10018 
10019                         n = snprintf(nbuf, sizeof(nbuf), "%s %s %s",
10020                                      hashstr, flagstr, iterstr);
10021                         if (n == sizeof(nbuf))
10022                                 return (ISC_R_NOSPACE);
10023                         n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter);
10024                         if (n != 3U)
10025                                 return (ISC_R_BADNUMBER);
10026 
10027                         if (hash > 0xffU || flags > 0xffU)
10028                                 return (ISC_R_RANGE);
10029 
10030                         ptr = next_token(&args, " \t");
10031                         if (ptr == NULL) {
10032                                 return (ISC_R_UNEXPECTEDEND);
10033                         } else if (strcasecmp(ptr, "auto") == 0) {
10034                                 /* Auto-generate a random salt.
10035                                  * XXXMUKS: This currently uses the
10036                                  * minimum recommended length by RFC
10037                                  * 5155 (64 bits). It should be made
10038                                  * configurable.
10039                                  */
10040                                 saltlen = 8;
10041                                 CHECK(generate_salt(salt, saltlen));
10042                         } else if (strcmp(ptr, "-") != 0) {
10043                                 isc_buffer_t buf;
10044 
10045                                 isc_buffer_init(&buf, salt, sizeof(salt));
10046                                 CHECK(isc_hex_decodestring(ptr, &buf));
10047                                 saltlen = isc_buffer_usedlength(&buf);
10048                         }
10049                 }
10050         } else if (strcasecmp(ptr, "-serial") == 0) {
10051                 ptr = next_token(&args, " \t");
10052                 if (ptr == NULL)
10053                         return (ISC_R_UNEXPECTEDEND);
10054                 CHECK(isc_parse_uint32(&serial, ptr, 10));
10055                 setserial = ISC_TRUE;
10056         } else
10057                 CHECK(DNS_R_SYNTAX);
10058 
10059         CHECK(zone_from_args(server, args, NULL, &zone, NULL,
10060                              text, ISC_FALSE));
10061         if (zone == NULL)
10062                 CHECK(ISC_R_UNEXPECTEDEND);
10063 
10064         if (clear) {
10065                 CHECK(dns_zone_keydone(zone, keystr));
10066                 (void) putstr(text, "request queued");
10067                 (void) putnull(text);
10068         } else if (chain) {
10069                 CHECK(dns_zone_setnsec3param(zone, (isc_uint8_t)hash,
10070                                              (isc_uint8_t)flags, iter,
10071                                              (isc_uint8_t)saltlen, salt,
10072                                              ISC_TRUE));
10073                 (void) putstr(text, "nsec3param request queued");
10074                 (void) putnull(text);
10075         } else if (setserial) {
10076                 CHECK(dns_zone_setserial(zone, serial));
10077                 (void) putstr(text, "serial request queued");
10078                 (void) putnull(text);
10079         } else if (list) {
10080                 privatetype = dns_zone_getprivatetype(zone);
10081                 origin = dns_zone_getorigin(zone);
10082                 CHECK(dns_zone_getdb(zone, &db));
10083                 CHECK(dns_db_findnode(db, origin, ISC_FALSE, &node));
10084                 dns_db_currentversion(db, &version);
10085 
10086                 result = dns_db_findrdataset(db, node, version, privatetype,
10087                                              dns_rdatatype_none, 0,
10088                                              &privset, NULL);
10089                 if (result == ISC_R_NOTFOUND) {
10090                         (void) putstr(text, "No signing records found");
10091                         (void) putnull(text);
10092                         result = ISC_R_SUCCESS;
10093                         goto cleanup;
10094                 }
10095 
10096                 for (result = dns_rdataset_first(&privset);
10097                      result == ISC_R_SUCCESS;
10098                      result = dns_rdataset_next(&privset))
10099                 {
10100                         dns_rdata_t priv = DNS_RDATA_INIT;
10101                         char output[BUFSIZ];
10102                         isc_buffer_t buf;
10103 
10104                         dns_rdataset_current(&privset, &priv);
10105 
10106                         isc_buffer_init(&buf, output, sizeof(output));
10107                         CHECK(dns_private_totext(&priv, &buf));
10108                         if (!first)
10109                                 CHECK(putstr(text, "\n"));
10110                         CHECK(putstr(text, output));
10111                         first = ISC_FALSE;
10112                 }
10113                 if (!first)
10114                         CHECK(putnull(text));
10115 
10116                 if (result == ISC_R_NOMORE)
10117                         result = ISC_R_SUCCESS;
10118         }
10119 
10120  cleanup:
10121         if (dns_rdataset_isassociated(&privset))
10122                 dns_rdataset_disassociate(&privset);
10123         if (node != NULL)
10124                 dns_db_detachnode(db, &node);
10125         if (version != NULL)
10126                 dns_db_closeversion(db, &version, ISC_FALSE);
10127         if (db != NULL)
10128                 dns_db_detach(&db);
10129         if (zone != NULL)
10130                 dns_zone_detach(&zone);
10131 
10132         return (result);
10133 }
10134 
10135 static isc_result_t
10136 putmem(isc_buffer_t **b, const char *str, size_t len) {
10137         isc_result_t result;
10138 
10139         result = isc_buffer_reserve(b, (unsigned int)len);
10140         if (result != ISC_R_SUCCESS)
10141                 return (ISC_R_NOSPACE);
10142 
10143         isc_buffer_putmem(*b, (const unsigned char *)str, (unsigned int)len);
10144         return (ISC_R_SUCCESS);
10145 }
10146 
10147 static inline isc_result_t
10148 putstr(isc_buffer_t **b, const char *str) {
10149         return (putmem(b, str, strlen(str)));
10150 }
10151 
10152 static isc_result_t
10153 putuint8(isc_buffer_t **b, isc_uint8_t val) {
10154         isc_result_t result;
10155 
10156         result = isc_buffer_reserve(b, 1);
10157         if (result != ISC_R_SUCCESS)
10158                 return (ISC_R_NOSPACE);
10159 
10160         isc_buffer_putuint8(*b, val);
10161         return (ISC_R_SUCCESS);
10162 }
10163 
10164 static inline isc_result_t
10165 putnull(isc_buffer_t **b) {
10166         return (putuint8(b, 0));
10167 }
10168 
10169 isc_result_t
10170 ns_server_zonestatus(ns_server_t *server, char *args, isc_buffer_t **text) {
10171         isc_result_t result = ISC_R_SUCCESS;
10172         dns_zone_t *zone = NULL, *raw = NULL;
10173         const char *type, *file, *zonename = NULL;
10174         isc_uint32_t serial, signed_serial, nodes;
10175         char serbuf[16], sserbuf[16], nodebuf[16], resignbuf[512];
10176         char lbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
10177         char xbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
10178         char rbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
10179         char kbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
10180         char rtbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
10181         isc_time_t loadtime, expiretime, refreshtime;
10182         isc_time_t refreshkeytime, resigntime;
10183         dns_zonetype_t zonetype;
10184         isc_boolean_t dynamic = ISC_FALSE, frozen = ISC_FALSE;
10185         isc_boolean_t hasraw = ISC_FALSE;
10186         isc_boolean_t secure, maintain, allow;
10187         dns_db_t *db = NULL, *rawdb = NULL;
10188         char **incfiles = NULL;
10189         int nfiles = 0;
10190 
10191         isc_time_settoepoch(&loadtime);
10192         isc_time_settoepoch(&refreshtime);
10193         isc_time_settoepoch(&expiretime);
10194         isc_time_settoepoch(&refreshkeytime);
10195         isc_time_settoepoch(&resigntime);
10196 
10197         CHECK(zone_from_args(server, args, NULL, &zone, &zonename,
10198                              text, ISC_TRUE));
10199         if (zone == NULL) {
10200                 result = ISC_R_UNEXPECTEDEND;
10201                 goto cleanup;
10202         }
10203 
10204         zonetype = dns_zone_gettype(zone);
10205         switch (zonetype) {
10206         case dns_zone_master:
10207                 type = "master";
10208                 break;
10209         case dns_zone_slave:
10210                 type = "slave";
10211                 break;
10212         case dns_zone_stub:
10213                 type = "stub";
10214                 break;
10215         case dns_zone_staticstub:
10216                 type = "staticstub";
10217                 break;
10218         case dns_zone_redirect:
10219                 type = "redirect";
10220                 break;
10221         case dns_zone_key:
10222                 type = "key";
10223                 break;
10224         case dns_zone_dlz:
10225                 type = "dlz";
10226                 break;
10227         default:
10228                 type = "unknown";
10229         }
10230 
10231         /* Inline signing? */
10232         CHECK(dns_zone_getdb(zone, &db));
10233         dns_zone_getraw(zone, &raw);
10234         hasraw = ISC_TF(raw != NULL);
10235         if (hasraw)
10236                 CHECK(dns_zone_getdb(raw, &rawdb));
10237 
10238         /* Serial number */
10239         serial = dns_zone_getserial(hasraw ? raw : zone);
10240         snprintf(serbuf, sizeof(serbuf), "%d", serial);
10241         if (hasraw) {
10242                 signed_serial = dns_zone_getserial(zone);
10243                 snprintf(sserbuf, sizeof(sserbuf), "%d", signed_serial);
10244         }
10245 
10246         /* Database node count */
10247         nodes = dns_db_nodecount(hasraw ? rawdb : db);
10248         snprintf(nodebuf, sizeof(nodebuf), "%d", nodes);
10249 
10250         /* Security */
10251         secure = dns_db_issecure(db);
10252         allow = ISC_TF((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0);
10253         maintain = ISC_TF((dns_zone_getkeyopts(zone) &
10254                            DNS_ZONEKEY_MAINTAIN) != 0);
10255 
10256         /* Master files */
10257         file = dns_zone_getfile(hasraw ? raw : zone);
10258         nfiles = dns_zone_getincludes(hasraw ? raw : zone, &incfiles);
10259 
10260         /* Load time */
10261         dns_zone_getloadtime(zone, &loadtime);
10262         isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf));
10263 
10264         /* Refresh/expire times */
10265         if (zonetype == dns_zone_slave ||
10266             zonetype == dns_zone_stub ||
10267             zonetype == dns_zone_redirect)
10268         {
10269                 dns_zone_getexpiretime(zone, &expiretime);
10270                 isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf));
10271                 dns_zone_getrefreshtime(zone, &refreshtime);
10272                 isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf));
10273         }
10274 
10275         /* Key refresh time */
10276         if (zonetype == dns_zone_master ||
10277             (zonetype == dns_zone_slave && hasraw))
10278         {
10279                 dns_zone_getrefreshkeytime(zone, &refreshkeytime);
10280                 isc_time_formathttptimestamp(&refreshkeytime, kbuf,
10281                                              sizeof(kbuf));
10282         }
10283 
10284         /* Dynamic? */
10285         if (zonetype == dns_zone_master) {
10286                 dynamic = dns_zone_isdynamic(hasraw ? raw : zone, ISC_TRUE);
10287                 frozen = dynamic && !dns_zone_isdynamic(hasraw ? raw : zone,
10288                                                         ISC_FALSE);
10289         }
10290 
10291         /* Next resign event */
10292         if (secure && (zonetype == dns_zone_master ||
10293              (zonetype == dns_zone_slave && hasraw)) &&
10294             ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_NORESIGN) == 0))
10295         {
10296                 dns_name_t *name;
10297                 dns_fixedname_t fixed;
10298                 dns_rdataset_t next;
10299 
10300                 dns_rdataset_init(&next);
10301                 dns_fixedname_init(&fixed);
10302                 name = dns_fixedname_name(&fixed);
10303 
10304                 result = dns_db_getsigningtime(db, &next, name);
10305                 if (result == ISC_R_SUCCESS) {
10306                         isc_stdtime_t timenow;
10307                         char namebuf[DNS_NAME_FORMATSIZE];
10308                         char typebuf[DNS_RDATATYPE_FORMATSIZE];
10309 
10310                         isc_stdtime_get(&timenow);
10311                         dns_name_format(name, namebuf, sizeof(namebuf));
10312                         dns_rdatatype_format(next.covers,
10313                                              typebuf, sizeof(typebuf));
10314                         snprintf(resignbuf, sizeof(resignbuf),
10315                                      "%s/%s", namebuf, typebuf);
10316                         isc_time_set(&resigntime, next.resign -
10317                                 dns_zone_getsigresigninginterval(zone), 0);
10318                         isc_time_formathttptimestamp(&resigntime, rtbuf,
10319                                                      sizeof(rtbuf));
10320                         dns_rdataset_disassociate(&next);
10321                 }
10322         }
10323 
10324         /* Create text */
10325         CHECK(putstr(text, "name: "));
10326         CHECK(putstr(text, zonename));
10327 
10328         CHECK(putstr(text, "\ntype: "));
10329         CHECK(putstr(text, type));
10330 
10331         if (file != NULL) {
10332                 int i;
10333                 CHECK(putstr(text, "\nfiles: "));
10334                 CHECK(putstr(text, file));
10335                 for (i = 0; i < nfiles; i++) {
10336                         CHECK(putstr(text, ", "));
10337                         if (incfiles[i] != NULL)
10338                                 CHECK(putstr(text, incfiles[i]));
10339                 }
10340         }
10341 
10342         CHECK(putstr(text, "\nserial: "));
10343         CHECK(putstr(text, serbuf));
10344         if (hasraw) {
10345                 CHECK(putstr(text, "\nsigned serial: "));
10346                 CHECK(putstr(text, sserbuf));
10347         }
10348 
10349         CHECK(putstr(text, "\nnodes: "));
10350         CHECK(putstr(text, nodebuf));
10351 
10352         if (! isc_time_isepoch(&loadtime)) {
10353                 CHECK(putstr(text, "\nlast loaded: "));
10354                 CHECK(putstr(text, lbuf));
10355         }
10356 
10357         if (! isc_time_isepoch(&refreshtime)) {
10358                 CHECK(putstr(text, "\nnext refresh: "));
10359                 CHECK(putstr(text, rbuf));
10360         }
10361 
10362         if (! isc_time_isepoch(&expiretime)) {
10363                 CHECK(putstr(text, "\nexpires: "));
10364                 CHECK(putstr(text, xbuf));
10365         }
10366 
10367         if (secure) {
10368                 CHECK(putstr(text, "\nsecure: yes"));
10369                 if (hasraw)
10370                         CHECK(putstr(text, "\ninline signing: yes"));
10371                 else
10372                         CHECK(putstr(text, "\ninline signing: no"));
10373         } else
10374                 CHECK(putstr(text, "\nsecure: no"));
10375 
10376         if (maintain) {
10377                 CHECK(putstr(text, "\nkey maintenance: automatic"));
10378                 if (! isc_time_isepoch(&refreshkeytime)) {
10379                         CHECK(putstr(text, "\nnext key event: "));
10380                         CHECK(putstr(text, kbuf));
10381                 }
10382         } else if (allow)
10383                 CHECK(putstr(text, "\nkey maintenance: on command"));
10384         else if (secure || hasraw)
10385                 CHECK(putstr(text, "\nkey maintenance: none"));
10386 
10387         if (!isc_time_isepoch(&resigntime)) {
10388                 CHECK(putstr(text, "\nnext resign node: "));
10389                 CHECK(putstr(text, resignbuf));
10390                 CHECK(putstr(text, "\nnext resign time: "));
10391                 CHECK(putstr(text, rtbuf));
10392         }
10393 
10394         if (dynamic) {
10395                 CHECK(putstr(text, "\ndynamic: yes"));
10396                 if (frozen)
10397                         CHECK(putstr(text, "\nfrozen: yes"));
10398                 else
10399                         CHECK(putstr(text, "\nfrozen: no"));
10400         } else
10401                 CHECK(putstr(text, "\ndynamic: no"));
10402 
10403         CHECK(putstr(text, "\nreconfigurable via modzone: "));
10404         CHECK(putstr(text, dns_zone_getadded(zone) ? "yes" : "no"));
10405 
10406  cleanup:
10407         /* Indicate truncated output if possible. */
10408         if (result == ISC_R_NOSPACE)
10409                 (void) putstr(text, "\n...");
10410         if ((result == ISC_R_SUCCESS || result == ISC_R_NOSPACE))
10411                 (void) putnull(text);
10412 
10413         if (db != NULL)
10414                 dns_db_detach(&db);
10415         if (rawdb != NULL)
10416                 dns_db_detach(&rawdb);
10417         if (incfiles != NULL) {
10418                 int i;
10419                 isc_mem_t *mctx = dns_zone_getmctx(hasraw ? raw : zone);
10420 
10421                 for (i = 0; i < nfiles; i++)
10422                         if (incfiles[i] != NULL)
10423                                 isc_mem_free(mctx, incfiles[i]);
10424                 isc_mem_free(mctx, incfiles);
10425         }
10426         if (raw != NULL)
10427                 dns_zone_detach(&raw);
10428         if (zone != NULL)
10429                 dns_zone_detach(&zone);
10430         return (result);
10431 }
10432 
10433 static inline isc_boolean_t
10434 argcheck(char *cmd, const char *full) {
10435         size_t l;
10436 
10437         if (cmd == NULL || cmd[0] != '-')
10438                 return (ISC_FALSE);
10439 
10440         cmd++;
10441         l = strlen(cmd);
10442         if (l > strlen(full) || strncasecmp(cmd, full, l) != 0)
10443                 return (ISC_FALSE);
10444 
10445         return (ISC_TRUE);
10446 }
10447 
10448 isc_result_t
10449 ns_server_nta(ns_server_t *server, char *args, isc_buffer_t **text) {
10450         dns_view_t *view;
10451         dns_ntatable_t *ntatable = NULL;
10452         isc_result_t result = ISC_R_SUCCESS;
10453         char *ptr, *nametext = NULL, *viewname;
10454         isc_stdtime_t now, when;
10455         isc_time_t t;
10456         char tbuf[64];
10457         const char *msg = NULL;
10458         isc_boolean_t dump = ISC_FALSE, force = ISC_FALSE;
10459         dns_fixedname_t fn;
10460         dns_name_t *ntaname;
10461         dns_ttl_t ntattl;
10462         isc_boolean_t ttlset = ISC_FALSE, excl = ISC_FALSE;
10463 
10464         UNUSED(force);
10465 
10466         dns_fixedname_init(&fn);
10467         ntaname = dns_fixedname_name(&fn);
10468 
10469         /* Skip the command name. */
10470         ptr = next_token(&args, " \t");
10471         if (ptr == NULL)
10472                 return (ISC_R_UNEXPECTEDEND);
10473 
10474         for (;;) {
10475                 /* Check for options */
10476                 ptr = next_token(&args, " \t");
10477                 if (ptr == NULL)
10478                         return (ISC_R_UNEXPECTEDEND);
10479 
10480                 if (argcheck(ptr, "dump"))
10481                         dump = ISC_TRUE;
10482                 else if (argcheck(ptr, "remove")) {
10483                         ntattl = 0;
10484                         ttlset = ISC_TRUE;
10485                 } else if (argcheck(ptr, "force")) {
10486                         force = ISC_TRUE;
10487                         continue;
10488                 } else if (argcheck(ptr, "lifetime")) {
10489                         isc_textregion_t tr;
10490 
10491                         ptr = next_token(&args, " \t");
10492                         if (ptr == NULL) {
10493                                 msg = "No lifetime specified";
10494                                 CHECK(ISC_R_UNEXPECTEDEND);
10495                         }
10496 
10497                         tr.base = ptr;
10498                         tr.length = strlen(ptr);
10499                         result = dns_ttl_fromtext(&tr, &ntattl);
10500                         if (result != ISC_R_SUCCESS) {
10501                                 msg = "could not parse NTA lifetime";
10502                                 CHECK(result);
10503                         }
10504 
10505                         if (ntattl > 604800) {
10506                                 msg = "NTA lifetime cannot exceed one week";
10507                                 CHECK(ISC_R_RANGE);
10508                         }
10509 
10510                         ttlset = ISC_TRUE;
10511                         continue;
10512                 } else
10513                         nametext = ptr;
10514 
10515                 break;
10516         }
10517 
10518         /*
10519          * If -dump was specified, list NTA's and return
10520          */
10521         if (dump) {
10522                 for (view = ISC_LIST_HEAD(server->viewlist);
10523                      view != NULL;
10524                      view = ISC_LIST_NEXT(view, link))
10525                 {
10526                         if (ntatable != NULL)
10527                                 dns_ntatable_detach(&ntatable);
10528                         result = dns_view_getntatable(view, &ntatable);
10529                         if (result == ISC_R_NOTFOUND) {
10530                                 result = ISC_R_SUCCESS;
10531                                 continue;
10532                         }
10533                         CHECK(dns_ntatable_totext(ntatable, text));
10534                 }
10535                 CHECK(putnull(text));
10536 
10537                 goto cleanup;
10538         }
10539 
10540         /* Get the NTA name. */
10541         if (nametext == NULL)
10542                 nametext = next_token(&args, " \t");
10543         if (nametext == NULL)
10544                 return (ISC_R_UNEXPECTEDEND);
10545 
10546         if (strcmp(nametext, ".") == 0)
10547                 ntaname = dns_rootname;
10548         else {
10549                 isc_buffer_t b;
10550                 isc_buffer_init(&b, nametext, strlen(nametext));
10551                 isc_buffer_add(&b, strlen(nametext));
10552                 CHECK(dns_name_fromtext(ntaname, &b, dns_rootname, 0, NULL));
10553         }
10554 
10555         /* Look for the view name. */
10556         viewname = next_token(&args, " \t");
10557 
10558         isc_stdtime_get(&now);
10559 
10560         result = isc_task_beginexclusive(server->task);
10561         RUNTIME_CHECK(result == ISC_R_SUCCESS);
10562         excl = ISC_TRUE;
10563         for (view = ISC_LIST_HEAD(server->viewlist);
10564              view != NULL;
10565              view = ISC_LIST_NEXT(view, link))
10566         {
10567                 if (viewname != NULL &&
10568                     strcmp(view->name, viewname) != 0)
10569                         continue;
10570 
10571                 if (view->nta_lifetime == 0)
10572                         continue;
10573 
10574                 if (!ttlset)
10575                         ntattl = view->nta_lifetime;
10576 
10577                 if (ntatable != NULL)
10578                         dns_ntatable_detach(&ntatable);
10579 
10580                 result = dns_view_getntatable(view, &ntatable);
10581                 if (result == ISC_R_NOTFOUND) {
10582                         result = ISC_R_SUCCESS;
10583                         continue;
10584                 }
10585 
10586                 result = dns_view_flushnode(view, ntaname, ISC_TRUE);
10587                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
10588                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
10589                               "flush tree '%s' in cache view '%s': %s",
10590                               nametext, view->name,
10591                               isc_result_totext(result));
10592 
10593                 if (ntattl != 0) {
10594                         CHECK(dns_ntatable_add(ntatable, ntaname,
10595                                                force, now, ntattl));
10596 
10597                         when = now + ntattl;
10598                         isc_time_set(&t, when, 0);
10599                         isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
10600 
10601                         CHECK(putstr(text, "Negative trust anchor added: "));
10602                         CHECK(putstr(text, nametext));
10603                         CHECK(putstr(text, "/"));
10604                         CHECK(putstr(text, view->name));
10605                         CHECK(putstr(text, ", expires "));
10606                         CHECK(putstr(text, tbuf));
10607 
10608                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
10609                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
10610                                       "added NTA '%s' (%d sec) in view '%s'",
10611                                       nametext, ntattl, view->name);
10612                 } else {
10613                         CHECK(dns_ntatable_delete(ntatable, ntaname));
10614 
10615                         CHECK(putstr(text, "Negative trust anchor removed: "));
10616                         CHECK(putstr(text, nametext));
10617                         CHECK(putstr(text, "/"));
10618                         CHECK(putstr(text, view->name));
10619 
10620                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
10621                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
10622                                       "removed NTA '%s' in view %s",
10623                                       nametext, view->name);
10624                 }
10625 
10626                 result = dns_view_saventa(view);
10627                 if (result != ISC_R_SUCCESS) {
10628                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
10629                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
10630                                       "error writing NTA file "
10631                                       "for view '%s': %s",
10632                                       view->name, isc_result_totext(result));
10633                 }
10634 
10635                 CHECK(putnull(text));
10636 
10637         }
10638 
10639  cleanup:
10640         if (msg != NULL) {
10641                 (void) putstr(text, msg);
10642                 (void) putnull(text);
10643         }
10644         if (excl)
10645                 isc_task_endexclusive(server->task);
10646         if (ntatable != NULL)
10647                 dns_ntatable_detach(&ntatable);
10648         return (result);
10649 }
10650 
10651 isc_result_t
10652 ns_server_saventa(ns_server_t *server) {
10653         dns_view_t *view;
10654 
10655         for (view = ISC_LIST_HEAD(server->viewlist);
10656              view != NULL;
10657              view = ISC_LIST_NEXT(view, link))
10658         {
10659                 isc_result_t result = dns_view_saventa(view);
10660 
10661                 if (result != ISC_R_SUCCESS) {
10662                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
10663                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
10664                                       "error writing NTA file "
10665                                       "for view '%s': %s",
10666                                       view->name, isc_result_totext(result));
10667                 }
10668         }
10669 
10670         return (ISC_R_SUCCESS);
10671 }
10672 
10673 isc_result_t
10674 ns_server_loadnta(ns_server_t *server) {
10675         dns_view_t *view;
10676 
10677         for (view = ISC_LIST_HEAD(server->viewlist);
10678              view != NULL;
10679              view = ISC_LIST_NEXT(view, link))
10680         {
10681                 isc_result_t result = dns_view_loadnta(view);
10682 
10683                 if ((result != ISC_R_SUCCESS) &&
10684                     (result != ISC_R_FILENOTFOUND) &&
10685                     (result != ISC_R_NOTFOUND))
10686                 {
10687                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
10688                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
10689                                       "error loading NTA file "
10690                                       "for view '%s': %s",
10691                                       view->name, isc_result_totext(result));
10692                 }
10693         }
10694 
10695         return (ISC_R_SUCCESS);
10696 }
10697 
10698 static isc_result_t
10699 mkey_refresh(dns_view_t *view, isc_buffer_t **text) {
10700         isc_result_t result;
10701         char msg[DNS_NAME_FORMATSIZE + 500] = "";
10702 
10703         snprintf(msg, sizeof(msg),
10704                  "refreshing managed keys for '%s'", view->name);
10705         CHECK(putstr(text, msg));
10706         CHECK(dns_zone_synckeyzone(view->managed_keys));
10707 
10708  cleanup:
10709         return (result);
10710 }
10711 
10712 static isc_result_t
10713 mkey_dumpzone(dns_view_t *view, isc_buffer_t **text) {
10714         isc_result_t result;
10715         dns_db_t *db = NULL;
10716         dns_dbversion_t *ver = NULL;
10717         dns_rriterator_t rrit;
10718         isc_stdtime_t now;
10719         dns_name_t *prevname = NULL;
10720 
10721         isc_stdtime_get(&now);
10722 
10723         CHECK(dns_zone_getdb(view->managed_keys, &db));
10724         dns_db_currentversion(db, &ver);
10725         dns_rriterator_init(&rrit, db, ver, 0);
10726         for (result = dns_rriterator_first(&rrit);
10727              result == ISC_R_SUCCESS;
10728              result = dns_rriterator_nextrrset(&rrit))
10729         {
10730                 char buf[DNS_NAME_FORMATSIZE + 500];
10731                 dns_name_t *name = NULL;
10732                 dns_rdataset_t *kdset = NULL;
10733                 dns_rdata_t rdata = DNS_RDATA_INIT;
10734                 dns_rdata_keydata_t kd;
10735                 isc_uint32_t ttl;
10736 
10737                 dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL);
10738                 if (kdset == NULL || kdset->type != dns_rdatatype_keydata ||
10739                     !dns_rdataset_isassociated(kdset))
10740                         continue;
10741 
10742                 if (name != prevname) {
10743                         char nbuf[DNS_NAME_FORMATSIZE];
10744                         dns_name_format(name, nbuf, sizeof(nbuf));
10745                         snprintf(buf, sizeof(buf), "\n\n    name: %s", nbuf);
10746                         CHECK(putstr(text, buf));
10747                 }
10748 
10749 
10750                 for (result = dns_rdataset_first(kdset);
10751                      result == ISC_R_SUCCESS;
10752                      result = dns_rdataset_next(kdset))
10753                 {
10754                         char alg[DNS_SECALG_FORMATSIZE];
10755                         char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
10756                         dns_keytag_t keyid;
10757                         isc_region_t r;
10758                         isc_time_t t;
10759                         isc_boolean_t revoked;
10760 
10761                         dns_rdata_reset(&rdata);
10762                         dns_rdataset_current(kdset, &rdata);
10763                         result = dns_rdata_tostruct(&rdata, &kd, NULL);
10764                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
10765 
10766                         dns_rdata_toregion(&rdata, &r);
10767                         isc_region_consume(&r, 12);
10768                         keyid = dst_region_computeid(&r, kd.algorithm);
10769 
10770                         snprintf(buf, sizeof(buf), "\n    keyid: %u", keyid);
10771                         CHECK(putstr(text, buf));
10772 
10773                         dns_secalg_format(kd.algorithm, alg, sizeof(alg));
10774                         snprintf(buf, sizeof(buf), "\n\talgorithm: %s", alg);
10775                         CHECK(putstr(text, buf));
10776 
10777                         revoked = ISC_TF((kd.flags & DNS_KEYFLAG_REVOKE) != 0);
10778                         snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s",
10779                                  revoked ? " REVOKE" : "",
10780                                  ((kd.flags & DNS_KEYFLAG_KSK) != 0)
10781                                    ? " SEP" : "",
10782                                  (kd.flags == 0) ? " (none)" : "");
10783                         CHECK(putstr(text, buf));
10784 
10785                         isc_time_set(&t, kd.refresh, 0);
10786                         isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
10787                         snprintf(buf, sizeof(buf),
10788                                  "\n\tnext refresh: %s", tbuf);
10789                         CHECK(putstr(text, buf));
10790 
10791                         if (kd.removehd != 0) {
10792                                 isc_time_set(&t, kd.removehd, 0);
10793                                 isc_time_formathttptimestamp(&t, tbuf,
10794                                                              sizeof(tbuf));
10795                                 snprintf(buf, sizeof(buf),
10796                                          "\n\tremove at: %s", tbuf);
10797                                 CHECK(putstr(text, buf));
10798                         }
10799 
10800                         isc_time_set(&t, kd.addhd, 0);
10801                         isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
10802                         if (kd.addhd == 0)
10803                                 snprintf(buf, sizeof(buf), "\n\tno trust");
10804                         else if (revoked)
10805                                 snprintf(buf, sizeof(buf),
10806                                          "\n\ttrust revoked");
10807                         else if (kd.addhd < now)
10808                                 snprintf(buf, sizeof(buf),
10809                                          "\n\ttrusted since: %s", tbuf);
10810                         else if (kd.addhd >= now)
10811                                 snprintf(buf, sizeof(buf),
10812                                          "\n\ttrust pending: %s", tbuf);
10813                         CHECK(putstr(text, buf));
10814                 }
10815         }
10816 
10817         if (result == ISC_R_NOMORE)
10818                 result = ISC_R_SUCCESS;
10819 
10820  cleanup:
10821         if (ver != NULL) {
10822                 dns_rriterator_destroy(&rrit);
10823                 dns_db_closeversion(db, &ver, ISC_FALSE);
10824         }
10825         if (db != NULL)
10826                 dns_db_detach(&db);
10827 
10828         return (result);
10829 }
10830 
10831 static isc_result_t
10832 mkey_status(dns_view_t *view, isc_buffer_t **text) {
10833         isc_result_t result;
10834         char msg[ISC_FORMATHTTPTIMESTAMP_SIZE];
10835         isc_time_t t;
10836 
10837         CHECK(putstr(text, "view: "));
10838         CHECK(putstr(text, view->name));
10839 
10840         CHECK(putstr(text, "\nnext scheduled event: "));
10841 
10842         dns_zone_getrefreshkeytime(view->managed_keys, &t);
10843         if (isc_time_isepoch(&t)) {
10844                 CHECK(putstr(text, "never"));
10845         } else {
10846                 isc_time_formathttptimestamp(&t, msg, sizeof(msg));
10847                 CHECK(putstr(text, msg));
10848         }
10849 
10850         CHECK(mkey_dumpzone(view, text));
10851 
10852  cleanup:
10853         return (result);
10854 }
10855 
10856 isc_result_t
10857 ns_server_mkeys(ns_server_t *server, char *args, isc_buffer_t **text) {
10858         char *cmd, *classtxt, *viewtxt = NULL;
10859         isc_result_t result = ISC_R_SUCCESS;
10860         dns_view_t *view = NULL;
10861         dns_rdataclass_t rdclass;
10862         char msg[DNS_NAME_FORMATSIZE + 500] = "";
10863         enum { NONE, STATUS, REFRESH, SYNC } opt = NONE;
10864         isc_boolean_t found = ISC_FALSE;
10865         isc_boolean_t first = ISC_TRUE;
10866 
10867         /* Skip rndc command name */
10868         cmd = next_token(&args, " \t");
10869         if (cmd == NULL)
10870                 return (ISC_R_UNEXPECTEDEND);
10871 
10872         /* Get managed-keys subcommand */
10873         cmd = next_token(&args, " \t");
10874         if (cmd == NULL)
10875                 return (ISC_R_UNEXPECTEDEND);
10876 
10877         if (strcasecmp(cmd, "status") == 0)
10878                 opt = STATUS;
10879         else if (strcasecmp(cmd, "refresh") == 0)
10880                 opt = REFRESH;
10881         else if (strcasecmp(cmd, "sync") == 0)
10882                 opt = SYNC;
10883         else {
10884                 snprintf(msg, sizeof(msg), "unknown command '%s'", cmd);
10885                 (void) putstr(text, msg);
10886                 result = ISC_R_UNEXPECTED;
10887                 goto cleanup;
10888         }
10889 
10890         /* Look for the optional class name. */
10891         classtxt = next_token(&args, " \t");
10892         if (classtxt != NULL) {
10893                 /* Look for the optional view name. */
10894                 viewtxt = next_token(&args, " \t");
10895         }
10896 
10897         if (classtxt == NULL) {
10898                 rdclass = dns_rdataclass_in;
10899         } else {
10900                 isc_textregion_t r;
10901                 r.base = classtxt;
10902                 r.length = strlen(classtxt);
10903                 result = dns_rdataclass_fromtext(&rdclass, &r);
10904                 if (result != ISC_R_SUCCESS) {
10905                         if (viewtxt == NULL) {
10906                                 rdclass = dns_rdataclass_in;
10907                                 viewtxt = classtxt;
10908                                 result = ISC_R_SUCCESS;
10909                         } else {
10910                                 snprintf(msg, sizeof(msg),
10911                                          "unknown class '%s'", classtxt);
10912                                 (void) putstr(text, msg);
10913                                 goto cleanup;
10914                         }
10915                 }
10916         }
10917 
10918         for (view = ISC_LIST_HEAD(server->viewlist);
10919              view != NULL;
10920              view = ISC_LIST_NEXT(view, link))
10921         {
10922                 if (viewtxt != NULL &&
10923                     (rdclass != view->rdclass ||
10924                      strcmp(view->name, viewtxt) != 0))
10925                         continue;
10926 
10927                 if (view->managed_keys == NULL) {
10928                         if (viewtxt != NULL) {
10929                                 snprintf(msg, sizeof(msg),
10930                                          "view '%s': no managed keys", viewtxt);
10931                                 CHECK(putstr(text, msg));
10932                                 goto cleanup;
10933                         } else
10934                                 continue;
10935                 }
10936 
10937                 found = ISC_TRUE;
10938 
10939                 switch (opt) {
10940                 case REFRESH:
10941                         CHECK(mkey_refresh(view, text));
10942                         break;
10943                 case STATUS:
10944                         if (!first)
10945                                 CHECK(putstr(text, "\n\n"));
10946                         CHECK(mkey_status(view, text));
10947                         first = ISC_FALSE;
10948                         break;
10949                 case SYNC:
10950                         CHECK(dns_zone_flush(view->managed_keys));
10951                         break;
10952                 default:
10953                         INSIST(0);
10954                 }
10955 
10956                 if (viewtxt != NULL)
10957                         break;
10958         }
10959 
10960         if (!found)
10961                 CHECK(putstr(text, "no views with managed keys"));
10962 
10963  cleanup:
10964         if (isc_buffer_usedlength(*text) > 0)
10965                 (void) putnull(text);
10966 
10967         return (result);
10968 }

Generated on Tue Apr 28 17:40:55 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha