From ae4007b6d9b9ff0e0dcef672fee0190ae4f2543f Mon Sep 17 00:00:00 2001 From: Adam Tkac Date: Sep 21 2012 10:39:08 +0000 Subject: Update to the latest master Signed-off-by: Adam Tkac --- diff --git a/.gitignore b/.gitignore index 063c30f..68aaccc 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ bind-dyndb-ldap-0.1.0b.tar.bz2 /bind-dyndb-ldap-1.1.0b1.tar.bz2 /bind-dyndb-ldap-1.1.0b2.tar.bz2 /bind-dyndb-ldap-1.1.0rc1.tar.bz2 +/bind-dyndb-ldap-2.0-20120921git7710d89.tar.bz2 diff --git a/bind-dyndb-ldap.spec b/bind-dyndb-ldap.spec index 114b92b..61e89f0 100644 --- a/bind-dyndb-ldap.spec +++ b/bind-dyndb-ldap.spec @@ -1,12 +1,12 @@ #%define PATCHVER P4 -%define PREVER rc1 +%define PREVER 20120921git7710d89 #%define VERSION %{version} #%define VERSION %{version}-%{PATCHVER} -%define VERSION %{version}%{PREVER} +%define VERSION %{version}-%{PREVER} Name: bind-dyndb-ldap -Version: 1.1.0 -Release: 0.16.%{PREVER}%{?dist} +Version: 2.0 +Release: 0.1.%{PREVER}%{?dist} Summary: LDAP back-end plug-in for BIND Group: System Environment/Libraries @@ -18,11 +18,10 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: bind-devel >= 32:9.6.1-0.3.b1 BuildRequires: krb5-devel BuildRequires: openldap-devel +BuildRequires: automake, autoconf, libtool Requires: bind >= 32:9.6.1-0.3.b1 -Patch0: bind-dyndb-ldap110-master.patch - %description This package provides an LDAP back-end plug-in for BIND. It features support for dynamic updates and internal caching, to lift the load @@ -32,10 +31,9 @@ off of your LDAP server. %prep %setup -q -n %{name}-%{VERSION} -%patch0 -p1 -b .master - %build export CFLAGS="`isc-config.sh --cflags dns` $RPM_OPT_FLAGS" +autoreconf -fiv %configure make %{?_smp_mflags} @@ -60,6 +58,10 @@ rm -rf %{buildroot} %changelog +* Fri Sep 21 2012 Adam Tkac 2.0-0.1.20120921git7710d89 +- update to the latest master +- bind-dyndb-ldap110-master.patch was merged + * Thu Aug 16 2012 Adam Tkac 1.1.0-0.16.rc1 - update to the latest git diff --git a/bind-dyndb-ldap110-master.patch b/bind-dyndb-ldap110-master.patch deleted file mode 100644 index 742f77e..0000000 --- a/bind-dyndb-ldap110-master.patch +++ /dev/null @@ -1,4014 +0,0 @@ -From f0d49c0eb816c958e4fa6bf4a073eb6ac592efad Mon Sep 17 00:00:00 2001 -From: Adam Tkac -Date: Thu, 26 Apr 2012 13:48:21 +0200 -Subject: [PATCH 01/32] Link ldap.so with relro, now and noexecstack linker - parameters. - -Signed-off-by: Adam Tkac ---- - src/Makefile.am | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/Makefile.am b/src/Makefile.am -index 84c774b..b7b4240 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -38,4 +38,4 @@ ldap_la_SOURCES = \ - - ldap_la_CFLAGS = -Wall -Wextra -std=gnu99 -O2 - --ldap_la_LDFLAGS = -module -avoid-version -+ldap_la_LDFLAGS = -module -avoid-version -Wl,-z,relro,-z,now,-z,noexecstack --- -1.7.11.2 - - -From 481e350f5848cf01da6743f259a6f12419fc4177 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Tue, 24 Apr 2012 15:09:32 +0200 -Subject: [PATCH 02/32] Add simple semaphore deadlock detection logic. - Signed-off-by: Petr Spacek - ---- - src/ldap_helper.c | 78 +++++++++++++++++++++++++++++++++---------------------- - src/semaphore.c | 26 ++++++++++++++++--- - src/semaphore.h | 6 ++++- - 3 files changed, 74 insertions(+), 36 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 6ebe4c0..5965d30 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -295,9 +295,10 @@ ldap_delete_zone2(ldap_instance_t *inst, dns_name_t *name, isc_boolean_t lock); - static isc_result_t ldap_pool_create(isc_mem_t *mctx, unsigned int connections, - ldap_pool_t **poolp); - static void ldap_pool_destroy(ldap_pool_t **poolp); --static ldap_connection_t * ldap_pool_getconnection(ldap_pool_t *pool); -+static isc_result_t ldap_pool_getconnection(ldap_pool_t *pool, -+ ldap_connection_t ** conn); - static void ldap_pool_putconnection(ldap_pool_t *pool, -- ldap_connection_t *ldap_conn); -+ ldap_connection_t ** conn); - static isc_result_t ldap_pool_connect(ldap_pool_t *pool, - ldap_instance_t *ldap_inst); - -@@ -401,6 +402,10 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, - ldap_settings[i++].target = &ldap_inst->dyn_update; - CHECK(set_settings(ldap_settings, argv)); - -+ /* Set timer for deadlock detection inside semaphore_wait_timed . */ -+ if (semaphore_wait_timeout.seconds < ldap_inst->timeout*SEM_WAIT_TIMEOUT_MUL) -+ semaphore_wait_timeout.seconds = ldap_inst->timeout*SEM_WAIT_TIMEOUT_MUL; -+ - /* Validate and check settings. */ - str_toupper(ldap_inst->sasl_mech); - if (ldap_inst->connections < 1) { -@@ -1088,7 +1093,7 @@ isc_result_t - refresh_zones_from_ldap(ldap_instance_t *ldap_inst) - { - isc_result_t result = ISC_R_SUCCESS; -- ldap_connection_t *ldap_conn; -+ ldap_connection_t *ldap_conn = NULL; - int zone_count = 0; - ldap_entry_t *entry; - dns_rbt_t *rbt = NULL; -@@ -1113,7 +1118,7 @@ refresh_zones_from_ldap(ldap_instance_t *ldap_inst) - - log_debug(2, "refreshing list of zones for %s", ldap_inst->db_name); - -- ldap_conn = ldap_pool_getconnection(ldap_inst->pool); -+ CHECK(ldap_pool_getconnection(ldap_inst->pool, &ldap_conn)); - - CHECK(ldap_query(ldap_inst, ldap_conn, str_buf(ldap_inst->base), - LDAP_SCOPE_SUBTREE, config_attrs, 0, -@@ -1226,7 +1231,7 @@ cleanup: - if (invalidate_nodechain) - dns_rbtnodechain_invalidate(&chain); - -- ldap_pool_putconnection(ldap_inst->pool, ldap_conn); -+ ldap_pool_putconnection(ldap_inst->pool, &ldap_conn); - - log_debug(2, "finished refreshing list of zones"); - -@@ -1380,7 +1385,7 @@ ldapdb_nodelist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *nam - dns_name_t *origin, ldapdb_nodelist_t *nodelist) - { - isc_result_t result; -- ldap_connection_t *ldap_conn; -+ ldap_connection_t *ldap_conn = NULL; - ldap_entry_t *entry; - ld_string_t *string = NULL; - ldapdb_node_t *node; -@@ -1391,7 +1396,7 @@ ldapdb_nodelist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *nam - REQUIRE(nodelist != NULL); - - /* RRs aren't in the cache, perform ordinary LDAP query */ -- ldap_conn = ldap_pool_getconnection(ldap_inst->pool); -+ CHECK(ldap_pool_getconnection(ldap_inst->pool, &ldap_conn)); - - INIT_LIST(*nodelist); - CHECK(str_new(mctx, &string)); -@@ -1438,7 +1443,7 @@ ldapdb_nodelist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *nam - result = ISC_R_SUCCESS; - - cleanup: -- ldap_pool_putconnection(ldap_inst->pool, ldap_conn); -+ ldap_pool_putconnection(ldap_inst->pool, &ldap_conn); - str_destroy(&string); - - return result; -@@ -1449,7 +1454,7 @@ ldapdb_rdatalist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *na - dns_name_t *origin, ldapdb_rdatalist_t *rdatalist) - { - isc_result_t result; -- ldap_connection_t *ldap_conn; -+ ldap_connection_t *ldap_conn = NULL; - ldap_entry_t *entry; - ld_string_t *string = NULL; - ldap_cache_t *cache; -@@ -1467,12 +1472,11 @@ ldapdb_rdatalist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *na - return result; - - /* RRs aren't in the cache, perform ordinary LDAP query */ -- ldap_conn = ldap_pool_getconnection(ldap_inst->pool); -- - INIT_LIST(*rdatalist); - CHECK(str_new(mctx, &string)); - CHECK(dnsname_to_dn(ldap_inst->zone_register, name, string)); - -+ CHECK(ldap_pool_getconnection(ldap_inst->pool, &ldap_conn)); - CHECK(ldap_query(ldap_inst, ldap_conn, str_buf(string), - LDAP_SCOPE_BASE, NULL, 0, "(objectClass=idnsRecord)")); - -@@ -1499,7 +1503,7 @@ ldapdb_rdatalist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *na - result = ISC_R_NOTFOUND; - - cleanup: -- ldap_pool_putconnection(ldap_inst->pool, ldap_conn); -+ ldap_pool_putconnection(ldap_inst->pool, &ldap_conn); - str_destroy(&string); - - if (result != ISC_R_SUCCESS) -@@ -2258,7 +2262,7 @@ modify_ldap_common(dns_name_t *owner, ldap_instance_t *ldap_inst, - zone_dn += 1; /* skip whitespace */ - } - -- ldap_conn = ldap_pool_getconnection(ldap_inst->pool); -+ CHECK(ldap_pool_getconnection(ldap_inst->pool, &ldap_conn)); - CHECK(ldap_query(ldap_inst, ldap_conn, zone_dn, - LDAP_SCOPE_BASE, attrs, 0, - "(&(objectClass=idnsZone)(idnsZoneActive=TRUE))")); -@@ -2489,9 +2493,7 @@ modify_ldap_common(dns_name_t *owner, ldap_instance_t *ldap_inst, - } - - cleanup: -- if (ldap_conn != NULL) -- ldap_pool_putconnection(ldap_inst->pool, ldap_conn); -- -+ ldap_pool_putconnection(ldap_inst->pool, &ldap_conn); - str_destroy(&owner_dn_ptr); - str_destroy(&owner_dn); - free_ldapmod(mctx, &change[0]); -@@ -2573,15 +2575,18 @@ ldap_pool_destroy(ldap_pool_t **poolp) - MEM_PUT_AND_DETACH(pool); - } - --static ldap_connection_t * --ldap_pool_getconnection(ldap_pool_t *pool) -+static isc_result_t -+ldap_pool_getconnection(ldap_pool_t *pool, ldap_connection_t ** conn) - { - ldap_connection_t *ldap_conn = NULL; - unsigned int i; -+ isc_result_t result; - - REQUIRE(pool != NULL); -+ REQUIRE(conn != NULL && *conn == NULL); -+ ldap_conn = *conn; - -- semaphore_wait(&pool->conn_semaphore); -+ CHECK(semaphore_wait_timed(&pool->conn_semaphore)); - for (i = 0; i < pool->connections; i++) { - ldap_conn = pool->conns[i]; - if (isc_mutex_trylock(&ldap_conn->lock) == ISC_R_SUCCESS) -@@ -2591,16 +2596,30 @@ ldap_pool_getconnection(ldap_pool_t *pool) - RUNTIME_CHECK(ldap_conn != NULL); - - INIT_LIST(ldap_conn->ldap_entries); -+ *conn = ldap_conn; - -- return ldap_conn; -+cleanup: -+ if (result != ISC_R_SUCCESS) { -+ log_error("timeout in ldap_pool_getconnection(): try to raise " -+ "'connections' parameter; potential deadlock?"); -+ } -+ return result; - } - - static void --ldap_pool_putconnection(ldap_pool_t *pool, ldap_connection_t *ldap_conn) -+ldap_pool_putconnection(ldap_pool_t *pool, ldap_connection_t **conn) - { -+ REQUIRE(conn != NULL); -+ ldap_connection_t *ldap_conn = *conn; -+ -+ if (ldap_conn == NULL) -+ return; -+ - ldap_query_free(ldap_conn); - UNLOCK(&ldap_conn->lock); - semaphore_signal(&pool->conn_semaphore); -+ -+ *conn = NULL; - } - - static isc_result_t -@@ -2727,7 +2746,7 @@ update_action(isc_task_t *task, isc_event_t *event) - ldap_psearchevent_t *pevent = (ldap_psearchevent_t *)event; - isc_result_t result ; - ldap_instance_t *inst = NULL; -- ldap_connection_t *conn; -+ ldap_connection_t *conn = NULL; - ldap_entry_t *entry; - isc_boolean_t delete = ISC_TRUE; - isc_mem_t *mctx; -@@ -2744,7 +2763,7 @@ update_action(isc_task_t *task, isc_event_t *event) - if (result != ISC_R_SUCCESS) - goto cleanup; - -- conn = ldap_pool_getconnection(inst->pool); -+ CHECK(ldap_pool_getconnection(inst->pool, &conn)); - - CHECK(ldap_query(inst, conn, pevent->dn, - LDAP_SCOPE_BASE, attrs, 0, -@@ -2762,14 +2781,13 @@ update_action(isc_task_t *task, isc_event_t *event) - if (delete) - CHECK(ldap_delete_zone(inst, pevent->dn, ISC_TRUE)); - -- ldap_pool_putconnection(inst->pool, conn); -- - cleanup: - if (result != ISC_R_SUCCESS) - log_error("update_action (psearch) failed for %s. " - "Zones can be outdated, run `rndc reload`", - pevent->dn); - -+ ldap_pool_putconnection(inst->pool, &conn); - isc_mem_free(mctx, pevent->dbname); - isc_mem_free(mctx, pevent->dn); - isc_mem_detach(&mctx); -@@ -2798,7 +2816,7 @@ update_config(isc_task_t *task, isc_event_t *event) - if (result != ISC_R_SUCCESS) - goto cleanup; - -- conn = ldap_pool_getconnection(inst->pool); -+ CHECK(ldap_pool_getconnection(inst->pool, &conn)); - - CHECK(ldap_query(inst, conn, pevent->dn, - LDAP_SCOPE_BASE, attrs, 0, -@@ -2817,14 +2835,12 @@ update_config(isc_task_t *task, isc_event_t *event) - - - cleanup: -- if (conn != NULL) -- ldap_pool_putconnection(inst->pool, conn); -- - if (result != ISC_R_SUCCESS) - log_error("update_config (psearch) failed for %s. " - "Configuration can be outdated, run `rndc reload`", - pevent->dn); - -+ ldap_pool_putconnection(inst->pool, &conn); - isc_mem_free(mctx, pevent->dbname); - isc_mem_free(mctx, pevent->dn); - isc_mem_detach(&mctx); -@@ -3087,7 +3103,7 @@ ldap_psearch_watcher(isc_threadarg_t arg) - tv.tv_usec = 0; - - /* Pick connection, one is reserved purely for this thread */ -- conn = ldap_pool_getconnection(inst->pool); -+ CHECK(ldap_pool_getconnection(inst->pool, &conn)); - - /* Try to connect. */ - while (conn->handle == NULL) { -@@ -3195,7 +3211,7 @@ soft_err: - log_debug(1, "Ending ldap_psearch_watcher"); - - cleanup: -- ldap_pool_putconnection(inst->pool, conn); -+ ldap_pool_putconnection(inst->pool, &conn); - - return (isc_threadresult_t)0; - } -diff --git a/src/semaphore.c b/src/semaphore.c -index 41d6a30..352219f 100644 ---- a/src/semaphore.c -+++ b/src/semaphore.c -@@ -27,8 +27,19 @@ - #include - #include - #include -+#include - - #include "semaphore.h" -+#include "util.h" -+ -+/* -+ * Timer setting for deadlock detection. Format: seconds, nanoseconds. -+ * These values will be overwriten during initialization -+ * from set_settings() with max(setting+SEM_WAIT_TIMEOUT_ADD, curr_value). -+ * -+ * Initial value can be useful in early phases of initialization. -+ */ -+isc_interval_t semaphore_wait_timeout = { 3, 0 }; - - /* - * Initialize a semaphore. -@@ -74,20 +85,27 @@ semaphore_destroy(semaphore_t *sem) - /* - * Wait on semaphore. This operation will try to acquire a lock on the - * semaphore. If the semaphore is already acquired as many times at it allows, -- * the function will block until someone releases the lock. -+ * the function will block until someone releases the lock OR timeout expire. -+ * -+ * @return ISC_R_SUCCESS or ISC_R_TIMEDOUT or other errors from ISC libs - */ --void --semaphore_wait(semaphore_t *sem) -+isc_result_t -+semaphore_wait_timed(semaphore_t *sem) - { -+ isc_result_t result; -+ isc_time_t abs_timeout; - REQUIRE(sem != NULL); - -+ CHECK(isc_time_nowplusinterval(&abs_timeout, &semaphore_wait_timeout)); - LOCK(&sem->mutex); - - while (sem->value <= 0) -- WAIT(&sem->cond, &sem->mutex); -+ CHECK(WAITUNTIL(&sem->cond, &sem->mutex, &abs_timeout)); - sem->value--; - -+cleanup: - UNLOCK(&sem->mutex); -+ return result; - } - - /* -diff --git a/src/semaphore.h b/src/semaphore.h -index 4ca4f65..1367747 100644 ---- a/src/semaphore.h -+++ b/src/semaphore.h -@@ -24,6 +24,10 @@ - #include - #include - -+/* Multiplier for to user-defined connection parameter 'timeout'. */ -+#define SEM_WAIT_TIMEOUT_MUL 6 /* times */ -+extern isc_interval_t semaphore_wait_timeout; -+ - /* - * Semaphore can be "acquired" multiple times. However, it has a maximum - * number of times someone can acquire him. If a semaphore is already acquired -@@ -40,7 +44,7 @@ typedef struct semaphore semaphore_t; - /* Public functions. */ - isc_result_t semaphore_init(semaphore_t *sem, int value); - void semaphore_destroy(semaphore_t *sem); --void semaphore_wait(semaphore_t *sem); -+isc_result_t semaphore_wait_timed(semaphore_t *sem); - void semaphore_signal(semaphore_t *sem); - - #endif /* !_LD_SEMAPHORE_H_ */ --- -1.7.11.2 - - -From 3d43fd66aa68ef275855391a94e47e9d2f30309d Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Mon, 23 Apr 2012 11:38:43 +0200 -Subject: [PATCH 03/32] Add proper DN escaping before LDAP library calls. - Signed-off-by: Petr Spacek - ---- - src/ldap_convert.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++--- - src/zone_register.c | 7 ++++ - src/zone_register.h | 3 ++ - 3 files changed, 110 insertions(+), 5 deletions(-) - -diff --git a/src/ldap_convert.c b/src/ldap_convert.c -index 6405a98..6b4e321 100644 ---- a/src/ldap_convert.c -+++ b/src/ldap_convert.c -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -32,6 +33,7 @@ - - #include - #include -+#include - - #include "str.h" - #include "ldap_convert.h" -@@ -189,6 +191,92 @@ cleanup: - return result; - } - -+/** -+ * Convert a string from DNS escaping to LDAP escaping. -+ * The Input string dns_str is expected to be the result of dns_name_tostring(). -+ * The DNS label can contain any binary data as described in -+ * http://tools.ietf.org/html/rfc2181#section-11 . -+ * -+ * DNS escaping uses form "\123" = ASCII value 123 (decimal) -+ * LDAP escaping users form "\7b" = ASCII value 7b (hexadecimal) -+ * -+ * Input (DNS escaped) example : _aaa,bbb\255\000ccc.555.ddd-eee -+ * Output (LDAP escaped) example: _aaa\2cbbb\ff\00ccc.555.ddd-eee -+ * -+ * The DNS to text functions from ISC libraries do not convert certain -+ * characters (e.g. ","). This function converts \123 form to \7b form in all -+ * cases. Other characters (not escaped by ISC libraries) will be additionally -+ * converted to the LDAP escape form. -+ * Input characters [a-zA-Z0-9._-] are left in raw ASCII form. -+ * -+ * If dns_str consists only of the characters in the [a-zA-Z0-9._-] set, it -+ * will be checked & copied to the output buffer, without any additional escaping. -+ */ -+isc_result_t -+dns_to_ldap_dn_escape(isc_mem_t *mctx, const char const * dns_str, char ** ldap_name) { -+ isc_result_t result = ISC_R_FAILURE; -+ char * esc_name = NULL; -+ int idx_symb_first = -1; /* index of first "nice" printable symbol in dns_str */ -+ int dns_idx = 0; -+ int esc_idx = 0; -+ -+ REQUIRE(dns_str != NULL); -+ REQUIRE(ldap_name != NULL && *ldap_name == NULL); -+ -+ int dns_str_len = strlen(dns_str); -+ -+ /** -+ * In worst case each symbol from DNS dns_str will be represented -+ * as "\xy" in ldap_name. (xy are hexadecimal digits) -+ */ -+ CHECKED_MEM_ALLOCATE(mctx, *ldap_name, 3 * dns_str_len + 1); -+ esc_name = *ldap_name; -+ -+ for (dns_idx = 0; dns_idx < dns_str_len; dns_idx++) { -+ if (isalnum(dns_str[dns_idx]) || dns_str[dns_idx] == '.' -+ || dns_str[dns_idx] == '-' || dns_str[dns_idx] == '_' ) { -+ if (idx_symb_first == -1) -+ idx_symb_first = dns_idx; -+ continue; -+ } else { /* some not very nice symbols */ -+ int ascii_val; -+ if (idx_symb_first != -1) { /* copy previous nice part */ -+ int length_ok = dns_idx - idx_symb_first; -+ memcpy(esc_name + esc_idx, dns_str + idx_symb_first, length_ok); -+ esc_idx += length_ok; -+ idx_symb_first = -1; -+ } -+ if (dns_str[dns_idx] != '\\') { /* not nice raw value, e.g. ',' */ -+ ascii_val = dns_str[dns_idx]; -+ } else { /* not nice value in DNS \123 decimal format */ -+ /* check if input length <= expected size */ -+ REQUIRE (dns_str_len > dns_idx + 3); /* this problem should never happen */ -+ ascii_val = 100 * (dns_str[dns_idx + 1] - '0') -+ + 10 * (dns_str[dns_idx + 2] - '0') -+ + (dns_str[dns_idx + 3] - '0'); -+ dns_idx += 3; -+ } -+ /* LDAP uses \xy escaping. "xy" represent two hexadecimal digits.*/ -+ /* TODO: optimize to bit mask & rotate & dec->hex table? */ -+ CHECK(isc_string_printf(esc_name + esc_idx, 4, "\\%02x", ascii_val)); -+ esc_idx += 3; /* isc_string_printf wrote 4 bytes including '\0' */ -+ } -+ } -+ if (idx_symb_first != -1) { /* copy last nice part */ -+ int length_ok = dns_idx - idx_symb_first; -+ memcpy(esc_name + esc_idx, dns_str + idx_symb_first, dns_idx - idx_symb_first); -+ esc_idx += length_ok; -+ idx_symb_first = -1; -+ } -+ esc_name[esc_idx] = '\0'; -+ return ISC_R_SUCCESS; -+ -+cleanup: -+ if (*ldap_name) -+ isc_mem_free(mctx, *ldap_name); -+ return result; -+} -+ - static isc_result_t - explode_dn(const char *dn, char ***explodedp, int notypes) - { -@@ -243,11 +331,15 @@ dnsname_to_dn(zone_register_t *zr, dns_name_t *name, ld_string_t *target) - isc_result_t result; - int label_count; - const char *zone_dn = NULL; -+ char *dns_str = NULL; -+ char *escaped_name = NULL; - - REQUIRE(zr != NULL); - REQUIRE(name != NULL); - REQUIRE(target != NULL); - -+ isc_mem_t * mctx = zr_get_mctx(zr); -+ - /* Find the DN of the zone we belong to. */ - { - DECLARE_BUFFERED_NAME(zone); -@@ -264,17 +356,15 @@ dnsname_to_dn(zone_register_t *zr, dns_name_t *name, ld_string_t *target) - - str_clear(target); - if (label_count > 0) { -- DECLARE_BUFFER(buffer, DNS_NAME_MAXTEXT); - dns_name_t labels; - -- INIT_BUFFER(buffer); - dns_name_init(&labels, NULL); -- - dns_name_getlabelsequence(name, 0, label_count, &labels); -- CHECK(dns_name_totext(&labels, ISC_TRUE, &buffer)); -+ CHECK(dns_name_tostring(&labels, &dns_str, mctx)); - -+ CHECK(dns_to_ldap_dn_escape(mctx, dns_str, &escaped_name)); - CHECK(str_cat_char(target, "idnsName=")); -- CHECK(str_cat_isc_buffer(target, &buffer)); -+ CHECK(str_cat_char(target, escaped_name)); - /* - * Modification of following line can affect modify_ldap_common(). - * See line with: char *zone_dn = strstr(str_buf(owner_dn),", ") + 1; -@@ -284,6 +374,10 @@ dnsname_to_dn(zone_register_t *zr, dns_name_t *name, ld_string_t *target) - CHECK(str_cat_char(target, zone_dn)); - - cleanup: -+ if (dns_str) -+ isc_mem_free(mctx, dns_str); -+ if (escaped_name) -+ isc_mem_free(mctx, escaped_name); - return result; - } - -@@ -328,3 +422,4 @@ rdatatype_to_ldap_attribute(dns_rdatatype_t rdtype, const char **target) - - return ISC_R_SUCCESS; - } -+ -diff --git a/src/zone_register.c b/src/zone_register.c -index fc6dc07..81d208f 100644 ---- a/src/zone_register.c -+++ b/src/zone_register.c -@@ -61,6 +61,13 @@ zr_get_rbt(zone_register_t *zr) - return zr->rbt; - } - -+isc_mem_t * -+zr_get_mctx(zone_register_t *zr) { -+ REQUIRE(zr); -+ -+ return zr->mctx; -+} -+ - /* - * Create a new zone register. - */ -diff --git a/src/zone_register.h b/src/zone_register.h -index e2408cb..fa8ef25 100644 ---- a/src/zone_register.h -+++ b/src/zone_register.h -@@ -45,4 +45,7 @@ zr_get_zone_ptr(zone_register_t *zr, dns_name_t *name, dns_zone_t **zonep); - dns_rbt_t * - zr_get_rbt(zone_register_t *zr); - -+isc_mem_t * -+zr_get_mctx(zone_register_t *zr); -+ - #endif /* !_LD_ZONE_REGISTER_H_ */ --- -1.7.11.2 - - -From 0744209bc4461bf2f4d83b0a8e3f7051132ddef3 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Thu, 7 Jun 2012 14:42:40 +0200 -Subject: [PATCH 04/32] Fix crash during BIND reload with persistent search - enabled. - https://fedorahosted.org/bind-dyndb-ldap/ticket/78 - Signed-off-by: Petr Spacek - -Signed-off-by: Adam Tkac ---- - src/ldap_helper.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 5965d30..dc4fdf5 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -3078,7 +3078,7 @@ static isc_threadresult_t - ldap_psearch_watcher(isc_threadarg_t arg) - { - ldap_instance_t *inst = (ldap_instance_t *)arg; -- ldap_connection_t *conn; -+ ldap_connection_t *conn = NULL; - struct timeval tv; - int ret, cnt; - isc_result_t result; --- -1.7.11.2 - - -From 0dccccec9cede75bd254f723bc9a49592c24a44b Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Thu, 7 Jun 2012 15:27:27 +0200 -Subject: [PATCH 05/32] Fix crash during zone unload when NS is not - resolvable. - https://fedorahosted.org/bind-dyndb-ldap/ticket/77 - Signed-off-by: Petr Spacek - -Signed-off-by: Adam Tkac ---- - src/ldap_helper.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index dc4fdf5..09c1f7d 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -30,6 +30,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -788,7 +789,12 @@ ldap_delete_zone2(ldap_instance_t *inst, dns_name_t *name, isc_boolean_t lock) - freeze = ISC_TRUE; - } - -- dns_zone_unload(zone); -+ /* Do not unload partially loaded zones, they have incomplete structures. */ -+ dns_db_t *dbp = NULL; -+ if (dns_zone_getdb(zone, &dbp) != DNS_R_NOTLOADED) { -+ dns_db_detach(&dbp); /* dns_zone_getdb() attaches DB implicitly */ -+ dns_zone_unload(zone); -+ } - CHECK(dns_zt_unmount(inst->view->zonetable, zone)); - CHECK(zr_del_zone(inst->zone_register, name)); - dns_zonemgr_releasezone(inst->zmgr, zone); -@@ -1013,7 +1019,7 @@ ldap_parse_zoneentry(ldap_entry_t *entry, ldap_instance_t *inst) - - /* Check if we are already serving given zone */ - result = zr_get_zone_ptr(inst->zone_register, &name, &zone); -- if (result != ISC_R_SUCCESS) { -+ if (result != ISC_R_SUCCESS) { /* TODO: What about other errors? */ - CHECK(create_zone(inst, &name, &zone)); - CHECK(zr_add_zone(inst->zone_register, zone, dn)); - publish = ISC_TRUE; -@@ -2760,6 +2766,7 @@ update_action(isc_task_t *task, isc_event_t *event) - mctx = pevent->mctx; - - result = manager_get_ldap_instance(pevent->dbname, &inst); -+ /* TODO: Can it happen? */ - if (result != ISC_R_SUCCESS) - goto cleanup; - --- -1.7.11.2 - - -From f06d4d5b524e9dd322574b617fe16a26a9e627ff Mon Sep 17 00:00:00 2001 -From: Adam Tkac -Date: Fri, 15 Jun 2012 14:05:25 +0200 -Subject: [PATCH 06/32] Check for Kerberos 5 development files in configure. - -Signed-off-by: Adam Tkac ---- - configure.ac | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/configure.ac b/configure.ac -index 37e986c..6686310 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -18,6 +18,8 @@ AC_CHECK_LIB([dns], [dns_name_init], [], - AC_MSG_ERROR([Install BIND9 development files])) - AC_CHECK_LIB([ldap], [ldap_initialize], [], - AC_MSG_ERROR([Install OpenLDAP development files])) -+AC_CHECK_LIB([krb5], [krb5_cc_initialize], [], -+ AC_MSG_ERROR([Install Kerberos 5 development files])) - - # Checks for header files. - AC_CHECK_HEADERS([stddef.h stdlib.h string.h strings.h]) --- -1.7.11.2 - - -From d52ad09a3942392995e73aa0ebc0daddc823ea75 Mon Sep 17 00:00:00 2001 -From: Adam Tkac -Date: Mon, 18 Jun 2012 15:30:19 +0200 -Subject: [PATCH 07/32] Use SIGUSR1 to wake-up and terminate psearch_watcher. - -The previously SIGTERM interfered with BIND9 SIGTERM handler. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=832015 - -Signed-off-by: Adam Tkac ---- - src/ldap_helper.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++------ - 1 file changed, 75 insertions(+), 9 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 09c1f7d..f3f2106 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -544,8 +544,11 @@ destroy_ldap_instance(ldap_instance_t **ldap_instp) - * Wake up the watcher thread. This might look like a hack - * but isc_thread_t is actually pthread_t and libisc don't - * have any isc_thread_kill() func. -+ * -+ * We use SIGUSR1 to not to interfere with any signal -+ * used by BIND itself. - */ -- REQUIRE(pthread_kill(ldap_inst->watcher, SIGTERM) == 0); -+ REQUIRE(pthread_kill(ldap_inst->watcher, SIGUSR1) == 0); - RUNTIME_CHECK(isc_thread_join(ldap_inst->watcher, NULL) - == ISC_R_SUCCESS); - ldap_inst->watcher = 0; -@@ -3081,6 +3084,65 @@ cleanup: - } - } - -+#define CHECK_EXIT \ -+ do { \ -+ if (inst->exiting) \ -+ goto cleanup; \ -+ } while (0) -+ -+/* -+ * This "sane" sleep allows us to end if signal set the "exiting" variable. -+ * -+ * Returns ISC_FALSE if we should terminate, ISC_TRUE otherwise. -+ */ -+static inline isc_boolean_t -+sane_sleep(const ldap_instance_t *inst, unsigned int timeout) -+{ -+ unsigned int remains = timeout; -+ -+ while (remains && !inst->exiting) -+ remains = sleep(remains); -+ -+ if (remains) -+ log_debug(99, "sane_sleep: interrupted"); -+ -+ return inst->exiting ? ISC_FALSE : ISC_TRUE; -+} -+ -+/* No-op signal handler for SIGUSR1 */ -+static void -+noop_handler(int signal) -+{ -+ UNUSED(signal); -+} -+ -+static inline void -+install_usr1handler(void) -+{ -+ struct sigaction sa; -+ struct sigaction oldsa; -+ int ret; -+ static isc_boolean_t once = ISC_FALSE; -+ -+ if (once) -+ return; -+ -+ memset(&sa, 0, sizeof(sa)); -+ sa.sa_handler = &noop_handler; -+ -+ ret = sigaction(SIGUSR1, &sa, &oldsa); -+ RUNTIME_CHECK(ret == 0); /* If sigaction fails, it's a bug */ -+ -+ /* Don't attempt to replace already existing handler */ -+ RUNTIME_CHECK(oldsa.sa_handler == NULL); -+ -+ once = ISC_TRUE; -+} -+ -+/* -+ * NOTE: -+ * Every blocking call in psearch_watcher thread must be preemptible. -+ */ - static isc_threadresult_t - ldap_psearch_watcher(isc_threadarg_t arg) - { -@@ -3093,14 +3155,16 @@ ldap_psearch_watcher(isc_threadarg_t arg) - - log_debug(1, "Entering ldap_psearch_watcher"); - -+ install_usr1handler(); -+ - /* - * By default, BIND sets threads to accept signals only via -- * sigwait(). However we need to use SIGTERM to interrupt -+ * sigwait(). However we need to use SIGUSR1 to interrupt - * watcher from waiting inside ldap_result so enable -- * asynchronous delivering of SIGTERM. -+ * asynchronous delivering of SIGUSR1. - */ - sigemptyset(&sigset); -- sigaddset(&sigset, SIGTERM); -+ sigaddset(&sigset, SIGUSR1); - ret = pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); - /* pthread_sigmask fails only due invalid args */ - RUNTIME_CHECK(ret == 0); -@@ -3114,12 +3178,12 @@ ldap_psearch_watcher(isc_threadarg_t arg) - - /* Try to connect. */ - while (conn->handle == NULL) { -- if (inst->exiting) -- goto cleanup; -+ CHECK_EXIT; - - log_error("ldap_psearch_watcher handle is NULL. " - "Next try in %ds", inst->reconnect_interval); -- sleep(inst->reconnect_interval); -+ if (!sane_sleep(inst, inst->reconnect_interval)) -+ goto cleanup; - ldap_connect(inst, conn, ISC_TRUE); - } - -@@ -3150,14 +3214,16 @@ restart: - while (!inst->exiting) { - ret = ldap_result(conn->handle, conn->msgid, 0, &tv, - &conn->result); -- - if (ret <= 0) { -+ /* Don't reconnect if signaled to exit */ -+ CHECK_EXIT; - while (handle_connection_error(inst, conn, ISC_TRUE) - != ISC_R_SUCCESS) { - log_error("ldap_psearch_watcher failed to handle " - "LDAP connection error. Reconnection " - "in %ds", inst->reconnect_interval); -- sleep(inst->reconnect_interval); -+ if (!sane_sleep(inst, inst->reconnect_interval)) -+ goto cleanup; - } - goto restart; - } --- -1.7.11.2 - - -From a7cd8ae747b3a81a02ab9e5dbefe1c595aa24ff6 Mon Sep 17 00:00:00 2001 -From: Adam Tkac -Date: Mon, 18 Jun 2012 15:54:18 +0200 -Subject: [PATCH 08/32] ldap_query can incorrectly return ISC_R_SUCCESS even - when failed - -Signed-off-by: Adam Tkac ---- - src/ldap_helper.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index f3f2106..7f0a6f4 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -1670,7 +1670,7 @@ retry: - goto retry; - } - -- return result; -+ return ISC_R_FAILURE; - } - - static void --- -1.7.11.2 - - -From 88dcade344af6e71503b85c4d2630343dbf7d7c0 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Mon, 7 May 2012 12:51:09 +0200 -Subject: [PATCH 09/32] Separate LDAP result from LDAP connection and fix - deadlock. This affects operation without persistent - search with connections count == 1. - -https://fedorahosted.org/bind-dyndb-ldap/ticket/66 - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 234 +++++++++++++++++++++++++++++++++--------------------- - 1 file changed, 143 insertions(+), 91 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 7f0a6f4..aa7f976 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -109,6 +109,7 @@ - * must acquire the semaphore and the lock. - */ - -+typedef struct ldap_qresult ldap_qresult_t; - typedef struct ldap_connection ldap_connection_t; - typedef struct ldap_pool ldap_pool_t; - typedef struct ldap_auth_pair ldap_auth_pair_t; -@@ -186,10 +187,8 @@ struct ldap_pool { - struct ldap_connection { - isc_mem_t *mctx; - isc_mutex_t lock; -- ld_string_t *query_string; - - LDAP *handle; -- LDAPMessage *result; - LDAPControl *serverctrls[2]; /* psearch/NULL or NULL/NULL */ - int msgid; - -@@ -198,19 +197,19 @@ struct ldap_connection { - isc_buffer_t rdata_target; - unsigned char *rdata_target_mem; - -- /* Cache. */ -- ldap_entrylist_t ldap_entries; -- - /* For reconnection logic. */ - isc_time_t next_reconnect; - unsigned int tries; -+}; - -- /* Temporary stuff. */ -- LDAPMessage *entry; -- BerElement *ber; -- char *attribute; -- char **values; -- char *dn; -+/** -+ * Result from single LDAP query. -+ */ -+struct ldap_qresult { -+ isc_mem_t *mctx; -+ ld_string_t *query_string; -+ LDAPMessage *result; -+ ldap_entrylist_t ldap_entries; - }; - - /* -@@ -271,9 +270,10 @@ static isc_result_t ldap_reconnect(ldap_instance_t *ldap_inst, - static isc_result_t handle_connection_error(ldap_instance_t *ldap_inst, - ldap_connection_t *ldap_conn, isc_boolean_t force); - static isc_result_t ldap_query(ldap_instance_t *ldap_inst, ldap_connection_t *ldap_conn, -- const char *base, -- int scope, char **attrs, int attrsonly, const char *filter, ...); --static void ldap_query_free(ldap_connection_t *ldap_conn); -+ ldap_qresult_t **ldap_qresultp, const char *base, int scope, char **attrs, -+ int attrsonly, const char *filter, ...); -+static isc_result_t ldap_query_create(isc_mem_t *mctx, ldap_qresult_t **ldap_qresultp); -+static void ldap_query_free(isc_boolean_t prepare_reuse, ldap_qresult_t **ldap_qresultp); - - /* Functions for writing to LDAP. */ - static isc_result_t ldap_modify_do(ldap_connection_t *ldap_conn, const char *dn, -@@ -608,8 +608,6 @@ new_ldap_connection(ldap_pool_t *pool, ldap_connection_t **ldap_connp) - - isc_mem_attach(pool->mctx, &ldap_conn->mctx); - -- CHECK(str_new(ldap_conn->mctx, &ldap_conn->query_string)); -- - CHECK(isc_lex_create(ldap_conn->mctx, TOKENSIZ, &ldap_conn->lex)); - CHECKED_MEM_GET(ldap_conn->mctx, ldap_conn->rdata_target_mem, MINTSIZ); - CHECK(ldap_pscontrol_create(ldap_conn->mctx, -@@ -637,8 +635,6 @@ destroy_ldap_connection(ldap_pool_t *pool, ldap_connection_t **ldap_connp) - if (ldap_conn->handle != NULL) - ldap_unbind_ext_s(ldap_conn->handle, NULL, NULL); - -- str_destroy(&ldap_conn->query_string); -- - if (ldap_conn->lex != NULL) - isc_lex_destroy(&ldap_conn->lex); - if (ldap_conn->rdata_target_mem != NULL) { -@@ -1103,6 +1099,8 @@ refresh_zones_from_ldap(ldap_instance_t *ldap_inst) - { - isc_result_t result = ISC_R_SUCCESS; - ldap_connection_t *ldap_conn = NULL; -+ ldap_qresult_t *ldap_config_qresult = NULL; -+ ldap_qresult_t *ldap_zones_qresult = NULL; - int zone_count = 0; - ldap_entry_t *entry; - dns_rbt_t *rbt = NULL; -@@ -1127,31 +1125,31 @@ refresh_zones_from_ldap(ldap_instance_t *ldap_inst) - - log_debug(2, "refreshing list of zones for %s", ldap_inst->db_name); - -+ /* Query for configuration and zones from LDAP and release LDAP connection -+ * before processing them. It prevents deadlock in situations where -+ * ldap_parse_zoneentry() requests another connection. */ - CHECK(ldap_pool_getconnection(ldap_inst->pool, &ldap_conn)); -- -- CHECK(ldap_query(ldap_inst, ldap_conn, str_buf(ldap_inst->base), -+ CHECK(ldap_query(ldap_inst, ldap_conn, &ldap_config_qresult, str_buf(ldap_inst->base), - LDAP_SCOPE_SUBTREE, config_attrs, 0, - "(objectClass=idnsConfigObject)")); -+ CHECK(ldap_query(ldap_inst, ldap_conn, &ldap_zones_qresult, str_buf(ldap_inst->base), -+ LDAP_SCOPE_SUBTREE, zone_attrs, 0, -+ "(&(objectClass=idnsZone)(idnsZoneActive=TRUE))")); -+ ldap_pool_putconnection(ldap_inst->pool, &ldap_conn); - -- for (entry = HEAD(ldap_conn->ldap_entries); -+ for (entry = HEAD(ldap_config_qresult->ldap_entries); - entry != NULL; - entry = NEXT(entry, link)) { - CHECK(ldap_parse_configentry(entry, ldap_inst)); - } - -- ldap_query_free(ldap_conn); -- -- CHECK(ldap_query(ldap_inst, ldap_conn, str_buf(ldap_inst->base), -- LDAP_SCOPE_SUBTREE, zone_attrs, 0, -- "(&(objectClass=idnsZone)(idnsZoneActive=TRUE))")); -- - /* - * Create RB-tree with all zones stored in LDAP for cross check - * with registered zones in plugin. - */ - CHECK(dns_rbt_create(ldap_inst->mctx, NULL, NULL, &rbt)); - -- for (entry = HEAD(ldap_conn->ldap_entries); -+ for (entry = HEAD(ldap_zones_qresult->ldap_entries); - entry != NULL; - entry = NEXT(entry, link)) { - -@@ -1240,6 +1238,8 @@ cleanup: - if (invalidate_nodechain) - dns_rbtnodechain_invalidate(&chain); - -+ ldap_query_free(ISC_FALSE, &ldap_config_qresult); -+ ldap_query_free(ISC_FALSE, &ldap_zones_qresult); - ldap_pool_putconnection(ldap_inst->pool, &ldap_conn); - - log_debug(2, "finished refreshing list of zones"); -@@ -1395,6 +1395,7 @@ ldapdb_nodelist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *nam - { - isc_result_t result; - ldap_connection_t *ldap_conn = NULL; -+ ldap_qresult_t *ldap_qresult = NULL; - ldap_entry_t *entry; - ld_string_t *string = NULL; - ldapdb_node_t *node; -@@ -1411,15 +1412,15 @@ ldapdb_nodelist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *nam - CHECK(str_new(mctx, &string)); - CHECK(dnsname_to_dn(ldap_inst->zone_register, name, string)); - -- CHECK(ldap_query(ldap_inst, ldap_conn, str_buf(string), -+ CHECK(ldap_query(ldap_inst, ldap_conn, &ldap_qresult, str_buf(string), - LDAP_SCOPE_SUBTREE, NULL, 0, "(objectClass=idnsRecord)")); - -- if (EMPTY(ldap_conn->ldap_entries)) { -+ if (EMPTY(ldap_qresult->ldap_entries)) { - result = ISC_R_NOTFOUND; - goto cleanup; - } - -- for (entry = HEAD(ldap_conn->ldap_entries); -+ for (entry = HEAD(ldap_qresult->ldap_entries); - entry != NULL; - entry = NEXT(entry, link)) { - node = NULL; -@@ -1452,6 +1453,7 @@ ldapdb_nodelist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *nam - result = ISC_R_SUCCESS; - - cleanup: -+ ldap_query_free(ISC_FALSE, &ldap_qresult); - ldap_pool_putconnection(ldap_inst->pool, &ldap_conn); - str_destroy(&string); - -@@ -1464,6 +1466,7 @@ ldapdb_rdatalist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *na - { - isc_result_t result; - ldap_connection_t *ldap_conn = NULL; -+ ldap_qresult_t *ldap_qresult = NULL; - ldap_entry_t *entry; - ld_string_t *string = NULL; - ldap_cache_t *cache; -@@ -1486,15 +1489,15 @@ ldapdb_rdatalist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *na - CHECK(dnsname_to_dn(ldap_inst->zone_register, name, string)); - - CHECK(ldap_pool_getconnection(ldap_inst->pool, &ldap_conn)); -- CHECK(ldap_query(ldap_inst, ldap_conn, str_buf(string), -+ CHECK(ldap_query(ldap_inst, ldap_conn, &ldap_qresult, str_buf(string), - LDAP_SCOPE_BASE, NULL, 0, "(objectClass=idnsRecord)")); - -- if (EMPTY(ldap_conn->ldap_entries)) { -+ if (EMPTY(ldap_qresult->ldap_entries)) { - result = ISC_R_NOTFOUND; - goto cleanup; - } - -- for (entry = HEAD(ldap_conn->ldap_entries); -+ for (entry = HEAD(ldap_qresult->ldap_entries); - entry != NULL; - entry = NEXT(entry, link)) { - if (ldap_parse_rrentry(mctx, entry, ldap_conn, -@@ -1512,6 +1515,7 @@ ldapdb_rdatalist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *na - result = ISC_R_NOTFOUND; - - cleanup: -+ ldap_query_free(ISC_FALSE, &ldap_qresult); - ldap_pool_putconnection(ldap_inst->pool, &ldap_conn); - str_destroy(&string); - -@@ -1609,55 +1613,65 @@ cleanup: - return result; - } - -+/** -+ * @param ldap_conn A LDAP connection structure obtained via ldap_get_connection(). -+ * @param ldap_qresult New ldap_qresult structure will be allocated and pointer -+ * to it will be returned through this parameter. The result -+ * has to be freed by caller via ldap_query_free(). -+ */ - static isc_result_t - ldap_query(ldap_instance_t *ldap_inst, ldap_connection_t *ldap_conn, -- const char *base, int scope, char **attrs, -+ ldap_qresult_t **ldap_qresultp, const char *base, int scope, char **attrs, - int attrsonly, const char *filter, ...) - { - va_list ap; - isc_result_t result; -+ ldap_qresult_t *ldap_qresult = NULL; - int cnt; - int ret; - int once = 0; - - REQUIRE(ldap_conn != NULL); -+ REQUIRE(ldap_qresultp != NULL && *ldap_qresultp == NULL); -+ -+ CHECK(ldap_query_create(ldap_inst->mctx, &ldap_qresult)); - - va_start(ap, filter); -- str_vsprintf(ldap_conn->query_string, filter, ap); -+ str_vsprintf(ldap_qresult->query_string, filter, ap); - va_end(ap); - - log_debug(2, "querying '%s' with '%s'", base, -- str_buf(ldap_conn->query_string)); -+ str_buf(ldap_qresult->query_string)); - - if (ldap_conn->handle == NULL) { - /* - * handle can be NULL when the first connection to LDAP wasn't - * successful -+ * TODO: handle this case inside ldap_pool_getconnection()? - */ -- result = ldap_connect(ldap_inst, ldap_conn, ISC_FALSE); -- if (result != ISC_R_SUCCESS) -- return result; -+ CHECK(ldap_connect(ldap_inst, ldap_conn, ISC_FALSE)); - } - - retry: - ret = ldap_search_ext_s(ldap_conn->handle, base, scope, -- str_buf(ldap_conn->query_string), -+ str_buf(ldap_qresult->query_string), - attrs, attrsonly, NULL, NULL, NULL, -- LDAP_NO_LIMIT, &ldap_conn->result); -+ LDAP_NO_LIMIT, &ldap_qresult->result); - if (ret == 0) { - ldap_conn->tries = 0; -- cnt = ldap_count_entries(ldap_conn->handle, ldap_conn->result); -+ cnt = ldap_count_entries(ldap_conn->handle, ldap_qresult->result); - log_debug(2, "entry count: %d", cnt); - - result = ldap_entrylist_create(ldap_conn->mctx, - ldap_conn->handle, -- ldap_conn->result, -- &ldap_conn->ldap_entries); -+ ldap_qresult->result, -+ &ldap_qresult->ldap_entries); - if (result != ISC_R_SUCCESS) { - log_error("failed to save LDAP query results"); - return result; - } - -+ *ldap_qresultp = ldap_qresult; - return ISC_R_SUCCESS; - } - -@@ -1669,38 +1683,70 @@ retry: - if (result == ISC_R_SUCCESS) - goto retry; - } -- -+cleanup: -+ ldap_query_free(ISC_FALSE, &ldap_qresult); - return ISC_R_FAILURE; - } - -+/** -+ * Allocate and initialize new ldap_qresult structure. -+ * @param[out] ldap_qresultp Newly allocated ldap_qresult structure. -+ * @return ISC_R_SUCCESS or ISC_R_NOMEMORY (from CHECKED_MEM_GET_PTR) -+ */ -+static isc_result_t -+ldap_query_create(isc_mem_t *mctx, ldap_qresult_t **ldap_qresultp) { -+ ldap_qresult_t *ldap_qresult = NULL; -+ isc_result_t result; -+ -+ CHECKED_MEM_GET_PTR(mctx, ldap_qresult); -+ ldap_qresult->mctx = mctx; -+ ldap_qresult->result = NULL; -+ ldap_qresult->query_string = NULL; -+ INIT_LIST(ldap_qresult->ldap_entries); -+ CHECK(str_new(mctx, &ldap_qresult->query_string)); -+ -+ *ldap_qresultp = ldap_qresult; -+ return ISC_R_SUCCESS; -+ -+cleanup: -+ SAFE_MEM_PUT_PTR(mctx, ldap_qresult); -+ return result; -+} -+ -+/** -+ * Free LDAP query result. Can free the whole structure or internal parts only. -+ * Freeing internal parts is suitable before reusing the structure. -+ * @param[in] prepare_reuse ISC_TRUE implies freeing internal parts, -+ * but not the whole structure. -+ * @param[in,out] ldap_qresultp Pointer to freed query. Will be set to NULL -+ * if prepare_reuse == ISC_FALSE. -+ */ - static void --ldap_query_free(ldap_connection_t *ldap_conn) -+ldap_query_free(isc_boolean_t prepare_reuse, ldap_qresult_t **ldap_qresultp) - { -- if (ldap_conn == NULL) -+ ldap_qresult_t *qresult; -+ REQUIRE(ldap_qresultp != NULL); -+ -+ qresult = *ldap_qresultp; -+ -+ if (qresult == NULL) - return; - -- if (ldap_conn->dn) { -- ldap_memfree(ldap_conn->dn); -- ldap_conn->dn = NULL; -- } -- if (ldap_conn->values) { -- ldap_value_free(ldap_conn->values); -- ldap_conn->values = NULL; -- } -- if (ldap_conn->attribute) { -- ldap_memfree(ldap_conn->attribute); -- ldap_conn->attribute = NULL; -- } -- if (ldap_conn->ber) { -- ber_free(ldap_conn->ber, 0); -- ldap_conn->ber = NULL; -- } -- if (ldap_conn->result) { -- ldap_msgfree(ldap_conn->result); -- ldap_conn->result = NULL; -+ if (qresult->result) { -+ ldap_msgfree(qresult->result); -+ qresult->result = NULL; - } - -- ldap_entrylist_destroy(ldap_conn->mctx, &ldap_conn->ldap_entries); -+ ldap_entrylist_destroy(qresult->mctx, &qresult->ldap_entries); -+ -+ if (prepare_reuse) { -+ str_clear(qresult->query_string); -+ INIT_LIST(qresult->ldap_entries); -+ } else { /* free the whole structure */ -+ str_destroy(&qresult->query_string); -+ SAFE_MEM_PUT_PTR(qresult->mctx, qresult); -+ *ldap_qresultp = NULL; -+ } - } - - /* FIXME: Tested with SASL/GSSAPI/KRB5 only */ -@@ -2246,6 +2292,7 @@ modify_ldap_common(dns_name_t *owner, ldap_instance_t *ldap_inst, - isc_result_t result; - isc_mem_t *mctx = ldap_inst->mctx; - ldap_connection_t *ldap_conn = NULL; -+ ldap_qresult_t *ldap_qresult = NULL; - ld_string_t *owner_dn = NULL; - LDAPMod *change[3] = { NULL }; - LDAPMod *change_ptr = NULL; -@@ -2272,12 +2319,12 @@ modify_ldap_common(dns_name_t *owner, ldap_instance_t *ldap_inst, - } - - CHECK(ldap_pool_getconnection(ldap_inst->pool, &ldap_conn)); -- CHECK(ldap_query(ldap_inst, ldap_conn, zone_dn, -+ CHECK(ldap_query(ldap_inst, ldap_conn, &ldap_qresult, zone_dn, - LDAP_SCOPE_BASE, attrs, 0, - "(&(objectClass=idnsZone)(idnsZoneActive=TRUE))")); - - /* only 0 or 1 active zone can be returned from query */ -- entry = HEAD(ldap_conn->ldap_entries); -+ entry = HEAD(ldap_qresult->ldap_entries); - if (entry == NULL) { - log_debug(3, "Active zone %s not found", zone_dn); - result = ISC_R_NOTFOUND; -@@ -2409,14 +2456,14 @@ modify_ldap_common(dns_name_t *owner, ldap_instance_t *ldap_inst, - char *owner_zone_dn_ptr = strstr(str_buf(owner_dn_ptr),", ") + 1; - - /* Get attribute "idnsAllowDynUpdate" for reverse zone or use default. */ -- ldap_query_free(ldap_conn); -+ ldap_query_free(ISC_FALSE, &ldap_qresult); - zone_dyn_update = ldap_inst->dyn_update; -- CHECK(ldap_query(ldap_inst, ldap_conn, owner_zone_dn_ptr, -+ CHECK(ldap_query(ldap_inst, ldap_conn, &ldap_qresult, owner_zone_dn_ptr, - LDAP_SCOPE_BASE, attrs, 0, - "(&(objectClass=idnsZone)(idnsZoneActive=TRUE))")); - - /* Only 0 or 1 active zone can be returned from query. */ -- entry = HEAD(ldap_conn->ldap_entries); -+ entry = HEAD(ldap_qresult->ldap_entries); - if (entry == NULL) { - log_debug(3, "Active zone %s not found", zone_dn); - result = ISC_R_NOTFOUND; -@@ -2502,6 +2549,7 @@ modify_ldap_common(dns_name_t *owner, ldap_instance_t *ldap_inst, - } - - cleanup: -+ ldap_query_free(ISC_FALSE, &ldap_qresult); - ldap_pool_putconnection(ldap_inst->pool, &ldap_conn); - str_destroy(&owner_dn_ptr); - str_destroy(&owner_dn); -@@ -2604,7 +2652,6 @@ ldap_pool_getconnection(ldap_pool_t *pool, ldap_connection_t ** conn) - - RUNTIME_CHECK(ldap_conn != NULL); - -- INIT_LIST(ldap_conn->ldap_entries); - *conn = ldap_conn; - - cleanup: -@@ -2624,7 +2671,6 @@ ldap_pool_putconnection(ldap_pool_t *pool, ldap_connection_t **conn) - if (ldap_conn == NULL) - return; - -- ldap_query_free(ldap_conn); - UNLOCK(&ldap_conn->lock); - semaphore_signal(&pool->conn_semaphore); - -@@ -2756,6 +2802,7 @@ update_action(isc_task_t *task, isc_event_t *event) - isc_result_t result ; - ldap_instance_t *inst = NULL; - ldap_connection_t *conn = NULL; -+ ldap_qresult_t *ldap_qresult = NULL; - ldap_entry_t *entry; - isc_boolean_t delete = ISC_TRUE; - isc_mem_t *mctx; -@@ -2775,11 +2822,11 @@ update_action(isc_task_t *task, isc_event_t *event) - - CHECK(ldap_pool_getconnection(inst->pool, &conn)); - -- CHECK(ldap_query(inst, conn, pevent->dn, -+ CHECK(ldap_query(inst, conn, &ldap_qresult, pevent->dn, - LDAP_SCOPE_BASE, attrs, 0, - "(&(objectClass=idnsZone)(idnsZoneActive=TRUE))")); - -- for (entry = HEAD(conn->ldap_entries); -+ for (entry = HEAD(ldap_qresult->ldap_entries); - entry != NULL; - entry = NEXT(entry, link)) { - delete = ISC_FALSE; -@@ -2797,6 +2844,7 @@ cleanup: - "Zones can be outdated, run `rndc reload`", - pevent->dn); - -+ ldap_query_free(ISC_FALSE, &ldap_qresult); - ldap_pool_putconnection(inst->pool, &conn); - isc_mem_free(mctx, pevent->dbname); - isc_mem_free(mctx, pevent->dn); -@@ -2811,6 +2859,7 @@ update_config(isc_task_t *task, isc_event_t *event) - isc_result_t result ; - ldap_instance_t *inst = NULL; - ldap_connection_t *conn = NULL; -+ ldap_qresult_t *ldap_qresult = NULL; - ldap_entry_t *entry; - isc_mem_t *mctx; - char *attrs[] = { -@@ -2828,14 +2877,14 @@ update_config(isc_task_t *task, isc_event_t *event) - - CHECK(ldap_pool_getconnection(inst->pool, &conn)); - -- CHECK(ldap_query(inst, conn, pevent->dn, -+ CHECK(ldap_query(inst, conn, &ldap_qresult, pevent->dn, - LDAP_SCOPE_BASE, attrs, 0, - "(objectClass=idnsConfigObject)")); - -- if (EMPTY(conn->ldap_entries)) -- log_error("Config object can not be empty"); -+ if (EMPTY(ldap_qresult->ldap_entries)) -+ log_error("Config object can not be empty"); /* TODO: WHY? */ - -- for (entry = HEAD(conn->ldap_entries); -+ for (entry = HEAD(ldap_qresult->ldap_entries); - entry != NULL; - entry = NEXT(entry, link)) { - result = ldap_parse_configentry(entry, inst); -@@ -2850,6 +2899,7 @@ cleanup: - "Configuration can be outdated, run `rndc reload`", - pevent->dn); - -+ ldap_query_free(ISC_FALSE, &ldap_qresult); - ldap_pool_putconnection(inst->pool, &conn); - isc_mem_free(mctx, pevent->dbname); - isc_mem_free(mctx, pevent->dn); -@@ -3148,6 +3198,7 @@ ldap_psearch_watcher(isc_threadarg_t arg) - { - ldap_instance_t *inst = (ldap_instance_t *)arg; - ldap_connection_t *conn = NULL; -+ ldap_qresult_t *ldap_qresult = NULL; - struct timeval tv; - int ret, cnt; - isc_result_t result; -@@ -3187,6 +3238,8 @@ ldap_psearch_watcher(isc_threadarg_t arg) - ldap_connect(inst, conn, ISC_TRUE); - } - -+ CHECK(ldap_query_create(conn->mctx, &ldap_qresult)); -+ - restart: - /* Perform initial lookup */ - if (inst->psearch) { -@@ -3213,7 +3266,7 @@ restart: - - while (!inst->exiting) { - ret = ldap_result(conn->handle, conn->msgid, 0, &tv, -- &conn->result); -+ &ldap_qresult->result); - if (ret <= 0) { - /* Don't reconnect if signaled to exit */ - CHECK_EXIT; -@@ -3225,6 +3278,7 @@ restart: - if (!sane_sleep(inst, inst->reconnect_interval)) - goto cleanup; - } -+ ldap_query_free(ISC_TRUE, &ldap_qresult); - goto restart; - } - -@@ -3237,14 +3291,14 @@ restart: - } - - conn->tries = 0; -- cnt = ldap_count_entries(conn->handle, conn->result); -- -+ cnt = ldap_count_entries(conn->handle, ldap_qresult->result); -+ - if (cnt > 0) { - log_debug(3, "Got psearch updates (%d)", cnt); - result = ldap_entrylist_append(conn->mctx, - conn->handle, -- conn->result, -- &conn->ldap_entries); -+ ldap_qresult->result, -+ &ldap_qresult->ldap_entries); - if (result != ISC_R_SUCCESS) { - /* - * Error means inconsistency of our zones -@@ -3256,7 +3310,7 @@ restart: - } - - ldap_entry_t *entry; -- for (entry = HEAD(conn->ldap_entries); -+ for (entry = HEAD(ldap_qresult->ldap_entries); - entry != NULL; - entry = NEXT(entry, link)) { - LDAPControl **ctrls = NULL; -@@ -3274,16 +3328,14 @@ restart: - psearch_update(inst, entry, ctrls); - } - soft_err: -- -- ldap_msgfree(conn->result); -- ldap_entrylist_destroy(conn->mctx, -- &conn->ldap_entries); -+ ldap_query_free(ISC_TRUE, &ldap_qresult); - } - } - - log_debug(1, "Ending ldap_psearch_watcher"); - - cleanup: -+ ldap_query_free(ISC_FALSE, &ldap_qresult); - ldap_pool_putconnection(inst->pool, &conn); - - return (isc_threadresult_t)0; --- -1.7.11.2 - - -From 3c382dd0296f6fe2931ddb0d18de220e6740011c Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Thu, 28 Jun 2012 13:52:38 +0200 -Subject: [PATCH 10/32] Add debug message to ldap_cache_getrdatalist() - -Signed-off-by: Petr Spacek ---- - src/cache.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/src/cache.c b/src/cache.c -index c8afb99..28f93c9 100644 ---- a/src/cache.c -+++ b/src/cache.c -@@ -26,6 +26,7 @@ - - #include - #include -+#include - - #include - -@@ -207,6 +208,14 @@ ldap_cache_getrdatalist(isc_mem_t *mctx, ldap_cache_t *cache, - - cleanup: - UNLOCK(&cache->mutex); -+ -+ if (isc_log_getdebuglevel(dns_lctx) >= 20) { -+ char dns_str[DNS_NAME_FORMATSIZE]; -+ dns_name_format(name, dns_str, sizeof(dns_str)); -+ log_debug(20, "cache search for '%s': %s", dns_str, -+ isc_result_totext(result)); -+ } -+ - return result; - } - --- -1.7.11.2 - - -From 99663b6d65cf5dc166b3cb6f83be1878b8de3163 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Wed, 27 Jun 2012 10:36:26 +0200 -Subject: [PATCH 11/32] Increment SOA serial for each ordinary record received - through psearch - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 93 insertions(+), 1 deletion(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index aa7f976..0df1e03 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -34,6 +34,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -173,6 +175,7 @@ struct ldap_instance { - isc_boolean_t exiting; - isc_boolean_t sync_ptr; - isc_boolean_t dyn_update; -+ isc_boolean_t serial_autoincrement; - }; - - struct ldap_pool { -@@ -343,6 +346,7 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, - { "ldap_hostname", default_string("") }, - { "sync_ptr", default_boolean(ISC_FALSE) }, - { "dyn_update", default_boolean(ISC_FALSE) }, -+ { "serial_autoincrement", default_boolean(ISC_FALSE) }, - end_of_settings - }; - -@@ -401,6 +405,7 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, - ldap_settings[i++].target = ldap_inst->ldap_hostname; - ldap_settings[i++].target = &ldap_inst->sync_ptr; - ldap_settings[i++].target = &ldap_inst->dyn_update; -+ ldap_settings[i++].target = &ldap_inst->serial_autoincrement; - CHECK(set_settings(ldap_settings, argv)); - - /* Set timer for deadlock detection inside semaphore_wait_timed . */ -@@ -463,6 +468,13 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, - "increasing limit"); - ldap_inst->connections = 3; - } -+ if (ldap_inst->serial_autoincrement == ISC_TRUE -+ && ldap_inst->psearch != ISC_TRUE) { -+ log_error("SOA serial number auto-increment feature requires " -+ "persistent search"); -+ result = ISC_R_FAILURE; -+ goto cleanup; -+ } - - CHECK(new_ldap_cache(mctx, argv, &ldap_inst->cache, ldap_inst->psearch)); - CHECK(ldap_pool_create(mctx, ldap_inst->connections, &ldap_inst->pool)); -@@ -2787,6 +2799,82 @@ ldap_pscontrol_destroy(isc_mem_t *mctx, LDAPControl **ctrlp) - *ctrlp = NULL; - } - -+static inline isc_result_t -+soa_serial_get(ldap_instance_t *inst, dns_name_t *zone_name, -+ isc_uint32_t *serial) { -+ isc_result_t result; -+ dns_zone_t *zone = NULL; -+ -+ CHECK(zr_get_zone_ptr(inst->zone_register, zone_name, &zone)); -+ CHECK(dns_zone_getserial2(zone, serial)); -+ dns_zone_detach(&zone); -+ -+cleanup: -+ return result; -+} -+ -+isc_result_t -+soa_serial_increment(isc_mem_t *mctx, ldap_instance_t *inst, -+ dns_name_t *zone_name) { -+ isc_result_t result = ISC_R_FAILURE; -+ ldap_connection_t * conn = NULL; -+ ld_string_t *zone_dn = NULL; -+ ldapdb_rdatalist_t rdatalist; -+ dns_rdatalist_t *rdlist = NULL; -+ dns_rdata_t *soa_rdata = NULL; -+ isc_uint32_t old_serial; -+ isc_uint32_t new_serial; -+ isc_time_t curr_time; -+ -+ REQUIRE(inst != NULL); -+ REQUIRE(zone_name != NULL); -+ -+ INIT_LIST(rdatalist); -+ CHECK(str_new(mctx, &zone_dn)); -+ CHECK(dnsname_to_dn(inst->zone_register, zone_name, zone_dn)); -+ log_debug(5, "incrementing SOA serial number in zone '%s'", -+ str_buf(zone_dn)); -+ -+ /* get original SOA rdata and serial value */ -+ CHECK(ldapdb_rdatalist_get(mctx, inst, zone_name, zone_name, &rdatalist)); -+ CHECK(ldapdb_rdatalist_findrdatatype(&rdatalist, dns_rdatatype_soa, &rdlist)); -+ soa_rdata = ISC_LIST_HEAD(rdlist->rdata); -+ CHECK(soa_serial_get(inst, zone_name, &old_serial)); -+ -+ /* Compute the new SOA serial - use actual timestamp. -+ * If timestamp <= oldSOAserial then increment old serial by one. */ -+ isc_time_now(&curr_time); -+ new_serial = isc_time_seconds(&curr_time) & 0xFFFFFFFF; -+ if (!isc_serial_gt(new_serial, old_serial)) { -+ /* increment by one, RFC1982, from bind-9.8.2/bin/named/update.c */ -+ new_serial = (old_serial + 1) & 0xFFFFFFFF; -+ } -+ if (new_serial == 0) -+ new_serial = 1; -+ log_debug(5,"zone '%s': old serial %u, new serial %u", -+ str_buf(zone_dn), old_serial, new_serial); -+ dns_soa_setserial(new_serial, soa_rdata); -+ -+ /* write the new serial back to DB */ -+ CHECK(ldap_pool_getconnection(inst->pool, &conn)); -+ CHECK(modify_soa_record(conn, str_buf(zone_dn), soa_rdata)); -+ CHECK(discard_from_cache(ldap_instance_getcache(inst), zone_name)); -+ -+ /* put the new SOA to inst->cache and compare old and new serials */ -+ CHECK(soa_serial_get(inst, zone_name, &new_serial)); -+ INSIST(isc_serial_gt(new_serial, old_serial) == ISC_TRUE); -+ -+cleanup: -+ if (result != ISC_R_SUCCESS) -+ log_error("SOA serial number incrementation failed in zone '%s'", -+ str_buf(zone_dn)); -+ -+ ldap_pool_putconnection(inst->pool, &conn); -+ str_destroy(&zone_dn); -+ ldapdb_rdatalist_destroy(mctx, &rdatalist); -+ return result; -+} -+ - /* - * update_action routine is processed asynchronously so it cannot assume - * anything about state of ldap_inst from where it was sent. The ldap_inst -@@ -2942,7 +3030,7 @@ update_record(isc_task_t *task, isc_event_t *event) - if (PSEARCH_DEL(pevent->chgtype)) { - log_debug(5, "psearch_update: Removing item from cache (%s)", - pevent->dn); -- } -+ } - - /* Get cache instance & clean old record */ - cache = ldap_instance_getcache(inst); -@@ -2966,6 +3054,10 @@ update_record(isc_task_t *task, isc_event_t *event) - /* Destroy rdatalist, it is now in the cache. */ - ldapdb_rdatalist_destroy(mctx, &rdatalist); - } -+ -+ if (inst->serial_autoincrement) { -+ CHECK(soa_serial_increment(mctx, inst, &origin)); -+ } - cleanup: - if (result != ISC_R_SUCCESS) - log_error("update_record (psearch) failed for %s. " --- -1.7.11.2 - - -From cd37fba03c5c86a766d1a9f893036ac3540e8b7c Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Mon, 2 Jul 2012 11:01:58 +0200 -Subject: [PATCH 12/32] Do not bump serial for each record during initial - database dump. - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 18 ++++++++++++++---- - 1 file changed, 14 insertions(+), 4 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 0df1e03..7eb18cb 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -2723,6 +2723,7 @@ cleanup: - #define LDAP_CONTROL_PERSISTENTSEARCH "2.16.840.1.113730.3.4.3" - #define LDAP_CONTROL_ENTRYCHANGE "2.16.840.1.113730.3.4.7" - -+#define LDAP_ENTRYCHANGE_NONE 0 /* entry change control is not present */ - #define LDAP_ENTRYCHANGE_ADD 1 - #define LDAP_ENTRYCHANGE_DEL 2 - #define LDAP_ENTRYCHANGE_MOD 4 -@@ -2733,6 +2734,7 @@ cleanup: - #define PSEARCH_DEL(chgtype) ((chgtype & LDAP_ENTRYCHANGE_DEL) != 0) - #define PSEARCH_MOD(chgtype) ((chgtype & LDAP_ENTRYCHANGE_MOD) != 0) - #define PSEARCH_MODDN(chgtype) ((chgtype & LDAP_ENTRYCHANGE_MODDN) != 0) -+#define PSEARCH_ANY(chgtype) ((chgtype & LDAP_ENTRYCHANGE_ALL) != 0) - /* - * Creates persistent search (aka psearch, - * http://tools.ietf.org/id/draft-ietf-ldapext-psearch-03.txt) control. -@@ -3036,9 +3038,11 @@ update_record(isc_task_t *task, isc_event_t *event) - cache = ldap_instance_getcache(inst); - CHECK(discard_from_cache(cache, &name)); - -- if (PSEARCH_ADD(pevent->chgtype) || PSEARCH_MOD(pevent->chgtype)) { -+ if (PSEARCH_ADD(pevent->chgtype) || PSEARCH_MOD(pevent->chgtype) || -+ !PSEARCH_ANY(pevent->chgtype)) { - /* -- * Find new data in LDAP. -+ * Find new data in LDAP. !PSEARCH_ANY indicates unchanged entry -+ * found during initial lookup (i.e. database dump). - * - * @todo Change this to convert ldap_entry_t to ldapdb_rdatalist_t. - */ -@@ -3055,7 +3059,13 @@ update_record(isc_task_t *task, isc_event_t *event) - ldapdb_rdatalist_destroy(mctx, &rdatalist); - } - -- if (inst->serial_autoincrement) { -+ log_debug(20,"psearch change type: none%d, add%d, del%d, mod%d, moddn%d", -+ !PSEARCH_ANY(pevent->chgtype), PSEARCH_ADD(pevent->chgtype), -+ PSEARCH_DEL(pevent->chgtype), PSEARCH_MOD(pevent->chgtype), -+ PSEARCH_MODDN(pevent->chgtype)); -+ -+ /* Do not bump serial during initial database dump. */ -+ if (inst->serial_autoincrement && PSEARCH_ANY(pevent->chgtype)) { - CHECK(soa_serial_increment(mctx, inst, &origin)); - } - cleanup: -@@ -3138,7 +3148,7 @@ psearch_update(ldap_instance_t *inst, ldap_entry_t *entry, LDAPControl **ctrls) - ldap_entryclass_t class; - isc_result_t result = ISC_R_SUCCESS; - ldap_psearchevent_t *pevent = NULL; -- int chgtype = LDAP_ENTRYCHANGE_ADD; -+ int chgtype = LDAP_ENTRYCHANGE_NONE; - char *moddn = NULL; - char *dn = NULL; - char *dbname = NULL; --- -1.7.11.2 - - -From 9a3f29c12db99597222ffa2bf0713d0b00cb4699 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Mon, 2 Jul 2012 16:40:23 +0200 -Subject: [PATCH 13/32] Maintain SOA serial for zone record changes also. Bump - serial after each BIND startup. Manual changes to - zone serial are allowed. - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 67 ++++++++++++++++++++++++++++++++++++++--------------- - src/zone_register.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++ - src/zone_register.h | 6 +++++ - 3 files changed, 113 insertions(+), 19 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 7eb18cb..a50674b 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -265,6 +265,8 @@ static isc_result_t ldap_parse_rrentry(isc_mem_t *mctx, ldap_entry_t *entry, - ldap_connection_t *conn, dns_name_t *origin, - const ld_string_t *fake_mname, ld_string_t *buf, - ldapdb_rdatalist_t *rdatalist); -+static inline isc_result_t ldap_get_zone_serial(ldap_instance_t *inst, -+ dns_name_t *zone_name, isc_uint32_t *serial); - - static isc_result_t ldap_connect(ldap_instance_t *ldap_inst, - ldap_connection_t *ldap_conn, isc_boolean_t force); -@@ -291,6 +293,8 @@ static isc_result_t ldap_rdata_to_char_array(isc_mem_t *mctx, - static void free_char_array(isc_mem_t *mctx, char ***valsp); - static isc_result_t modify_ldap_common(dns_name_t *owner, ldap_instance_t *ldap_inst, - dns_rdatalist_t *rdlist, int mod_op, isc_boolean_t delete_node); -+static isc_result_t soa_serial_increment(isc_mem_t *mctx, ldap_instance_t *inst, -+ dns_name_t *zone_name); - - static isc_result_t - ldap_delete_zone2(ldap_instance_t *inst, dns_name_t *name, isc_boolean_t lock); -@@ -996,8 +1000,9 @@ ldap_parse_zoneentry(ldap_entry_t *entry, ldap_instance_t *inst) - isc_result_t result; - isc_boolean_t unlock = ISC_FALSE; - isc_boolean_t publish = ISC_FALSE; -- isc_boolean_t load = ISC_FALSE; - isc_task_t *task = inst->task; -+ isc_uint32_t ldap_serial; -+ isc_uint32_t zr_serial; - - dns_name_init(&name, NULL); - -@@ -1016,11 +1021,11 @@ ldap_parse_zoneentry(ldap_entry_t *entry, ldap_instance_t *inst) - * Fetch forwarders. - * Forwarding has top priority hence when the forwarders are properly - * set up all others attributes are ignored. -- */ -+ */ - result = ldap_entry_getvalues(entry, "idnsForwarders", &values); - if (result == ISC_R_SUCCESS) { - log_debug(2, "Setting forwarders for %s", dn); -- CHECK(configure_zone_forwarders(entry, inst, &name, &values)); -+ CHECK(configure_zone_forwarders(entry, inst, &name, &values)); - /* DO NOT CHANGE ANYTHING ELSE after forwarders are set up! */ - goto cleanup; - } else { -@@ -1076,17 +1081,41 @@ ldap_parse_zoneentry(ldap_entry_t *entry, ldap_instance_t *inst) - /* Everything is set correctly, publish zone */ - CHECK(publish_zone(inst, zone)); - } -- load = ISC_TRUE; - --cleanup: -- if (load) { -- /* -- * Don't bother if load fails, server will return -- * SERVFAIL for queries beneath this zone. This is -- * admin's problem. -- */ -- (void) dns_zone_load(zone); -+ /* -+ * Don't bother if load fails, server will return -+ * SERVFAIL for queries beneath this zone. This is -+ * admin's problem. -+ */ -+ result = dns_zone_load(zone); -+ if (result != ISC_R_SUCCESS && result != DNS_R_UPTODATE -+ && result != DNS_R_DYNAMIC && result != DNS_R_CONTINUE) -+ goto cleanup; -+ -+ result = ISC_R_SUCCESS; -+ -+ /* initialize serial in zone register and always increment serial -+ * for a new zone (typically after BIND start) -+ * - the zone was possibly changed in meanwhile */ -+ if (publish) { -+ CHECK(ldap_get_zone_serial(inst, &name, &ldap_serial)); -+ CHECK(zr_set_zone_serial(inst->zone_register, &name, ldap_serial)); -+ } -+ -+ /* SOA serial autoincrement feature for SOA record: -+ * 1) remember old SOA serial from zone register -+ * 2) compare old and new SOA serial from LDAP DB -+ * 3) if (old == new) then do autoincrement, remember new serial otherwise */ -+ if (inst->serial_autoincrement) { -+ CHECK(ldap_get_zone_serial(inst, &name, &ldap_serial)); -+ CHECK(zr_get_zone_serial(inst->zone_register, &name, &zr_serial)); -+ if (ldap_serial == zr_serial) -+ CHECK(soa_serial_increment(inst->mctx, inst, &name)); -+ else -+ CHECK(zr_set_zone_serial(inst->zone_register, &name, ldap_serial)); - } -+ -+cleanup: - if (unlock) - isc_task_endexclusive(task); - if (dns_name_dynamic(&name)) -@@ -1094,7 +1123,7 @@ cleanup: - if (zone != NULL) - dns_zone_detach(&zone); - -- return ISC_R_SUCCESS; -+ return result; - } - - /* -@@ -2802,7 +2831,7 @@ ldap_pscontrol_destroy(isc_mem_t *mctx, LDAPControl **ctrlp) - } - - static inline isc_result_t --soa_serial_get(ldap_instance_t *inst, dns_name_t *zone_name, -+ldap_get_zone_serial(ldap_instance_t *inst, dns_name_t *zone_name, - isc_uint32_t *serial) { - isc_result_t result; - dns_zone_t *zone = NULL; -@@ -2815,7 +2844,7 @@ cleanup: - return result; - } - --isc_result_t -+static isc_result_t - soa_serial_increment(isc_mem_t *mctx, ldap_instance_t *inst, - dns_name_t *zone_name) { - isc_result_t result = ISC_R_FAILURE; -@@ -2841,7 +2870,7 @@ soa_serial_increment(isc_mem_t *mctx, ldap_instance_t *inst, - CHECK(ldapdb_rdatalist_get(mctx, inst, zone_name, zone_name, &rdatalist)); - CHECK(ldapdb_rdatalist_findrdatatype(&rdatalist, dns_rdatatype_soa, &rdlist)); - soa_rdata = ISC_LIST_HEAD(rdlist->rdata); -- CHECK(soa_serial_get(inst, zone_name, &old_serial)); -+ CHECK(ldap_get_zone_serial(inst, zone_name, &old_serial)); - - /* Compute the new SOA serial - use actual timestamp. - * If timestamp <= oldSOAserial then increment old serial by one. */ -@@ -2863,7 +2892,7 @@ soa_serial_increment(isc_mem_t *mctx, ldap_instance_t *inst, - CHECK(discard_from_cache(ldap_instance_getcache(inst), zone_name)); - - /* put the new SOA to inst->cache and compare old and new serials */ -- CHECK(soa_serial_get(inst, zone_name, &new_serial)); -+ CHECK(ldap_get_zone_serial(inst, zone_name, &new_serial)); - INSIST(isc_serial_gt(new_serial, old_serial) == ISC_TRUE); - - cleanup: -@@ -2930,9 +2959,9 @@ update_action(isc_task_t *task, isc_event_t *event) - - cleanup: - if (result != ISC_R_SUCCESS) -- log_error("update_action (psearch) failed for %s. " -+ log_error("update_action (psearch) failed for '%s': %s. " - "Zones can be outdated, run `rndc reload`", -- pevent->dn); -+ pevent->dn, isc_result_totext(result)); - - ldap_query_free(ISC_FALSE, &ldap_qresult); - ldap_pool_putconnection(inst->pool, &conn); -diff --git a/src/zone_register.c b/src/zone_register.c -index 81d208f..1de6bf1 100644 ---- a/src/zone_register.c -+++ b/src/zone_register.c -@@ -50,6 +50,7 @@ struct zone_register { - typedef struct { - dns_zone_t *zone; - char *dn; -+ isc_uint32_t serial; /* last value processed by plugin (!= value in DB) */ - } zone_info_t; - - /* Callback for dns_rbt_create(). */ -@@ -136,6 +137,7 @@ create_zone_info(isc_mem_t *mctx, dns_zone_t *zone, const char *dn, - - CHECKED_MEM_GET_PTR(mctx, zinfo); - CHECKED_MEM_STRDUP(mctx, dn, zinfo->dn); -+ zinfo->serial = 0; - zinfo->zone = NULL; - dns_zone_attach(zone, &zinfo->zone); - -@@ -312,3 +314,60 @@ zr_get_zone_ptr(zone_register_t *zr, dns_name_t *name, dns_zone_t **zonep) - - return result; - } -+ -+/** -+ * Return last SOA serial value processed by autoincrement feature. -+ */ -+isc_result_t -+zr_get_zone_serial(zone_register_t *zr, dns_name_t *name, isc_uint32_t *serialp) -+{ -+ isc_result_t result; -+ void *zinfo = NULL; -+ -+ REQUIRE(zr != NULL); -+ REQUIRE(name != NULL); -+ REQUIRE(serialp != NULL); -+ -+ if (!dns_name_isabsolute(name)) { -+ log_bug("trying to find zone with a relative name"); -+ return ISC_R_FAILURE; -+ } -+ -+ RWLOCK(&zr->rwlock, isc_rwlocktype_read); -+ -+ result = dns_rbt_findname(zr->rbt, name, 0, NULL, &zinfo); -+ if (result == ISC_R_SUCCESS) -+ *serialp = ((zone_info_t *)zinfo)->serial; -+ -+ RWUNLOCK(&zr->rwlock, isc_rwlocktype_read); -+ -+ return result; -+} -+ -+/** -+ * Set last SOA serial value processed by autoincrement feature. -+ */ -+isc_result_t -+zr_set_zone_serial(zone_register_t *zr, dns_name_t *name, isc_uint32_t serial) -+{ -+ isc_result_t result; -+ void *zinfo = NULL; -+ -+ REQUIRE(zr != NULL); -+ REQUIRE(name != NULL); -+ -+ if (!dns_name_isabsolute(name)) { -+ log_bug("trying to find zone with a relative name"); -+ return ISC_R_FAILURE; -+ } -+ -+ RWLOCK(&zr->rwlock, isc_rwlocktype_read); -+ -+ result = dns_rbt_findname(zr->rbt, name, 0, NULL, &zinfo); -+ if (result == ISC_R_SUCCESS) -+ ((zone_info_t *)zinfo)->serial = serial; -+ -+ RWUNLOCK(&zr->rwlock, isc_rwlocktype_read); -+ -+ return result; -+} -diff --git a/src/zone_register.h b/src/zone_register.h -index fa8ef25..6ac3a92 100644 ---- a/src/zone_register.h -+++ b/src/zone_register.h -@@ -48,4 +48,10 @@ zr_get_rbt(zone_register_t *zr); - isc_mem_t * - zr_get_mctx(zone_register_t *zr); - -+isc_result_t -+zr_set_zone_serial(zone_register_t *zr, dns_name_t *name, isc_uint32_t serial); -+ -+isc_result_t -+zr_get_zone_serial(zone_register_t *zr, dns_name_t *name, isc_uint32_t *serialp); -+ - #endif /* !_LD_ZONE_REGISTER_H_ */ --- -1.7.11.2 - - -From c379d81508fbfa00ecb5da727ff7b097ebb29a3d Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Tue, 10 Jul 2012 14:23:46 +0200 -Subject: [PATCH 14/32] Add support for replicated environments to SOA serial - autoincrement feature. 389 DS sends entry change - notification even if modifyTimestamp was modified - because of replication from another DS. This code - computes digest from resource records in zone object - and compares these digests for each received entry - change notification. False entry change notifications - are revealed this way and no incrementation is done - in that case. - -http://fedorahosted.org/bind-dyndb-ldap/ticket/67 - -Signed-off-by: Petr Spacek ---- - src/ldap_driver.c | 16 +------ - src/ldap_helper.c | 47 ++++++++++++++----- - src/rdlist.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++- - src/rdlist.h | 13 ++++++ - src/zone_register.c | 35 ++++++++++----- - src/zone_register.h | 6 ++- - 6 files changed, 204 insertions(+), 40 deletions(-) - -diff --git a/src/ldap_driver.c b/src/ldap_driver.c -index a87db18..cae45d4 100644 ---- a/src/ldap_driver.c -+++ b/src/ldap_driver.c -@@ -110,7 +110,6 @@ static void *ldapdb_version = &dummy; - - static void free_ldapdb(ldapdb_t *ldapdb); - static void detachnode(dns_db_t *db, dns_dbnode_t **targetp); --static unsigned int rdatalist_length(const dns_rdatalist_t *rdlist); - static isc_result_t clone_rdatalist_to_rdataset(isc_mem_t *mctx, - dns_rdatalist_t *rdlist, - dns_rdataset_t *rdataset); -@@ -545,6 +544,7 @@ found: - goto skipfind; - - result = ldapdb_rdatalist_findrdatatype(&rdatalist, type, &rdlist); -+ - if (result != ISC_R_SUCCESS) { - /* No exact rdtype match. Check CNAME */ - -@@ -1006,20 +1006,6 @@ cleanup: - return result; - } - --static unsigned int --rdatalist_length(const dns_rdatalist_t *rdlist) --{ -- dns_rdata_t *ptr = HEAD(rdlist->rdata); -- unsigned int length = 0; -- -- while (ptr != NULL) { -- length++; -- ptr = NEXT(ptr, link); -- } -- -- return length; --} -- - static isc_result_t - subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, - dns_rdataset_t *rdataset, unsigned int options, -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index a50674b..0b1ed73 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -71,6 +71,7 @@ - #include "ldap_entry.h" - #include "ldap_helper.h" - #include "log.h" -+#include "rdlist.h" - #include "semaphore.h" - #include "settings.h" - #include "str.h" -@@ -1002,9 +1003,16 @@ ldap_parse_zoneentry(ldap_entry_t *entry, ldap_instance_t *inst) - isc_boolean_t publish = ISC_FALSE; - isc_task_t *task = inst->task; - isc_uint32_t ldap_serial; -- isc_uint32_t zr_serial; -+ isc_uint32_t zr_serial; /* SOA serial value from in-memory zone register */ -+ unsigned char ldap_digest[RDLIST_DIGESTLENGTH]; -+ unsigned char *zr_digest = NULL; -+ ldapdb_rdatalist_t rdatalist; -+ -+ REQUIRE(entry != NULL); -+ REQUIRE(inst != NULL); - - dns_name_init(&name, NULL); -+ INIT_LIST(rdatalist); - - /* Derive the dns name of the zone from the DN. */ - dn = entry->dn; -@@ -1098,21 +1106,39 @@ ldap_parse_zoneentry(ldap_entry_t *entry, ldap_instance_t *inst) - * for a new zone (typically after BIND start) - * - the zone was possibly changed in meanwhile */ - if (publish) { -+ memset(ldap_digest, 0, RDLIST_DIGESTLENGTH); - CHECK(ldap_get_zone_serial(inst, &name, &ldap_serial)); -- CHECK(zr_set_zone_serial(inst->zone_register, &name, ldap_serial)); -+ CHECK(zr_set_zone_serial_digest(inst->zone_register, &name, ldap_serial, -+ ldap_digest)); - } - - /* SOA serial autoincrement feature for SOA record: -- * 1) remember old SOA serial from zone register -- * 2) compare old and new SOA serial from LDAP DB -- * 3) if (old == new) then do autoincrement, remember new serial otherwise */ -+ * 1) Remember old (already processed) SOA serial and digest computed from -+ * zone root records in zone register. -+ * 2) After each change notification compare the old and new SOA serials -+ * and recomputed digests. If: -+ * 3a) Nothing was changed (false change notification received) - do nothing -+ * 3b) Serial was changed - remember the new serial and recompute digest, -+ * do not autoincrement (respect external change). -+ * 3c) The old and new serials are same: autoincrement only if something -+ * else was changed. -+ */ - if (inst->serial_autoincrement) { - CHECK(ldap_get_zone_serial(inst, &name, &ldap_serial)); -- CHECK(zr_get_zone_serial(inst->zone_register, &name, &zr_serial)); -- if (ldap_serial == zr_serial) -- CHECK(soa_serial_increment(inst->mctx, inst, &name)); -- else -- CHECK(zr_set_zone_serial(inst->zone_register, &name, ldap_serial)); -+ CHECK(ldapdb_rdatalist_get(inst->mctx, inst, &name, -+ &name, &rdatalist)); -+ CHECK(rdatalist_digest(inst->mctx, &rdatalist, ldap_digest)); -+ -+ CHECK(zr_get_zone_serial_digest(inst->zone_register, &name, &zr_serial, -+ &zr_digest)); -+ if (ldap_serial == zr_serial) { -+ /* serials are same - increment only if something was changed */ -+ if (memcmp(zr_digest, ldap_digest, RDLIST_DIGESTLENGTH) != 0) -+ CHECK(soa_serial_increment(inst->mctx, inst, &name)); -+ } else { /* serial in LDAP was changed - update zone register */ -+ CHECK(zr_set_zone_serial_digest(inst->zone_register, &name, -+ ldap_serial, ldap_digest)); -+ } - } - - cleanup: -@@ -1122,6 +1148,7 @@ cleanup: - dns_name_free(&name, inst->mctx); - if (zone != NULL) - dns_zone_detach(&zone); -+ ldapdb_rdatalist_destroy(inst->mctx, &rdatalist); - - return result; - } -diff --git a/src/rdlist.c b/src/rdlist.c -index 903c948..a16de45 100644 ---- a/src/rdlist.c -+++ b/src/rdlist.c -@@ -2,7 +2,7 @@ - * Authors: Adam Tkac - * Martin Nagy - * -- * Copyright (C) 2009 Red Hat -+ * Copyright (C) 2009-2012 Red Hat - * see file 'COPYING' for use and warranty information - * - * This program is free software; you can redistribute it and/or -@@ -22,17 +22,27 @@ - #include - #include - #include -+#include -+#include - - #include - #include - - #include -+#include - - #include "ldap_helper.h" /* TODO: Move things from ldap_helper here? */ - #include "rdlist.h" - #include "util.h" - - -+/* useful only for RR sorting purposes */ -+typedef struct rr_sort rr_sort_t; -+struct rr_sort { -+ dns_rdatalist_t *rdatalist; /* contains RR class, type, TTL */ -+ isc_region_t rdatareg; /* handle to binary area with RR data */ -+}; -+ - static isc_result_t - rdata_clone(isc_mem_t *mctx, dns_rdata_t *source, dns_rdata_t **targetp) - { -@@ -106,6 +116,121 @@ cleanup: - return result; - } - -+unsigned int -+rdatalist_length(const dns_rdatalist_t *rdlist) -+{ -+ dns_rdata_t *ptr = HEAD(rdlist->rdata); -+ unsigned int length = 0; -+ -+ while (ptr != NULL) { -+ length++; -+ ptr = NEXT(ptr, link); -+ } -+ -+ return length; -+} -+ -+static int -+rr_sort_compare(const void *rdl1, const void *rdl2) { -+ const rr_sort_t *r1 = rdl1; -+ const rr_sort_t *r2 = rdl2; -+ int res; -+ -+ res = r1->rdatalist->rdclass - r2->rdatalist->rdclass; -+ if (res != 0) -+ return res; -+ -+ res = r1->rdatalist->type - r2->rdatalist->type; -+ if (res != 0) -+ return res; -+ -+ res = r1->rdatalist->ttl - r2->rdatalist->ttl; -+ if (res != 0) -+ return res; -+ -+ res = isc_region_compare((isc_region_t *)&r1->rdatareg, -+ (isc_region_t *)&r2->rdatareg); -+ -+ return res; -+} -+ -+/** -+ * Compute MD5 digest from all resource records in input rrdatalist. -+ * All RRs are sorted by class, type, ttl and data respectively. For this reason -+ * digest should be unambigous. -+ * -+ * @param rdlist[in] List of RRsets. Each RRset contains a list of individual RR -+ * @param digest[out] Pointer to unsigned char[RDLIST_DIGESTLENGTH] array -+ * @return ISC_R_SUCCESS and MD5 digest in unsigned char array "digest" -+ * In case of any error the array will stay untouched. -+ */ -+isc_result_t -+rdatalist_digest(isc_mem_t *mctx, ldapdb_rdatalist_t *rdlist, -+ unsigned char *digest) { -+ isc_result_t result; -+ isc_buffer_t *rrs = NULL; /* array of all resource records from input rdlist */ -+ unsigned int rrs_len = 0; -+ isc_md5_t md5ctx; -+ -+ REQUIRE(rdlist != NULL); -+ REQUIRE(digest != NULL); -+ -+ /* Compute count of RRs to avoid dynamic reallocations. -+ * The count is expected to be small number (< 20). */ -+ for (dns_rdatalist_t *rrset = HEAD(*rdlist); -+ rrset != NULL; -+ rrset = NEXT(rrset, link)) { -+ -+ rrs_len += rdatalist_length(rrset); -+ } -+ CHECK(isc_buffer_allocate(mctx, &rrs, rrs_len*sizeof(rr_sort_t))); -+ -+ /* Fill each rr_sort structure in array rrs with pointer to RRset -+ * and coresponding data region from each RR. rrs array will be sorted. */ -+ for (dns_rdatalist_t *rrset = HEAD(*rdlist); -+ rrset != NULL; -+ rrset = NEXT(rrset, link)) { -+ -+ for (dns_rdata_t *rr = HEAD(rrset->rdata); -+ rr != NULL; -+ rr = NEXT(rr, link)) { -+ -+ rr_sort_t rr_sort_rec; -+ rr_sort_rec.rdatalist = rrset; -+ dns_rdata_toregion(rr, &rr_sort_rec.rdatareg); -+ -+ isc_buffer_putmem(rrs, (const unsigned char *)(&rr_sort_rec), -+ sizeof(rr_sort_t)); -+ } -+ } -+ qsort(isc_buffer_base(rrs), rrs_len, sizeof(rr_sort_t), rr_sort_compare); -+ -+ isc_md5_init(&md5ctx); -+ for (unsigned int i = 0; i < rrs_len; i++ ) { -+ rr_sort_t *rr_rec = (rr_sort_t *)isc_buffer_base(rrs) + i; -+ isc_md5_update(&md5ctx, -+ (const unsigned char *)&rr_rec->rdatalist->rdclass, -+ sizeof(rr_rec->rdatalist->rdclass)); -+ isc_md5_update(&md5ctx, -+ (const unsigned char *)&rr_rec->rdatalist->type, -+ sizeof(rr_rec->rdatalist->type)); -+ isc_md5_update(&md5ctx, -+ (const unsigned char *)&rr_rec->rdatalist->ttl, -+ sizeof(rr_rec->rdatalist->ttl)); -+ isc_md5_update(&md5ctx, -+ (const unsigned char *)(rr_rec->rdatareg.base), -+ rr_rec->rdatareg.length); -+ } -+ isc_md5_final(&md5ctx, digest); -+ isc_md5_invalidate(&md5ctx); -+ -+cleanup: -+ if (rrs != NULL) -+ isc_buffer_free(&rrs); -+ -+ return result; -+} -+ - isc_result_t - ldap_rdatalist_copy(isc_mem_t *mctx, ldapdb_rdatalist_t source, - ldapdb_rdatalist_t *target) -diff --git a/src/rdlist.h b/src/rdlist.h -index 04b9915..465197a 100644 ---- a/src/rdlist.h -+++ b/src/rdlist.h -@@ -22,6 +22,12 @@ - #ifndef _LD_RDLIST_H_ - #define _LD_RDLIST_H_ - -+#include -+ -+#include "types.h" -+ -+#define RDLIST_DIGESTLENGTH ISC_MD5_DIGESTLENGTH -+ - isc_result_t - rdatalist_clone(isc_mem_t *mctx, dns_rdatalist_t *source, - dns_rdatalist_t **targetp); -@@ -30,4 +36,11 @@ isc_result_t - ldap_rdatalist_copy(isc_mem_t *mctx, ldapdb_rdatalist_t source, - ldapdb_rdatalist_t *target); - -+unsigned int -+rdatalist_length(const dns_rdatalist_t *rdlist); -+ -+isc_result_t -+rdatalist_digest(isc_mem_t *mctx, ldapdb_rdatalist_t *rdlist, -+ unsigned char *digest); -+ - #endif /* !_LD_RDLIST_H_ */ -diff --git a/src/zone_register.c b/src/zone_register.c -index 1de6bf1..b2b938f 100644 ---- a/src/zone_register.c -+++ b/src/zone_register.c -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -31,6 +32,7 @@ - #include "log.h" - #include "util.h" - #include "zone_register.h" -+#include "rdlist.h" - - /* - * The zone register is a red-black tree that maps a dns name of a zone to the -@@ -51,6 +53,7 @@ typedef struct { - dns_zone_t *zone; - char *dn; - isc_uint32_t serial; /* last value processed by plugin (!= value in DB) */ -+ unsigned char digest[RDLIST_DIGESTLENGTH]; /* MD5 digest from all RRs in zone record */ - } zone_info_t; - - /* Callback for dns_rbt_create(). */ -@@ -316,17 +319,19 @@ zr_get_zone_ptr(zone_register_t *zr, dns_name_t *name, dns_zone_t **zonep) - } - - /** -- * Return last SOA serial value processed by autoincrement feature. -+ * Return last values processed by autoincrement feature. - */ - isc_result_t --zr_get_zone_serial(zone_register_t *zr, dns_name_t *name, isc_uint32_t *serialp) -+zr_get_zone_serial_digest(zone_register_t *zr, dns_name_t *name, -+ isc_uint32_t *serialp, unsigned char ** digestp) - { - isc_result_t result; -- void *zinfo = NULL; -+ zone_info_t *zinfo = NULL; - - REQUIRE(zr != NULL); - REQUIRE(name != NULL); - REQUIRE(serialp != NULL); -+ REQUIRE(digestp != NULL && *digestp == NULL); - - if (!dns_name_isabsolute(name)) { - log_bug("trying to find zone with a relative name"); -@@ -335,9 +340,11 @@ zr_get_zone_serial(zone_register_t *zr, dns_name_t *name, isc_uint32_t *serialp) - - RWLOCK(&zr->rwlock, isc_rwlocktype_read); - -- result = dns_rbt_findname(zr->rbt, name, 0, NULL, &zinfo); -- if (result == ISC_R_SUCCESS) -- *serialp = ((zone_info_t *)zinfo)->serial; -+ result = dns_rbt_findname(zr->rbt, name, 0, NULL, (void *)&zinfo); -+ if (result == ISC_R_SUCCESS) { -+ *serialp = zinfo->serial; -+ *digestp = zinfo->digest; -+ } - - RWUNLOCK(&zr->rwlock, isc_rwlocktype_read); - -@@ -345,16 +352,18 @@ zr_get_zone_serial(zone_register_t *zr, dns_name_t *name, isc_uint32_t *serialp) - } - - /** -- * Set last SOA serial value processed by autoincrement feature. -+ * Set last SOA serial and digest from RRs processed by autoincrement feature. - */ - isc_result_t --zr_set_zone_serial(zone_register_t *zr, dns_name_t *name, isc_uint32_t serial) -+zr_set_zone_serial_digest(zone_register_t *zr, dns_name_t *name, -+ isc_uint32_t serial, unsigned char *digest) - { - isc_result_t result; -- void *zinfo = NULL; -+ zone_info_t *zinfo = NULL; - - REQUIRE(zr != NULL); - REQUIRE(name != NULL); -+ REQUIRE(digest != NULL); - - if (!dns_name_isabsolute(name)) { - log_bug("trying to find zone with a relative name"); -@@ -363,9 +372,11 @@ zr_set_zone_serial(zone_register_t *zr, dns_name_t *name, isc_uint32_t serial) - - RWLOCK(&zr->rwlock, isc_rwlocktype_read); - -- result = dns_rbt_findname(zr->rbt, name, 0, NULL, &zinfo); -- if (result == ISC_R_SUCCESS) -- ((zone_info_t *)zinfo)->serial = serial; -+ result = dns_rbt_findname(zr->rbt, name, 0, NULL, (void *)&zinfo); -+ if (result == ISC_R_SUCCESS) { -+ zinfo->serial = serial; -+ memcpy(zinfo->digest, digest, RDLIST_DIGESTLENGTH); -+ } - - RWUNLOCK(&zr->rwlock, isc_rwlocktype_read); - -diff --git a/src/zone_register.h b/src/zone_register.h -index 6ac3a92..dea2c9d 100644 ---- a/src/zone_register.h -+++ b/src/zone_register.h -@@ -49,9 +49,11 @@ isc_mem_t * - zr_get_mctx(zone_register_t *zr); - - isc_result_t --zr_set_zone_serial(zone_register_t *zr, dns_name_t *name, isc_uint32_t serial); -+zr_set_zone_serial_digest(zone_register_t *zr, dns_name_t *name, -+ isc_uint32_t serial, unsigned char *digest); - - isc_result_t --zr_get_zone_serial(zone_register_t *zr, dns_name_t *name, isc_uint32_t *serialp); -+zr_get_zone_serial_digest(zone_register_t *zr, dns_name_t *name, -+ isc_uint32_t *serialp, unsigned char ** digestp); - - #endif /* !_LD_ZONE_REGISTER_H_ */ --- -1.7.11.2 - - -From 93ae7491a80ba8c4789f8770e14c053b67176de4 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Wed, 11 Jul 2012 15:04:50 +0200 -Subject: [PATCH 15/32] Add documention for serial_autoincrement feature. - -Signed-off-by: Petr Spacek ---- - README | 18 ++++++++++++++++++ - 1 file changed, 18 insertions(+) - -diff --git a/README b/README -index 08badc5..7539e76 100644 ---- a/README -+++ b/README -@@ -221,6 +221,24 @@ ldap_hostname (default "") - is used and named service has Kerberos principal different from - /bin/hostname output. - -+serial_autoincrement (default no) -+ Automatically increment SOA serial number after each change in LDAP. -+ External changes done by other LDAP clients are detected with -+ persistent search. -+ -+ If serial number is lower than current UNIX timestamp, then -+ it is set to the timestamp value. If SOA serial is greater or equal -+ to current timestamp, then the serial is incremented by one. -+ -+ In multi-master LDAP environments it is recommended to make -+ idnsSOAserial attribute non-replicated (locally significant). -+ It is recommended to not use multiple masters for single slave zone -+ if SOA serial is locally significant. Serial numbers between masters -+ aren't synchronized. It will cause problems with zone transfers from -+ multiple masters. -+ -+ This function requires persistent search and 4 connections at least. -+ - sync_ptr (default no) - Set this option to "yes" if you would like to keep PTR record - synchronized with coresponding A/AAAA record for all zones. --- -1.7.11.2 - - -From d673f5b54132a14798ec8a355be6cf4911fe10d1 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Wed, 11 Jul 2012 12:10:16 +0200 -Subject: [PATCH 16/32] Prevent doubled LDAP queries during nonexistent DNS - name lookups. This problem was introduced in commit - cd33194c5a61e98cba53212458cce02b849077ba - (CVE-2012-2134 fix). - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 0b1ed73..9ae3c80 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -1697,6 +1697,7 @@ ldap_query(ldap_instance_t *ldap_inst, ldap_connection_t *ldap_conn, - ldap_qresult_t *ldap_qresult = NULL; - int cnt; - int ret; -+ int ldap_err_code; - int once = 0; - - REQUIRE(ldap_conn != NULL); -@@ -1743,8 +1744,12 @@ retry: - return ISC_R_SUCCESS; - } - -+ ret = ldap_get_option(ldap_conn->handle, LDAP_OPT_RESULT_CODE, -+ (void *)&ldap_err_code); -+ if (ret == LDAP_OPT_SUCCESS && ldap_err_code == LDAP_NO_SUCH_OBJECT) -+ return ISC_R_NOTFOUND; - /* some error happened during ldap_search, try to recover */ -- if (!once) { -+ else if (!once) { - once++; - result = handle_connection_error(ldap_inst, ldap_conn, - ISC_FALSE); --- -1.7.11.2 - - -From e44ce4d9c42ad9b1226cea5b62e9040f2d7e4df2 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Thu, 12 Jul 2012 17:10:58 +0200 -Subject: [PATCH 17/32] Prevent crashes in ldap_pool_*() function family. - -https://fedorahosted.org/bind-dyndb-ldap/ticket/84 - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 18 +++++++++++------- - 1 file changed, 11 insertions(+), 7 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 9ae3c80..8015db7 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -555,6 +555,7 @@ destroy_ldap_instance(ldap_instance_t **ldap_instp) - - dns_rbtnodechain_invalidate(&chain); - -+ /* TODO: Terminate psearch watcher sooner? */ - if (ldap_inst->psearch && ldap_inst->watcher != 0) { - ldap_inst->exiting = ISC_TRUE; - /* -@@ -645,9 +646,12 @@ destroy_ldap_connection(ldap_pool_t *pool, ldap_connection_t **ldap_connp) - { - ldap_connection_t *ldap_conn; - -- REQUIRE(ldap_connp != NULL && *ldap_connp != NULL); -+ REQUIRE(ldap_connp != NULL); - - ldap_conn = *ldap_connp; -+ if (ldap_conn == NULL) -+ return; -+ - DESTROYLOCK(&ldap_conn->lock); - if (ldap_conn->handle != NULL) - ldap_unbind_ext_s(ldap_conn->handle, NULL, NULL); -@@ -2676,8 +2680,7 @@ ldap_pool_create(isc_mem_t *mctx, unsigned int connections, ldap_pool_t **poolp) - return ISC_R_SUCCESS; - - cleanup: -- if (pool != NULL) -- ldap_pool_destroy(&pool); -+ ldap_pool_destroy(&pool); - return result; - } - static void -@@ -2687,9 +2690,11 @@ ldap_pool_destroy(ldap_pool_t **poolp) - ldap_connection_t *ldap_conn; - unsigned int i; - -- REQUIRE(poolp != NULL && *poolp != NULL); -+ REQUIRE(poolp != NULL); - - pool = *poolp; -+ if (pool == NULL) -+ return; - - for (i = 0; i < pool->connections; i++) { - ldap_conn = pool->conns[i]; -@@ -2703,6 +2708,7 @@ ldap_pool_destroy(ldap_pool_t **poolp) - semaphore_destroy(&pool->conn_semaphore); - - MEM_PUT_AND_DETACH(pool); -+ *poolp = NULL; - } - - static isc_result_t -@@ -2774,9 +2780,7 @@ ldap_pool_connect(ldap_pool_t *pool, ldap_instance_t *ldap_inst) - - cleanup: - for (i = 0; i < pool->connections; i++) { -- ldap_conn = pool->conns[i]; -- if (ldap_conn != NULL) -- destroy_ldap_connection(pool, &ldap_conn); -+ destroy_ldap_connection(pool, &pool->conns[i]); - } - return result; - } --- -1.7.11.2 - - -From 640511903fb2cde66dfd759a14f2fab69554f48e Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Wed, 18 Jul 2012 14:32:48 +0200 -Subject: [PATCH 18/32] Add missing return value check to new_ldap_instance(). - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 8015db7..4fd5fa2 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -454,7 +454,8 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, - result = ISC_R_FAILURE; - goto cleanup; - } else { -- str_sprintf(ldap_inst->krb5_principal, "DNS/%s", hostname); -+ CHECK(str_sprintf(ldap_inst->krb5_principal, -+ "DNS/%s", hostname)); - log_debug(2, "SASL mech GSSAPI defined but krb5_principal" - "and sasl_user are empty, using default %s", - str_buf(ldap_inst->krb5_principal)); --- -1.7.11.2 - - -From 0f27c0743ca0dcb6f1f4e8d2bd3e0b6157296e59 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Wed, 18 Jul 2012 13:39:12 +0200 -Subject: [PATCH 19/32] Raise connection count automatically if - serial_autoincrement is enabled. - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 4fd5fa2..f21c449 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -481,6 +481,12 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, - result = ISC_R_FAILURE; - goto cleanup; - } -+ if (ldap_inst->serial_autoincrement == ISC_TRUE -+ && ldap_inst->connections < 4) { -+ log_error("serial_autoincrement needs at least 4 connections, " -+ "increasing limit"); -+ ldap_inst->connections = 4; -+ } - - CHECK(new_ldap_cache(mctx, argv, &ldap_inst->cache, ldap_inst->psearch)); - CHECK(ldap_pool_create(mctx, ldap_inst->connections, &ldap_inst->pool)); --- -1.7.11.2 - - -From 2d9e71d47997cd75635412cd81349692a8cac1c2 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Wed, 18 Jul 2012 13:01:28 +0200 -Subject: [PATCH 20/32] Add support for modify DN operation to persistent - search. - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 108 ++++++++++++++++++++++++++++++++++++++++++++---------- - 1 file changed, 89 insertions(+), 19 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index f21c449..baf26b2 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -239,6 +239,7 @@ struct ldap_psearchevent { - isc_mem_t *mctx; - char *dbname; - char *dn; -+ char *prevdn; - int chgtype; - }; - -@@ -316,6 +317,9 @@ static isc_result_t ldap_pscontrol_create(isc_mem_t *mctx, LDAPControl **ctrlp); - static void ldap_pscontrol_destroy(isc_mem_t *mctx, LDAPControl **ctrlp); - - static isc_threadresult_t ldap_psearch_watcher(isc_threadarg_t arg); -+static void psearch_update(ldap_instance_t *inst, ldap_entry_t *entry, -+ LDAPControl **ctrls); -+ - - /* Persistent updates watcher */ - static isc_threadresult_t -@@ -796,6 +800,7 @@ ldap_delete_zone2(ldap_instance_t *inst, dns_name_t *name, isc_boolean_t lock) - if (result == ISC_R_SUCCESS) - unlock = ISC_TRUE; - -+ /* TODO: flush cache records belonging to deleted zone */ - CHECK(discard_from_cache(inst->cache, name)); - } - -@@ -2964,18 +2969,25 @@ update_action(isc_task_t *task, isc_event_t *event) - isc_result_t result ; - ldap_instance_t *inst = NULL; - ldap_connection_t *conn = NULL; -- ldap_qresult_t *ldap_qresult = NULL; -- ldap_entry_t *entry; -+ ldap_qresult_t *ldap_qresult_zone = NULL; -+ ldap_qresult_t *ldap_qresult_record = NULL; -+ ldap_entry_t *entry_zone = NULL; -+ ldap_entry_t *entry_record = NULL; - isc_boolean_t delete = ISC_TRUE; - isc_mem_t *mctx; -- char *attrs[] = { -+ dns_name_t prevname; -+ char *attrs_zone[] = { - "idnsName", "idnsUpdatePolicy", "idnsAllowQuery", - "idnsAllowTransfer", "idnsForwardPolicy", "idnsForwarders", NULL - }; -+ char *attrs_record[] = { -+ "objectClass", "dn", NULL -+ }; - - UNUSED(task); - - mctx = pevent->mctx; -+ dns_name_init(&prevname, NULL); - - result = manager_get_ldap_instance(pevent->dbname, &inst); - /* TODO: Can it happen? */ -@@ -2983,18 +2995,43 @@ update_action(isc_task_t *task, isc_event_t *event) - goto cleanup; - - CHECK(ldap_pool_getconnection(inst->pool, &conn)); -- -- CHECK(ldap_query(inst, conn, &ldap_qresult, pevent->dn, -- LDAP_SCOPE_BASE, attrs, 0, -+ CHECK(ldap_query(inst, conn, &ldap_qresult_zone, pevent->dn, -+ LDAP_SCOPE_BASE, attrs_zone, 0, - "(&(objectClass=idnsZone)(idnsZoneActive=TRUE))")); - -- for (entry = HEAD(ldap_qresult->ldap_entries); -- entry != NULL; -- entry = NEXT(entry, link)) { -+ for (entry_zone = HEAD(ldap_qresult_zone->ldap_entries); -+ entry_zone != NULL; -+ entry_zone = NEXT(entry_zone, link)) { - delete = ISC_FALSE; - result = ldap_parse_zoneentry(entry, inst); - if (result != ISC_R_SUCCESS) - goto cleanup; -+ -+ if (PSEARCH_MODDN(pevent->chgtype)) { -+ if (dn_to_dnsname(inst->mctx, pevent->prevdn, &prevname, NULL) -+ == ISC_R_SUCCESS) { -+ CHECK(ldap_delete_zone(inst, pevent->prevdn, ISC_TRUE)); -+ } else { -+ log_debug(5, "update_action: old zone wasn't managed " -+ "by plugin, dn '%s'", pevent->prevdn); -+ } -+ -+ /* fill the cache with records from renamed zone */ -+ CHECK(ldap_query(inst, conn, &ldap_qresult_record, pevent->dn, -+ LDAP_SCOPE_ONELEVEL, attrs_record, 0, -+ "(objectClass=idnsRecord)")); -+ -+ /* LDAP schema requires SOA record (at least) */ -+ INSIST(HEAD(ldap_qresult_record->ldap_entries) != NULL); -+ for (entry_record = HEAD(ldap_qresult_record->ldap_entries); -+ entry_record != NULL; -+ entry_record = NEXT(entry_record, link)) { -+ -+ psearch_update(inst, entry_record, NULL); -+ } -+ } -+ -+ INSIST(NEXT(entry_zone, link) == NULL); /* no multiple zones with same DN */ - } - - if (delete) -@@ -3006,9 +3043,14 @@ cleanup: - "Zones can be outdated, run `rndc reload`", - pevent->dn, isc_result_totext(result)); - -- ldap_query_free(ISC_FALSE, &ldap_qresult); -+ ldap_query_free(ISC_FALSE, &ldap_qresult_zone); -+ ldap_query_free(ISC_FALSE, &ldap_qresult_record); - ldap_pool_putconnection(inst->pool, &conn); -+ if (dns_name_dynamic(&prevname)) -+ dns_name_free(&prevname, inst->mctx); - isc_mem_free(mctx, pevent->dbname); -+ if (pevent->prevdn != NULL) -+ isc_mem_free(mctx, pevent->prevdn); - isc_mem_free(mctx, pevent->dn); - isc_mem_detach(&mctx); - isc_event_free(&event); -@@ -3097,8 +3139,12 @@ update_record(isc_task_t *task, isc_event_t *event) - /* Convert domain name from text to struct dns_name_t. */ - dns_name_t name; - dns_name_t origin; -+ dns_name_t prevname; -+ dns_name_t prevorigin; - dns_name_init(&name, NULL); - dns_name_init(&origin, NULL); -+ dns_name_init(&prevname, NULL); -+ dns_name_init(&prevorigin, NULL); - CHECK(dn_to_dnsname(mctx, pevent->dn, &name, &origin)); - - if (PSEARCH_DEL(pevent->chgtype)) { -@@ -3110,8 +3156,21 @@ update_record(isc_task_t *task, isc_event_t *event) - cache = ldap_instance_getcache(inst); - CHECK(discard_from_cache(cache, &name)); - -+ if (PSEARCH_MODDN(pevent->chgtype)) { -+ /* remove previous name only if it was inside DNS subtree */ -+ if(dn_to_dnsname(mctx, pevent->prevdn, &prevname, &prevorigin) -+ == ISC_R_SUCCESS) { -+ log_debug(5, "psearch_update: removing name from cache, dn: '%s'", -+ pevent->prevdn); -+ CHECK(discard_from_cache(cache, &prevname)); -+ } else { -+ log_debug(5, "psearch_update: old name wasn't managed " -+ "by plugin, dn '%s'", pevent->prevdn); -+ } -+ } -+ - if (PSEARCH_ADD(pevent->chgtype) || PSEARCH_MOD(pevent->chgtype) || -- !PSEARCH_ANY(pevent->chgtype)) { -+ PSEARCH_MODDN(pevent->chgtype) || !PSEARCH_ANY(pevent->chgtype)) { - /* - * Find new data in LDAP. !PSEARCH_ANY indicates unchanged entry - * found during initial lookup (i.e. database dump). -@@ -3148,9 +3207,15 @@ cleanup: - - if (dns_name_dynamic(&name)) - dns_name_free(&name, inst->mctx); -+ if (dns_name_dynamic(&prevname)) -+ dns_name_free(&prevname, inst->mctx); - if (dns_name_dynamic(&origin)) - dns_name_free(&origin, inst->mctx); -+ if (dns_name_dynamic(&prevorigin)) -+ dns_name_free(&prevorigin, inst->mctx); - isc_mem_free(mctx, pevent->dbname); -+ if (pevent->prevdn != NULL) -+ isc_mem_free(mctx, pevent->prevdn); - isc_mem_free(mctx, pevent->dn); - isc_mem_detach(&mctx); - isc_event_free(&event); -@@ -3221,8 +3286,9 @@ psearch_update(ldap_instance_t *inst, ldap_entry_t *entry, LDAPControl **ctrls) - isc_result_t result = ISC_R_SUCCESS; - ldap_psearchevent_t *pevent = NULL; - int chgtype = LDAP_ENTRYCHANGE_NONE; -- char *moddn = NULL; - char *dn = NULL; -+ char *prevdn_ldap = NULL; -+ char *prevdn = NULL; - char *dbname = NULL; - isc_mem_t *mctx = NULL; - isc_taskaction_t action = NULL; -@@ -3235,7 +3301,7 @@ psearch_update(ldap_instance_t *inst, ldap_entry_t *entry, LDAPControl **ctrls) - } - - if (ctrls != NULL) -- CHECK(ldap_parse_entrychangectrl(ctrls, &chgtype, &moddn)); -+ CHECK(ldap_parse_entrychangectrl(ctrls, &chgtype, &prevdn_ldap)); - - isc_mem_attach(inst->mctx, &mctx); - -@@ -3250,11 +3316,12 @@ psearch_update(ldap_instance_t *inst, ldap_entry_t *entry, LDAPControl **ctrls) - goto cleanup; - } - -- /* TODO: Handle moddn case. */ - if (PSEARCH_MODDN(chgtype)) { -- log_error("psearch moddn change is not implemented"); -- result = ISC_R_FAILURE; -- goto cleanup; -+ prevdn = isc_mem_strdup(mctx, prevdn_ldap); -+ if (prevdn == NULL) { -+ result = ISC_R_NOMEMORY; -+ goto cleanup; -+ } - } - - /* -@@ -3288,6 +3355,7 @@ psearch_update(ldap_instance_t *inst, ldap_entry_t *entry, LDAPControl **ctrls) - pevent->mctx = mctx; - pevent->dbname = dbname; - pevent->dn = dn; -+ pevent->prevdn = prevdn; - pevent->chgtype = chgtype; - isc_task_send(inst->task, (isc_event_t **)&pevent); - -@@ -3297,10 +3365,12 @@ cleanup: - isc_mem_free(mctx, dbname); - if (dn != NULL) - isc_mem_free(mctx, dn); -+ if (prevdn != NULL) -+ isc_mem_free(mctx, prevdn); - if (mctx != NULL) - isc_mem_detach(&mctx); -- if (moddn != NULL) -- ldap_memfree(moddn); -+ if (prevdn_ldap != NULL) -+ ldap_memfree(prevdn); - - log_error("psearch_update failed for %s zone. " - "Zone can be outdated, run `rndc reload`", --- -1.7.11.2 - - -From 16c402e39e467731422b27a6247e0e222e36586c Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Wed, 18 Jul 2012 13:04:10 +0200 -Subject: [PATCH 21/32] Rename persistent search update_action() to - update_zone(). - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index baf26b2..c00869f 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -2963,7 +2963,7 @@ cleanup: - * operation but zones don't change often. - */ - static void --update_action(isc_task_t *task, isc_event_t *event) -+update_zone(isc_task_t *task, isc_event_t *event) - { - ldap_psearchevent_t *pevent = (ldap_psearchevent_t *)event; - isc_result_t result ; -@@ -3334,7 +3334,7 @@ psearch_update(ldap_instance_t *inst, ldap_entry_t *entry, LDAPControl **ctrls) - if ((class & LDAP_ENTRYCLASS_CONFIG) != 0) - action = update_config; - else if ((class & LDAP_ENTRYCLASS_ZONE) != 0) -- action = update_action; -+ action = update_zone; - else if ((class & LDAP_ENTRYCLASS_RR) != 0) - action = update_record; - else { --- -1.7.11.2 - - -From 4083460acbdce1760aa347ec68abd27d25e1059a Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Wed, 18 Jul 2012 13:05:59 +0200 -Subject: [PATCH 22/32] Minor code cleanup in persistent search error - handling. - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 10 ++-------- - 1 file changed, 2 insertions(+), 8 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index c00869f..5cfa1e1 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -2989,11 +2989,7 @@ update_zone(isc_task_t *task, isc_event_t *event) - mctx = pevent->mctx; - dns_name_init(&prevname, NULL); - -- result = manager_get_ldap_instance(pevent->dbname, &inst); -- /* TODO: Can it happen? */ -- if (result != ISC_R_SUCCESS) -- goto cleanup; -- -+ CHECK(manager_get_ldap_instance(pevent->dbname, &inst)); - CHECK(ldap_pool_getconnection(inst->pool, &conn)); - CHECK(ldap_query(inst, conn, &ldap_qresult_zone, pevent->dn, - LDAP_SCOPE_BASE, attrs_zone, 0, -@@ -3003,9 +2999,7 @@ update_zone(isc_task_t *task, isc_event_t *event) - entry_zone != NULL; - entry_zone = NEXT(entry_zone, link)) { - delete = ISC_FALSE; -- result = ldap_parse_zoneentry(entry, inst); -- if (result != ISC_R_SUCCESS) -- goto cleanup; -+ CHECK(ldap_parse_zoneentry(entry_zone, inst)); - - if (PSEARCH_MODDN(pevent->chgtype)) { - if (dn_to_dnsname(inst->mctx, pevent->prevdn, &prevname, NULL) --- -1.7.11.2 - - -From 6f7fd9c9ed9b9c78c1034972f903e8d41de902a8 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Wed, 18 Jul 2012 13:27:16 +0200 -Subject: [PATCH 23/32] Minor persistent search logging cleanup. - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 21 +++++++++++---------- - 1 file changed, 11 insertions(+), 10 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 5cfa1e1..6ac76fa 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -3141,8 +3141,8 @@ update_record(isc_task_t *task, isc_event_t *event) - dns_name_init(&prevorigin, NULL); - CHECK(dn_to_dnsname(mctx, pevent->dn, &name, &origin)); - -- if (PSEARCH_DEL(pevent->chgtype)) { -- log_debug(5, "psearch_update: Removing item from cache (%s)", -+ if (PSEARCH_DEL(pevent->chgtype) || PSEARCH_MODDN(pevent->chgtype)) { -+ log_debug(5, "psearch_update: removing name from cache, dn: '%s'", - pevent->dn); - } - -@@ -3171,7 +3171,7 @@ update_record(isc_task_t *task, isc_event_t *event) - * - * @todo Change this to convert ldap_entry_t to ldapdb_rdatalist_t. - */ -- log_debug(5, "psearch_update: Updating item in cache (%s)", -+ log_debug(5, "psearch_update: updating name in cache, dn: '%s'", - pevent->dn); - CHECK(ldapdb_rdatalist_get(mctx, inst, &name, &origin, &rdatalist)); - -@@ -3184,18 +3184,13 @@ update_record(isc_task_t *task, isc_event_t *event) - ldapdb_rdatalist_destroy(mctx, &rdatalist); - } - -- log_debug(20,"psearch change type: none%d, add%d, del%d, mod%d, moddn%d", -- !PSEARCH_ANY(pevent->chgtype), PSEARCH_ADD(pevent->chgtype), -- PSEARCH_DEL(pevent->chgtype), PSEARCH_MOD(pevent->chgtype), -- PSEARCH_MODDN(pevent->chgtype)); -- - /* Do not bump serial during initial database dump. */ - if (inst->serial_autoincrement && PSEARCH_ANY(pevent->chgtype)) { - CHECK(soa_serial_increment(mctx, inst, &origin)); - } - cleanup: - if (result != ISC_R_SUCCESS) -- log_error("update_record (psearch) failed for %s. " -+ log_error("update_record (psearch) failed, dn '%s'. " - "Records can be outdated, run `rndc reload`", - pevent->dn); - -@@ -3289,7 +3284,7 @@ psearch_update(ldap_instance_t *inst, ldap_entry_t *entry, LDAPControl **ctrls) - - class = ldap_entry_getclass(entry); - if (class == LDAP_ENTRYCLASS_NONE) { -- log_error("psearch_update: ignoring unknown entry [dn %s]", -+ log_error("psearch_update: ignoring entry with unknown class, dn '%s'", - entry->dn); - return; /* ignore it, it's OK */ - } -@@ -3297,6 +3292,12 @@ psearch_update(ldap_instance_t *inst, ldap_entry_t *entry, LDAPControl **ctrls) - if (ctrls != NULL) - CHECK(ldap_parse_entrychangectrl(ctrls, &chgtype, &prevdn_ldap)); - -+ -+ log_debug(20,"psearch change type: none%d, add%d, del%d, mod%d, moddn%d", -+ !PSEARCH_ANY(chgtype), PSEARCH_ADD(chgtype), -+ PSEARCH_DEL(chgtype), PSEARCH_MOD(chgtype), -+ PSEARCH_MODDN(chgtype)); -+ - isc_mem_attach(inst->mctx, &mctx); - - dn = isc_mem_strdup(mctx, entry->dn); --- -1.7.11.2 - - -From 77c06ea1910a9737bf7e2d9f5c53eeb83827c332 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Fri, 20 Jul 2012 14:18:41 +0200 -Subject: [PATCH 24/32] Fix two memory leaks in ldap_query(). - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 14 ++++++++------ - 1 file changed, 8 insertions(+), 6 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 6ac76fa..daffac7 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -1753,19 +1753,21 @@ retry: - &ldap_qresult->ldap_entries); - if (result != ISC_R_SUCCESS) { - log_error("failed to save LDAP query results"); -- return result; -+ goto cleanup; - } - - *ldap_qresultp = ldap_qresult; - return ISC_R_SUCCESS; -+ } else { -+ result = ISC_R_FAILURE; - } - - ret = ldap_get_option(ldap_conn->handle, LDAP_OPT_RESULT_CODE, - (void *)&ldap_err_code); -- if (ret == LDAP_OPT_SUCCESS && ldap_err_code == LDAP_NO_SUCH_OBJECT) -- return ISC_R_NOTFOUND; -- /* some error happened during ldap_search, try to recover */ -- else if (!once) { -+ if (ret == LDAP_OPT_SUCCESS && ldap_err_code == LDAP_NO_SUCH_OBJECT) { -+ result = ISC_R_NOTFOUND; -+ } else if (!once) { -+ /* some error happened during ldap_search, try to recover */ - once++; - result = handle_connection_error(ldap_inst, ldap_conn, - ISC_FALSE); -@@ -1774,7 +1776,7 @@ retry: - } - cleanup: - ldap_query_free(ISC_FALSE, &ldap_qresult); -- return ISC_R_FAILURE; -+ return result; - } - - /** --- -1.7.11.2 - - -From 85763ded13a2c2a641da4a9bbf0950170a6aecf8 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Wed, 25 Jul 2012 10:07:20 +0200 -Subject: [PATCH 25/32] Handle incomplete/invalid zone unload in same way as - ns_server_del_zone(). - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index daffac7..cc7003a 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -823,7 +823,7 @@ ldap_delete_zone2(ldap_instance_t *inst, dns_name_t *name, isc_boolean_t lock) - - /* Do not unload partially loaded zones, they have incomplete structures. */ - dns_db_t *dbp = NULL; -- if (dns_zone_getdb(zone, &dbp) != DNS_R_NOTLOADED) { -+ if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { - dns_db_detach(&dbp); /* dns_zone_getdb() attaches DB implicitly */ - dns_zone_unload(zone); - } --- -1.7.11.2 - - -From b04dfcbe328a8e713597921f7a43c9c8dd801e63 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Thu, 19 Jul 2012 14:13:12 +0200 -Subject: [PATCH 26/32] Cleanup in logging code. - -Signed-off-by: Petr Spacek ---- - src/log.c | 22 ++-------------------- - src/log.h | 19 ++++++++++++++++--- - 2 files changed, 18 insertions(+), 23 deletions(-) - -diff --git a/src/log.c b/src/log.c -index b23e472..f731df7 100644 ---- a/src/log.c -+++ b/src/log.c -@@ -28,31 +28,13 @@ - #include "log.h" - - void --log_debug(int level, const char *format, ...) -+log_write(int level, const char *format, ...) - { - va_list args; - - va_start(args, format); --#ifdef LOG_AS_ERROR -- UNUSED(level); - isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DYNDB, -- ISC_LOG_ERROR, format, args); --#else -- isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DYNDB, -- ISC_LOG_DEBUG(level), format, args); --#endif -- -- va_end(args); --} -- --void --log_error(const char *format, ...) --{ -- va_list args; -- -- va_start(args, format); -- isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DYNDB, -- ISC_LOG_ERROR, format, args); -+ level, format, args); - va_end(args); - - } -diff --git a/src/log.h b/src/log.h -index 0df4e25..898639b 100644 ---- a/src/log.h -+++ b/src/log.h -@@ -22,6 +22,13 @@ - #define _LD_LOG_H_ - - #include -+#include -+ -+#ifdef LOG_AS_ERROR -+#define GET_LOG_LEVEL(level) ISC_LOG_ERROR -+#else -+#define GET_LOG_LEVEL(level) (level) -+#endif - - #define fatal_error(...) \ - isc_error_fatal(__FILE__, __LINE__, __VA_ARGS__) -@@ -30,10 +37,16 @@ - log_error("bug in %s(): " fmt, __func__,##__VA_ARGS__) - - #define log_error_r(fmt, ...) \ -- log_error(fmt ": %s", ##__VA_ARGS__, isc_result_totext(result)) -+ log_error(fmt ": %s", ##__VA_ARGS__, dns_result_totext(result)) - - /* Basic logging functions */ --void log_debug(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3); --void log_error(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); -+#define log_error(format, ...) \ -+ log_write(GET_LOG_LEVEL(ISC_LOG_ERROR), format, ##__VA_ARGS__) -+ -+#define log_debug(level, format, ...) \ -+ log_write(GET_LOG_LEVEL(level), format, ##__VA_ARGS__) -+ -+void -+log_write(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3); - - #endif /* !_LD_LOG_H_ */ --- -1.7.11.2 - - -From f345805c73c294db42452ae966c48fbc36c48006 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Fri, 20 Jul 2012 14:55:43 +0200 -Subject: [PATCH 27/32] Fix and harden DNS-to-LDAP name conversion. Fixes - CVE-2012-3429. - -Signed-off-by: Petr Spacek ---- - src/ldap_convert.c | 44 +++++++++++++++++++++++++++++++++----------- - 1 file changed, 33 insertions(+), 11 deletions(-) - -diff --git a/src/ldap_convert.c b/src/ldap_convert.c -index 6b4e321..3352c57 100644 ---- a/src/ldap_convert.c -+++ b/src/ldap_convert.c -@@ -192,16 +192,23 @@ cleanup: - } - - /** -+ * WARNING! This function is used to mangle input from network -+ * and it is security sensitive. -+ * - * Convert a string from DNS escaping to LDAP escaping. - * The Input string dns_str is expected to be the result of dns_name_tostring(). - * The DNS label can contain any binary data as described in - * http://tools.ietf.org/html/rfc2181#section-11 . - * -- * DNS escaping uses form "\123" = ASCII value 123 (decimal) -+ * DNS escaping uses 2 forms: (see dns_name_totext2() in bind/lib/dns/name.c) -+ * form "\123" = ASCII value 123 (decimal) -+ * form "\$" = character '$' is escaped with '\' -+ * WARNING! Some characters are not escaped at all (e.g. ','). -+ * - * LDAP escaping users form "\7b" = ASCII value 7b (hexadecimal) - * -- * Input (DNS escaped) example : _aaa,bbb\255\000ccc.555.ddd-eee -- * Output (LDAP escaped) example: _aaa\2cbbb\ff\00ccc.555.ddd-eee -+ * Input (DNS escaped) example: \$.\255_aaa,bbb\127\000ccc.555.ddd-eee -+ * Output (LDAP escaped) example: \24.\ff_aaa\2cbbb\7f\00ccc.555.ddd-eee - * - * The DNS to text functions from ISC libraries do not convert certain - * characters (e.g. ","). This function converts \123 form to \7b form in all -@@ -248,13 +255,23 @@ dns_to_ldap_dn_escape(isc_mem_t *mctx, const char const * dns_str, char ** ldap_ - } - if (dns_str[dns_idx] != '\\') { /* not nice raw value, e.g. ',' */ - ascii_val = dns_str[dns_idx]; -- } else { /* not nice value in DNS \123 decimal format */ -- /* check if input length <= expected size */ -- REQUIRE (dns_str_len > dns_idx + 3); /* this problem should never happen */ -- ascii_val = 100 * (dns_str[dns_idx + 1] - '0') -- + 10 * (dns_str[dns_idx + 2] - '0') -- + (dns_str[dns_idx + 3] - '0'); -- dns_idx += 3; -+ } else { /* DNS escaped value, it starts with '\' */ -+ if (!(dns_idx + 1 < dns_str_len)) { -+ CHECK(DNS_R_BADESCAPE); /* this problem should never happen */ -+ } -+ if (isdigit(dns_str[dns_idx + 1])) { /* \123 decimal format */ -+ /* check if input length <= expected size */ -+ if (!(dns_idx + 3 < dns_str_len)) { -+ CHECK(DNS_R_BADESCAPE); /* this problem should never happen */ -+ } -+ ascii_val = 100 * (dns_str[dns_idx + 1] - '0') -+ + 10 * (dns_str[dns_idx + 2] - '0') -+ + (dns_str[dns_idx + 3] - '0'); -+ dns_idx += 3; -+ } else { /* \$ single char format */ -+ ascii_val = dns_str[dns_idx + 1]; -+ dns_idx += 1; -+ } - } - /* LDAP uses \xy escaping. "xy" represent two hexadecimal digits.*/ - /* TODO: optimize to bit mask & rotate & dec->hex table? */ -@@ -272,8 +289,13 @@ dns_to_ldap_dn_escape(isc_mem_t *mctx, const char const * dns_str, char ** ldap_ - return ISC_R_SUCCESS; - - cleanup: -- if (*ldap_name) -+ if (result == DNS_R_BADESCAPE) -+ log_bug("improperly escaped DNS string: '%s'", dns_str); -+ -+ if (*ldap_name) { - isc_mem_free(mctx, *ldap_name); -+ *ldap_name = NULL; -+ } - return result; - } - --- -1.7.11.2 - - -From a116dccbbf652f1ace443d3eb3fc7dde793acf13 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Mon, 30 Jul 2012 19:39:14 +0200 -Subject: [PATCH 28/32] Fix zone transfers with non-FQDNs. - -https://fedorahosted.org/bind-dyndb-ldap/ticket/47 - -Signed-off-by: Petr Spacek ---- - src/ldap_driver.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/ldap_driver.c b/src/ldap_driver.c -index cae45d4..d958d15 100644 ---- a/src/ldap_driver.c -+++ b/src/ldap_driver.c -@@ -689,7 +689,7 @@ createiterator(dns_db_t *db, - - ldapdb_t *ldapdb = (ldapdb_t *) db; - result = ldapdb_nodelist_get(ldapdb->common.mctx, ldapdb->ldap_inst, -- &ldapdb->common.origin, NULL, -+ &ldapdb->common.origin, &ldapdb->common.origin, - &ldapiter->nodelist); - - *iteratorp = (dns_dbiterator_t *) ldapiter; --- -1.7.11.2 - - -From 815f075d3dd36fa44c59300361e02e5a61caaa51 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Fri, 27 Jul 2012 14:18:15 +0200 -Subject: [PATCH 29/32] Extend API to be compatible with libdns interface >= - 90. - -Signed-off-by: Petr Spacek ---- - src/ldap_driver.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/src/ldap_driver.c b/src/ldap_driver.c -index d958d15..6db291f 100644 ---- a/src/ldap_driver.c -+++ b/src/ldap_driver.c -@@ -1213,8 +1213,12 @@ static dns_dbmethods_t ldapdb_methods = { - #endif /* LIBDNS_VERSION_MAJOR >= 45 */ - #if LIBDNS_VERSION_MAJOR >= 82 - NULL, /* rpz_enabled */ -- NULL /* rpz_findips */ -+ NULL, /* rpz_findips */ - #endif /* LIBDNS_VERSION_MAJOR >= 82 */ -+#if LIBDNS_VERSION_MAJOR >= 90 -+ NULL, /* findnodeext */ -+ NULL /* findext */ -+#endif /* LIBDNS_VERSION_MAJOR >= 90 */ - }; - - static isc_result_t --- -1.7.11.2 - - -From b2b5fc80b0ae472be40d4c5096aa9adcd8222922 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Fri, 27 Jul 2012 14:58:22 +0200 -Subject: [PATCH 30/32] Fix and comment ispersistent() call in LDAP driver - interface. - -Signed-off-by: Petr Spacek ---- - src/ldap_driver.c | 15 ++++++++++++++- - 1 file changed, 14 insertions(+), 1 deletion(-) - -diff --git a/src/ldap_driver.c b/src/ldap_driver.c -index 6db291f..b10aa00 100644 ---- a/src/ldap_driver.c -+++ b/src/ldap_driver.c -@@ -309,6 +309,11 @@ free_ldapdb(ldapdb_t *ldapdb) - isc_mem_putanddetach(&ldapdb->common.mctx, ldapdb, sizeof(*ldapdb)); - } - -+ -+/** -+ * This method should never be called, because LDAP DB is "persistent". -+ * See ispersistent() function. -+ */ - static isc_result_t - beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) - { -@@ -323,6 +328,10 @@ beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) - return ISC_R_SUCCESS; - } - -+/** -+ * This method should never be called, because LDAP DB is "persistent". -+ * See ispersistent() function. -+ */ - static isc_result_t - endload(dns_db_t *db, dns_dbload_t **dbloadp) - { -@@ -1114,12 +1123,16 @@ nodecount(dns_db_t *db) - return ISC_R_NOTIMPLEMENTED; - } - -+/** -+ * Return TRUE, because database does not need to be loaded from disk -+ * or written to disk. -+ */ - static isc_boolean_t - ispersistent(dns_db_t *db) - { - UNUSED(db); - -- return ISC_R_NOTIMPLEMENTED; -+ return ISC_TRUE; - } - - static void --- -1.7.11.2 - - -From ce547f03a86fbbcdb2db0629da615f04a35579b8 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Tue, 31 Jul 2012 14:33:53 +0200 -Subject: [PATCH 31/32] Separate RR data parsing from LDAP connections. - -Signed-off-by: Petr Spacek ---- - src/ldap_helper.c | 78 ++++++++++++++++++++++++++++++------------------------- - 1 file changed, 42 insertions(+), 36 deletions(-) - -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index cc7003a..3fded5b 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -196,11 +196,6 @@ struct ldap_connection { - LDAPControl *serverctrls[2]; /* psearch/NULL or NULL/NULL */ - int msgid; - -- /* Parsing. */ -- isc_lex_t *lex; -- isc_buffer_t rdata_target; -- unsigned char *rdata_target_mem; -- - /* For reconnection logic. */ - isc_time_t next_reconnect; - unsigned int tries; -@@ -214,6 +209,11 @@ struct ldap_qresult { - ld_string_t *query_string; - LDAPMessage *result; - ldap_entrylist_t ldap_entries; -+ -+ /* Parsing. */ -+ isc_lex_t *lex; -+ isc_buffer_t rdata_target; -+ unsigned char *rdata_target_mem; - }; - - /* -@@ -256,15 +256,15 @@ static void destroy_ldap_connection(ldap_pool_t *pool, - static isc_result_t findrdatatype_or_create(isc_mem_t *mctx, - ldapdb_rdatalist_t *rdatalist, dns_rdataclass_t rdclass, - dns_rdatatype_t rdtype, dns_ttl_t ttl, dns_rdatalist_t **rdlistp); --static isc_result_t add_soa_record(isc_mem_t *mctx, ldap_connection_t *ldap_conn, -+static isc_result_t add_soa_record(isc_mem_t *mctx, ldap_qresult_t *qresult, - dns_name_t *origin, ldap_entry_t *entry, - ldapdb_rdatalist_t *rdatalist, const ld_string_t *fake_mname); --static isc_result_t parse_rdata(isc_mem_t *mctx, ldap_connection_t *ldap_conn, -+static isc_result_t parse_rdata(isc_mem_t *mctx, ldap_qresult_t *qresult, - dns_rdataclass_t rdclass, dns_rdatatype_t rdtype, - dns_name_t *origin, const char *rdata_text, - dns_rdata_t **rdatap); - static isc_result_t ldap_parse_rrentry(isc_mem_t *mctx, ldap_entry_t *entry, -- ldap_connection_t *conn, dns_name_t *origin, -+ ldap_qresult_t *qresult, dns_name_t *origin, - const ld_string_t *fake_mname, ld_string_t *buf, - ldapdb_rdatalist_t *rdatalist); - static inline isc_result_t ldap_get_zone_serial(ldap_instance_t *inst, -@@ -637,8 +637,6 @@ new_ldap_connection(ldap_pool_t *pool, ldap_connection_t **ldap_connp) - - isc_mem_attach(pool->mctx, &ldap_conn->mctx); - -- CHECK(isc_lex_create(ldap_conn->mctx, TOKENSIZ, &ldap_conn->lex)); -- CHECKED_MEM_GET(ldap_conn->mctx, ldap_conn->rdata_target_mem, MINTSIZ); - CHECK(ldap_pscontrol_create(ldap_conn->mctx, - &ldap_conn->serverctrls[0])); - -@@ -667,12 +665,6 @@ destroy_ldap_connection(ldap_pool_t *pool, ldap_connection_t **ldap_connp) - if (ldap_conn->handle != NULL) - ldap_unbind_ext_s(ldap_conn->handle, NULL, NULL); - -- if (ldap_conn->lex != NULL) -- isc_lex_destroy(&ldap_conn->lex); -- if (ldap_conn->rdata_target_mem != NULL) { -- isc_mem_put(ldap_conn->mctx, -- ldap_conn->rdata_target_mem, MINTSIZ); -- } - if (ldap_conn->serverctrls[0] != NULL) { - ldap_pscontrol_destroy(ldap_conn->mctx, - &ldap_conn->serverctrls[0]); -@@ -1431,7 +1423,7 @@ free_rdatalist(isc_mem_t *mctx, dns_rdatalist_t *rdlist) - - static isc_result_t - ldap_parse_rrentry(isc_mem_t *mctx, ldap_entry_t *entry, -- ldap_connection_t *conn, dns_name_t *origin, -+ ldap_qresult_t *qresult, dns_name_t *origin, - const ld_string_t *fake_mname, ld_string_t *buf, - ldapdb_rdatalist_t *rdatalist) - { -@@ -1443,7 +1435,7 @@ ldap_parse_rrentry(isc_mem_t *mctx, ldap_entry_t *entry, - dns_rdatalist_t *rdlist = NULL; - ldap_attribute_t *attr; - -- result = add_soa_record(mctx, conn, origin, entry, -+ result = add_soa_record(mctx, qresult, origin, entry, - rdatalist, fake_mname); - if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) - goto cleanup; -@@ -1458,7 +1450,7 @@ ldap_parse_rrentry(isc_mem_t *mctx, ldap_entry_t *entry, - CHECK(findrdatatype_or_create(mctx, rdatalist, rdclass, - rdtype, ttl, &rdlist)); - while (ldap_attr_nextvalue(attr, buf) != NULL) { -- CHECK(parse_rdata(mctx, conn, rdclass, -+ CHECK(parse_rdata(mctx, qresult, rdclass, - rdtype, origin, - str_buf(buf), &rdata)); - APPEND(rdlist->rdata, rdata, link); -@@ -1518,7 +1510,7 @@ ldapdb_nodelist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *nam - result = ldapdbnode_create(mctx, &node_name, &node); - dns_name_free(&node_name, mctx); - if (result == ISC_R_SUCCESS) { -- result = ldap_parse_rrentry(mctx, entry, ldap_conn, -+ result = ldap_parse_rrentry(mctx, entry, ldap_qresult, - origin, ldap_inst->fake_mname, - string, &node->rdatalist); - } -@@ -1584,7 +1576,7 @@ ldapdb_rdatalist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *na - for (entry = HEAD(ldap_qresult->ldap_entries); - entry != NULL; - entry = NEXT(entry, link)) { -- if (ldap_parse_rrentry(mctx, entry, ldap_conn, -+ if (ldap_parse_rrentry(mctx, entry, ldap_qresult, - origin, ldap_inst->fake_mname, - string, rdatalist) != ISC_R_SUCCESS ) { - log_error("Failed to parse RR entry (%s)", str_buf(string)); -@@ -1610,7 +1602,7 @@ cleanup: - } - - static isc_result_t --add_soa_record(isc_mem_t *mctx, ldap_connection_t *ldap_conn, dns_name_t *origin, -+add_soa_record(isc_mem_t *mctx, ldap_qresult_t *qresult, dns_name_t *origin, - ldap_entry_t *entry, ldapdb_rdatalist_t *rdatalist, - const ld_string_t *fake_mname) - { -@@ -1624,7 +1616,7 @@ add_soa_record(isc_mem_t *mctx, ldap_connection_t *ldap_conn, dns_name_t *origin - - CHECK(ldap_entry_getfakesoa(entry, fake_mname, string)); - rdclass = ldap_entry_getrdclass(entry); -- CHECK(parse_rdata(mctx, ldap_conn, rdclass, dns_rdatatype_soa, origin, -+ CHECK(parse_rdata(mctx, qresult, rdclass, dns_rdatatype_soa, origin, - str_buf(string), &rdata)); - - CHECK(findrdatatype_or_create(mctx, rdatalist, rdclass, dns_rdatatype_soa, -@@ -1641,7 +1633,7 @@ cleanup: - } - - static isc_result_t --parse_rdata(isc_mem_t *mctx, ldap_connection_t *ldap_conn, -+parse_rdata(isc_mem_t *mctx, ldap_qresult_t *qresult, - dns_rdataclass_t rdclass, dns_rdatatype_t rdtype, - dns_name_t *origin, const char *rdata_text, dns_rdata_t **rdatap) - { -@@ -1651,7 +1643,7 @@ parse_rdata(isc_mem_t *mctx, ldap_connection_t *ldap_conn, - isc_region_t rdatamem; - dns_rdata_t *rdata; - -- REQUIRE(ldap_conn != NULL); -+ REQUIRE(qresult != NULL); - REQUIRE(rdata_text != NULL); - REQUIRE(rdatap != NULL); - -@@ -1665,30 +1657,30 @@ parse_rdata(isc_mem_t *mctx, ldap_connection_t *ldap_conn, - isc_buffer_add(&lex_buffer, text.length); - isc_buffer_setactive(&lex_buffer, text.length); - -- CHECK(isc_lex_openbuffer(ldap_conn->lex, &lex_buffer)); -+ CHECK(isc_lex_openbuffer(qresult->lex, &lex_buffer)); - -- isc_buffer_init(&ldap_conn->rdata_target, ldap_conn->rdata_target_mem, -+ isc_buffer_init(&qresult->rdata_target, qresult->rdata_target_mem, - MINTSIZ); -- CHECK(dns_rdata_fromtext(NULL, rdclass, rdtype, ldap_conn->lex, origin, -- 0, mctx, &ldap_conn->rdata_target, NULL)); -+ CHECK(dns_rdata_fromtext(NULL, rdclass, rdtype, qresult->lex, origin, -+ 0, mctx, &qresult->rdata_target, NULL)); - - CHECKED_MEM_GET_PTR(mctx, rdata); - dns_rdata_init(rdata); - -- rdatamem.length = isc_buffer_usedlength(&ldap_conn->rdata_target); -+ rdatamem.length = isc_buffer_usedlength(&qresult->rdata_target); - CHECKED_MEM_GET(mctx, rdatamem.base, rdatamem.length); - -- memcpy(rdatamem.base, isc_buffer_base(&ldap_conn->rdata_target), -+ memcpy(rdatamem.base, isc_buffer_base(&qresult->rdata_target), - rdatamem.length); - dns_rdata_fromregion(rdata, rdclass, rdtype, &rdatamem); - -- isc_lex_close(ldap_conn->lex); -+ isc_lex_close(qresult->lex); - - *rdatap = rdata; - return ISC_R_SUCCESS; - - cleanup: -- isc_lex_close(ldap_conn->lex); -+ isc_lex_close(qresult->lex); - if (rdata != NULL) - isc_mem_put(mctx, rdata, sizeof(*rdata)); - if (rdatamem.base != NULL) -@@ -1790,17 +1782,26 @@ ldap_query_create(isc_mem_t *mctx, ldap_qresult_t **ldap_qresultp) { - isc_result_t result; - - CHECKED_MEM_GET_PTR(mctx, ldap_qresult); -+ ZERO_PTR(ldap_qresult); - ldap_qresult->mctx = mctx; -- ldap_qresult->result = NULL; -- ldap_qresult->query_string = NULL; - INIT_LIST(ldap_qresult->ldap_entries); - CHECK(str_new(mctx, &ldap_qresult->query_string)); - -+ CHECKED_MEM_GET(ldap_qresult->mctx, ldap_qresult->rdata_target_mem, MINTSIZ); -+ CHECK(isc_lex_create(ldap_qresult->mctx, TOKENSIZ, &ldap_qresult->lex)); -+ - *ldap_qresultp = ldap_qresult; - return ISC_R_SUCCESS; - - cleanup: -- SAFE_MEM_PUT_PTR(mctx, ldap_qresult); -+ if (ldap_qresult != NULL) { -+ str_destroy(&ldap_qresult->query_string); -+ SAFE_MEM_PUT(ldap_qresult->mctx, ldap_qresult->rdata_target_mem, MINTSIZ); -+ if (ldap_qresult->lex != NULL) -+ isc_lex_destroy(&ldap_qresult->lex); -+ SAFE_MEM_PUT_PTR(mctx, ldap_qresult); -+ } -+ - return result; - } - -@@ -1833,8 +1834,13 @@ ldap_query_free(isc_boolean_t prepare_reuse, ldap_qresult_t **ldap_qresultp) - if (prepare_reuse) { - str_clear(qresult->query_string); - INIT_LIST(qresult->ldap_entries); -+ isc_lex_close(qresult->lex); - } else { /* free the whole structure */ - str_destroy(&qresult->query_string); -+ if (qresult->lex != NULL) -+ isc_lex_destroy(&qresult->lex); -+ if (qresult->rdata_target_mem != NULL) -+ isc_mem_put(qresult->mctx, qresult->rdata_target_mem, MINTSIZ); - SAFE_MEM_PUT_PTR(qresult->mctx, qresult); - *ldap_qresultp = NULL; - } --- -1.7.11.2 - - -From 468329216825f1694e0163f12c9f6d7c50dcc075 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Fri, 27 Jul 2012 11:18:42 +0200 -Subject: [PATCH 32/32] Flush zones and RRs cache when handling persistent - search reconnection - -https://fedorahosted.org/bind-dyndb-ldap/ticket/44 - -Signed-off-by: Petr Spacek ---- - src/cache.c | 25 ++++++++++++++++++++++++- - src/cache.h | 7 +++++++ - src/ldap_helper.c | 32 ++++++++++++++++++++++++++------ - src/ldap_helper.h | 2 +- - src/zone_manager.c | 4 ++-- - 5 files changed, 60 insertions(+), 10 deletions(-) - -diff --git a/src/cache.c b/src/cache.c -index 28f93c9..898d48b 100644 ---- a/src/cache.c -+++ b/src/cache.c -@@ -38,7 +38,7 @@ - #include "util.h" - - struct ldap_cache { -- isc_mutex_t mutex; -+ isc_mutex_t mutex; /* TODO: RWLOCK? */ - isc_mem_t *mctx; - dns_rbt_t *rbt; - isc_interval_t cache_ttl; -@@ -303,3 +303,26 @@ discard_from_cache(ldap_cache_t *cache, dns_name_t *name) - - return result; - } -+ -+isc_result_t -+flush_ldap_cache(ldap_cache_t *cache) -+{ -+ isc_result_t result; -+ -+ REQUIRE(cache != NULL); -+ -+ LOCK(&cache->mutex); -+ if (!ldap_cache_enabled(cache)) { -+ result = ISC_R_SUCCESS; -+ } else { -+ dns_rbt_destroy(&cache->rbt); -+ CHECK(dns_rbt_create(cache->mctx, cache_node_deleter, NULL, -+ &cache->rbt)); -+ } -+ -+cleanup: -+ if (result != ISC_R_SUCCESS) -+ log_error_r("cache flush failed"); -+ UNLOCK(&cache->mutex); -+ return result; -+} -diff --git a/src/cache.h b/src/cache.h -index 6a4e356..a7aa5b7 100644 ---- a/src/cache.h -+++ b/src/cache.h -@@ -77,4 +77,11 @@ ldap_cache_enabled(ldap_cache_t *cache); - isc_result_t - discard_from_cache(ldap_cache_t *cache, dns_name_t *name); - -+/** -+ * Discard all names from the cache and re-initialize internal RB-tree. -+ * @return ISC_R_SUCCESS even if cache is disabled. -+ */ -+isc_result_t -+flush_ldap_cache(ldap_cache_t *cache); -+ - #endif /* !_LD_CACHE_H_ */ -diff --git a/src/ldap_helper.c b/src/ldap_helper.c -index 3fded5b..5aa1d39 100644 ---- a/src/ldap_helper.c -+++ b/src/ldap_helper.c -@@ -1167,11 +1167,14 @@ cleanup: - * added. In that case, only modify the zone's properties, like the update - * policy. - * -+ * @param delete_only Do LDAP vs. zone register cross-check and delete zones -+ * which aren't in LDAP, but do not load new zones. -+ * - * Returns ISC_R_SUCCESS if we found and successfully added at least one zone. - * Returns ISC_R_FAILURE otherwise. - */ - isc_result_t --refresh_zones_from_ldap(ldap_instance_t *ldap_inst) -+refresh_zones_from_ldap(ldap_instance_t *ldap_inst, isc_boolean_t delete_only) - { - isc_result_t result = ISC_R_SUCCESS; - ldap_connection_t *ldap_conn = NULL; -@@ -1194,8 +1197,8 @@ refresh_zones_from_ldap(ldap_instance_t *ldap_inst) - - REQUIRE(ldap_inst != NULL); - -- if (ldap_inst->psearch) { -- /* Watcher does the work for us */ -+ if (ldap_inst->psearch && !delete_only) { -+ /* Watcher does the work for us, but deletion is allowed. */ - return ISC_R_SUCCESS; - } - -@@ -1246,7 +1249,8 @@ refresh_zones_from_ldap(ldap_instance_t *ldap_inst) - continue; - } - -- CHECK(ldap_parse_zoneentry(entry, ldap_inst)); -+ if (!delete_only) -+ CHECK(ldap_parse_zoneentry(entry, ldap_inst)); - zone_count++; - } - -@@ -1272,10 +1276,16 @@ refresh_zones_from_ldap(ldap_instance_t *ldap_inst) - node = NULL; - - result = dns_rbtnodechain_current(&chain, &fname, &forig, &node); -- if (result != ISC_R_SUCCESS) -+ if (result != ISC_R_SUCCESS) { -+ if (result != ISC_R_NOTFOUND) -+ log_error_r( -+ "unable to walk through RB-tree during zone_refresh"); - goto next; -+ } - -- if (dns_name_concatenate(&fname, &forig, &aname, aname.buffer) != ISC_R_SUCCESS) { -+ if (dns_name_concatenate(&fname, &forig, &aname, aname.buffer) -+ != ISC_R_SUCCESS) { -+ log_error_r("unable to concatenate DNS names during zone_refresh"); - goto next; - } - -@@ -3450,6 +3460,7 @@ ldap_psearch_watcher(isc_threadarg_t arg) - int ret, cnt; - isc_result_t result; - sigset_t sigset; -+ isc_boolean_t flush_required; - - log_debug(1, "Entering ldap_psearch_watcher"); - -@@ -3489,6 +3500,7 @@ ldap_psearch_watcher(isc_threadarg_t arg) - - restart: - /* Perform initial lookup */ -+ flush_required = ISC_TRUE; - if (inst->psearch) { - log_debug(1, "Sending initial psearch lookup"); - ret = ldap_search_ext(conn->handle, -@@ -3527,6 +3539,14 @@ restart: - } - ldap_query_free(ISC_TRUE, &ldap_qresult); - goto restart; -+ } else if (flush_required == ISC_TRUE) { -+ /* First LDAP result after (re)start was received successfully: -+ * Unload old zones and flush record cache. -+ * We want to save cache in case of search timeout during restart. -+ */ -+ CHECK(refresh_zones_from_ldap(inst, ISC_TRUE)); -+ CHECK(flush_ldap_cache(inst->cache)); -+ flush_required = ISC_FALSE; - } - - switch (ret) { -diff --git a/src/ldap_helper.h b/src/ldap_helper.h -index bc78410..f6cbdc5 100644 ---- a/src/ldap_helper.h -+++ b/src/ldap_helper.h -@@ -82,7 +82,7 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, - isc_task_t *task, ldap_instance_t **ldap_instp); - void destroy_ldap_instance(ldap_instance_t **ldap_inst); - isc_result_t --refresh_zones_from_ldap(ldap_instance_t *ldap_inst); -+refresh_zones_from_ldap(ldap_instance_t *ldap_inst, isc_boolean_t delete_only); - - /* Functions for writing to LDAP. */ - isc_result_t write_to_ldap(dns_name_t *owner, ldap_instance_t *ldap_inst, -diff --git a/src/zone_manager.c b/src/zone_manager.c -index eb761aa..ca3edd0 100644 ---- a/src/zone_manager.c -+++ b/src/zone_manager.c -@@ -180,7 +180,7 @@ manager_create_db_instance(isc_mem_t *mctx, const char *name, - APPEND(instance_list, db_inst, link); - UNLOCK(&instance_list_lock); - -- result = refresh_zones_from_ldap(db_inst->ldap_inst); -+ result = refresh_zones_from_ldap(db_inst->ldap_inst, ISC_FALSE); - if (result != ISC_R_SUCCESS) { - /* In case we don't find any zones, we at least return - * ISC_R_SUCCESS so BIND won't exit because of this. */ -@@ -221,7 +221,7 @@ refresh_zones_action(isc_task_t *task, isc_event_t *event) - - UNUSED(task); - -- refresh_zones_from_ldap(db_inst->ldap_inst); -+ refresh_zones_from_ldap(db_inst->ldap_inst, ISC_FALSE); - - isc_event_free(&event); - } --- -1.7.11.2 - diff --git a/sources b/sources index 7f2aa43..bebfedd 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -a18effcecebe9b1bf1513f6c7d7712bd bind-dyndb-ldap-1.1.0rc1.tar.bz2 +c7cf4b0fa7e15671177367532dbc11cb bind-dyndb-ldap-2.0-20120921git7710d89.tar.bz2