Hello, this patch set is preparation work for per-server config in LDAP, which is required for DNS location in IPA.
This patch set should not cause any user-visible changes. https://fedorahosted.org/bind-dyndb-ldap/ticket/162 -- Petr^2 Spacek
From 5a4e0b7026dc4f7f786d1d59a3a9ad33bfe89e30 Mon Sep 17 00:00:00 2001 From: Petr Spacek <pspa...@redhat.com> Date: Wed, 4 May 2016 16:20:44 +0200 Subject: [PATCH] Fix in destroy_ldap_instance() caused by uninitialized MetaLDAP. This happened only if an new_ldap_instance() failed with an error before initializing MetaLDAP. --- src/mldap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mldap.c b/src/mldap.c index 8cffe8a1fbf8eaa20aae79c28ad8d7a305494f19..143abce757f3d65e68356a2c0e660c475ed0ab58 100644 --- a/src/mldap.c +++ b/src/mldap.c @@ -79,7 +79,7 @@ void mldap_destroy(mldapdb_t **mldapp) { mldapdb_t *mldap; - REQUIRE(mldapp != NULL && *mldapp != NULL); + REQUIRE(mldapp != NULL); mldap = *mldapp; if (mldap == NULL) -- 2.5.5
From 6c4cabd8be5d90502786a5f4356dbb4742ec7a70 Mon Sep 17 00:00:00 2001 From: Petr Spacek <pspa...@redhat.com> Date: Thu, 2 Jun 2016 15:30:19 +0200 Subject: [PATCH] Separate BIND config utilities from ACL parsing. In future we will use the code from multiple modules. There should be no user-visible changes caused by this split. https://fedorahosted.org/bind-dyndb-ldap/ticket/162 --- src/Makefile.am | 2 + src/acl.c | 118 +++-------------------------------------------------- src/bindcfg.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/bindcfg.h | 24 +++++++++++ src/zone_manager.c | 3 ++ 5 files changed, 151 insertions(+), 112 deletions(-) create mode 100644 src/bindcfg.c create mode 100644 src/bindcfg.h diff --git a/src/Makefile.am b/src/Makefile.am index 58f73ec9d37471471036fb532ac239523512eb80..595fb4d95577f025e97dbce0770325a82a053ad8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,6 +3,7 @@ bindplugindir=$(libdir)/bind HDRS = \ acl.h \ + bindcfg.h \ compat.h \ empty_zones.h \ fs.h \ @@ -31,6 +32,7 @@ HDRS = \ ldap_la_SOURCES = \ $(HDRS) \ acl.c \ + bindcfg.c \ empty_zones.c \ fwd_register.c \ fs.c \ diff --git a/src/acl.c b/src/acl.c index e4b3f524876ac93a177613c7f325883398367af8..d03a34d8c4ba5016ae9b248dc86781952d92c8d4 100644 --- a/src/acl.c +++ b/src/acl.c @@ -6,13 +6,11 @@ #include <isccfg/aclconf.h> #include <isccfg/cfg.h> -#include <isccfg/namedconf.h> #include <isccfg/grammar.h> #include <isc/buffer.h> #include <isc/log.h> #include <isc/mem.h> -#include <isc/once.h> #include <isc/result.h> #include <isc/types.h> #include <isc/util.h> @@ -30,17 +28,12 @@ #include <strings.h> #include "acl.h" +#include "bindcfg.h" #include "str.h" #include "util.h" #include "log.h" #include "types.h" -static isc_once_t once = ISC_ONCE_INIT; -static cfg_type_t *update_policy; -static cfg_type_t *allow_query; -static cfg_type_t *allow_transfer; -static cfg_type_t *forwarders; - /* Following definitions are necessary for context ("map" configuration object) * required during ACL parsing. */ static cfg_clausedef_t * empty_map_clausesets[] = { @@ -60,105 +53,6 @@ const enum_txt_assoc_t acl_type_txts[] = { { -1, NULL } /* end marker */ }; -static cfg_type_t * ATTR_NONNULLS ATTR_CHECKRESULT -get_type_from_tuplefield(const cfg_type_t *cfg_type, const char *name) -{ - cfg_type_t *ret = NULL; - const cfg_tuplefielddef_t *field; - - REQUIRE(cfg_type != NULL && cfg_type->of != NULL); - REQUIRE(name != NULL); - - field = (cfg_tuplefielddef_t *)cfg_type->of; - for (int i = 0; field[i].name != NULL; i++) { - if (!strcmp(field[i].name, name)) { - ret = field[i].type; - break; - } - } - - return ret; -} - -static cfg_type_t * ATTR_NONNULLS ATTR_CHECKRESULT -get_type_from_clause(const cfg_clausedef_t *clause, const char *name) -{ - cfg_type_t *ret = NULL; - - REQUIRE(clause != NULL); - REQUIRE(name != NULL); - - for (int i = 0; clause[i].name != NULL; i++) { - if (!strcmp(clause[i].name, name)) { - ret = clause[i].type; - break; - } - } - - return ret; -} - -static cfg_type_t * ATTR_NONNULLS ATTR_CHECKRESULT -get_type_from_clause_array(const cfg_type_t *cfg_type, const char *name) -{ - cfg_type_t *ret = NULL; - const cfg_clausedef_t **clauses; - - REQUIRE(cfg_type != NULL && cfg_type->of != NULL); - REQUIRE(name != NULL); - - clauses = (const cfg_clausedef_t **)cfg_type->of; - for (int i = 0; clauses[i] != NULL; i++) { - ret = get_type_from_clause(clauses[i], name); - if (ret != NULL) - break; - } - - return ret; -} - -static void -init_cfgtypes(void) -{ - cfg_type_t *zoneopts; - - zoneopts = &cfg_type_namedconf; - zoneopts = get_type_from_clause_array(zoneopts, "zone"); - zoneopts = get_type_from_tuplefield(zoneopts, "options"); - - update_policy = get_type_from_clause_array(zoneopts, "update-policy"); - allow_query = get_type_from_clause_array(zoneopts, "allow-query"); - allow_transfer = get_type_from_clause_array(zoneopts, "allow-transfer"); - forwarders = get_type_from_clause_array(zoneopts, "forwarders"); -} - -static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT -parse(cfg_parser_t *parser, const char *string, cfg_type_t **type, - cfg_obj_t **objp) -{ - isc_result_t result; - isc_buffer_t buffer; - size_t string_len; - cfg_obj_t *ret = NULL; - - REQUIRE(parser != NULL); - REQUIRE(string != NULL); - REQUIRE(objp != NULL && *objp == NULL); - - RUNTIME_CHECK(isc_once_do(&once, init_cfgtypes) == ISC_R_SUCCESS); - - string_len = strlen(string); - isc_buffer_init(&buffer, (char *)string, string_len); - isc_buffer_add(&buffer, string_len); - - result = cfg_parse_buffer(parser, &buffer, *type, &ret); - - if (result == ISC_R_SUCCESS) - *objp = ret; - - return result; -} - /* * The rest of the code in this file is either copied from, or based on code * from ISC BIND, file bin/named/config.c. @@ -408,7 +302,7 @@ acl_configure_zone_ssutable(const char *policy_str, dns_zone_t *zone) CHECK(bracket_str(mctx, policy_str, &new_policy_str)); CHECK(cfg_parser_create(mctx, dns_lctx, &parser)); - result = parse(parser, str_buf(new_policy_str), &update_policy, &policy); + result = cfg_parse_strbuf(parser, str_buf(new_policy_str), &cfg_type_update_policy, &policy); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, @@ -509,15 +403,15 @@ acl_from_ldap(isc_mem_t *mctx, const char *aclstr, acl_type_t type, CHECK(cfg_parser_create(mctx, dns_lctx, &parser)); CHECK(cfg_parser_create(mctx, dns_lctx, &parser_empty)); - CHECK(parse(parser_empty, "{}", &empty_map_p, &cctx)); + CHECK(cfg_parse_strbuf(parser_empty, "{}", &empty_map_p, &cctx)); switch (type) { case acl_type_query: - CHECK(parse(parser, str_buf(new_aclstr), &allow_query, + CHECK(cfg_parse_strbuf(parser, str_buf(new_aclstr), &cfg_type_allow_query, &aclobj)); break; case acl_type_transfer: - CHECK(parse(parser, str_buf(new_aclstr), &allow_transfer, + CHECK(cfg_parse_strbuf(parser, str_buf(new_aclstr), &cfg_type_allow_transfer, &aclobj)); break; default: @@ -602,7 +496,7 @@ acl_parse_forwarder(const char *forwarder_str, isc_mem_t *mctx, CHECK(bracket_str(mctx, forwarder_str, &new_forwarder_str)); CHECK(cfg_parser_create(mctx, dns_lctx, &parser)); - CHECK(parse(parser, str_buf(new_forwarder_str), &forwarders, &forwarders_cfg)); + CHECK(cfg_parse_strbuf(parser, str_buf(new_forwarder_str), &cfg_type_forwarders, &forwarders_cfg)); faddresses = cfg_tuple_get(forwarders_cfg, "addresses"); element = cfg_list_first(faddresses); diff --git a/src/bindcfg.c b/src/bindcfg.c new file mode 100644 index 0000000000000000000000000000000000000000..9b429ba31c8ca800062237c80481eb53a81122c9 --- /dev/null +++ b/src/bindcfg.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2009-2016 bind-dyndb-ldap authors; see COPYING for license + * + * Utilities for BIND configuration parsers. + */ + +#include "config.h" + +#include <isccfg/grammar.h> +#include <isccfg/namedconf.h> + +#include <util.h> + +#include "bindcfg.h" + +cfg_type_t *cfg_type_update_policy; +cfg_type_t *cfg_type_allow_query; +cfg_type_t *cfg_type_allow_transfer; +cfg_type_t *cfg_type_forwarders; + +static cfg_type_t * ATTR_NONNULLS ATTR_CHECKRESULT +get_type_from_tuplefield(const cfg_type_t *cfg_type, const char *name) +{ + cfg_type_t *ret = NULL; + const cfg_tuplefielddef_t *field; + + REQUIRE(cfg_type != NULL && cfg_type->of != NULL); + REQUIRE(name != NULL); + + field = (cfg_tuplefielddef_t *)cfg_type->of; + for (int i = 0; field[i].name != NULL; i++) { + if (!strcmp(field[i].name, name)) { + ret = field[i].type; + break; + } + } + + return ret; +} + +static cfg_type_t * ATTR_NONNULLS ATTR_CHECKRESULT +get_type_from_clause(const cfg_clausedef_t *clause, const char *name) +{ + cfg_type_t *ret = NULL; + + REQUIRE(clause != NULL); + REQUIRE(name != NULL); + + for (int i = 0; clause[i].name != NULL; i++) { + if (!strcmp(clause[i].name, name)) { + ret = clause[i].type; + break; + } + } + + return ret; +} + +static cfg_type_t * ATTR_NONNULLS ATTR_CHECKRESULT +get_type_from_clause_array(const cfg_type_t *cfg_type, const char *name) +{ + cfg_type_t *ret = NULL; + const cfg_clausedef_t **clauses; + + REQUIRE(cfg_type != NULL && cfg_type->of != NULL); + REQUIRE(name != NULL); + + clauses = (const cfg_clausedef_t **)cfg_type->of; + for (int i = 0; clauses[i] != NULL; i++) { + ret = get_type_from_clause(clauses[i], name); + if (ret != NULL) + break; + } + + return ret; +} + +void +cfg_init_types(void) +{ + cfg_type_t *zoneopts; + + zoneopts = &cfg_type_namedconf; + zoneopts = get_type_from_clause_array(zoneopts, "zone"); + zoneopts = get_type_from_tuplefield(zoneopts, "options"); + + cfg_type_update_policy = get_type_from_clause_array(zoneopts, "update-policy"); + cfg_type_allow_query = get_type_from_clause_array(zoneopts, "allow-query"); + cfg_type_allow_transfer = get_type_from_clause_array(zoneopts, "allow-transfer"); + cfg_type_forwarders = get_type_from_clause_array(zoneopts, "forwarders"); +} + +isc_result_t +cfg_parse_strbuf(cfg_parser_t *parser, const char *string, cfg_type_t **type, + cfg_obj_t **objp) +{ + isc_result_t result; + isc_buffer_t buffer; + size_t string_len; + cfg_obj_t *ret = NULL; + + REQUIRE(parser != NULL); + REQUIRE(string != NULL); + REQUIRE(objp != NULL && *objp == NULL); + + string_len = strlen(string); + isc_buffer_init(&buffer, (char *)string, string_len); + isc_buffer_add(&buffer, string_len); + + result = cfg_parse_buffer(parser, &buffer, *type, &ret); + + if (result == ISC_R_SUCCESS) + *objp = ret; + + return result; +} diff --git a/src/bindcfg.h b/src/bindcfg.h new file mode 100644 index 0000000000000000000000000000000000000000..a7b882d6a0486ffa539374d8fd91478ec122aab8 --- /dev/null +++ b/src/bindcfg.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2009-2016 bind-dyndb-ldap authors; see COPYING for license + */ + +#ifndef _LD_BINDCFG_H_ +#define _LD_BINDCFG_H_ + +#include <isccfg/cfg.h> + +#include "util.h" + +extern cfg_type_t *cfg_type_update_policy; +extern cfg_type_t *cfg_type_allow_query; +extern cfg_type_t *cfg_type_allow_transfer; +extern cfg_type_t *cfg_type_forwarders; + +void +cfg_init_types(void); + +isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT +cfg_parse_strbuf(cfg_parser_t *parser, const char *string, cfg_type_t **type, + cfg_obj_t **objp); + +#endif /* _LD_BINDCFG_H_ */ diff --git a/src/zone_manager.c b/src/zone_manager.c index 93e3fe5675713876d02ce52d036aa2f8a90e288e..85e19fb21ad1167338fdd11dc86e8b62c9f4d39e 100644 --- a/src/zone_manager.c +++ b/src/zone_manager.c @@ -18,6 +18,8 @@ #include <unistd.h> #include "config.h" + +#include "bindcfg.h" #include "ldap_convert.h" #include "ldap_helper.h" #include "log.h" @@ -50,6 +52,7 @@ initialize_manager(void) log_info("bind-dyndb-ldap version " VERSION " compiled at " __TIME__ " " __DATE__ ", compiler " __VERSION__); + cfg_init_types(); } void -- 2.5.5
From 758f19f84aa6ebbcfe17fc9e1a01091342f63631 Mon Sep 17 00:00:00 2001 From: Petr Spacek <pspa...@redhat.com> Date: Thu, 2 Jun 2016 15:36:59 +0200 Subject: [PATCH] Settings: Support enum description->value mapping. https://fedorahosted.org/bind-dyndb-ldap/ticket/162 --- src/settings.c | 20 ++++++++++++++++++++ src/settings.h | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/src/settings.c b/src/settings.c index 5755f83c4c92125b19af00dd724d9927c4bdc89c..a54abfb42af2a7e426e489f83fd218b76a5c0138 100644 --- a/src/settings.c +++ b/src/settings.c @@ -659,3 +659,23 @@ get_enum_description(const enum_txt_assoc_t *map, int value, const char **desc) } return ISC_R_NOTFOUND; } + +isc_result_t +get_enum_value(const enum_txt_assoc_t *map, const char *description, + int *value) { + const enum_txt_assoc_t *record; + + REQUIRE(map != NULL); + REQUIRE(description != NULL); + REQUIRE(value != NULL); + + for (record = map; + record->description != NULL && record->value != -1; + record++) { + if (strcasecmp(record->description, description) == 0) { + *value = record->value; + return ISC_R_SUCCESS; + } + } + return ISC_R_NOTFOUND; +} diff --git a/src/settings.h b/src/settings.h index eeae00add799e525241492b16e84ed14cf73c846..c2b9cd7174f43cdeae57b5c601e9f6ec5d646104 100644 --- a/src/settings.h +++ b/src/settings.h @@ -111,4 +111,8 @@ setting_update_from_ldap_entry(const char *name, settings_set_t *set, isc_result_t get_enum_description(const enum_txt_assoc_t *map, int value, const char **desc) ATTR_NONNULLS ATTR_CHECKRESULT; +isc_result_t +get_enum_value(const enum_txt_assoc_t *map, const char *description, + int *value) ATTR_NONNULLS ATTR_CHECKRESULT; + #endif /* !_LD_SETTINGS_H_ */ -- 2.5.5
From df82481bb2e2edcadc9159e1244b0289950f9def Mon Sep 17 00:00:00 2001 From: Petr Spacek <pspa...@redhat.com> Date: Thu, 2 Jun 2016 15:37:49 +0200 Subject: [PATCH] Settings: Expose API for setting_unset and setting_find to other modules. https://fedorahosted.org/bind-dyndb-ldap/ticket/162 --- src/settings.c | 2 +- src/settings.h | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/settings.c b/src/settings.c index a54abfb42af2a7e426e489f83fd218b76a5c0138..24004248ac706a5594ec803d79d99b2fa9335dc4 100644 --- a/src/settings.c +++ b/src/settings.c @@ -354,7 +354,7 @@ cleanup: * @retval ISC_R_NOTFOUND Required setting was not found * in given set of settings. */ -static isc_result_t +isc_result_t setting_unset(const char *const name, const settings_set_t *set) { isc_result_t result; diff --git a/src/settings.h b/src/settings.h index c2b9cd7174f43cdeae57b5c601e9f6ec5d646104..e1d46f80392a2f7bcd42b01e3997ac4ff0c67a45 100644 --- a/src/settings.h +++ b/src/settings.h @@ -88,6 +88,11 @@ isc_boolean_t settings_set_isfilled(settings_set_t *set) ATTR_NONNULLS ATTR_CHECKRESULT; isc_result_t +setting_find(const char *name, const settings_set_t *set, + isc_boolean_t recursive, isc_boolean_t filled_only, + setting_t **found) ATTR_CHECKRESULT; + +isc_result_t setting_get_uint(const char * const name, const settings_set_t * const set, isc_uint32_t * target) ATTR_NONNULLS ATTR_CHECKRESULT; @@ -104,6 +109,10 @@ setting_set(const char *const name, const settings_set_t *set, const char *const value) ATTR_NONNULLS ATTR_CHECKRESULT; isc_result_t +setting_unset(const char *const name, const settings_set_t *set) +ATTR_NONNULLS ATTR_CHECKRESULT; + +isc_result_t setting_update_from_ldap_entry(const char *name, settings_set_t *set, const char *attr_name, ldap_entry_t *entry) ATTR_NONNULLS ATTR_CHECKRESULT; -- 2.5.5
From 8fc9d186f62ae2730045a928e9852264808c3c88 Mon Sep 17 00:00:00 2001 From: Petr Spacek <pspa...@redhat.com> Date: Thu, 2 Jun 2016 17:08:24 +0200 Subject: [PATCH] Untangle forwarder configuration from LDAP code. Previously code handling forwarders was so interleaved with LDAP code that it was impossible to add another layer for per-server config. This is preparatory work which untangles LDAP and forwarders to enable further development. As far as I can tell the user-visible behavior should not be changed by this patch. https://fedorahosted.org/bind-dyndb-ldap/ticket/162 --- src/Makefile.am | 2 + src/acl.c | 99 --------- src/acl.h | 12 +- src/fwd.c | 585 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/fwd.h | 37 ++++ src/ldap_helper.c | 457 +++++++++--------------------------------- src/ldap_helper.h | 7 + 7 files changed, 729 insertions(+), 470 deletions(-) create mode 100644 src/fwd.c create mode 100644 src/fwd.h diff --git a/src/Makefile.am b/src/Makefile.am index 595fb4d95577f025e97dbce0770325a82a053ad8..238d8ef209fb320cd1a6c3fcdc35af411c7c8373 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,6 +7,7 @@ HDRS = \ compat.h \ empty_zones.h \ fs.h \ + fwd.h \ fwd_register.h \ krb5_helper.h \ ldap_convert.h \ @@ -34,6 +35,7 @@ ldap_la_SOURCES = \ acl.c \ bindcfg.c \ empty_zones.c \ + fwd.c \ fwd_register.c \ fs.c \ krb5_helper.c \ diff --git a/src/acl.c b/src/acl.c index d03a34d8c4ba5016ae9b248dc86781952d92c8d4..0d475f08b42ed7bf83574924b7336cab7280abf0 100644 --- a/src/acl.c +++ b/src/acl.c @@ -263,24 +263,6 @@ cleanup: return result; } -static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT -semicolon_bracket_str(isc_mem_t *mctx, const char *str, ld_string_t **bracket_strp) -{ - ld_string_t *tmp = NULL; - isc_result_t result; - - CHECK(str_new(mctx, &tmp)); - CHECK(str_sprintf(tmp, "{ %s; }", str)); - - *bracket_strp = tmp; - - return ISC_R_SUCCESS; - -cleanup: - str_destroy(&tmp); - return result; -} - isc_result_t acl_configure_zone_ssutable(const char *policy_str, dns_zone_t *zone) { @@ -445,84 +427,3 @@ cleanup: return result; } - - -/** - * Parse nameserver IP address with or without port specified in BIND9 syntax. - * IPv4 and IPv6 addresses are supported, see examples. - * - * @param[in] forwarder_str String with IP address and optionally port. - * @param[in] mctx Memory for allocating temporary and sa structure. - * @param[out] sa Socket address structure. - * - * @return Pointer to newly allocated isc_sockaddr_t structure. - * - * @example - * "192.168.0.100" -> { address:192.168.0.100, port:53 } - * "192.168.0.100 port 553" -> { address:192.168.0.100, port:553 } - * "0102:0304:0506:0708:090A:0B0C:0D0E:0FAA" -> - * { address:0102:0304:0506:0708:090A:0B0C:0D0E:0FAA, port:53 } - * "0102:0304:0506:0708:090A:0B0C:0D0E:0FAA port 553" -> - * { address:0102:0304:0506:0708:090A:0B0C:0D0E:0FAA, port:553 } - * - */ -isc_result_t -acl_parse_forwarder(const char *forwarder_str, isc_mem_t *mctx, -#if LIBDNS_VERSION_MAJOR < 140 - isc_sockaddr_t **fw) -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - dns_forwarder_t **fw) -#endif -{ - isc_result_t result = ISC_R_SUCCESS; - cfg_parser_t *parser = NULL; - - cfg_obj_t *forwarders_cfg = NULL; - ld_string_t *new_forwarder_str = NULL; - const cfg_obj_t *faddresses; - const cfg_listelt_t *element; - const cfg_obj_t *forwarder; - isc_sockaddr_t addr; - - in_port_t port = 53; - - REQUIRE(forwarder_str != NULL); - REQUIRE(fw != NULL && *fw == NULL); - - /* add semicolon and brackets as necessary for parser */ - if (!index(forwarder_str, ';')) - CHECK(semicolon_bracket_str(mctx, forwarder_str, &new_forwarder_str)); - else - CHECK(bracket_str(mctx, forwarder_str, &new_forwarder_str)); - - CHECK(cfg_parser_create(mctx, dns_lctx, &parser)); - CHECK(cfg_parse_strbuf(parser, str_buf(new_forwarder_str), &cfg_type_forwarders, &forwarders_cfg)); - - faddresses = cfg_tuple_get(forwarders_cfg, "addresses"); - element = cfg_list_first(faddresses); - if (!element) { - result = ISC_R_FAILURE; - goto cleanup; - } - - forwarder = cfg_listelt_value(element); - CHECKED_MEM_GET_PTR(mctx, *fw); - addr = *cfg_obj_assockaddr(forwarder); - if (isc_sockaddr_getport(&addr) == 0) - isc_sockaddr_setport(&addr, port); -#if LIBDNS_VERSION_MAJOR < 140 - **fw = addr; -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - (*fw)->addr = addr; - (*fw)->dscp = cfg_obj_getdscp(forwarder); -#endif - - -cleanup: - if (forwarders_cfg != NULL) - cfg_obj_destroy(parser, &forwarders_cfg); - if (parser != NULL) - cfg_parser_destroy(&parser); - str_destroy(&new_forwarder_str); - return result; -} diff --git a/src/acl.h b/src/acl.h index ef1fcb780df4af4c2d661ea2715f629614d168da..ce1210ec28185cc1ec347489b4fc04ae4b568ead 100644 --- a/src/acl.h +++ b/src/acl.h @@ -5,6 +5,9 @@ #ifndef _LD_ACL_H_ #define _LD_ACL_H_ +#include "config.h" + +#include "ldap_entry.h" #include "types.h" #include <dns/acl.h> @@ -28,13 +31,4 @@ acl_from_ldap(isc_mem_t *mctx, const char *aclstr, acl_type_t type, * Please refer to BIND 9 ARM (Administrator Reference Manual) about ACLs. */ -isc_result_t -acl_parse_forwarder(const char *forwarders_str, isc_mem_t *mctx, -#if LIBDNS_VERSION_MAJOR < 140 - isc_sockaddr_t **fw) -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - dns_forwarder_t **fw) -#endif -ATTR_NONNULLS ATTR_CHECKRESULT; - #endif /* !_LD_ACL_H_ */ diff --git a/src/fwd.c b/src/fwd.c new file mode 100644 index 0000000000000000000000000000000000000000..e17b55a77cfc7f2813b891dbc9cccd3ad9c2ebc1 --- /dev/null +++ b/src/fwd.c @@ -0,0 +1,585 @@ +/** + * Copyright (C) 2016 bind-dyndb-ldap authors; see COPYING for license + * + * DNS forwarding helpers. + */ + +#include "config.h" + +#include <isccfg/grammar.h> + +#include <dns/forward.h> +#include <dns/fixedname.h> +#include <dns/view.h> + +#include "bindcfg.h" +#include "empty_zones.h" +#include "fwd.h" +#include "ldap_helper.h" +#include "lock.h" +#include "settings.h" + +const enum_txt_assoc_t forwarder_policy_txts[] = { + { dns_fwdpolicy_none, "none" }, + { dns_fwdpolicy_first, "first" }, + { dns_fwdpolicy_only, "only" }, + { -1, NULL } /* end marker */ +}; + +/** + * @pre closure points to a valid isc_buffer + * @pre isc_buffer has non-NULL mctx + * @pre isc_buffer has NULL buffer OR a buffer allocated from mctx + * + * @post closure contains \0 terminated string which is concatenation + * of previous context and input text + */ +static void +buffer_append_str(void *closure, const char *text, int textlen) { + isc_buffer_t *out_buf = closure; + isc_region_t new_space; + isc_region_t old_space; + + REQUIRE(ISC_BUFFER_VALID(out_buf)); + REQUIRE(out_buf->mctx != NULL); + REQUIRE(text != NULL); + + /* Allocate sufficiently long output buffer. */ + isc_buffer_region(out_buf, &old_space); + new_space.length = isc_buffer_length(out_buf) + textlen + 1; + new_space.base = isc_mem_get(out_buf->mctx, new_space.length); + RUNTIME_CHECK(new_space.base != NULL); + isc_buffer_reinit(out_buf, new_space.base, new_space.length); + if (old_space.base != NULL) + isc_mem_put(out_buf->mctx, old_space.base, old_space.length); + + /* Append output text and \0-terminate it. + * Overwrite \0 at the end if needed. */ + if (isc_buffer_usedlength(out_buf) != 0) + /* Previous string is \0 terminated, chop \0. */ + isc_buffer_subtract(out_buf, 1); + isc_buffer_putstr(out_buf, text); + isc_buffer_putuint8(out_buf, '\0'); +} + +static size_t +fwd_list_len(dns_forwarders_t *fwdrs) { + size_t len = 0; + + REQUIRE(fwdrs != NULL); + +#if LIBDNS_VERSION_MAJOR < 140 + for (isc_sockaddr_t *fwdr = ISC_LIST_HEAD(fwdrs->addrs); +#else /* LIBDNS_VERSION_MAJOR >= 140 */ + for (dns_forwarder_t *fwdr = ISC_LIST_HEAD(fwdrs->fwdrs); +#endif + fwdr != NULL; + fwdr = ISC_LIST_NEXT(fwdr, link)) { + len++; + } + return len; +} + +/** + * Generate dummy string which looks like list of forwarders + * with list_len elements. This string might be fed into cfg parser. + * + * Caller has to deallocate resulting dummy_string. + */ +static isc_result_t +fwd_list_gen_dummy_config_string(isc_mem_t *mctx, size_t list_len, + isc_buffer_t **dummy_string) { + isc_result_t result; + const char prefix[] = "{ "; + const char suffix[] = "} // dummy string, please ignore"; + const char fill[] = "127.0.0.1; "; + size_t target_size = sizeof(prefix) \ + + list_len*sizeof(fill) + + sizeof(suffix) + + 1; /* \0 */ + isc_buffer_t *output = NULL; + + REQUIRE(dummy_string != NULL && *dummy_string == NULL); + + CHECK(isc_buffer_allocate(mctx, &output, target_size)); + isc_buffer_putstr(output, prefix); + for (size_t i = 0; i < list_len; i++) + isc_buffer_putstr(output, fill); + isc_buffer_putstr(output, suffix); + isc_buffer_putuint8(output, '\0'); + *dummy_string = output; + +cleanup: + if (result != ISC_R_SUCCESS && output != NULL) + isc_buffer_free(&output); + + return result; +} + +/** + * Generate list of all values as bracketed list. + * This string might be fed into cfg parser. + * + * Caller has to deallocate resulting output buffer. + */ +isc_result_t +fwd_print_bracketed_values_buf(isc_mem_t *mctx, ldap_valuelist_t *values, + isc_buffer_t **string) { + isc_result_t result; + ldap_value_t *value; + const char prefix[] = "{ "; + const char suffix[] = "}"; + isc_buffer_t tmp_buf; /* hack: only the base buffer is allocated */ + + REQUIRE(string != NULL && *string == NULL); + + isc_buffer_initnull(&tmp_buf); + tmp_buf.mctx = mctx; + + buffer_append_str(&tmp_buf, prefix, 2); + for (value = HEAD(*values); + value != NULL && value->value != NULL; + value = NEXT(value, link)) { + buffer_append_str(&tmp_buf, value->value, strlen(value->value)); + buffer_append_str(&tmp_buf, "; ", 2); + } + buffer_append_str(&tmp_buf, suffix, 2); + + /* create and copy string from tmp to output buffer */ + CHECK(isc_buffer_allocate(mctx, string, tmp_buf.used)); + isc_buffer_putmem(*string, isc_buffer_base(&tmp_buf), tmp_buf.used); + +cleanup: + if (tmp_buf.base != NULL) + isc_mem_put(mctx, tmp_buf.base, tmp_buf.length); + return result; +} + +isc_result_t +fwd_print_list_buff(isc_mem_t *mctx, dns_forwarders_t *fwdrs, + isc_buffer_t **out_buf) { + isc_result_t result; + size_t list_len; + isc_buffer_t *dummy_fwdr_buf = NULL; /* fully dynamic allocation */ + isc_buffer_t tmp_buf; /* hack: only the base buffer is allocated */ + + cfg_parser_t *parser = NULL; + cfg_obj_t *forwarders_cfg = NULL; + const cfg_obj_t *faddresses; + const cfg_listelt_t *fwdr_cfg; /* config representation */ + /* internal representation */ +#if LIBDNS_VERSION_MAJOR < 140 + isc_sockaddr_t *fwdr_int; +#else /* LIBDNS_VERSION_MAJOR >= 140 */ + dns_forwarder_t *fwdr_int; +#endif + + isc_buffer_initnull(&tmp_buf); + tmp_buf.mctx = mctx; + CHECK(cfg_parser_create(mctx, dns_lctx, &parser)); + + /* Create dummy string with list of IP addresses of the same length + * as the original list of forwarders. Parse this string to obtain + * nested cfg structures which will be filled with data for actual + * forwarders. + * + * This is nasty hack but it is easiest way to create list of cfg_objs + * I found. + */ + list_len = fwd_list_len(fwdrs); + CHECK(fwd_list_gen_dummy_config_string(mctx, + list_len, &dummy_fwdr_buf)); + CHECK(cfg_parse_buffer(parser, dummy_fwdr_buf, + cfg_type_forwarders, &forwarders_cfg)); + + /* Walk through internal representation and cfg representation and copy + * data from the internal one to cfg data structures.*/ + faddresses = cfg_tuple_get(forwarders_cfg, "addresses"); + for (fwdr_int = ISC_LIST_HEAD( +#if LIBDNS_VERSION_MAJOR < 140 + fwdrs->addrs +#else /* LIBDNS_VERSION_MAJOR >= 140 */ + fwdrs->fwdrs +#endif + ), fwdr_cfg = cfg_list_first(faddresses); + INSIST((fwdr_int == NULL) == (fwdr_cfg == NULL)), fwdr_int != NULL; + fwdr_int = ISC_LIST_NEXT(fwdr_int, link), fwdr_cfg = cfg_list_next(fwdr_cfg)) { +#if LIBDNS_VERSION_MAJOR < 140 + fwdr_cfg->obj->value.sockaddr = *fwdr_int; +#else /* LIBDNS_VERSION_MAJOR >= 140 */ + fwdr_cfg->obj->value.sockaddrdscp.sockaddr = fwdr_int->addr; + fwdr_cfg->obj->value.sockaddrdscp.dscp = fwdr_int->dscp; +#endif + } + cfg_print(faddresses, buffer_append_str, &tmp_buf); + + /* create and copy string from tmp to output buffer */ + CHECK(isc_buffer_allocate(mctx, out_buf, tmp_buf.used)); + isc_buffer_putmem(*out_buf, isc_buffer_base(&tmp_buf), + isc_buffer_usedlength(&tmp_buf)); + +cleanup: + if (forwarders_cfg != NULL) + cfg_obj_destroy(parser, &forwarders_cfg); + if (parser != NULL) + cfg_parser_destroy(&parser); + if (dummy_fwdr_buf != NULL) { + if (tmp_buf.base != NULL) + isc_mem_put(mctx, tmp_buf.base, tmp_buf.length); + isc_buffer_free(&dummy_fwdr_buf); + } + + return result; +} + +/** + * Parse list of nameserver IP addresses with or without port specified + * in BIND9 syntax. IPv4 and IPv6 addresses are supported, see examples. + * + * @param[in] forwarder_str String with IP addresses and optionally port. + * @param[in] mctx Memory for allocating list of forwarders. + * @param[out] fwdrs Pointer to list of newly allocated forwarders. + * + * @return ISC_R_SUCCESS if parsing was successful + * + * @pre list of forwarders pointed to by fwdrs is empty + * + * @example + * "{ 192.168.0.100; }" -> { address:192.168.0.100, port:53 } + * "{ 192.168.0.100 port 553;} " -> { address:192.168.0.100, port:553 } + * "{ 0102:0304:0506:0708:090A:0B0C:0D0E:0FAA; }" + * -> { address:0102:0304:0506:0708:090A:0B0C:0D0E:0FAA, port:53 } + * "{ 0102:0304:0506:0708:090A:0B0C:0D0E:0FAA port 553; }" -> + * -> { address:0102:0304:0506:0708:090A:0B0C:0D0E:0FAA, port:553 } + * "{ 192.168.0.100; 0102:0304:0506:0708:090A:0B0C:0D0E:0FAA port 553; }" + * -> { address:192.168.0.100, port:53; + * address:0102:0304:0506:0708:090A:0B0C:0D0E:0FAA, port:553 } + */ + +static isc_result_t +fwd_parse_str(const char *fwdrs_str, isc_mem_t *mctx, +#if LIBDNS_VERSION_MAJOR < 140 + isc_sockaddrlist_t *fwdrs +#else /* LIBDNS_VERSION_MAJOR >= 140 */ + dns_forwarderlist_t *fwdrs +#endif + ) +{ + isc_result_t result = ISC_R_SUCCESS; + cfg_parser_t *parser = NULL; + + cfg_obj_t *fwdrs_cfg = NULL; + const cfg_obj_t *faddresses; + const cfg_listelt_t *listel; + const cfg_obj_t *fwdr_cfg; + isc_sockaddr_t addr; +#if LIBDNS_VERSION_MAJOR < 140 + isc_sockaddr_t *fwdr; +#else /* LIBDNS_VERSION_MAJOR >= 140 */ + dns_forwarder_t *fwdr; +#endif + + in_port_t port = 53; + + REQUIRE(fwdrs_str != NULL); + REQUIRE(fwdrs != NULL); + REQUIRE(ISC_LIST_EMPTY(*fwdrs)); + + /* parse string like { ip; ip port dscp; } to list of cfg objects */ + CHECK(cfg_parser_create(mctx, dns_lctx, &parser)); + CHECK(cfg_parse_strbuf(parser, fwdrs_str, + &cfg_type_forwarders, &fwdrs_cfg)); + faddresses = cfg_tuple_get(fwdrs_cfg, "addresses"); + + /* transform list of cfg objects to linked list of forwarders */ + for (listel = cfg_list_first(faddresses); + listel != NULL; + listel = cfg_list_next(listel)) { + fwdr_cfg = cfg_listelt_value(listel); + addr = *cfg_obj_assockaddr(fwdr_cfg); + if (isc_sockaddr_getport(&addr) == 0) + isc_sockaddr_setport(&addr, port); + CHECKED_MEM_GET_PTR(mctx, fwdr); +#if LIBDNS_VERSION_MAJOR < 140 + *fwdr = addr; +#else /* LIBDNS_VERSION_MAJOR >= 140 */ + fwdr->addr = addr; + fwdr->dscp = cfg_obj_getdscp(fwdr_cfg); +#endif + ISC_LINK_INIT(fwdr, link); + ISC_LIST_APPEND(*fwdrs, fwdr, link); + } + +cleanup: + if (fwdrs_cfg != NULL) + cfg_obj_destroy(parser, &fwdrs_cfg); + if (parser != NULL) + cfg_parser_destroy(&parser); + return result; +} + +static void +fwdr_list_free(isc_mem_t *mctx, +#if LIBDNS_VERSION_MAJOR < 140 + isc_sockaddrlist_t *fwdrs +#else /* LIBDNS_VERSION_MAJOR >= 140 */ + dns_forwarderlist_t *fwdrs +#endif + ) { +#if LIBDNS_VERSION_MAJOR < 140 + isc_sockaddr_t *fwdr; +#else /* LIBDNS_VERSION_MAJOR >= 140 */ + dns_forwarder_t *fwdr; +#endif + while (!ISC_LIST_EMPTY(*fwdrs)) { + fwdr = ISC_LIST_HEAD(*fwdrs); + ISC_LIST_UNLINK(*fwdrs, fwdr, link); + SAFE_MEM_PUT_PTR(mctx, fwdr); + } +} + +/** + * Read forwarding policy (from idnsForwardingPolicy attribute) and + * list of forwarders (from idnsForwarders multi-value attribute) + * and update settings (forward_policy and forwarders) in given set of settings. + * + * This function does not change actual forwarding configuration. + * @see configure_zone_forwarders + * + * @post Forward_policy is always non-empty because default value is stored + * if nothing is found in the LDAP entry. + * Setting forwarders may be left unset if no forwarders are specified. + * + * @retval ISC_R_SUCCESS Config was parsed and stored in settings + * @retval errors Forwarding policy is invalid + * or specified forwarders are invalid. + */ +isc_result_t +fwd_parse_ldap(ldap_entry_t *entry, settings_set_t *set) { + isc_result_t result; + isc_result_t first; + ldap_valuelist_t values; + ldap_value_t *value; + isc_buffer_t *tmp_buf = NULL; /* hack: only the base buffer is allocated */ +#if LIBDNS_VERSION_MAJOR < 140 + isc_sockaddrlist_t fwdrs; +#else /* LIBDNS_VERSION_MAJOR >= 140 */ + dns_forwarderlist_t fwdrs; +#endif + const char *setting_str = NULL; + + /** + * BIND forward policies are "first" (default) or "only". + * We invented option "none" which disables forwarding for zone + * regardless idnsForwarders attribute and global forwarders. + */ + dns_fwdpolicy_t fwdpolicy; + + REQUIRE(entry != NULL); + REQUIRE(set != NULL); + + ISC_LIST_INIT(fwdrs); + + /* forward policy */ + result = ldap_entry_getvalues(entry, "idnsForwardPolicy", &values); + /* validate LDAP entry before copying it into settings set */ + if (result == ISC_R_SUCCESS + && HEAD(values) != NULL + && HEAD(values)->value != NULL) { + value = HEAD(values); + if (get_enum_value(forwarder_policy_txts, value->value, + (int *)&fwdpolicy) != ISC_R_SUCCESS) + { + log_error("%s: invalid value '%s' in idnsForwardPolicy " + "attribute; valid values: first, only, none", + ldap_entry_logname(entry), value->value); + CLEANUP_WITH(ISC_R_UNEXPECTEDTOKEN); + } + } + result = setting_update_from_ldap_entry("forward_policy", set, + "idnsForwardPolicy", + entry); + first = result; + if (result != ISC_R_SUCCESS && result != ISC_R_IGNORE) + goto cleanup; + result = setting_find("forward_policy", set, ISC_FALSE, ISC_TRUE, NULL); + if (result == ISC_R_NOTFOUND) { + log_debug(2, "defaulting to forward policy 'first' for " + "%s", ldap_entry_logname(entry)); + CHECK(setting_set("forward_policy", set, "first")); + } + + /* forwarders */ + result = ldap_entry_getvalues(entry, "idnsForwarders", &values); + if (result == ISC_R_SUCCESS + && HEAD(values) != NULL && HEAD(values)->value != NULL) { + /* Forwarders: concatenate IP addresses to one { string; } */ + CHECK(fwd_print_bracketed_values_buf(entry->mctx, &values, + &tmp_buf)); + setting_str = isc_buffer_base(tmp_buf); + /* just sanity check, the result is unused */ + CHECK(fwd_parse_str(setting_str, entry->mctx, &fwdrs)); + } + if (!ISC_LIST_EMPTY(fwdrs)) { + result = setting_set("forwarders", set, setting_str); + if (result == ISC_R_SUCCESS) + log_debug(2, "setting 'forwarders' (idnsFowarders) was changed " + "to '%s' in %s", setting_str, ldap_entry_logname(entry)); + else if (result != ISC_R_IGNORE) + goto cleanup; + } else { + result = setting_unset("forwarders", set); + } + + /* return "ignore" only if no change was done in any of the settings */ + result = (result == ISC_R_IGNORE) ? first : result; + +cleanup: + if (result != ISC_R_SUCCESS && result != ISC_R_IGNORE + && setting_str != NULL) + log_error_r("unable to parse forwarders '%s'", setting_str); + if (tmp_buf != NULL) + isc_buffer_free(&tmp_buf); + fwdr_list_free(entry->mctx, &fwdrs); + return result; +} + +/** + * Read forwarding policy and list of forwarders from set of settings + * and update actual forwarding configuration. + * + * Enable forwarding if forwarders are specified and policy is not 'none'. + * Disable forwarding if forwarding policy is 'none' or list of forwarders + * is empty. + * + * Global forwarders will be used if all list of forwarders is not present + * at all. Global forwarders use configuration in following priority order: + * global LDAP config > named.conf + * + * @retval ISC_R_SUCCESS Forwarding configuration was updated. + * @retval ISC_R_NOMEMORY + * @retval others Some RBT manipulation errors including ISC_R_FAILURE. + */ +isc_result_t +fwd_configure_zone(settings_set_t *set, ldap_instance_t *inst, + dns_name_t *name) +{ + isc_result_t result; + isc_mem_t *mctx = NULL; + dns_view_t *view = NULL; + isc_result_t lock_state = ISC_R_IGNORE; +#if LIBDNS_VERSION_MAJOR < 140 + isc_sockaddrlist_t fwdrs; +#else /* LIBDNS_VERSION_MAJOR >= 140 */ + dns_forwarderlist_t fwdrs; +#endif + isc_boolean_t is_global_config; + dns_fixedname_t foundname; + const char *msg_use_global_fwds; + const char *msg_obj_type; + /** + * BIND forward policies are "first" (default) or "only". + * We invented option "none" which disables forwarding for zone + * regardless idnsForwarders attribute and global forwarders. + */ + dns_fwdpolicy_t fwdpolicy; + const char *fwdpolicy_str = NULL; + const char *forwarders_str = NULL; + + REQUIRE(inst != NULL && name != NULL); + ldap_instance_attachmem(inst, &mctx); + ldap_instance_attachview(inst, &view); + + dns_fixedname_init(&foundname); + ISC_LIST_INIT(fwdrs); + + if (dns_name_equal(name, dns_rootname)) { + is_global_config = ISC_TRUE; + msg_obj_type = "global configuration"; + msg_use_global_fwds = "; global forwarders will be disabled"; + } else { + is_global_config = ISC_FALSE; + msg_obj_type = "zone"; + msg_use_global_fwds = "; global forwarders will be used " + "(if they are configured)"; + } + + /* fetch forward policy */ + CHECK(setting_get_str("forward_policy", set, &fwdpolicy_str)); + result = get_enum_value(forwarder_policy_txts, + fwdpolicy_str, (int *)&fwdpolicy); + INSIST(result == ISC_R_SUCCESS); + log_debug(5, "%s %s: forward policy is '%s'", msg_obj_type, + set->name, fwdpolicy_str); + if (fwdpolicy == dns_fwdpolicy_none) + log_debug(5, "%s %s: forwarding explicitly disabled " + "(policy 'none', ignoring all forwarders)", + msg_obj_type, set->name); + + /* Fetch forwarders configured for particular zone. + * Global config (root zone) is special case because it can be set in + * named.conf, LDAP global object or root zone in LDAP so inheritance + * is necessary. + * For all other zones (non-root) zones *do not* use recursive getter + * and let BIND to handle inheritance in fwdtable itself. */ + if (fwdpolicy != dns_fwdpolicy_none + && (setting_find("forwarders", set, ISC_FALSE, ISC_TRUE, NULL) == ISC_R_SUCCESS + || is_global_config == ISC_TRUE)) { + CHECK(setting_get_str("forwarders", set, &forwarders_str)); + CHECK(fwd_parse_str(forwarders_str, mctx, &fwdrs)); + } else { + ISC_LIST_INIT(fwdrs); + log_debug(5, "list of forwarders in %s is empty%s", + set->name, msg_use_global_fwds); + } + + /* update forwarding table */ + run_exclusive_enter(inst, &lock_state); + CHECK(fwd_delete_table(view, name, msg_obj_type, set->name)); + if (fwdpolicy != dns_fwdpolicy_none && !ISC_LIST_EMPTY(fwdrs)) { +#if LIBDNS_VERSION_MAJOR < 140 + CHECK(dns_fwdtable_add(view->fwdtable, name, &fwdrs, + fwdpolicy)); +#else /* LIBDNS_VERSION_MAJOR >= 140 */ + CHECK(dns_fwdtable_addfwd(view->fwdtable, name, &fwdrs, + fwdpolicy)); +#endif + } + dns_view_flushcache(view); + run_exclusive_exit(inst, lock_state); + lock_state = ISC_R_IGNORE; /* prevent double-unlock */ + log_debug(5, "%s %s: forwarder table was updated: %s", + msg_obj_type, set->name, + dns_result_totext(result)); + + /* Handle collisions with automatic empty zones. */ + if (fwdpolicy != dns_fwdpolicy_none && !ISC_LIST_EMPTY(fwdrs)) + CHECK(empty_zone_handle_conflicts(name, + view->zonetable, + (fwdpolicy == dns_fwdpolicy_first))); + +cleanup: + run_exclusive_exit(inst, lock_state); + if (result != ISC_R_SUCCESS) + log_error_r("%s %s: forwarding table update failed", + msg_obj_type, set->name); + fwdr_list_free(mctx, &fwdrs); + dns_view_detach(&view); + isc_mem_detach(&mctx); + return result; +} + +isc_result_t +fwd_delete_table(dns_view_t *view, dns_name_t *name, + const char *msg_obj_type, const char *logname) { + isc_result_t result; + + result = dns_fwdtable_delete(view->fwdtable, name); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { + log_error_r("%s %s: failed to delete forwarders", + msg_obj_type, logname); + return result; + } else { + return ISC_R_SUCCESS; /* ISC_R_NOTFOUND = nothing to delete */ + } +} diff --git a/src/fwd.h b/src/fwd.h new file mode 100644 index 0000000000000000000000000000000000000000..79bec61539cacd7d4537ee8e70122570d01741b7 --- /dev/null +++ b/src/fwd.h @@ -0,0 +1,37 @@ +/* + * DNS forwarding utilities. + */ + +#ifndef _LD_FWD_H_ +#define _LD_FWD_H_ + +#include "config.h" +#include "ldap_entry.h" +#include "util.h" + +extern const enum_txt_assoc_t forwarder_policy_txts[]; + +isc_result_t +fwd_print_list_buff(isc_mem_t *mctx, dns_forwarders_t *fwdrs, + isc_buffer_t **out_buf) + ATTR_NONNULLS ATTR_CHECKRESULT; + +isc_result_t +fwd_print_bracketed_values_buf(isc_mem_t *mctx, ldap_valuelist_t *values, + isc_buffer_t **string) + ATTR_NONNULLS ATTR_CHECKRESULT; + +isc_result_t +fwd_parse_ldap(ldap_entry_t *entry, settings_set_t *set) + ATTR_NONNULLS ATTR_CHECKRESULT; + +isc_result_t +fwd_configure_zone(settings_set_t *set, ldap_instance_t *inst, dns_name_t *name) + ATTR_NONNULLS ATTR_CHECKRESULT; + +isc_result_t +fwd_delete_table(dns_view_t *view, dns_name_t *name, + const char *msg_obj_type, const char *logname) + ATTR_NONNULLS ATTR_CHECKRESULT; + +#endif /* _LD_FWD_H_ */ diff --git a/src/ldap_helper.c b/src/ldap_helper.c index 451ecdba20d6aa4c57ea438fe466a70426e9abfa..b13f17368e712102ceb0211172700c94c3213cbe 100644 --- a/src/ldap_helper.c +++ b/src/ldap_helper.c @@ -41,6 +41,8 @@ #include <isc/serial.h> #include <isc/string.h> +#include <isccfg/cfg.h> + #include <alloca.h> #define LDAP_DEPRECATED 1 #include <ldap.h> @@ -57,6 +59,7 @@ #include "acl.h" #include "empty_zones.h" #include "fs.h" +#include "fwd.h" #include "krb5_helper.h" #include "ldap_convert.h" #include "ldap_driver.h" @@ -78,13 +81,6 @@ #include "rbt_helper.h" #include "fwd_register.h" -const enum_txt_assoc_t forwarder_policy_txts[] = { - { dns_fwdpolicy_none, "none" }, - { dns_fwdpolicy_first, "first" }, - { dns_fwdpolicy_only, "only" }, - { -1, NULL } /* end marker */ -}; - #define LDAP_OPT_CHECK(r, ...) \ do { \ if ((r) != LDAP_OPT_SUCCESS) { \ @@ -131,13 +127,6 @@ struct ldap_auth_pair { char *name; /* String representation used in configuration file */ }; -/* BIND 9.10 changed forwarder representation in struct dns_forwarders */ -#if LIBDNS_VERSION_MAJOR < 140 - #define inst_fwdlist(inst) ((inst)->orig_global_forwarders.addrs) -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - #define inst_fwdlist(inst) ((inst)->orig_global_forwarders.fwdrs) -#endif - /* These are typedefed in ldap_helper.h */ struct ldap_instance { isc_mem_t *mctx; @@ -166,7 +155,6 @@ struct ldap_instance { /* Settings. */ settings_set_t *local_settings; settings_set_t *global_settings; - dns_forwarders_t orig_global_forwarders; /* from named.conf */ sync_ctx_t *sctx; mldapdb_t *mldapdb; @@ -250,13 +238,20 @@ static const setting_t settings_local_default[] = { { "verbose_checks", no_default_boolean }, { "directory", no_default_string }, { "nsec3param", default_string("0 0 0 00") }, /* NSEC only */ + /* Defaults for forwarding here must be overridden by values from + * from named.conf (i.e. copied to inst->local_settings) + * during start up to allow settings_set_isfilled() to pass.*/ + { "forward_policy", no_default_string }, + { "forwarders", no_default_string }, end_of_settings }; /** Global settings from idnsConfig object. */ static setting_t settings_global_default[] = { - { "dyn_update", no_default_boolean }, - { "sync_ptr", no_default_boolean }, + { "dyn_update", no_default_boolean }, + { "sync_ptr", no_default_boolean }, + { "forward_policy", default_string("first") }, + { "forwarders", default_string("{ /* uninitialized global config */ }") }, end_of_settings }; @@ -508,7 +503,9 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, isc_result_t result; ldap_instance_t *ldap_inst; dns_view_t *view = NULL; - dns_forwarders_t *orig_global_forwarders = NULL; + dns_forwarders_t *named_conf_forwarders = NULL; + isc_buffer_t *forwarders_list = NULL; + const char *forward_policy = NULL; isc_uint32_t connections; char settings_name[PRINT_BUFF_SIZE]; ldap_globalfwd_handleez_t *gfwdevent = NULL; @@ -524,7 +521,6 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, view = dns_dyndb_get_view(dyndb_args); dns_view_attach(view, &ldap_inst->view); ldap_inst->zmgr = dns_dyndb_get_zonemgr(dyndb_args); - ISC_LIST_INIT(inst_fwdlist(ldap_inst)); ldap_inst->task = task; ldap_inst->watcher = 0; CHECK(sync_ctx_init(ldap_inst->mctx, ldap_inst, &ldap_inst->sctx)); @@ -544,42 +540,22 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, ldap_inst->local_settings, &ldap_inst->global_settings)); CHECK(settings_set_fill(ldap_inst->local_settings, argv)); - CHECK(validate_local_instance_settings(ldap_inst, ldap_inst->local_settings)); - if (settings_set_isfilled(ldap_inst->global_settings) != ISC_TRUE) - CLEANUP_WITH(ISC_R_FAILURE); - - CHECK(setting_get_uint("connections", ldap_inst->local_settings, &connections)); - - CHECK(zr_create(mctx, ldap_inst, ldap_inst->global_settings, - &ldap_inst->zone_register)); - CHECK(fwdr_create(ldap_inst->mctx, &ldap_inst->fwd_register)); - CHECK(mldap_new(mctx, &ldap_inst->mldapdb)); - - CHECK(isc_mutex_init(&ldap_inst->kinit_lock)); /* copy global forwarders setting for configuration roll back in * configure_zone_forwarders() */ result = dns_fwdtable_find(ldap_inst->view->fwdtable, dns_rootname, - &orig_global_forwarders); + &named_conf_forwarders); if (result == ISC_R_SUCCESS) { -#if LIBDNS_VERSION_MAJOR < 140 - isc_sockaddr_t *fwdr; - isc_sockaddr_t *new_fwdr; - for (fwdr = ISC_LIST_HEAD(orig_global_forwarders->addrs); -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - dns_forwarder_t *fwdr; - dns_forwarder_t *new_fwdr; - for (fwdr = ISC_LIST_HEAD(orig_global_forwarders->fwdrs); -#endif - fwdr != NULL; - fwdr = ISC_LIST_NEXT(fwdr, link)) { - CHECKED_MEM_GET_PTR(mctx, new_fwdr); - *new_fwdr = *fwdr; - ISC_LINK_INIT(new_fwdr, link); - ISC_LIST_APPEND(inst_fwdlist(ldap_inst), new_fwdr, link); - } - ldap_inst->orig_global_forwarders.fwdpolicy = - orig_global_forwarders->fwdpolicy; + /* Copy forwarding config from named.conf into local_settings */ + CHECK(fwd_print_list_buff(mctx, named_conf_forwarders, + &forwarders_list)); + CHECK(setting_set("forwarders", ldap_inst->local_settings, + isc_buffer_base(forwarders_list))); + CHECK(get_enum_description(forwarder_policy_txts, + named_conf_forwarders->fwdpolicy, + &forward_policy)); + CHECK(setting_set("forward_policy", ldap_inst->local_settings, + forward_policy)); /* Make sure we disable conflicting automatic empty zones. * This will be done in event to prevent the plugin from @@ -597,18 +573,35 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, if (gfwdevent == NULL) CLEANUP_WITH(ISC_R_NOMEMORY); /* policy == first does not override automatic empty zones */ - gfwdevent->warn_only = (orig_global_forwarders->fwdpolicy + gfwdevent->warn_only = (named_conf_forwarders->fwdpolicy == dns_fwdpolicy_first); isc_task_send(task, (isc_event_t **)&gfwdevent); } else if (result == ISC_R_NOTFOUND) { /* global forwarders are not configured */ - ldap_inst->orig_global_forwarders.fwdpolicy = dns_fwdpolicy_none; + CHECK(setting_set("forwarders", ldap_inst->local_settings, + "{ /* empty list of forwarders */ }")); + CHECK(setting_set("forward_policy", ldap_inst->local_settings, + "first")); } else { goto cleanup; } + CHECK(validate_local_instance_settings(ldap_inst, + ldap_inst->local_settings)); + if (settings_set_isfilled(ldap_inst->global_settings) != ISC_TRUE) + CLEANUP_WITH(ISC_R_FAILURE); + + CHECK(setting_get_uint("connections", ldap_inst->local_settings, &connections)); + + CHECK(zr_create(mctx, ldap_inst, ldap_inst->global_settings, + &ldap_inst->zone_register)); + CHECK(fwdr_create(ldap_inst->mctx, &ldap_inst->fwd_register)); + CHECK(mldap_new(mctx, &ldap_inst->mldapdb)); + + CHECK(isc_mutex_init(&ldap_inst->kinit_lock)); + CHECK(ldap_pool_create(mctx, connections, &ldap_inst->pool)); CHECK(ldap_pool_connect(ldap_inst->pool, ldap_inst)); @@ -621,6 +614,8 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, } cleanup: + if (forwarders_list != NULL) + isc_buffer_free(&forwarders_list); if (result != ISC_R_SUCCESS) destroy_ldap_instance(&ldap_inst); else @@ -635,11 +630,6 @@ destroy_ldap_instance(ldap_instance_t **ldap_instp) { ldap_instance_t *ldap_inst; const char *db_name; -#if LIBDNS_VERSION_MAJOR < 140 - isc_sockaddr_t *fwdr; -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - dns_forwarder_t *fwdr; -#endif REQUIRE(ldap_instp != NULL); @@ -675,12 +665,6 @@ destroy_ldap_instance(ldap_instance_t **ldap_instp) DESTROYLOCK(&ldap_inst->kinit_lock); - while (!ISC_LIST_EMPTY(inst_fwdlist(ldap_inst))) { - fwdr = ISC_LIST_HEAD(inst_fwdlist(ldap_inst)); - ISC_LIST_UNLINK(inst_fwdlist(ldap_inst), fwdr, link); - SAFE_MEM_PUT_PTR(ldap_inst->mctx, fwdr); - } - settings_set_free(&ldap_inst->global_settings); settings_set_free(&ldap_inst->local_settings); @@ -1260,21 +1244,6 @@ configure_zone_ssutable(dns_zone_t *zone, const char *update_str) return result; } -static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT -delete_forwarding_table(ldap_instance_t *inst, dns_name_t *name, - const char *msg_obj_type, const char *logname) { - isc_result_t result; - - result = dns_fwdtable_delete(inst->view->fwdtable, name); - if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { - log_error_r("%s %s: failed to delete forwarders", - msg_obj_type, logname); - return result; - } else { - return ISC_R_SUCCESS; /* ISC_R_NOTFOUND = nothing to delete */ - } -} - /* Delete zone by dns zone name */ isc_result_t ldap_delete_zone2(ldap_instance_t *inst, dns_name_t *name, isc_boolean_t lock, @@ -1295,8 +1264,8 @@ ldap_delete_zone2(ldap_instance_t *inst, dns_name_t *name, isc_boolean_t lock, run_exclusive_enter(inst, &lock_state); if (!preserve_forwarding) { - CHECK(delete_forwarding_table(inst, name, "zone", - zone_name_char)); + CHECK(fwd_delete_table(inst->view, name, "zone", + zone_name_char)); isforward = fwdr_zone_ispresent(inst->fwd_register, name); if (isforward == ISC_R_SUCCESS) CHECK(fwdr_del_zone(inst->fwd_register, name)); @@ -1368,7 +1337,7 @@ unpublish_zone(ldap_instance_t *inst, dns_name_t *name, const char *logname) { } CHECK(dns_view_findzone(inst->view, name, &zone_in_view)); INSIST(zone_in_view == raw || zone_in_view == secure); - CHECK(delete_forwarding_table(inst, name, "zone", logname)); + CHECK(fwd_delete_table(inst->view, name, "zone", logname)); CHECK(dns_zt_unmount(inst->view->zonetable, zone_in_view)); cleanup: @@ -1387,273 +1356,6 @@ cleanup: return result; } -/** - * Read forwarding policy (from idnsForwardingPolicy attribute) and - * list of forwarders (from idnsForwarders multi-value attribute) - * and update forwarding settings for given zone. - * - * Enable forwarding if forwarders are specified and policy is not 'none'. - * Disable forwarding if forwarding policy is 'none' or list of forwarders - * is empty. - * - * Invalid forwarders are skipped, forwarding will be enabled if at least - * one valid forwarder is defined. Global forwarders will be used if all - * defined forwarders are invalid or list of forwarders is not present at all. - * - * @retval ISC_R_SUCCESS Forwarding was enabled. - * @retval ISC_R_DISABLED Forwarding was disabled. - * @retval ISC_R_UNEXPECTEDTOKEN Forwarding policy is invalid - * or all specified forwarders are invalid. - * @retval ISC_R_NOMEMORY - * @retval others Some RBT manipulation errors including ISC_R_FAILURE. - */ -static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT -configure_zone_forwarders(ldap_entry_t *entry, ldap_instance_t *inst, - dns_name_t *name) -{ - isc_result_t result; - isc_result_t orig_result; - isc_result_t lock_state = ISC_R_IGNORE; - ldap_valuelist_t values; - ldap_value_t *value; -#if LIBDNS_VERSION_MAJOR < 140 - isc_sockaddrlist_t fwdrs; -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - dns_forwarderlist_t fwdrs; -#endif - isc_boolean_t is_global_config; - isc_boolean_t fwdtbl_deletion_requested = ISC_TRUE; - isc_boolean_t fwdtbl_update_requested = ISC_FALSE; - dns_forwarders_t *old_setting = NULL; - dns_fixedname_t foundname; - const char *msg_use_global_fwds; - const char *msg_obj_type; - const char *msg_forwarders_not_def; - const char *msg_forward_policy = NULL; - /** - * BIND forward policies are "first" (default) or "only". - * We invented option "none" which disables forwarding for zone - * regardless idnsForwarders attribute and global forwarders. - */ - dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_first; - - REQUIRE(entry != NULL && inst != NULL && name != NULL); - ISC_LIST_INIT(fwdrs); - dns_fixedname_init(&foundname); - if (dns_name_equal(name, dns_rootname)) { - is_global_config = ISC_TRUE; - msg_obj_type = "global configuration"; - msg_use_global_fwds = "; global forwarders will be disabled"; - msg_forwarders_not_def = "; global forwarders from " - "configuration file will be used"; - } else { - is_global_config = ISC_FALSE; - msg_obj_type = "zone"; - msg_use_global_fwds = "; global forwarders will be used " - "(if they are configured)"; - msg_forwarders_not_def = msg_use_global_fwds; - } - - /* - * Fetch forward policy. - */ - result = ldap_entry_getvalues(entry, "idnsForwardPolicy", &values); - if (result == ISC_R_SUCCESS) { - value = HEAD(values); - if (value != NULL && value->value != NULL) { - if (strcasecmp(value->value, "only") == 0) - fwdpolicy = dns_fwdpolicy_only; - else if (strcasecmp(value->value, "first") == 0) - fwdpolicy = dns_fwdpolicy_first; - else if (strcasecmp(value->value, "none") == 0) - fwdpolicy = dns_fwdpolicy_none; - else { - log_error("%s %s: invalid value '%s' in " - "idnsForwardPolicy attribute; " - "valid values: first, only, none" - "%s", - msg_obj_type, - ldap_entry_logname(entry), - value->value, msg_use_global_fwds); - CLEANUP_WITH(ISC_R_UNEXPECTEDTOKEN); - } - } - } - - if (fwdpolicy == dns_fwdpolicy_none) { - ISC_LIST_INIT(values); /* ignore idnsForwarders in LDAP */ - } else { - result = ldap_entry_getvalues(entry, "idnsForwarders", &values); - if (result == ISC_R_NOTFOUND || EMPTY(values)) { - log_debug(5, "%s %s: idnsForwarders attribute is " - "not present%s", msg_obj_type, - ldap_entry_logname(entry), - msg_forwarders_not_def); - if (is_global_config) { - ISC_LIST_INIT(values); - fwdrs = inst_fwdlist(inst); - fwdpolicy = inst->orig_global_forwarders.fwdpolicy; - } else { - CLEANUP_WITH(ISC_R_DISABLED); - } - } - } - - CHECK(get_enum_description(forwarder_policy_txts, fwdpolicy, - &msg_forward_policy)); - log_debug(5, "%s %s: forward policy is '%s'", msg_obj_type, - ldap_entry_logname(entry), msg_forward_policy); - - for (value = HEAD(values); value != NULL; value = NEXT(value, link)) { -#if LIBDNS_VERSION_MAJOR < 140 - isc_sockaddr_t *fwdr = NULL; -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - dns_forwarder_t *fwdr = NULL; -#endif - char forwarder_txt[ISC_SOCKADDR_FORMATSIZE]; - - if (acl_parse_forwarder(value->value, inst->mctx, &fwdr) - != ISC_R_SUCCESS) { - log_error("%s %s: could not parse forwarder '%s'", - msg_obj_type, ldap_entry_logname(entry), - value->value); - continue; - } - - ISC_LINK_INIT(fwdr, link); - ISC_LIST_APPEND(fwdrs, fwdr, link); - isc_sockaddr_format( -#if LIBDNS_VERSION_MAJOR < 140 - fwdr, -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - &fwdr->addr, -#endif - forwarder_txt, ISC_SOCKADDR_FORMATSIZE); - log_debug(5, "%s %s: adding forwarder '%s'", msg_obj_type, - ldap_entry_logname(entry), forwarder_txt); - } - - if (fwdpolicy != dns_fwdpolicy_none && ISC_LIST_EMPTY(fwdrs)) { - log_debug(5, "%s %s: all idnsForwarders are invalid%s", - msg_obj_type, ldap_entry_logname(entry), - msg_use_global_fwds); - CLEANUP_WITH(ISC_R_UNEXPECTEDTOKEN); - } else if (fwdpolicy == dns_fwdpolicy_none) { - log_debug(5, "%s %s: forwarding explicitly disabled " - "(policy 'none', ignoring global forwarders)", - msg_obj_type, ldap_entry_logname(entry)); - } - - /* Check for old and new forwarding settings equality. */ - result = dns_fwdtable_find2(inst->view->fwdtable, name, - dns_fixedname_name(&foundname), - &old_setting); - if (result == ISC_R_SUCCESS && - (dns_name_equal(name, dns_fixedname_name(&foundname)) == ISC_TRUE)) { -#if LIBDNS_VERSION_MAJOR < 140 - isc_sockaddr_t *s1, *s2; -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - dns_forwarder_t *s1, *s2; -#endif - - if (fwdpolicy != old_setting->fwdpolicy) - fwdtbl_update_requested = ISC_TRUE; - - /* Check address lists item by item. */ -#if LIBDNS_VERSION_MAJOR < 140 - for (s1 = ISC_LIST_HEAD(fwdrs), s2 = ISC_LIST_HEAD(old_setting->addrs); -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - for (s1 = ISC_LIST_HEAD(fwdrs), s2 = ISC_LIST_HEAD(old_setting->fwdrs); -#endif - s1 != NULL && s2 != NULL && !fwdtbl_update_requested; - s1 = ISC_LIST_NEXT(s1, link), s2 = ISC_LIST_NEXT(s2, link)) -#if LIBDNS_VERSION_MAJOR < 140 - if (!isc_sockaddr_equal(s1, s2)) { -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - if (!isc_sockaddr_equal(&s1->addr, &s2->addr) || - s1->dscp != s2->dscp) { -#endif - fwdtbl_update_requested = ISC_TRUE; - } - - if (!fwdtbl_update_requested && ((s1 != NULL) || (s2 != NULL))) - fwdtbl_update_requested = ISC_TRUE; - - } else if (!(result == ISC_R_NOTFOUND && fwdpolicy == dns_fwdpolicy_none)) { - /* No forwarder in the table and policy 'none' = no change. */ - fwdtbl_update_requested = ISC_TRUE; - } - if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) - log_error_r("%s %s: can't obtain old forwarding settings", - msg_obj_type, ldap_entry_logname(entry)); - - if (fwdtbl_update_requested) { - if (fwdpolicy != dns_fwdpolicy_none) { - /* Handle collisions with automatic empty zones. */ - CHECK(empty_zone_handle_conflicts(name, - inst->view->zonetable, - (fwdpolicy == dns_fwdpolicy_first))); - } - - /* Something was changed - set forward table up. */ - CHECK(delete_forwarding_table(inst, name, msg_obj_type, - ldap_entry_logname(entry))); -#if LIBDNS_VERSION_MAJOR < 140 - result = dns_fwdtable_add(inst->view->fwdtable, name, &fwdrs, - fwdpolicy); -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - result = dns_fwdtable_addfwd(inst->view->fwdtable, name, &fwdrs, - fwdpolicy); -#endif - if (result != ISC_R_SUCCESS) - log_error_r("%s %s: forwarding table update failed", - msg_obj_type, ldap_entry_logname(entry)); - } else { - result = ISC_R_SUCCESS; - log_debug(5, "%s %s: forwarding table unmodified", - msg_obj_type, ldap_entry_logname(entry)); - } - if (result == ISC_R_SUCCESS) { - fwdtbl_deletion_requested = ISC_FALSE; - if (fwdpolicy == dns_fwdpolicy_none) - result = ISC_R_DISABLED; - } - -cleanup: - if (ISC_LIST_HEAD(fwdrs) != - ISC_LIST_HEAD(inst_fwdlist(inst))) { - while(!ISC_LIST_EMPTY(fwdrs)) { -#if LIBDNS_VERSION_MAJOR < 140 - isc_sockaddr_t *fwdr = NULL; -#else /* LIBDNS_VERSION_MAJOR >= 140 */ - dns_forwarder_t *fwdr = NULL; -#endif - fwdr = ISC_LIST_HEAD(fwdrs); - ISC_LIST_UNLINK(fwdrs, fwdr, link); - SAFE_MEM_PUT_PTR(inst->mctx, fwdr); - } - } - if (fwdtbl_deletion_requested) { - orig_result = result; - result = delete_forwarding_table(inst, name, msg_obj_type, - ldap_entry_logname(entry)); - if (result == ISC_R_SUCCESS) - result = orig_result; - } - if (fwdtbl_deletion_requested || fwdtbl_update_requested) { - log_debug(5, "%s %s: forwarder table was updated: %s", - msg_obj_type, ldap_entry_logname(entry), - dns_result_totext(result)); - orig_result = result; - run_exclusive_enter(inst, &lock_state); - result = dns_view_flushcache(inst->view); - run_exclusive_exit(inst, lock_state); - if (result == ISC_R_SUCCESS) - result = orig_result; - } - return result; -} - /* Parse the config object entry */ static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT ldap_parse_configentry(ldap_entry_t *entry, ldap_instance_t *inst) @@ -1665,11 +1367,14 @@ ldap_parse_configentry(ldap_entry_t *entry, ldap_instance_t *inst) log_debug(3, "Parsing configuration object"); - /* idnsForwardPolicy change is handled by configure_zone_forwarders() */ - result = configure_zone_forwarders(entry, inst, dns_rootname); - if (result != ISC_R_SUCCESS && result != ISC_R_DISABLED) { - log_error_r("global forwarder could not be set up"); - } + result = fwd_parse_ldap(entry, inst->global_settings); + if (result == ISC_R_SUCCESS) + result = fwd_configure_zone(inst->global_settings, inst, + dns_rootname); + if (result != ISC_R_SUCCESS) + log_error_r("global forwarder could not be set up"); + else if (result != ISC_R_IGNORE) + goto cleanup; result = setting_update_from_ldap_entry("dyn_update", inst->global_settings, @@ -1699,25 +1404,37 @@ ldap_parse_fwd_zoneentry(ldap_entry_t *entry, ldap_instance_t *inst) char name_txt[DNS_NAME_FORMATSIZE]; isc_result_t result; + static const setting_t fwdz_defaults[] = { + { "forward_policy", no_default_string }, + { "forwarders", no_default_string }, + end_of_settings + }; + settings_set_t *fwdz_settings = NULL; + REQUIRE(entry != NULL); REQUIRE(inst != NULL); + /* Zone is active */ CHECK(ldap_entry_getvalues(entry, "idnsZoneActive", &values)); if (HEAD(values) != NULL && strcasecmp(HEAD(values)->value, "TRUE") != 0) { /* Zone is not active */ result = ldap_delete_zone2(inst, &entry->fqdn, ISC_TRUE, ISC_FALSE); goto cleanup; } - /* Zone is active */ - result = configure_zone_forwarders(entry, inst, &entry->fqdn); - if (result != ISC_R_DISABLED && result != ISC_R_SUCCESS) { - log_error_r("%s: could not configure forwarding", + CHECK(settings_set_create(inst->mctx, fwdz_defaults, sizeof(fwdz_defaults), + "fake fwdz settings", inst->global_settings, + &fwdz_settings)); + result = fwd_parse_ldap(entry, fwdz_settings); + if (result == ISC_R_IGNORE) { + log_error_r("%s: invalid object: either " + "forwarding policy or forwarders must be set", ldap_entry_logname(entry)); goto cleanup; } + CHECK(fwd_configure_zone(fwdz_settings, inst, &entry->fqdn)); result = fwdr_add_zone(inst->fwd_register, &entry->fqdn); if (result != ISC_R_EXISTS && result != ISC_R_SUCCESS) { @@ -1731,6 +1448,7 @@ ldap_parse_fwd_zoneentry(ldap_entry_t *entry, ldap_instance_t *inst) log_info("forward zone '%s': loaded", name_txt); cleanup: + settings_set_free(&fwdz_settings); return result; } @@ -2258,10 +1976,6 @@ ldap_parse_master_zoneentry(ldap_entry_t * const entry, dns_db_t * const olddb, run_exclusive_enter(inst, &lock_state); - result = configure_zone_forwarders(entry, inst, &entry->fqdn); - if (result != ISC_R_SUCCESS && result != ISC_R_DISABLED) - goto cleanup; - result = ldap_entry_getvalues(entry, "idnsSecInlineSigning", &values); if (result == ISC_R_NOTFOUND || HEAD(values) == NULL) want_secure = ISC_FALSE; @@ -2296,7 +2010,14 @@ ldap_parse_master_zoneentry(ldap_entry_t * const entry, dns_db_t * const olddb, CHECK(zr_get_zone_settings(inst->zone_register, &entry->fqdn, &zone_settings)); CHECK(zone_master_reconfigure(entry, zone_settings, raw, secure, task)); - + result = fwd_parse_ldap(entry, zone_settings); + if (result == ISC_R_SUCCESS) { + result = fwd_configure_zone(zone_settings, inst, &entry->fqdn); + if (result != ISC_R_SUCCESS) + log_error_r("%s: could not configure forwarding", + ldap_entry_logname(entry)); + } else if (result != ISC_R_IGNORE) + goto cleanup; /* synchronize zone origin with LDAP */ CHECK(zr_get_zone_dbs(inst->zone_register, &entry->fqdn, &ldapdb, &rbtdb)); CHECK(dns_db_newversion(ldapdb, &version)); @@ -4624,6 +4345,18 @@ ldap_instance_gettask(ldap_instance_t *ldap_inst) return ldap_inst->task; } +void +ldap_instance_attachview(ldap_instance_t *ldap_inst, dns_view_t **view) +{ + dns_view_attach(ldap_inst->view, view); +} + +void +ldap_instance_attachmem(ldap_instance_t *ldap_inst, isc_mem_t **mctx) +{ + isc_mem_attach(ldap_inst->mctx, mctx); +} + isc_boolean_t ldap_instance_isexiting(ldap_instance_t *ldap_inst) { diff --git a/src/ldap_helper.h b/src/ldap_helper.h index b4b1ee59edb3414b305888271dc425980a1fd3df..1d691a29a06db645acb3979a1425df9ecb8577d7 100644 --- a/src/ldap_helper.h +++ b/src/ldap_helper.h @@ -96,4 +96,11 @@ ldap_instance_untaint_start(ldap_instance_t *ldap_inst); isc_result_t ldap_instance_untaint_finish(ldap_instance_t *ldap_inst, unsigned int count); +void +ldap_instance_attachview(ldap_instance_t *ldap_inst, dns_view_t **view) ATTR_NONNULLS; + +void +ldap_instance_attachmem(ldap_instance_t *ldap_inst, isc_mem_t **mctx) + ATTR_NONNULLS; + #endif /* !_LD_LDAP_HELPER_H_ */ -- 2.5.5
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code