/* * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* $Id: zoneconf.c,v 1.147 2008/09/24 02:46:21 marka Exp $ */ /*% */ #include #include #include #include #include #include /* Required for HP/UX (and others?) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* ACLs associated with zone */ typedef enum { allow_notify, allow_query, allow_transfer, allow_update, allow_update_forwarding } acl_type_t; /*% * These are BIND9 server defaults, not necessarily identical to the * library defaults defined in zone.c. */ #define RETERR(x) do { \ isc_result_t _r = (x); \ if (_r != ISC_R_SUCCESS) \ return (_r); \ } while (0) /*% * Convenience function for configuring a single zone ACL. */ static isc_result_t configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig, const cfg_obj_t *config, acl_type_t acltype, cfg_aclconfctx_t *actx, dns_zone_t *zone, void (*setzacl)(dns_zone_t *, dns_acl_t *), void (*clearzacl)(dns_zone_t *)) { isc_result_t result; const cfg_obj_t *maps[5] = {NULL, NULL, NULL, NULL, NULL}; const cfg_obj_t *aclobj = NULL; int i = 0; dns_acl_t **aclp = NULL, *acl = NULL; const char *aclname; dns_view_t *view; view = dns_zone_getview(zone); switch (acltype) { case allow_notify: if (view != NULL) aclp = &view->notifyacl; aclname = "allow-notify"; break; case allow_query: if (view != NULL) aclp = &view->queryacl; aclname = "allow-query"; break; case allow_transfer: if (view != NULL) aclp = &view->transferacl; aclname = "allow-transfer"; break; case allow_update: if (view != NULL) aclp = &view->updateacl; aclname = "allow-update"; break; case allow_update_forwarding: if (view != NULL) aclp = &view->upfwdacl; aclname = "allow-update-forwarding"; break; default: INSIST(0); return (ISC_R_FAILURE); } /* First check to see if ACL is defined within the zone */ if (zconfig != NULL) { maps[0] = cfg_tuple_get(zconfig, "options"); ns_config_get(maps, aclname, &aclobj); if (aclobj != NULL) { aclp = NULL; goto parse_acl; } } /* Failing that, see if there's a default ACL already in the view */ if (aclp != NULL && *aclp != NULL) { (*setzacl)(zone, *aclp); return (ISC_R_SUCCESS); } /* Check for default ACLs that haven't been parsed yet */ if (vconfig != NULL) maps[i++] = cfg_tuple_get(vconfig, "options"); if (config != NULL) { const cfg_obj_t *options = NULL; (void)cfg_map_get(config, "options", &options); if (options != NULL) maps[i++] = options; } maps[i++] = ns_g_defaults; maps[i] = NULL; result = ns_config_get(maps, aclname, &aclobj); if (aclobj == NULL) { (*clearzacl)(zone); return (ISC_R_SUCCESS); } parse_acl: result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, actx, dns_zone_getmctx(zone), 0, &acl); if (result != ISC_R_SUCCESS) return (result); (*setzacl)(zone, acl); /* Set the view default now */ if (aclp != NULL) dns_acl_attach(acl, aclp); dns_acl_detach(&acl); return (ISC_R_SUCCESS); } /*% * Parse the zone update-policy statement. */ static isc_result_t configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone) { const cfg_obj_t *updatepolicy = NULL; const cfg_listelt_t *element, *element2; dns_ssutable_t *table = NULL; isc_mem_t *mctx = dns_zone_getmctx(zone); isc_result_t result; (void)cfg_map_get(zconfig, "update-policy", &updatepolicy); if (updatepolicy == NULL) { dns_zone_setssutable(zone, NULL); return (ISC_R_SUCCESS); } result = dns_ssutable_create(mctx, &table); if (result != ISC_R_SUCCESS) return (result); for (element = cfg_list_first(updatepolicy); element != NULL; element = cfg_list_next(element)) { const cfg_obj_t *stmt = cfg_listelt_value(element); const cfg_obj_t *mode = cfg_tuple_get(stmt, "mode"); const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity"); const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype"); const cfg_obj_t *dname = cfg_tuple_get(stmt, "name"); const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types"); const char *str; isc_boolean_t grant = ISC_FALSE; unsigned int mtype = DNS_SSUMATCHTYPE_NAME; dns_fixedname_t fname, fident; isc_buffer_t b; dns_rdatatype_t *types; unsigned int i, n; str = cfg_obj_asstring(mode); if (strcasecmp(str, "grant") == 0) grant = ISC_TRUE; else if (strcasecmp(str, "deny") == 0) grant = ISC_FALSE; else INSIST(0); str = cfg_obj_asstring(matchtype); if (strcasecmp(str, "name") == 0) mtype = DNS_SSUMATCHTYPE_NAME; else if (strcasecmp(str, "subdomain") == 0) mtype = DNS_SSUMATCHTYPE_SUBDOMAIN; else if (strcasecmp(str, "wildcard") == 0) mtype = DNS_SSUMATCHTYPE_WILDCARD; else if (strcasecmp(str, "self") == 0) mtype = DNS_SSUMATCHTYPE_SELF; else if (strcasecmp(str, "selfsub") == 0) mtype = DNS_SSUMATCHTYPE_SELFSUB; else if (strcasecmp(str, "selfwild") == 0) mtype = DNS_SSUMATCHTYPE_SELFWILD; else if (strcasecmp(str, "ms-self") == 0) mtype = DNS_SSUMATCHTYPE_SELFMS; else if (strcasecmp(str, "krb5-self") == 0) mtype = DNS_SSUMATCHTYPE_SELFKRB5; else if (strcasecmp(str, "ms-subdomain") == 0) mtype = DNS_SSUMATCHTYPE_SUBDOMAINMS; else if (strcasecmp(str, "krb5-subdomain") == 0) mtype = DNS_SSUMATCHTYPE_SUBDOMAINKRB5; else if (strcasecmp(str, "tcp-self") == 0) mtype = DNS_SSUMATCHTYPE_TCPSELF; else if (strcasecmp(str, "6to4-self") == 0) mtype = DNS_SSUMATCHTYPE_6TO4SELF; else INSIST(0); dns_fixedname_init(&fident); str = cfg_obj_asstring(identity); isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); result = dns_name_fromtext(dns_fixedname_name(&fident), &b, dns_rootname, ISC_FALSE, NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, "'%s' is not a valid name", str); goto cleanup; } dns_fixedname_init(&fname); str = cfg_obj_asstring(dname); isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); result = dns_name_fromtext(dns_fixedname_name(&fname), &b, dns_rootname, ISC_FALSE, NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, "'%s' is not a valid name", str); goto cleanup; } n = ns_config_listcount(typelist); if (n == 0) types = NULL; else { types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t)); if (types == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } i = 0; for (element2 = cfg_list_first(typelist); element2 != NULL; element2 = cfg_list_next(element2)) { const cfg_obj_t *typeobj; isc_textregion_t r; INSIST(i < n); typeobj = cfg_listelt_value(element2); str = cfg_obj_asstring(typeobj); DE_CONST(str, r.base); r.length = strlen(str); result = dns_rdatatype_fromtext(&types[i++], &r); if (result != ISC_R_SUCCESS) { cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, "'%s' is not a valid type", str); isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t)); goto cleanup; } } INSIST(i == n); result = dns_ssutable_addrule(table, grant, dns_fixedname_name(&fident), mtype, dns_fixedname_name(&fname), n, types); if (types != NULL) isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t)); if (result != ISC_R_SUCCESS) { goto cleanup; } } result = ISC_R_SUCCESS; dns_zone_setssutable(zone, table); cleanup: dns_ssutable_detach(&table); return (result); } /*% * Convert a config file zone type into a server zone type. */ static inline dns_zonetype_t zonetype_fromconfig(const cfg_obj_t *map) { const cfg_obj_t *obj = NULL; isc_result_t result; result = cfg_map_get(map, "type", &obj); INSIST(result == ISC_R_SUCCESS); return (ns_config_getzonetype(obj)); } /*% * Helper function for strtoargv(). Pardon the gratuitous recursion. */ static isc_result_t strtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp, unsigned int n) { isc_result_t result; /* Discard leading whitespace. */ while (*s == ' ' || *s == '\t') s++; if (*s == '\0') { /* We have reached the end of the string. */ *argcp = n; *argvp = isc_mem_get(mctx, n * sizeof(char *)); if (*argvp == NULL) return (ISC_R_NOMEMORY); } else { char *p = s; while (*p != ' ' && *p != '\t' && *p != '\0') p++; if (*p != '\0') *p++ = '\0'; result = strtoargvsub(mctx, p, argcp, argvp, n + 1); if (result != ISC_R_SUCCESS) return (result); (*argvp)[n] = s; } return (ISC_R_SUCCESS); } /*% * Tokenize the string "s" into whitespace-separated words, * return the number of words in '*argcp' and an array * of pointers to the words in '*argvp'. The caller * must free the array using isc_mem_put(). The string * is modified in-place. */ static isc_result_t strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) { return (strtoargvsub(mctx, s, argcp, argvp, 0)); } static void checknames(dns_zonetype_t ztype, const cfg_obj_t **maps, const cfg_obj_t **objp) { const char *zone = NULL; isc_result_t result; switch (ztype) { case dns_zone_slave: zone = "slave"; break; case dns_zone_master: zone = "master"; break; default: INSIST(0); } result = ns_checknames_get(maps, zone, objp); INSIST(result == ISC_R_SUCCESS); } isc_result_t ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac, dns_zone_t *zone) { isc_result_t result; const char *zname; dns_rdataclass_t zclass; dns_rdataclass_t vclass; const cfg_obj_t *maps[5]; const cfg_obj_t *zoptions = NULL; const cfg_obj_t *options = NULL; const cfg_obj_t *obj; const char *filename = NULL; dns_notifytype_t notifytype = dns_notifytype_yes; isc_sockaddr_t *addrs; dns_name_t **keynames; isc_uint32_t count; char *cpval; unsigned int dbargc; char **dbargv; static char default_dbtype[] = "rbt"; isc_mem_t *mctx = dns_zone_getmctx(zone); dns_dialuptype_t dialup = dns_dialuptype_no; dns_zonetype_t ztype; int i; isc_int32_t journal_size; isc_boolean_t multi; isc_boolean_t alt; dns_view_t *view; isc_boolean_t check = ISC_FALSE, fail = ISC_FALSE; isc_boolean_t warn = ISC_FALSE, ignore = ISC_FALSE; isc_boolean_t ixfrdiff; dns_masterformat_t masterformat; dns_stats_t *zoneqrystats; isc_boolean_t zonestats_on; int seconds; i = 0; if (zconfig != NULL) { zoptions = cfg_tuple_get(zconfig, "options"); maps[i++] = zoptions; } if (vconfig != NULL) maps[i++] = cfg_tuple_get(vconfig, "options"); if (config != NULL) { (void)cfg_map_get(config, "options", &options); if (options != NULL) maps[i++] = options; } maps[i++] = ns_g_defaults; maps[i++] = NULL; if (vconfig != NULL) RETERR(ns_config_getclass(cfg_tuple_get(vconfig, "class"), dns_rdataclass_in, &vclass)); else vclass = dns_rdataclass_in; /* * Configure values common to all zone types. */ zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); RETERR(ns_config_getclass(cfg_tuple_get(zconfig, "class"), vclass, &zclass)); dns_zone_setclass(zone, zclass); ztype = zonetype_fromconfig(zoptions); dns_zone_settype(zone, ztype); obj = NULL; result = cfg_map_get(zoptions, "database", &obj); if (result == ISC_R_SUCCESS) cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); else cpval = default_dbtype; if (cpval == NULL) return(ISC_R_NOMEMORY); result = strtoargv(mctx, cpval, &dbargc, &dbargv); if (result != ISC_R_SUCCESS && cpval != default_dbtype) { isc_mem_free(mctx, cpval); return (result); } /* * ANSI C is strange here. There is no logical reason why (char **) * cannot be promoted automatically to (const char * const *) by the * compiler w/o generating a warning. */ result = dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv); isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv)); if (cpval != default_dbtype) isc_mem_free(mctx, cpval); if (result != ISC_R_SUCCESS) return (result); obj = NULL; result = cfg_map_get(zoptions, "file", &obj); if (result == ISC_R_SUCCESS) filename = cfg_obj_asstring(obj); masterformat = dns_masterformat_text; obj = NULL; result= ns_config_get(maps, "masterfile-format", &obj); if (result == ISC_R_SUCCESS) { const char *masterformatstr = cfg_obj_asstring(obj); if (strcasecmp(masterformatstr, "text") == 0) masterformat = dns_masterformat_text; else if (strcasecmp(masterformatstr, "raw") == 0) masterformat = dns_masterformat_raw; else INSIST(0); } RETERR(dns_zone_setfile2(zone, filename, masterformat)); obj = NULL; result = cfg_map_get(zoptions, "journal", &obj); if (result == ISC_R_SUCCESS) RETERR(dns_zone_setjournal(zone, cfg_obj_asstring(obj))); if (ztype == dns_zone_slave) RETERR(configure_zone_acl(zconfig, vconfig, config, allow_notify, ac, zone, dns_zone_setnotifyacl, dns_zone_clearnotifyacl)); /* * XXXAG This probably does not make sense for stubs. */ RETERR(configure_zone_acl(zconfig, vconfig, config, allow_query, ac, zone, dns_zone_setqueryacl, dns_zone_clearqueryacl)); obj = NULL; result = ns_config_get(maps, "dialup", &obj); INSIST(result == ISC_R_SUCCESS); if (cfg_obj_isboolean(obj)) { if (cfg_obj_asboolean(obj)) dialup = dns_dialuptype_yes; else dialup = dns_dialuptype_no; } else { const char *dialupstr = cfg_obj_asstring(obj); if (strcasecmp(dialupstr, "notify") == 0) dialup = dns_dialuptype_notify; else if (strcasecmp(dialupstr, "notify-passive") == 0) dialup = dns_dialuptype_notifypassive; else if (strcasecmp(dialupstr, "refresh") == 0) dialup = dns_dialuptype_refresh; else if (strcasecmp(dialupstr, "passive") == 0) dialup = dns_dialuptype_passive; else INSIST(0); } dns_zone_setdialup(zone, dialup); obj = NULL; result = ns_config_get(maps, "zone-statistics", &obj); INSIST(result == ISC_R_SUCCESS); zonestats_on = cfg_obj_asboolean(obj); zoneqrystats = NULL; if (zonestats_on) { RETERR(dns_generalstats_create(mctx, &zoneqrystats, dns_nsstatscounter_max)); } dns_zone_setrequeststats(zone, zoneqrystats); if (zoneqrystats != NULL) dns_stats_detach(&zoneqrystats); /* * Configure master functionality. This applies * to primary masters (type "master") and slaves * acting as masters (type "slave"), but not to stubs. */ if (ztype != dns_zone_stub) { obj = NULL; result = ns_config_get(maps, "notify", &obj); INSIST(result == ISC_R_SUCCESS); if (cfg_obj_isboolean(obj)) { if (cfg_obj_asboolean(obj)) notifytype = dns_notifytype_yes; else notifytype = dns_notifytype_no; } else { const char *notifystr = cfg_obj_asstring(obj); if (strcasecmp(notifystr, "explicit") == 0) notifytype = dns_notifytype_explicit; else if (strcasecmp(notifystr, "master-only") == 0) notifytype = dns_notifytype_masteronly; else INSIST(0); } dns_zone_setnotifytype(zone, notifytype); obj = NULL; result = ns_config_get(maps, "also-notify", &obj); if (result == ISC_R_SUCCESS) { isc_sockaddr_t *addrs = NULL; isc_uint32_t addrcount; result = ns_config_getiplist(config, obj, 0, mctx, &addrs, &addrcount); if (result != ISC_R_SUCCESS) return (result); result = dns_zone_setalsonotify(zone, addrs, addrcount); ns_config_putiplist(mctx, &addrs, addrcount); if (result != ISC_R_SUCCESS) return (result); } else RETERR(dns_zone_setalsonotify(zone, NULL, 0)); obj = NULL; result = ns_config_get(maps, "notify-source", &obj); INSIST(result == ISC_R_SUCCESS); RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj))); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "notify-source-v6", &obj); INSIST(result == ISC_R_SUCCESS); RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj))); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "notify-to-soa", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setoption(zone, DNS_ZONEOPT_NOTIFYTOSOA, cfg_obj_asboolean(obj)); dns_zone_setisself(zone, ns_client_isself, NULL); RETERR(configure_zone_acl(zconfig, vconfig, config, allow_transfer, ac, zone, dns_zone_setxfracl, dns_zone_clearxfracl)); obj = NULL; result = ns_config_get(maps, "max-transfer-time-out", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60); obj = NULL; result = ns_config_get(maps, "max-transfer-idle-out", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60); obj = NULL; result = ns_config_get(maps, "max-journal-size", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setjournalsize(zone, -1); if (cfg_obj_isstring(obj)) { const char *str = cfg_obj_asstring(obj); INSIST(strcasecmp(str, "unlimited") == 0); journal_size = ISC_UINT32_MAX / 2; } else { isc_resourcevalue_t value; value = cfg_obj_asuint64(obj); if (value > ISC_UINT32_MAX / 2) { cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "'max-journal-size " "%" ISC_PRINT_QUADFORMAT "d' " "is too large", value); RETERR(ISC_R_RANGE); } journal_size = (isc_uint32_t)value; } dns_zone_setjournalsize(zone, journal_size); obj = NULL; result = ns_config_get(maps, "ixfr-from-differences", &obj); INSIST(result == ISC_R_SUCCESS); if (cfg_obj_isboolean(obj)) ixfrdiff = cfg_obj_asboolean(obj); else if (strcasecmp(cfg_obj_asstring(obj), "master") && ztype == dns_zone_master) ixfrdiff = ISC_TRUE; else if (strcasecmp(cfg_obj_asstring(obj), "slave") && ztype == dns_zone_slave) ixfrdiff = ISC_TRUE; else ixfrdiff = ISC_FALSE; dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS, ixfrdiff); checknames(ztype, maps, &obj); INSIST(obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { fail = ISC_FALSE; check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { fail = check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { fail = check = ISC_FALSE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, check); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL, fail); obj = NULL; result = ns_config_get(maps, "notify-delay", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setnotifydelay(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "check-sibling", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSIBLING, cfg_obj_asboolean(obj)); obj = NULL; result = ns_config_get(maps, "zero-no-soa-ttl", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj)); obj = NULL; result = ns_config_get(maps, "nsec3-test-zone", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setoption(zone, DNS_ZONEOPT_NSEC3TESTZONE, cfg_obj_asboolean(obj)); } /* * Configure update-related options. These apply to * primary masters only. */ if (ztype == dns_zone_master) { dns_acl_t *updateacl; RETERR(configure_zone_acl(zconfig, vconfig, config, allow_update, ac, zone, dns_zone_setupdateacl, dns_zone_clearupdateacl)); updateacl = dns_zone_getupdateacl(zone); if (updateacl != NULL && dns_acl_isinsecure(updateacl)) isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_SERVER, ISC_LOG_WARNING, "zone '%s' allows updates by IP " "address, which is insecure", zname); RETERR(configure_zone_ssutable(zoptions, zone)); obj = NULL; result = ns_config_get(maps, "sig-validity-interval", &obj); INSIST(result == ISC_R_SUCCESS); { const cfg_obj_t *validity, *resign; validity = cfg_tuple_get(obj, "validity"); seconds = cfg_obj_asuint32(validity) * 86400; dns_zone_setsigvalidityinterval(zone, seconds); resign = cfg_tuple_get(obj, "re-sign"); if (cfg_obj_isvoid(resign)) { seconds /= 4; } else { if (seconds > 7 * 86400) seconds = cfg_obj_asuint32(resign) * 86400; else seconds = cfg_obj_asuint32(resign) * 3600; } dns_zone_setsigresigninginterval(zone, seconds); } obj = NULL; result = ns_config_get(maps, "key-directory", &obj); if (result == ISC_R_SUCCESS) { filename = cfg_obj_asstring(obj); if (!isc_file_isabsolute(filename)) { cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "key-directory '%s' " "is not absolute", filename); return (ISC_R_FAILURE); } RETERR(dns_zone_setkeydirectory(zone, filename)); } obj = NULL; result = ns_config_get(maps, "sig-signing-signatures", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setsignatures(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "sig-signing-nodes", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setnodes(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "sig-signing-type", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setprivatetype(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "update-check-ksk", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK, cfg_obj_asboolean(obj)); } else if (ztype == dns_zone_slave) { RETERR(configure_zone_acl(zconfig, vconfig, config, allow_update_forwarding, ac, zone, dns_zone_setforwardacl, dns_zone_clearforwardacl)); } /*% * Primary master functionality. */ if (ztype == dns_zone_master) { obj = NULL; result = ns_config_get(maps, "check-wildcard", &obj); if (result == ISC_R_SUCCESS) check = cfg_obj_asboolean(obj); else check = ISC_FALSE; dns_zone_setoption(zone, DNS_ZONEOPT_CHECKWILDCARD, check); obj = NULL; result = ns_config_get(maps, "check-mx", &obj); INSIST(obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { fail = ISC_FALSE; check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { fail = check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { fail = check = ISC_FALSE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMX, check); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMXFAIL, fail); obj = NULL; result = ns_config_get(maps, "check-integrity", &obj); INSIST(obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKINTEGRITY, cfg_obj_asboolean(obj)); obj = NULL; result = ns_config_get(maps, "check-mx-cname", &obj); INSIST(obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { warn = ISC_TRUE; ignore = ISC_FALSE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { warn = ignore = ISC_FALSE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { warn = ignore = ISC_TRUE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_WARNMXCNAME, warn); dns_zone_setoption(zone, DNS_ZONEOPT_IGNOREMXCNAME, ignore); obj = NULL; result = ns_config_get(maps, "check-srv-cname", &obj); INSIST(obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { warn = ISC_TRUE; ignore = ISC_FALSE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { warn = ignore = ISC_FALSE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { warn = ignore = ISC_TRUE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_WARNSRVCNAME, warn); dns_zone_setoption(zone, DNS_ZONEOPT_IGNORESRVCNAME, ignore); } /* * Configure slave functionality. */ switch (ztype) { case dns_zone_slave: case dns_zone_stub: count = 0; obj = NULL; result = cfg_map_get(zoptions, "masters", &obj); if (obj != NULL) { addrs = NULL; keynames = NULL; RETERR(ns_config_getipandkeylist(config, obj, mctx, &addrs, &keynames, &count)); result = dns_zone_setmasterswithkeys(zone, addrs, keynames, count); ns_config_putipandkeylist(mctx, &addrs, &keynames, count); } else result = dns_zone_setmasters(zone, NULL, 0); RETERR(result); multi = ISC_FALSE; if (count > 1) { obj = NULL; result = ns_config_get(maps, "multi-master", &obj); INSIST(result == ISC_R_SUCCESS); multi = cfg_obj_asboolean(obj); } dns_zone_setoption(zone, DNS_ZONEOPT_MULTIMASTER, multi); obj = NULL; result = ns_config_get(maps, "max-transfer-time-in", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setmaxxfrin(zone, cfg_obj_asuint32(obj) * 60); obj = NULL; result = ns_config_get(maps, "max-transfer-idle-in", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setidlein(zone, cfg_obj_asuint32(obj) * 60); obj = NULL; result = ns_config_get(maps, "max-refresh-time", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setmaxrefreshtime(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "min-refresh-time", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setminrefreshtime(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "max-retry-time", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setmaxretrytime(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "min-retry-time", &obj); INSIST(result == ISC_R_SUCCESS); dns_zone_setminretrytime(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "transfer-source", &obj); INSIST(result == ISC_R_SUCCESS); RETERR(dns_zone_setxfrsource4(zone, cfg_obj_assockaddr(obj))); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "transfer-source-v6", &obj); INSIST(result == ISC_R_SUCCESS); RETERR(dns_zone_setxfrsource6(zone, cfg_obj_assockaddr(obj))); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "alt-transfer-source", &obj); INSIST(result == ISC_R_SUCCESS); RETERR(dns_zone_setaltxfrsource4(zone, cfg_obj_assockaddr(obj))); obj = NULL; result = ns_config_get(maps, "alt-transfer-source-v6", &obj); INSIST(result == ISC_R_SUCCESS); RETERR(dns_zone_setaltxfrsource6(zone, cfg_obj_assockaddr(obj))); obj = NULL; (void)ns_config_get(maps, "use-alt-transfer-source", &obj); if (obj == NULL) { /* * Default off when views are in use otherwise * on for BIND 8 compatibility. */ view = dns_zone_getview(zone); if (view != NULL && strcmp(view->name, "_default") == 0) alt = ISC_TRUE; else alt = ISC_FALSE; } else alt = cfg_obj_asboolean(obj); dns_zone_setoption(zone, DNS_ZONEOPT_USEALTXFRSRC, alt); obj = NULL; (void)ns_config_get(maps, "try-tcp-refresh", &obj); dns_zone_setoption(zone, DNS_ZONEOPT_TRYTCPREFRESH, cfg_obj_asboolean(obj)); break; default: break; } return (ISC_R_SUCCESS); } isc_boolean_t ns_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig) { const cfg_obj_t *zoptions = NULL; const cfg_obj_t *obj = NULL; const char *cfilename; const char *zfilename; zoptions = cfg_tuple_get(zconfig, "options"); if (zonetype_fromconfig(zoptions) != dns_zone_gettype(zone)) return (ISC_FALSE); obj = NULL; (void)cfg_map_get(zoptions, "file", &obj); if (obj != NULL) cfilename = cfg_obj_asstring(obj); else cfilename = NULL; zfilename = dns_zone_getfile(zone); if (!((cfilename == NULL && zfilename == NULL) || (cfilename != NULL && zfilename != NULL && strcmp(cfilename, zfilename) == 0))) return (ISC_FALSE); return (ISC_TRUE); }