]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
refactor newzones configuration
authorEvan Hunt <each@isc.org>
Thu, 23 Oct 2025 20:44:56 +0000 (13:44 -0700)
committerColin Vidal <colin@isc.org>
Wed, 29 Oct 2025 22:49:49 +0000 (23:49 +0100)
instead of using an opaque ns_cfgctx pointer to store the configuration
data to be used by addzone and modzone, there are now fields in the
dns_view object to store the view configuration and LMDB database
environment. the global configuration is now stored in the named_server
object, along with the ACL context.

bin/named/include/named/server.h
bin/named/server.c
lib/dns/include/dns/view.h
lib/dns/view.c
lib/isccfg/aclconf.c
lib/isccfg/include/isccfg/aclconf.h

index da28b0cf5b44ddb24ebd0116912d52bd6c218f4c..d22c943d1abe7818b3d5fbfdc2cf4d8ac320c1f8 100644 (file)
@@ -110,6 +110,7 @@ struct named_server {
        isc_signal_t *sigusr1;
 
        cfg_aclconfctx_t *aclctx;
+       cfg_obj_t        *config;
 };
 
 #define NAMED_SERVER_MAGIC    ISC_MAGIC('S', 'V', 'E', 'R')
index 61cc44cca3085ae321594f01161dceeba13bb547..1b3767467bd99eda62cb40ae59e948a3f71fb01d 100644 (file)
@@ -301,18 +301,6 @@ typedef struct matching_view_ctx {
        dns_view_t *view;
 } matching_view_ctx_t;
 
-/*%
- * Configuration context to retain for each view that allows
- * new zones to be added at runtime.
- */
-typedef struct ns_cfgctx {
-       isc_mem_t *mctx;
-       cfg_obj_t *config;
-       cfg_obj_t *vconfig;
-       cfg_obj_t *nzf_config;
-       cfg_aclconfctx_t *aclctx;
-} ns_cfgctx_t;
-
 /*%
  * A function to write out added-zone configuration to the new_zone_file
  * specified in 'view'. Maybe called by delete_zoneconf().
@@ -509,9 +497,6 @@ find_maplist(const cfg_obj_t *config, const char *listname, const char *name);
 static isc_result_t
 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
 
-static void
-newzone_cfgctx_destroy(void **cfgp);
-
 static isc_result_t
 putstr(isc_buffer_t **b, const char *str);
 
@@ -545,7 +530,7 @@ nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
 #endif /* ifdef HAVE_LMDB */
 
 static isc_result_t
-load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg);
+load_nzf(dns_view_t *view);
 
 /*%
  * Configure a single view ACL at '*aclp'.  Get its configuration from
@@ -2339,29 +2324,20 @@ catz_addmodzone_cb(void *arg) {
        const cfg_obj_t *zlist = NULL;
        cfg_obj_t *zoneconf = NULL;
        cfg_obj_t *zoneobj = NULL;
-       ns_cfgctx_t *cfg = NULL;
        dns_zone_t *zone = NULL;
+       dns_view_t *view = cz->view;
 
        if (isc_loop_shuttingdown(isc_loop_get(isc_tid()))) {
                goto cleanup;
        }
 
-       /*
-        * A non-empty 'catalog-zones' statement implies that 'allow-new-zones'
-        * is true, so this is expected to be non-NULL.
-        */
-       cfg = (ns_cfgctx_t *)cz->view->new_zone_config;
-       if (cfg == NULL) {
-               CHECK(ISC_R_FAILURE);
-       }
-
        name = dns_catz_entry_getname(cz->entry);
 
        isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
        dns_name_totext(name, DNS_NAME_OMITFINALDOT, &namebuf);
        isc_buffer_putuint8(&namebuf, 0);
 
-       result = dns_fwdtable_find(cz->view->fwdtable, name, &dnsforwarders);
+       result = dns_fwdtable_find(view->fwdtable, name, &dnsforwarders);
        if (result == ISC_R_SUCCESS &&
            dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
        {
@@ -2374,7 +2350,7 @@ catz_addmodzone_cb(void *arg) {
                goto cleanup;
        }
 
-       result = dns_view_findzone(cz->view, name, DNS_ZTFIND_EXACT, &zone);
+       result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone);
 
        if (cz->mod) {
                dns_catz_zone_t *parentcatz;
@@ -2455,7 +2431,7 @@ catz_addmodzone_cb(void *arg) {
        confbuf = NULL;
        result = dns_catz_generate_zonecfg(cz->origin, cz->entry, &confbuf);
        if (result == ISC_R_SUCCESS) {
-               result = cfg_parse_buffer(cfg->mctx, confbuf, "catz", 0,
+               result = cfg_parse_buffer(isc_g_mctx, confbuf, "catz", 0,
                                          &cfg_type_addzoneconf, 0, &zoneconf);
                isc_buffer_free(&confbuf);
        }
@@ -2481,12 +2457,12 @@ catz_addmodzone_cb(void *arg) {
 
        /* Mark view unfrozen so that zone can be added */
        isc_loopmgr_pause();
-       dns_view_thaw(cz->view);
-       result = configure_zone(cfg->config, zoneobj, cfg->vconfig, cz->view,
-                               &cz->cbd->server->viewlist,
-                               &cz->cbd->server->kasplist, cfg->aclctx, true,
-                               false, true, cz->mod);
-       dns_view_freeze(cz->view);
+       dns_view_thaw(view);
+       result = configure_zone(
+               cz->cbd->server->config, zoneobj, view->newzone.vconfig, view,
+               &cz->cbd->server->viewlist, &cz->cbd->server->kasplist,
+               cz->cbd->server->aclctx, true, false, true, cz->mod);
+       dns_view_freeze(view);
        isc_loopmgr_resume();
 
        if (result != ISC_R_SUCCESS) {
@@ -2498,7 +2474,7 @@ catz_addmodzone_cb(void *arg) {
        }
 
        /* Is it there yet? */
-       CHECK(dns_view_findzone(cz->view, name, DNS_ZTFIND_EXACT, &zone));
+       CHECK(dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone));
 
        /*
         * Load the zone from the master file.  If this fails, we'll
@@ -2520,7 +2496,7 @@ catz_addmodzone_cb(void *arg) {
                }
 
                /* Remove the zone from the zone table */
-               dns_view_delzone(cz->view, zone);
+               dns_view_delzone(view, zone);
                goto cleanup;
        }
 
@@ -2540,7 +2516,7 @@ cleanup:
        }
        dns_catz_entry_detach(cz->origin, &cz->entry);
        dns_catz_zone_detach(&cz->origin);
-       dns_view_weakdetach(&cz->view);
+       dns_view_weakdetach(&view);
        isc_mem_putanddetach(&cz->mctx, cz, sizeof(*cz));
 }
 
@@ -2707,7 +2683,6 @@ catz_reconfigure(dns_catz_entry_t *entry, void *arg1, void *arg2) {
        char nameb[DNS_NAME_FORMATSIZE];
        cfg_obj_t *zoneconf = NULL;
        cfg_obj_t *zoneobj = NULL;
-       ns_cfgctx_t *cfg = NULL;
        dns_zone_t *zone = NULL;
        isc_result_t result;
 
@@ -2722,18 +2697,9 @@ catz_reconfigure(dns_catz_entry_t *entry, void *arg1, void *arg2) {
                return;
        }
 
-       /*
-        * A non-empty 'catalog-zones' statement implies that 'allow-new-zones'
-        * is true, so this is expected to be non-NULL.
-        */
-       cfg = (ns_cfgctx_t *)view->new_zone_config;
-       if (cfg == NULL) {
-               CHECK(ISC_R_FAILURE);
-       }
-
        result = dns_catz_generate_zonecfg(data->catz, entry, &confbuf);
        if (result == ISC_R_SUCCESS) {
-               result = cfg_parse_buffer(cfg->mctx, confbuf, "catz", 0,
+               result = cfg_parse_buffer(isc_g_mctx, confbuf, "catz", 0,
                                          &cfg_type_addzoneconf, 0, &zoneconf);
                isc_buffer_free(&confbuf);
        }
@@ -2756,10 +2722,10 @@ catz_reconfigure(dns_catz_entry_t *entry, void *arg1, void *arg2) {
        }
        zoneobj = cfg_listelt_value(cfg_list_first(zlist));
 
-       result = configure_zone(data->config, zoneobj, cfg->vconfig, view,
-                               &data->cbd->server->viewlist,
-                               &data->cbd->server->kasplist, cfg->aclctx, true,
-                               false, true, true);
+       result = configure_zone(
+               data->config, zoneobj, view->newzone.vconfig, view,
+               &data->cbd->server->viewlist, &data->cbd->server->kasplist,
+               data->cbd->server->aclctx, true, false, true, true);
        if (result != ISC_R_SUCCESS) {
                isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
                              ISC_LOG_ERROR,
@@ -7156,23 +7122,83 @@ cleanup:
        return result;
 }
 
+static void
+newzone_cleanup(dns_view_t *view) {
+       if (view->newzone.vconfig != NULL) {
+               cfg_obj_detach(&view->newzone.vconfig);
+       }
+       if (view->newzone.nzconfig != NULL) {
+               cfg_obj_detach(&view->newzone.nzconfig);
+       }
+
+#ifdef HAVE_LMDB
+       if (view->newzone.dbenv != NULL) {
+               mdb_env_close(view->newzone.dbenv);
+               view->newzone.dbenv = NULL;
+       }
+#endif /* ifdef HAVE_LMDB */
+
+       if (view->newzone.file != NULL) {
+               isc_mem_free(view->mctx, view->newzone.file);
+       }
+       if (view->newzone.dir != NULL) {
+               isc_mem_free(view->mctx, view->newzone.dir);
+       }
+       if (view->newzone.db != NULL) {
+               isc_mem_free(view->mctx, view->newzone.db);
+       }
+
+       view->newzone.allowed = false;
+}
+
 static isc_result_t
-setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
-              cfg_aclconfctx_t *aclctx) {
+nz_filename(dns_view_t *view, const char *suffix, char *buffer, size_t buflen) {
+       isc_result_t result;
+       char newbuf[PATH_MAX];
+
+       result = isc_file_sanitize(view->newzone.dir, view->name, suffix,
+                                  buffer, buflen);
+       if (result != ISC_R_SUCCESS) {
+               return result;
+       } else if (view->newzone.dir == NULL || isc_file_exists(buffer)) {
+               return ISC_R_SUCCESS;
+       } else {
+               /* Save buffer */
+               strlcpy(newbuf, buffer, sizeof(newbuf));
+       }
+
+       /*
+        * It isn't in the specified directory; check CWD.
+        */
+       result = isc_file_sanitize(NULL, view->name, suffix, buffer, buflen);
+       if (result != ISC_R_SUCCESS || isc_file_exists(buffer)) {
+               return result;
+       }
+
+       /*
+        * File does not exist in either 'directory' or CWD,
+        * so use the path in 'directory'.
+        */
+       strlcpy(buffer, newbuf, buflen);
+       return ISC_R_SUCCESS;
+}
+
+static isc_result_t
+setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig) {
        isc_result_t result = ISC_R_SUCCESS;
-       bool allow = false;
-       ns_cfgctx_t *nzcfg = NULL;
        const cfg_obj_t *maps[4];
        const cfg_obj_t *options = NULL, *voptions = NULL;
        const cfg_obj_t *nz = NULL;
-       const cfg_obj_t *nzdir = NULL;
        const char *dir = NULL;
        const cfg_obj_t *obj = NULL;
+       char buffer[1024];
        int i = 0;
-       uint64_t mapsize = 0ULL;
 
        REQUIRE(config != NULL);
 
+       /* Unnecessary but harmless */
+       newzone_cleanup(view);
+
        if (vconfig != NULL) {
                voptions = cfg_tuple_get(vconfig, "options");
        }
@@ -7187,11 +7213,26 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
 
        result = named_config_get(maps, "allow-new-zones", &nz);
        if (result == ISC_R_SUCCESS) {
-               allow = cfg_obj_asboolean(nz);
+               view->newzone.allowed = cfg_obj_asboolean(nz);
        }
-       result = named_config_get(maps, "new-zones-directory", &nzdir);
+       if (!view->newzone.allowed) {
+               /*
+                * A non-empty catalog-zones statement implies allow-new-zones
+                */
+               const cfg_obj_t *cz = NULL;
+               result = named_config_get(maps, "catalog-zones", &cz);
+               if (result == ISC_R_SUCCESS) {
+                       const cfg_listelt_t *e =
+                               cfg_list_first(cfg_tuple_get(cz, "zone list"));
+                       if (e != NULL) {
+                               view->newzone.allowed = true;
+                       }
+               }
+       }
+
+       result = named_config_get(maps, "new-zones-directory", &obj);
        if (result == ISC_R_SUCCESS) {
-               dir = cfg_obj_asstring(nzdir);
+               dir = cfg_obj_asstring(obj);
                result = isc_file_isdirectory(dir);
                if (result != ISC_R_SUCCESS) {
                        isc_log_write(DNS_LOGCATEGORY_SECURITY,
@@ -7209,78 +7250,86 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
                        return ISC_R_NOPERM;
                }
 
-               dns_view_setnewzonedir(view, dir);
+               view->newzone.dir = isc_mem_strdup(view->mctx, dir);
        }
 
+       CHECK(nz_filename(view, "nzf", buffer, sizeof(buffer)));
+       view->newzone.file = isc_mem_strdup(view->mctx, buffer);
+
 #ifdef HAVE_LMDB
+       uint64_t mapsize = 0ULL;
+
+       obj = NULL;
        result = named_config_get(maps, "lmdb-mapsize", &obj);
        if (result == ISC_R_SUCCESS && obj != NULL) {
                mapsize = cfg_obj_asuint64(obj);
                if (mapsize < (1ULL << 20)) { /* 1 megabyte */
                        cfg_obj_log(obj, ISC_LOG_ERROR,
-                                   "'lmdb-mapsize "
-                                   "%" PRId64 "' "
-                                   "is too small",
+                                   "'lmdb-mapsize %" PRId64 "' is too small",
                                    mapsize);
                        return ISC_R_FAILURE;
                } else if (mapsize > (1ULL << 40)) { /* 1 terabyte */
                        cfg_obj_log(obj, ISC_LOG_ERROR,
-                                   "'lmdb-mapsize "
-                                   "%" PRId64 "' "
-                                   "is too large",
+                                   "'lmdb-mapsize %" PRId64 "' is too large",
                                    mapsize);
                        return ISC_R_FAILURE;
                }
        }
-#else  /* ifdef HAVE_LMDB */
-       UNUSED(obj);
-#endif /* HAVE_LMDB */
 
-       /*
-        * A non-empty catalog-zones statement implies allow-new-zones
-        */
-       if (!allow) {
-               const cfg_obj_t *cz = NULL;
-               result = named_config_get(maps, "catalog-zones", &cz);
-               if (result == ISC_R_SUCCESS) {
-                       const cfg_listelt_t *e =
-                               cfg_list_first(cfg_tuple_get(cz, "zone list"));
-                       if (e != NULL) {
-                               allow = true;
-                       }
-               }
-       }
+       if (view->newzone.allowed) {
+               CHECK(nz_filename(view, "nzd", buffer, sizeof(buffer)));
+               view->newzone.db = isc_mem_strdup(view->mctx, buffer);
 
-       if (!allow) {
-               dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
-               return ISC_R_SUCCESS;
-       }
+               MDB_env *env = NULL;
+               int status = mdb_env_create(&env);
+               if (status != MDB_SUCCESS) {
+                       isc_log_write(DNS_LOGCATEGORY_GENERAL,
+                                     ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
+                                     "mdb_env_create failed: %s",
+                                     mdb_strerror(status));
+                       CHECK(ISC_R_FAILURE);
+               }
 
-       nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
-       *nzcfg = (ns_cfgctx_t){ 0 };
+               if (mapsize != 0ULL) {
+                       status = mdb_env_set_mapsize(env, mapsize);
+                       if (status != MDB_SUCCESS) {
+                               isc_log_write(DNS_LOGCATEGORY_GENERAL,
+                                             ISC_LOGMODULE_OTHER,
+                                             ISC_LOG_ERROR,
+                                             "mdb_env_set_mapsize failed: %s",
+                                             mdb_strerror(status));
+                               CHECK(ISC_R_FAILURE);
+                       }
+                       view->newzone.mapsize = mapsize;
+               }
 
-       /*
-        * We attach the parser that will be used for added zones to avoid
-        * a shutdown race later.
-        */
-       isc_mem_attach(view->mctx, &nzcfg->mctx);
-       cfg_aclconfctx_attach(aclctx, &nzcfg->aclctx);
+               status = mdb_env_open(env, view->newzone.db, DNS_LMDB_FLAGS,
+                                     0600);
+               if (status != MDB_SUCCESS) {
+                       isc_log_write(DNS_LOGCATEGORY_GENERAL,
+                                     ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
+                                     "mdb_env_open of '%s' failed: %s",
+                                     view->newzone.db, mdb_strerror(status));
+                       CHECK(ISC_R_FAILURE);
+               }
 
-       result = dns_view_setnewzones(view, true, nzcfg, newzone_cfgctx_destroy,
-                                     mapsize);
-       if (result != ISC_R_SUCCESS) {
-               cfg_aclconfctx_detach(&nzcfg->aclctx);
-               isc_mem_putanddetach(&nzcfg->mctx, nzcfg, sizeof(*nzcfg));
-               dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
-               return result;
+               view->newzone.dbenv = env;
+               env = NULL;
        }
+#endif /* HAVE_LMDB */
 
-       cfg_obj_attach(config, &nzcfg->config);
+       view->newzone.cleanup = newzone_cleanup;
        if (vconfig != NULL) {
-               cfg_obj_attach(vconfig, &nzcfg->vconfig);
+               cfg_obj_attach(vconfig, &view->newzone.vconfig);
        }
 
-       result = load_nzf(view, nzcfg);
+       if (view->newzone.allowed) {
+               result = load_nzf(view);
+       }
+       return result;
+
+cleanup:
+       newzone_cleanup(view);
        return result;
 }
 
@@ -7330,11 +7379,10 @@ static isc_result_t
 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
                   cfg_aclconfctx_t *aclctx, dns_kasplist_t *kasplist) {
        isc_result_t result;
-       ns_cfgctx_t *nzctx = NULL;
        const cfg_obj_t *zonelist = NULL;
 
-       nzctx = view->new_zone_config;
-       if (nzctx == NULL || nzctx->nzf_config == NULL) {
+       if (!view->newzone.allowed || view->newzone.nzconfig == NULL) {
+               /* New zones are disallowed, or the NZF file is empty */
                return ISC_R_SUCCESS;
        }
 
@@ -7343,7 +7391,7 @@ configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
                      view->name);
 
        zonelist = NULL;
-       cfg_map_get(nzctx->nzf_config, "zone", &zonelist);
+       cfg_map_get(view->newzone.nzconfig, "zone", &zonelist);
 
        CFG_LIST_FOREACH(zonelist, element) {
                const cfg_obj_t *zconfig = cfg_listelt_value(element);
@@ -7412,14 +7460,14 @@ data_to_cfg(dns_view_t *view, MDB_val *key, MDB_val *data, isc_buffer_t **text,
        snprintf(bufname, sizeof(bufname), "%.*s", (int)zone_name_len,
                 zone_name);
 
-       result = cfg_parse_buffer(view->mctx, *text, bufname, 0,
+       result = cfg_parse_buffer(isc_g_mctx, *text, bufname, 0,
                                  &cfg_type_addzoneconf, 0, &zoneconf);
        if (result != ISC_R_SUCCESS) {
                isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
                              ISC_LOG_ERROR,
                              "parsing config for zone '%.*s' in "
                              "NZD database '%s' failed",
-                             (int)zone_name_len, zone_name, view->new_zone_db);
+                             (int)zone_name_len, zone_name, view->newzone.db);
                goto cleanup;
        }
 
@@ -7453,7 +7501,7 @@ typedef isc_result_t (*newzone_cfg_cb_t)(const cfg_obj_t *zconfig,
  * transforming NZD data into a zone configuration object or if "callback"
  * returns an error.
  *
- * Caller must hold 'view->new_zone_lock'.
+ * Caller must hold 'view->newzone.lock'.
  */
 static isc_result_t
 for_all_newzone_cfgs(newzone_cfg_cb_t callback, cfg_obj_t *config,
@@ -7560,23 +7608,22 @@ configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
        MDB_txn *txn = NULL;
        MDB_dbi dbi;
 
-       if (view->new_zone_config == NULL) {
+       if (!view->newzone.allowed) {
                return ISC_R_SUCCESS;
        }
 
-       LOCK(&view->new_zone_lock);
+       LOCK(&view->newzone.lock);
 
        result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
        if (result != ISC_R_SUCCESS) {
-               UNLOCK(&view->new_zone_lock);
+               UNLOCK(&view->newzone.lock);
                return ISC_R_SUCCESS;
        }
 
        isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
                      ISC_LOG_INFO,
-                     "loading NZD configs from '%s' "
-                     "for view '%s'",
-                     view->new_zone_db, view->name);
+                     "loading NZD configs from '%s' for view '%s'",
+                     view->newzone.db, view->name);
 
        result = for_all_newzone_cfgs(configure_newzone, config, vconfig, view,
                                      aclctx, kasplist, txn, dbi);
@@ -7596,7 +7643,7 @@ configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
 
        (void)nzd_close(&txn, false);
 
-       UNLOCK(&view->new_zone_lock);
+       UNLOCK(&view->newzone.lock);
 
        return result;
 }
@@ -7607,8 +7654,7 @@ configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
                      ISC_LOG_DEBUG(1), "apply_configuration: %s", __func__);
 
 static isc_result_t
-create_views(cfg_obj_t *config, cfg_aclconfctx_t *aclctx,
-            dns_viewlist_t *viewlist) {
+create_views(cfg_obj_t *config, dns_viewlist_t *viewlist) {
        isc_result_t result = ISC_R_SUCCESS;
        const cfg_obj_t *bindview = NULL;
        const cfg_obj_t *views = NULL;
@@ -7640,9 +7686,8 @@ create_views(cfg_obj_t *config, cfg_aclconfctx_t *aclctx,
                CHECK(create_view(vconfig, viewlist, &view));
                INSIST(view != NULL);
 
-               result = setup_newzones(view, config, vconfig, aclctx);
+               CHECK(setup_newzones(view, config, vconfig));
                explicitviews = true;
-
                dns_view_detach(&view);
        }
 
@@ -7654,7 +7699,7 @@ create_views(cfg_obj_t *config, cfg_aclconfctx_t *aclctx,
                CHECK(create_view(NULL, viewlist, &view));
                INSIST(view != NULL);
 
-               CHECK(setup_newzones(view, config, NULL, aclctx));
+               CHECK(setup_newzones(view, config, NULL));
                dns_view_detach(&view);
        }
 
@@ -7919,7 +7964,7 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
                goto cleanup_kasplist;
        }
 
-       result = create_views(config, aclctx, &viewlist);
+       result = create_views(config, &viewlist);
        if (result != ISC_R_SUCCESS) {
                goto cleanup_viewlist;
        }
@@ -8903,6 +8948,11 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
         */
        named_g_defaultconfigtime = isc_time_now();
 
+       if (server->config != NULL) {
+               cfg_obj_detach(&server->config);
+       }
+       cfg_obj_attach(config, &server->config);
+
        isc_loopmgr_resume();
        exclusive = false;
 
@@ -9701,6 +9751,10 @@ named_server_destroy(named_server_t **serverp) {
                isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
        }
 
+       if (server->config != NULL) {
+               cfg_obj_detach(&server->config);
+       }
+
        server->magic = 0;
        isc_mem_put(server->mctx, server, sizeof(*server));
        *serverp = NULL;
@@ -12147,9 +12201,9 @@ nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) {
        FILE *fp = NULL;
        bool offsetok = false;
 
-       LOCK(&view->new_zone_lock);
+       LOCK(&view->newzone.lock);
 
-       CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
+       CHECK(isc_stdio_open(view->newzone.file, "a", &fp));
        CHECK(isc_stdio_seek(fp, 0, SEEK_END));
 
        CHECK(isc_stdio_tell(fp, &offset));
@@ -12171,8 +12225,7 @@ cleanup:
                if (offsetok) {
                        isc_result_t result2;
 
-                       result2 = isc_file_truncate(view->new_zone_file,
-                                                   offset);
+                       result2 = isc_file_truncate(view->newzone.file, offset);
                        if (result2 != ISC_R_SUCCESS) {
                                isc_log_write(NAMED_LOGCATEGORY_GENERAL,
                                              NAMED_LOGMODULE_SERVER,
@@ -12180,12 +12233,12 @@ cleanup:
                                              "Error truncating NZF file '%s' "
                                              "during rollback from append: "
                                              "%s",
-                                             view->new_zone_file,
+                                             view->newzone.file,
                                              isc_result_totext(result2));
                        }
                }
        }
-       UNLOCK(&view->new_zone_lock);
+       UNLOCK(&view->newzone.lock);
        return result;
 }
 
@@ -12197,7 +12250,7 @@ nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
        char tmp[1024];
        isc_result_t result;
 
-       result = isc_file_template(view->new_zone_file, "nzf-XXXXXXXX", tmp,
+       result = isc_file_template(view->newzone.file, "nzf-XXXXXXXX", tmp,
                                   sizeof(tmp));
        if (result == ISC_R_SUCCESS) {
                result = isc_file_openunique(tmp, &fp);
@@ -12229,7 +12282,7 @@ nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
        if (result != ISC_R_SUCCESS) {
                goto cleanup;
        }
-       CHECK(isc_file_rename(tmp, view->new_zone_file));
+       CHECK(isc_file_rename(tmp, view->newzone.file));
        return result;
 
 cleanup:
@@ -12241,24 +12294,24 @@ cleanup:
 }
 
 static isc_result_t
-load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg) {
+load_nzf(dns_view_t *view) {
        isc_result_t result;
 
        /* The new zone file may not exist. That is OK. */
-       if (!isc_file_exists(view->new_zone_file)) {
+       if (!isc_file_exists(view->newzone.file)) {
                return ISC_R_SUCCESS;
        }
 
        /*
-        * Parse the configuration in the NZF file.  This may be called in
-        * multiple views, so we reset the parser each time.
+        * Parse the configuration in the NZF file.
         */
-       result = cfg_parse_file(nzcfg->mctx, view->new_zone_file,
-                               &cfg_type_addzoneconf, 0, &nzcfg->nzf_config);
+       result = cfg_parse_file(view->mctx, view->newzone.file,
+                               &cfg_type_addzoneconf, 0,
+                               &view->newzone.nzconfig);
        if (result != ISC_R_SUCCESS) {
                isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
                              ISC_LOG_ERROR, "Error parsing NZF file '%s': %s",
-                             view->new_zone_file, isc_result_totext(result));
+                             view->newzone.file, isc_result_totext(result));
        }
 
        return result;
@@ -12393,7 +12446,7 @@ cleanup:
 /*
  * Check whether the new zone database for 'view' can be opened for writing.
  *
- * Caller must hold 'view->new_zone_lock'.
+ * Caller must hold 'view->newzone.lock'.
  */
 static isc_result_t
 nzd_writable(dns_view_t *view) {
@@ -12404,7 +12457,7 @@ nzd_writable(dns_view_t *view) {
 
        REQUIRE(view != NULL);
 
-       status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, 0, &txn);
+       status = mdb_txn_begin(view->newzone.dbenv, 0, 0, &txn);
        if (status != MDB_SUCCESS) {
                isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
                              ISC_LOG_WARNING, "mdb_txn_begin: %s",
@@ -12427,7 +12480,7 @@ nzd_writable(dns_view_t *view) {
 /*
  * Open the new zone database for 'view' and start a transaction for it.
  *
- * Caller must hold 'view->new_zone_lock'.
+ * Caller must hold 'view->newzone.lock'.
  */
 static isc_result_t
 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
@@ -12438,7 +12491,7 @@ nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
        REQUIRE(txnp != NULL && *txnp == NULL);
        REQUIRE(dbi != NULL);
 
-       status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, flags, &txn);
+       status = mdb_txn_begin(view->newzone.dbenv, 0, flags, &txn);
        if (status != MDB_SUCCESS) {
                isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
                              ISC_LOG_WARNING, "mdb_txn_begin: %s",
@@ -12468,7 +12521,7 @@ cleanup:
 }
 
 /*
- * nzd_env_close() and nzd_env_reopen are a kluge to address the
+ * nzd_env_close() and nzd_env_reopen() are a kluge to address the
  * problem of an NZD file possibly being created before we drop
  * root privileges.
  */
@@ -12479,15 +12532,15 @@ nzd_env_close(dns_view_t *view) {
        char lockpath[PATH_MAX];
        int status, ret;
 
-       if (view->new_zone_dbenv == NULL) {
+       if (view->newzone.dbenv == NULL) {
                return;
        }
 
-       status = mdb_env_get_path(view->new_zone_dbenv, &dbpath);
+       status = mdb_env_get_path(view->newzone.dbenv, &dbpath);
        INSIST(status == MDB_SUCCESS);
        snprintf(lockpath, sizeof(lockpath), "%s-lock", dbpath);
        strlcpy(dbpath_copy, dbpath, sizeof(dbpath_copy));
-       mdb_env_close((MDB_env *)view->new_zone_dbenv);
+       mdb_env_close(view->newzone.dbenv);
 
        /*
         * Database files must be owned by the eventual user, not by root.
@@ -12501,7 +12554,7 @@ nzd_env_close(dns_view_t *view) {
         */
        (void)isc_file_remove(lockpath);
 
-       view->new_zone_dbenv = NULL;
+       view->newzone.dbenv = NULL;
 }
 
 static isc_result_t
@@ -12510,7 +12563,7 @@ nzd_env_reopen(dns_view_t *view) {
        MDB_env *env = NULL;
        int status;
 
-       if (view->new_zone_db == NULL) {
+       if (view->newzone.db == NULL) {
                return ISC_R_SUCCESS;
        }
 
@@ -12524,8 +12577,8 @@ nzd_env_reopen(dns_view_t *view) {
                CHECK(ISC_R_FAILURE);
        }
 
-       if (view->new_zone_mapsize != 0ULL) {
-               status = mdb_env_set_mapsize(env, view->new_zone_mapsize);
+       if (view->newzone.mapsize != 0ULL) {
+               status = mdb_env_set_mapsize(env, view->newzone.mapsize);
                if (status != MDB_SUCCESS) {
                        isc_log_write(DNS_LOGCATEGORY_GENERAL,
                                      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
@@ -12535,15 +12588,15 @@ nzd_env_reopen(dns_view_t *view) {
                }
        }
 
-       status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
+       status = mdb_env_open(env, view->newzone.db, DNS_LMDB_FLAGS, 0600);
        if (status != MDB_SUCCESS) {
                isc_log_write(DNS_LOGCATEGORY_GENERAL, ISC_LOGMODULE_OTHER,
                              ISC_LOG_ERROR, "mdb_env_open of '%s' failed: %s",
-                             view->new_zone_db, mdb_strerror(status));
+                             view->newzone.db, mdb_strerror(status));
                CHECK(ISC_R_FAILURE);
        }
 
-       view->new_zone_dbenv = env;
+       view->newzone.dbenv = env;
        env = NULL;
        result = ISC_R_SUCCESS;
 
@@ -12558,7 +12611,7 @@ cleanup:
  * If 'commit' is true, commit the new zone database transaction pointed to by
  * 'txnp'; otherwise, abort that transaction.
  *
- * Caller must hold 'view->new_zone_lock' for the view that the transaction
+ * Caller must hold 'view->newzone.lock' for the view that the transaction
  * pointed to by 'txnp' was started for.
  */
 static isc_result_t
@@ -12587,10 +12640,10 @@ nzd_close(MDB_txn **txnp, bool commit) {
  * If there's an existing NZF file, load it and migrate its data
  * to the NZD.
  *
- * Caller must hold view->new_zone_lock.
+ * Caller must hold view->newzone.lock.
  */
 static isc_result_t
-load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg) {
+load_nzf(dns_view_t *view) {
        isc_result_t result;
        cfg_obj_t *nzf_config = NULL;
        int status;
@@ -12603,13 +12656,11 @@ load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg) {
        MDB_val key, data;
        ns_dzarg_t dzarg;
 
-       UNUSED(nzcfg);
-
        /*
         * If NZF file doesn't exist, or NZD DB exists and already
         * has data, return without attempting migration.
         */
-       if (!isc_file_exists(view->new_zone_file)) {
+       if (!isc_file_exists(view->newzone.file)) {
                result = ISC_R_SUCCESS;
                goto cleanup;
        }
@@ -12618,19 +12669,19 @@ load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg) {
                      ISC_LOG_INFO,
                      "Migrating zones from NZF file '%s' to "
                      "NZD database '%s'",
-                     view->new_zone_file, view->new_zone_db);
+                     view->newzone.file, view->newzone.db);
        /*
         * Instead of blindly copying lines, we parse the NZF file using
         * the configuration parser, because it validates it against the
         * config type, giving us a guarantee that valid configuration
         * will be written to DB.
         */
-       result = cfg_parse_file(nzcfg->mctx, view->new_zone_file,
+       result = cfg_parse_file(isc_g_mctx, view->newzone.file,
                                &cfg_type_addzoneconf, 0, &nzf_config);
        if (result != ISC_R_SUCCESS) {
                isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
                              ISC_LOG_ERROR, "Error parsing NZF file '%s': %s",
-                             view->new_zone_file, isc_result_totext(result));
+                             view->newzone.file, isc_result_totext(result));
                goto cleanup;
        }
 
@@ -12715,10 +12766,10 @@ load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg) {
         * if an NZD database is found for the view. But we rename NZF file
         * to a backup name here.
         */
-       strlcpy(tempname, view->new_zone_file, sizeof(tempname));
+       strlcpy(tempname, view->newzone.file, sizeof(tempname));
        if (strlen(tempname) < sizeof(tempname) - 1) {
                strlcat(tempname, "~", sizeof(tempname));
-               isc_file_rename(view->new_zone_file, tempname);
+               isc_file_rename(view->newzone.file, tempname);
        }
 
 cleanup:
@@ -12876,7 +12927,7 @@ delete_zoneconf(dns_view_t *view, const cfg_obj_t *config,
        REQUIRE(config != NULL);
        REQUIRE(zname != NULL);
 
-       LOCK(&view->new_zone_lock);
+       LOCK(&view->newzone.lock);
 
        cfg_map_get(config, "zone", &zl);
 
@@ -12906,19 +12957,19 @@ delete_zoneconf(dns_view_t *view, const cfg_obj_t *config,
        /*
         * Write config to NZF file if appropriate
         */
-       if (nzfwriter != NULL && view->new_zone_file != NULL) {
+       if (nzfwriter != NULL && view->newzone.file != NULL) {
                result = nzfwriter(config, view);
        }
 
 cleanup:
-       UNLOCK(&view->new_zone_lock);
+       UNLOCK(&view->newzone.lock);
        return result;
 }
 
 static isc_result_t
-do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
-          dns_name_t *name, cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj,
-          bool redirect, isc_buffer_t **text) {
+do_addzone(named_server_t *server, dns_view_t *view, dns_name_t *name,
+          cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj, bool redirect,
+          isc_buffer_t **text) {
        isc_result_t result, tresult;
        dns_zone_t *zone = NULL;
        const cfg_obj_t *voptions = NULL;
@@ -12933,6 +12984,12 @@ do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        UNUSED(zoneconf);
 #endif
 
+       if (!view->newzone.allowed) {
+               result = ISC_R_NOPERM;
+               TCHECK(putstr(text, "new zone configuration is not allowed"));
+               goto cleanup;
+       }
+
        /* Zone shouldn't already exist */
        if (redirect) {
                result = (view->redirect == NULL) ? ISC_R_NOTFOUND
@@ -12953,11 +13010,11 @@ do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        /*
         * Make sure we can open the configuration save file
         */
-       result = isc_stdio_open(view->new_zone_file, "a", &fp);
+       result = isc_stdio_open(view->newzone.file, "a", &fp);
        if (result != ISC_R_SUCCESS) {
                isc_loopmgr_resume();
                TCHECK(putstr(text, "unable to create '"));
-               TCHECK(putstr(text, view->new_zone_file));
+               TCHECK(putstr(text, view->newzone.file));
                TCHECK(putstr(text, "': "));
                TCHECK(putstr(text, isc_result_totext(result)));
                goto cleanup;
@@ -12966,14 +13023,14 @@ do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        (void)isc_stdio_close(fp);
        fp = NULL;
 #else  /* HAVE_LMDB */
-       LOCK(&view->new_zone_lock);
+       LOCK(&view->newzone.lock);
        locked = true;
        /* Make sure we can open the NZD database */
        result = nzd_writable(view);
        if (result != ISC_R_SUCCESS) {
                isc_loopmgr_resume();
                TCHECK(putstr(text, "unable to open NZD database for '"));
-               TCHECK(putstr(text, view->new_zone_db));
+               TCHECK(putstr(text, view->newzone.db));
                TCHECK(putstr(text, "'"));
                result = ISC_R_FAILURE;
                goto cleanup;
@@ -12981,13 +13038,13 @@ do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
 #endif /* HAVE_LMDB */
 
        /* Check zone syntax */
-       if (cfg->vconfig != NULL) {
-               voptions = cfg_tuple_get(cfg->vconfig, "options");
+       if (view->newzone.vconfig != NULL) {
+               voptions = cfg_tuple_get(view->newzone.vconfig, "options");
        }
-       result = isccfg_check_zoneconf(zoneobj, voptions, cfg->config, NULL,
+       result = isccfg_check_zoneconf(zoneobj, voptions, server->config, NULL,
                                       NULL, NULL, NULL, view->name,
                                       view->rdclass, BIND_CHECK_PLUGINS,
-                                      cfg->aclctx, cfg->mctx);
+                                      server->aclctx, isc_g_mctx);
        if (result != ISC_R_SUCCESS) {
                isc_loopmgr_resume();
                goto cleanup;
@@ -12995,9 +13052,9 @@ do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
 
        /* Mark view unfrozen and configure zone */
        dns_view_thaw(view);
-       result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view,
-                               &server->viewlist, &server->kasplist,
-                               cfg->aclctx, true, false, false, false);
+       result = configure_zone(server->config, zoneobj, view->newzone.vconfig,
+                               view, &server->viewlist, &server->kasplist,
+                               server->aclctx, true, false, false, false);
        dns_view_freeze(view);
 
        isc_loopmgr_resume();
@@ -13031,11 +13088,11 @@ do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
         * we've created. If there was a previous one, merge the new
         * zone into it.
         */
-       if (cfg->nzf_config == NULL) {
-               cfg_obj_attach(zoneconf, &cfg->nzf_config);
+       if (view->newzone.nzconfig == NULL) {
+               cfg_obj_attach(zoneconf, &view->newzone.nzconfig);
        } else {
                cfg_obj_t *z = UNCONST(zoneobj);
-               CHECK(cfg_map_add(cfg->nzf_config, z, "zone"));
+               CHECK(cfg_map_add(view->newzone.nzconfig, z, "zone"));
        }
        cleanup_config = true;
 #endif /* HAVE_LMDB */
@@ -13084,7 +13141,8 @@ cleanup:
                (void)isc_stdio_close(fp);
        }
        if (result != ISC_R_SUCCESS && cleanup_config) {
-               tresult = delete_zoneconf(view, cfg->nzf_config, name, NULL);
+               tresult = delete_zoneconf(view, view->newzone.nzconfig, name,
+                                         NULL);
                RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
        }
 #else  /* HAVE_LMDB */
@@ -13092,7 +13150,7 @@ cleanup:
                (void)nzd_close(&txn, false);
        }
        if (locked) {
-               UNLOCK(&view->new_zone_lock);
+               UNLOCK(&view->newzone.lock);
        }
 #endif /* HAVE_LMDB */
 
@@ -13104,9 +13162,9 @@ cleanup:
 }
 
 static isc_result_t
-do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
-          dns_name_t *name, const char *zname, const cfg_obj_t *zoneobj,
-          bool redirect, isc_buffer_t **text) {
+do_modzone(named_server_t *server, dns_view_t *view, dns_name_t *name,
+          const char *zname, const cfg_obj_t *zoneobj, bool redirect,
+          isc_buffer_t **text) {
        isc_result_t result, tresult;
        dns_zone_t *zone = NULL;
        const cfg_obj_t *voptions = NULL;
@@ -13120,6 +13178,12 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        bool locked = false;
 #endif /* HAVE_LMDB */
 
+       if (!view->newzone.allowed) {
+               result = ISC_R_NOPERM;
+               TCHECK(putstr(text, "new zone configuration is not allowed"));
+               goto cleanup;
+       }
+
        /* Zone must already exist */
        if (redirect) {
                if (view->redirect != NULL) {
@@ -13138,22 +13202,14 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        added = dns_zone_getadded(zone);
        dns_zone_detach(&zone);
 
-#ifndef HAVE_LMDB
-       cfg = (ns_cfgctx_t *)view->new_zone_config;
-       if (cfg == NULL) {
-               TCHECK(putstr(text, "new zone config is not set"));
-               CHECK(ISC_R_FAILURE);
-       }
-#endif /* ifndef HAVE_LMDB */
-
        isc_loopmgr_pause();
 
 #ifndef HAVE_LMDB
        /* Make sure we can open the configuration save file */
-       result = isc_stdio_open(view->new_zone_file, "a", &fp);
+       result = isc_stdio_open(view->newzone.file, "a", &fp);
        if (result != ISC_R_SUCCESS) {
                TCHECK(putstr(text, "unable to open '"));
-               TCHECK(putstr(text, view->new_zone_file));
+               TCHECK(putstr(text, view->newzone.file));
                TCHECK(putstr(text, "': "));
                TCHECK(putstr(text, isc_result_totext(result)));
                isc_loopmgr_resume();
@@ -13162,13 +13218,13 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        (void)isc_stdio_close(fp);
        fp = NULL;
 #else  /* HAVE_LMDB */
-       LOCK(&view->new_zone_lock);
+       LOCK(&view->newzone.lock);
        locked = true;
        /* Make sure we can open the NZD database */
        result = nzd_writable(view);
        if (result != ISC_R_SUCCESS) {
                TCHECK(putstr(text, "unable to open NZD database for '"));
-               TCHECK(putstr(text, view->new_zone_db));
+               TCHECK(putstr(text, view->newzone.db));
                TCHECK(putstr(text, "'"));
                result = ISC_R_FAILURE;
                isc_loopmgr_resume();
@@ -13177,13 +13233,13 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
 #endif /* HAVE_LMDB */
 
        /* Check zone syntax */
-       if (cfg->vconfig != NULL) {
-               voptions = cfg_tuple_get(cfg->vconfig, "options");
+       if (view->newzone.vconfig != NULL) {
+               voptions = cfg_tuple_get(view->newzone.vconfig, "options");
        }
-       result = isccfg_check_zoneconf(zoneobj, voptions, cfg->config, NULL,
+       result = isccfg_check_zoneconf(zoneobj, voptions, server->config, NULL,
                                       NULL, NULL, NULL, view->name,
                                       view->rdclass, BIND_CHECK_PLUGINS,
-                                      cfg->aclctx, cfg->mctx);
+                                      server->aclctx, isc_g_mctx);
        if (result != ISC_R_SUCCESS) {
                isc_loopmgr_resume();
                goto cleanup;
@@ -13191,9 +13247,9 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
 
        /* Reconfigure the zone */
        dns_view_thaw(view);
-       result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view,
-                               &server->viewlist, &server->kasplist,
-                               cfg->aclctx, true, false, false, true);
+       result = configure_zone(server->config, zoneobj, view->newzone.vconfig,
+                               view, &server->viewlist, &server->kasplist,
+                               server->aclctx, true, false, false, true);
        dns_view_freeze(view);
 
        isc_loopmgr_resume();
@@ -13217,7 +13273,7 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
 #ifndef HAVE_LMDB
        /* Remove old zone from configuration (and NZF file if applicable) */
        if (added) {
-               result = delete_zoneconf(view, cfg->nzf_config,
+               result = delete_zoneconf(view, view->newzone.nzconfig,
                                         dns_zone_getorigin(zone),
                                         nzf_writeconf);
                if (result != ISC_R_SUCCESS) {
@@ -13230,12 +13286,12 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
 #endif /* HAVE_LMDB */
 
        if (!added) {
-               if (cfg->vconfig == NULL) {
-                       result = delete_zoneconf(view, cfg->config,
+               if (view->newzone.vconfig == NULL) {
+                       result = delete_zoneconf(view, server->config,
                                                 dns_zone_getorigin(zone),
                                                 NULL);
                } else {
-                       voptions = cfg_tuple_get(cfg->vconfig, "options");
+                       voptions = cfg_tuple_get(server->config, "options");
                        result = delete_zoneconf(
                                view, voptions, dns_zone_getorigin(zone), NULL);
                }
@@ -13286,7 +13342,7 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
 #ifndef HAVE_LMDB
        /* Store the new zone configuration; also in NZF if applicable */
        z = UNCONST(zoneobj);
-       CHECK(cfg_map_add(cfg->nzf_config, z, "zone"));
+       CHECK(cfg_map_add(view->newzone.nzconfig, z, "zone"));
 #endif /* HAVE_LMDB */
 
        if (added) {
@@ -13322,7 +13378,7 @@ cleanup:
                (void)nzd_close(&txn, false);
        }
        if (locked) {
-               UNLOCK(&view->new_zone_lock);
+               UNLOCK(&view->newzone.lock);
        }
 #endif /* HAVE_LMDB */
 
@@ -13342,7 +13398,6 @@ named_server_changezone(named_server_t *server, char *command,
        isc_result_t result;
        bool addzone;
        bool redirect = false;
-       ns_cfgctx_t *cfg = NULL;
        cfg_obj_t *zoneconf = NULL;
        const cfg_obj_t *zoneobj = NULL;
        const char *zonename;
@@ -13365,9 +13420,9 @@ named_server_changezone(named_server_t *server, char *command,
 
        /* Are we accepting new zones in this view? */
 #ifdef HAVE_LMDB
-       if (view->new_zone_db == NULL)
+       if (view->newzone.db == NULL)
 #else  /* ifdef HAVE_LMDB */
-       if (view->new_zone_file == NULL)
+       if (view->newzone.file == NULL)
 #endif /* HAVE_LMDB */
        {
                (void)putstr(text, "Not allowing new zones in view '");
@@ -13376,11 +13431,6 @@ named_server_changezone(named_server_t *server, char *command,
                CHECK(ISC_R_NOPERM);
        }
 
-       cfg = (ns_cfgctx_t *)view->new_zone_config;
-       if (cfg == NULL) {
-               CHECK(ISC_R_FAILURE);
-       }
-
        zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name"));
        isc_buffer_constinit(&buf, zonename, strlen(zonename));
        isc_buffer_add(&buf, strlen(zonename));
@@ -13397,10 +13447,10 @@ named_server_changezone(named_server_t *server, char *command,
        }
 
        if (addzone) {
-               CHECK(do_addzone(server, cfg, view, dnsname, zoneconf, zoneobj,
+               CHECK(do_addzone(server, view, dnsname, zoneconf, zoneobj,
                                 redirect, text));
        } else {
-               CHECK(do_modzone(server, cfg, view, dnsname, zonename, zoneobj,
+               CHECK(do_modzone(server, view, dnsname, zonename, zoneobj,
                                 redirect, text));
        }
 
@@ -13444,6 +13494,7 @@ inuse(const char *file, bool first, isc_buffer_t **text) {
 
 typedef struct {
        dns_zone_t *zone;
+       named_server_t *server;
        bool cleanup;
 } ns_dzctx_t;
 
@@ -13457,7 +13508,6 @@ rmzone(void *arg) {
        dns_catz_zone_t *catz = NULL;
        char zonename[DNS_NAME_FORMATSIZE];
        dns_view_t *view = NULL;
-       ns_cfgctx_t *cfg = NULL;
        dns_db_t *dbp = NULL;
        bool added;
        isc_result_t result;
@@ -13471,7 +13521,6 @@ rmzone(void *arg) {
        /* Dig out configuration for this zone */
        zone = dz->zone;
        view = dns_zone_getview(zone);
-       cfg = (ns_cfgctx_t *)view->new_zone_config;
        dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
 
        isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
@@ -13485,16 +13534,16 @@ rmzone(void *arg) {
        added = dns_zone_getadded(zone);
        catz = dns_zone_get_parentcatz(zone);
 
-       if (added && catz == NULL && cfg != NULL) {
+       if (added && catz == NULL) {
 #ifdef HAVE_LMDB
                /* Make sure we can open the NZD database */
-               LOCK(&view->new_zone_lock);
+               LOCK(&view->newzone.lock);
                result = nzd_open(view, 0, &txn, &dbi);
                if (result != ISC_R_SUCCESS) {
                        isc_log_write(NAMED_LOGCATEGORY_GENERAL,
                                      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
                                      "unable to open NZD database for '%s'",
-                                     view->new_zone_db);
+                                     view->newzone.db);
                } else {
                        result = nzd_save(&txn, dbi, zone, NULL);
                }
@@ -13509,9 +13558,9 @@ rmzone(void *arg) {
                if (txn != NULL) {
                        (void)nzd_close(&txn, false);
                }
-               UNLOCK(&view->new_zone_lock);
+               UNLOCK(&view->newzone.lock);
 #else  /* ifdef HAVE_LMDB */
-               result = delete_zoneconf(view, cfg->nzf_config,
+               result = delete_zoneconf(view, view->newzone.nzconfig,
                                         dns_zone_getorigin(zone),
                                         nzf_writeconf);
                if (result != ISC_R_SUCCESS) {
@@ -13523,14 +13572,14 @@ rmzone(void *arg) {
 #endif /* HAVE_LMDB */
        }
 
-       if (!added && cfg != NULL) {
-               if (cfg->vconfig != NULL) {
-                       const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
-                                                                 "options");
+       if (!added) {
+               if (view->newzone.vconfig != NULL) {
+                       const cfg_obj_t *voptions =
+                               cfg_tuple_get(view->newzone.vconfig, "options");
                        result = delete_zoneconf(
                                view, voptions, dns_zone_getorigin(zone), NULL);
                } else {
-                       result = delete_zoneconf(view, cfg->config,
+                       result = delete_zoneconf(view, dz->server->config,
                                                 dns_zone_getorigin(zone),
                                                 NULL);
                }
@@ -13659,6 +13708,12 @@ named_server_delzone(named_server_t *server, isc_lex_t *lex,
        }
 
        view = dns_zone_getview(zone);
+
+       if (!view->newzone.allowed) {
+               TCHECK(putstr(text, "new zone configuration is not allowed"));
+               CHECK(ISC_R_NOPERM);
+       }
+
        if (dns_zone_gettype(zone) == dns_zone_redirect) {
                dns_zone_detach(&view->redirect);
        } else {
@@ -13669,6 +13724,7 @@ named_server_delzone(named_server_t *server, isc_lex_t *lex,
        dz = isc_mem_get(isc_g_mctx, sizeof(*dz));
        *dz = (ns_dzctx_t){
                .cleanup = cleanup,
+               .server = server,
        };
        dns_zone_attach(zone, &dz->zone);
        isc_async_run(dns_zone_getloop(zone), rmzone, dz);
@@ -13798,32 +13854,6 @@ cleanup:
        return result;
 }
 
-static void
-newzone_cfgctx_destroy(void **cfgp) {
-       ns_cfgctx_t *cfg;
-
-       REQUIRE(cfgp != NULL && *cfgp != NULL);
-
-       cfg = *cfgp;
-
-       if (cfg->config != NULL) {
-               cfg_obj_detach(&cfg->config);
-       }
-       if (cfg->vconfig != NULL) {
-               cfg_obj_detach(&cfg->vconfig);
-       }
-       if (cfg->nzf_config != NULL) {
-               cfg_obj_detach(&cfg->nzf_config);
-       }
-
-       if (cfg->aclctx != NULL) {
-               cfg_aclconfctx_detach(&cfg->aclctx);
-       }
-
-       isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
-       *cfgp = NULL;
-}
-
 isc_result_t
 named_server_signing(named_server_t *server, isc_lex_t *lex,
                     isc_buffer_t **text) {
index d536cccbd3ebbb165d101d06f16c49a5f1bcc437..1c3bbdb06e35a50428a768e80f036d21243eef32 100644 (file)
 #include <dns/types.h>
 #include <dns/zt.h>
 
+/*
+ * These are opaque types that will be used by named to save
+ * newzones configuration in the view.
+ */
+typedef struct cfg_obj cfg_obj_t;
+typedef struct MDB_env MDB_env;
+
 struct dns_view {
        /* Unlocked. */
        unsigned int       magic;
@@ -203,28 +210,26 @@ struct dns_view {
        ISC_LINK(struct dns_view) link;
        dns_viewlist_t *viewlist;
 
-       dns_zone_t *managed_keys;
-       dns_zone_t *redirect;
-       dns_name_t *redirectzone; /* points to
-                                  * redirectfixed
-                                  * when valid */
+       dns_zone_t     *managed_keys;
+       dns_zone_t     *redirect;
+       dns_name_t     *redirectzone; /* points to redirectfixed when valid */
        dns_fixedname_t redirectfixed;
 
        /*
-        * File and configuration data for zones added at runtime
-        * (only used in BIND9).
-        *
-        * XXX: This should be a pointer to an opaque type that
-        * named implements.
+        * File and configuration data for zones added at runtime.
         */
-       char    *new_zone_dir;
-       char    *new_zone_file;
-       char    *new_zone_db;
-       void    *new_zone_dbenv;
-       uint64_t new_zone_mapsize;
-       void    *new_zone_config;
-       void (*cfg_destroy)(void **);
-       isc_mutex_t new_zone_lock;
+       struct {
+               bool       allowed;
+               char      *dir;
+               char      *file;
+               char      *db;
+               MDB_env   *dbenv;
+               uint64_t   mapsize;
+               cfg_obj_t *vconfig;
+               cfg_obj_t *nzconfig;
+               void (*cleanup)(dns_view_t *);
+               isc_mutex_t lock;
+       } newzone;
 
        unsigned char secret[32]; /* Client secret */
        unsigned int  v6bias;
@@ -1047,44 +1052,6 @@ dns_view_istrusted(dns_view_t *view, const dns_name_t *keyname,
  * \li 'dnskey' is valid.
  */
 
-isc_result_t
-dns_view_setnewzones(dns_view_t *view, bool allow, void *cfgctx,
-                    void (*cfg_destroy)(void **), uint64_t mapsize);
-/*%<
- * Set whether or not to allow zones to be created or deleted at runtime.
- *
- * If 'allow' is true, determines the filename into which new zone
- * configuration will be written.  Preserves the configuration context
- * (a pointer to which is passed in 'cfgctx') for use when parsing new
- * zone configuration.  'cfg_destroy' points to a callback routine to
- * destroy the configuration context when the view is destroyed.  (This
- * roundabout method is used in order to avoid libdns having a dependency
- * on libisccfg and libbind9.)
- *
- * If 'allow' is false, removes any existing references to
- * configuration context and frees any memory.
- *
- * Requires:
- * \li 'view' is valid.
- *
- * Returns:
- * \li ISC_R_SUCCESS
- * \li ISC_R_NOSPACE
- */
-
-void
-dns_view_setnewzonedir(dns_view_t *view, const char *dir);
-const char *
-dns_view_getnewzonedir(dns_view_t *view);
-/*%<
- * Set/get the path to the directory in which NZF or NZD files should
- * be stored. If the path was previously set to a non-NULL value,
- * the previous value is freed.
- *
- * Requires:
- * \li 'view' is valid.
- */
-
 void
 dns_view_restorekeyring(dns_view_t *view);
 
index 164b54becb0d5f9f31a76ab6eb48a84b8612ab50..7efc9234a2a48cd4b8fab59fffc0bf31f2115c7c 100644 (file)
@@ -160,7 +160,7 @@ dns_view_create(isc_mem_t *mctx, dns_dispatchmgr_t *dispatchmgr,
                view->mctx, UNREACH_HOLD_TIME_INITIAL_SEC,
                UNREACH_HOLD_TIME_MAX_SEC, UNREACH_BACKOFF_ELIGIBLE_SEC);
 
-       isc_mutex_init(&view->new_zone_lock);
+       isc_mutex_init(&view->newzone.lock);
 
        dns_order_create(view->mctx, &view->order);
 
@@ -345,20 +345,16 @@ destroy(dns_view_t *view) {
                dns_dt_detach(&view->dtenv);
        }
 #endif /* HAVE_DNSTAP */
-       dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
-       if (view->new_zone_file != NULL) {
-               isc_mem_free(view->mctx, view->new_zone_file);
-       }
-       if (view->new_zone_dir != NULL) {
-               isc_mem_free(view->mctx, view->new_zone_dir);
+       if (view->newzone.cleanup != NULL) {
+               view->newzone.cleanup(view);
        }
 #ifdef HAVE_LMDB
-       if (view->new_zone_dbenv != NULL) {
-               mdb_env_close((MDB_env *)view->new_zone_dbenv);
-               view->new_zone_dbenv = NULL;
+       if (view->newzone.dbenv != NULL) {
+               mdb_env_close((MDB_env *)view->newzone.dbenv);
+               view->newzone.dbenv = NULL;
        }
-       if (view->new_zone_db != NULL) {
-               isc_mem_free(view->mctx, view->new_zone_db);
+       if (view->newzone.db != NULL) {
+               isc_mem_free(view->mctx, view->newzone.db);
        }
 #endif /* HAVE_LMDB */
        dns_fwdtable_destroy(&view->fwdtable);
@@ -369,7 +365,7 @@ destroy(dns_view_t *view) {
        if (view->unreachcache != NULL) {
                dns_unreachcache_destroy(&view->unreachcache);
        }
-       isc_mutex_destroy(&view->new_zone_lock);
+       isc_mutex_destroy(&view->newzone.lock);
        isc_mutex_destroy(&view->lock);
        isc_refcount_destroy(&view->references);
        isc_refcount_destroy(&view->weakrefs);
@@ -1680,185 +1676,6 @@ finish:
        return answer;
 }
 
-/*
- * Create path to a directory and a filename constructed from viewname.
- * This is a front-end to isc_file_sanitize(), allowing backward
- * compatibility to older versions when a file couldn't be expected
- * to be in the specified directory but might be in the current working
- * directory instead.
- *
- * It first tests for the existence of a file <viewname>.<suffix> in
- * 'directory'. If the file does not exist, it checks again in the
- * current working directory. If it does not exist there either,
- * return the path inside the directory.
- *
- * Returns ISC_R_SUCCESS if a path to an existing file is found or
- * a new path is created; returns ISC_R_NOSPACE if the path won't
- * fit in 'buflen'.
- */
-
-static isc_result_t
-nz_legacy(const char *directory, const char *viewname, const char *suffix,
-         char *buffer, size_t buflen) {
-       isc_result_t result;
-       char newbuf[PATH_MAX];
-
-       result = isc_file_sanitize(directory, viewname, suffix, buffer, buflen);
-       if (result != ISC_R_SUCCESS) {
-               return result;
-       } else if (directory == NULL || isc_file_exists(buffer)) {
-               return ISC_R_SUCCESS;
-       } else {
-               /* Save buffer */
-               strlcpy(newbuf, buffer, sizeof(newbuf));
-       }
-
-       /*
-        * It isn't in the specified directory; check CWD.
-        */
-       result = isc_file_sanitize(NULL, viewname, suffix, buffer, buflen);
-       if (result != ISC_R_SUCCESS || isc_file_exists(buffer)) {
-               return result;
-       }
-
-       /*
-        * File does not exist in either 'directory' or CWD,
-        * so use the path in 'directory'.
-        */
-       strlcpy(buffer, newbuf, buflen);
-       return ISC_R_SUCCESS;
-}
-
-isc_result_t
-dns_view_setnewzones(dns_view_t *view, bool allow, void *cfgctx,
-                    void (*cfg_destroy)(void **), uint64_t mapsize) {
-       isc_result_t result = ISC_R_SUCCESS;
-       char buffer[1024];
-#ifdef HAVE_LMDB
-       MDB_env *env = NULL;
-       int status;
-#endif /* ifdef HAVE_LMDB */
-
-#ifndef HAVE_LMDB
-       UNUSED(mapsize);
-#endif /* ifndef HAVE_LMDB */
-
-       REQUIRE(DNS_VIEW_VALID(view));
-       REQUIRE((cfgctx != NULL && cfg_destroy != NULL) || !allow);
-
-       if (view->new_zone_file != NULL) {
-               isc_mem_free(view->mctx, view->new_zone_file);
-       }
-
-#ifdef HAVE_LMDB
-       if (view->new_zone_dbenv != NULL) {
-               mdb_env_close((MDB_env *)view->new_zone_dbenv);
-               view->new_zone_dbenv = NULL;
-       }
-
-       if (view->new_zone_db != NULL) {
-               isc_mem_free(view->mctx, view->new_zone_db);
-       }
-#endif /* HAVE_LMDB */
-
-       if (view->new_zone_config != NULL) {
-               view->cfg_destroy(&view->new_zone_config);
-               view->cfg_destroy = NULL;
-       }
-
-       if (!allow) {
-               return ISC_R_SUCCESS;
-       }
-
-       CHECK(nz_legacy(view->new_zone_dir, view->name, "nzf", buffer,
-                       sizeof(buffer)));
-
-       view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
-
-#ifdef HAVE_LMDB
-       CHECK(nz_legacy(view->new_zone_dir, view->name, "nzd", buffer,
-                       sizeof(buffer)));
-
-       view->new_zone_db = isc_mem_strdup(view->mctx, buffer);
-
-       status = mdb_env_create(&env);
-       if (status != MDB_SUCCESS) {
-               isc_log_write(DNS_LOGCATEGORY_GENERAL, ISC_LOGMODULE_OTHER,
-                             ISC_LOG_ERROR, "mdb_env_create failed: %s",
-                             mdb_strerror(status));
-               CHECK(ISC_R_FAILURE);
-       }
-
-       if (mapsize != 0ULL) {
-               status = mdb_env_set_mapsize(env, mapsize);
-               if (status != MDB_SUCCESS) {
-                       isc_log_write(DNS_LOGCATEGORY_GENERAL,
-                                     ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
-                                     "mdb_env_set_mapsize failed: %s",
-                                     mdb_strerror(status));
-                       CHECK(ISC_R_FAILURE);
-               }
-               view->new_zone_mapsize = mapsize;
-       }
-
-       status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
-       if (status != MDB_SUCCESS) {
-               isc_log_write(DNS_LOGCATEGORY_GENERAL, ISC_LOGMODULE_OTHER,
-                             ISC_LOG_ERROR, "mdb_env_open of '%s' failed: %s",
-                             view->new_zone_db, mdb_strerror(status));
-               CHECK(ISC_R_FAILURE);
-       }
-
-       view->new_zone_dbenv = env;
-       env = NULL;
-#endif /* HAVE_LMDB */
-
-       view->new_zone_config = cfgctx;
-       view->cfg_destroy = cfg_destroy;
-
-cleanup:
-       if (result != ISC_R_SUCCESS) {
-               if (view->new_zone_file != NULL) {
-                       isc_mem_free(view->mctx, view->new_zone_file);
-               }
-
-#ifdef HAVE_LMDB
-               if (view->new_zone_db != NULL) {
-                       isc_mem_free(view->mctx, view->new_zone_db);
-               }
-               if (env != NULL) {
-                       mdb_env_close(env);
-               }
-#endif /* HAVE_LMDB */
-               view->new_zone_config = NULL;
-               view->cfg_destroy = NULL;
-       }
-
-       return result;
-}
-
-void
-dns_view_setnewzonedir(dns_view_t *view, const char *dir) {
-       REQUIRE(DNS_VIEW_VALID(view));
-
-       if (view->new_zone_dir != NULL) {
-               isc_mem_free(view->mctx, view->new_zone_dir);
-       }
-
-       if (dir == NULL) {
-               return;
-       }
-
-       view->new_zone_dir = isc_mem_strdup(view->mctx, dir);
-}
-
-const char *
-dns_view_getnewzonedir(dns_view_t *view) {
-       REQUIRE(DNS_VIEW_VALID(view));
-
-       return view->new_zone_dir;
-}
-
 isc_result_t
 dns_view_searchdlz(dns_view_t *view, const dns_name_t *name,
                   unsigned int minlabels, dns_clientinfomethods_t *methods,
index 2e386a1ffdb9ce1325d30ef36f31be84e0b7c552..8076c82971c49efeb699490c1178a9a77b780455 100644 (file)
@@ -58,33 +58,18 @@ cfg_aclconfctx_create(isc_mem_t *mctx, cfg_aclconfctx_t **aclctxp) {
        return ISC_R_SUCCESS;
 }
 
-void
-cfg_aclconfctx_attach(cfg_aclconfctx_t *src, cfg_aclconfctx_t **dest) {
-       REQUIRE(src != NULL);
-       REQUIRE(dest != NULL && *dest == NULL);
-
-       isc_refcount_increment(&src->references);
-       *dest = src;
-}
-
-void
-cfg_aclconfctx_detach(cfg_aclconfctx_t **aclctxp) {
-       REQUIRE(aclctxp != NULL && *aclctxp != NULL);
-
-       cfg_aclconfctx_t *aclctx = *aclctxp;
-       *aclctxp = NULL;
-
-       if (isc_refcount_decrement(&aclctx->references) == 1) {
-               isc_refcount_destroy(&aclctx->references);
-               ISC_LIST_FOREACH(aclctx->named_acl_cache, dacl, nextincache) {
-                       ISC_LIST_UNLINK(aclctx->named_acl_cache, dacl,
-                                       nextincache);
-                       dns_acl_detach(&dacl);
-               }
-               isc_mem_putanddetach(&aclctx->mctx, aclctx, sizeof(*aclctx));
+static void
+destroy_aclctx(cfg_aclconfctx_t *aclctx) {
+       isc_refcount_destroy(&aclctx->references);
+       ISC_LIST_FOREACH(aclctx->named_acl_cache, dacl, nextincache) {
+               ISC_LIST_UNLINK(aclctx->named_acl_cache, dacl, nextincache);
+               dns_acl_detach(&dacl);
        }
+       isc_mem_putanddetach(&aclctx->mctx, aclctx, sizeof(*aclctx));
 }
 
+ISC_REFCOUNT_IMPL(cfg_aclconfctx, destroy_aclctx);
+
 /*
  * Find the definition of the named acl whose name is "name".
  */
index 9ad8253bd18705accecb3f7ba6f95c8c05931e5b..6ce2a5b7617d1c486236220f682ef6d42cd23474 100644 (file)
@@ -39,19 +39,6 @@ cfg_aclconfctx_create(isc_mem_t *mctx, cfg_aclconfctx_t **aclctxp);
  * Creates and initializes an ACL configuration context.
  */
 
-void
-cfg_aclconfctx_detach(cfg_aclconfctx_t **aclctxp);
-/*
- * Removes a reference to an ACL configuration context; when references
- * reaches zero, clears the contents and deallocate the structure.
- */
-
-void
-cfg_aclconfctx_attach(cfg_aclconfctx_t *src, cfg_aclconfctx_t **dest);
-/*
- * Attaches a pointer to an existing ACL configuration context.
- */
-
 isc_result_t
 cfg_acl_fromconfig(const cfg_obj_t *caml, const cfg_obj_t *cctx,
                   cfg_aclconfctx_t *ctx, isc_mem_t *mctx,
@@ -72,3 +59,5 @@ cfg_acl_fromconfig(const cfg_obj_t *caml, const cfg_obj_t *cctx,
  *     'ctx' to be non NULL.
  *     '*target' to be NULL or a valid dns_acl_t.
  */
+
+ISC_REFCOUNT_DECL(cfg_aclconfctx);