3a72537007
Signed-off-by: Adam Tkac <vonsch@gmail.com>
4015 lines
127 KiB
Diff
4015 lines
127 KiB
Diff
From f0d49c0eb816c958e4fa6bf4a073eb6ac592efad Mon Sep 17 00:00:00 2001
|
|
From: Adam Tkac <atkac@redhat.com>
|
|
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 <atkac@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
Date: Tue, 24 Apr 2012 15:09:32 +0200
|
|
Subject: [PATCH 02/32] Add simple semaphore deadlock detection logic.
|
|
Signed-off-by: Petr Spacek <pspacek@redhat.com>
|
|
|
|
---
|
|
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 <isc/condition.h>
|
|
#include <isc/result.h>
|
|
#include <isc/util.h>
|
|
+#include <isc/time.h>
|
|
|
|
#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 <isc/condition.h>
|
|
#include <isc/mutex.h>
|
|
|
|
+/* 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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
|
|
---
|
|
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 <isc/buffer.h>
|
|
#include <isc/mem.h>
|
|
#include <isc/util.h>
|
|
+#include <isc/string.h>
|
|
|
|
#include <dns/name.h>
|
|
#include <dns/rdatatype.h>
|
|
@@ -32,6 +33,7 @@
|
|
|
|
#include <errno.h>
|
|
#include <strings.h>
|
|
+#include <ctype.h>
|
|
|
|
#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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
|
|
Signed-off-by: Adam Tkac <atkac@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
|
|
Signed-off-by: Adam Tkac <atkac@redhat.com>
|
|
---
|
|
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 <dns/ttl.h>
|
|
#include <dns/view.h>
|
|
#include <dns/zone.h>
|
|
+#include <dns/db.h>
|
|
#include <dns/zt.h>
|
|
#include <dns/byaddr.h>
|
|
#include <dns/forward.h>
|
|
@@ -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 <atkac@redhat.com>
|
|
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 <atkac@redhat.com>
|
|
---
|
|
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 <atkac@redhat.com>
|
|
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 <atkac@redhat.com>
|
|
---
|
|
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 <atkac@redhat.com>
|
|
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 <atkac@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <dns/rbt.h>
|
|
#include <dns/result.h>
|
|
+#include <dns/log.h>
|
|
|
|
#include <string.h>
|
|
|
|
@@ -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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <dns/zt.h>
|
|
#include <dns/byaddr.h>
|
|
#include <dns/forward.h>
|
|
+#include <dns/soa.h>
|
|
+#include <isc/serial.h>
|
|
|
|
#include <isc/buffer.h>
|
|
#include <isc/lex.h>
|
|
@@ -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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <atkac@redhat.com>
|
|
* Martin Nagy <mnagy@redhat.com>
|
|
*
|
|
- * 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 <isc/mem.h>
|
|
#include <isc/result.h>
|
|
#include <isc/util.h>
|
|
+#include <isc/buffer.h>
|
|
+#include <isc/md5.h>
|
|
|
|
#include <dns/rdata.h>
|
|
#include <dns/rdatalist.h>
|
|
|
|
#include <string.h>
|
|
+#include <stdlib.h>
|
|
|
|
#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 <isc/md5.h>
|
|
+
|
|
+#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 <isc/mem.h>
|
|
#include <isc/rwlock.h>
|
|
#include <isc/util.h>
|
|
+#include <isc/md5.h>
|
|
|
|
#include <dns/rbt.h>
|
|
#include <dns/result.h>
|
|
@@ -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 <pspacek@redhat.com>
|
|
Date: Wed, 11 Jul 2012 15:04:50 +0200
|
|
Subject: [PATCH 15/32] Add documention for serial_autoincrement feature.
|
|
|
|
Signed-off-by: Petr Spacek <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
Date: Wed, 18 Jul 2012 13:27:16 +0200
|
|
Subject: [PATCH 23/32] Minor persistent search logging cleanup.
|
|
|
|
Signed-off-by: Petr Spacek <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
Date: Thu, 19 Jul 2012 14:13:12 +0200
|
|
Subject: [PATCH 26/32] Cleanup in logging code.
|
|
|
|
Signed-off-by: Petr Spacek <pspacek@redhat.com>
|
|
---
|
|
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 <isc/error.h>
|
|
+#include <dns/log.h>
|
|
+
|
|
+#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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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 <pspacek@redhat.com>
|
|
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 <pspacek@redhat.com>
|
|
---
|
|
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
|
|
|