Hello,

this patch set adds meta-database which is one of prerequisites for other work.

These changes should not be user-visible. You might compile the plugin with
CFLAGS="-DMETADB_DEBUG" and check contect of /tmp/metadb.db after BIND shutdown.

Please see
https://fedorahosted.org/bind-dyndb-ldap/ticket/151
https://fedorahosted.org/bind-dyndb-ldap/wiki/Design/MetaDB
for further information and let me know if you can help you somehow.

-- 
Petr^2 Spacek
From cb7f1aef90d356b195ddae46e3841627234e9208 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Wed, 29 Apr 2015 11:13:41 +0200
Subject: [PATCH] Add LDAP UUID -> meta-database name mapping function.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 configure.ac    |  2 ++
 src/Makefile.am |  2 ++
 src/mldap.c     | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/mldap.h     | 11 ++++++++++
 4 files changed, 83 insertions(+)
 create mode 100644 src/mldap.c
 create mode 100644 src/mldap.h

diff --git a/configure.ac b/configure.ac
index 9026f6d70fb008813681ab3f3eb51e9e2fec7be0..d7e64772e43a743d75d1b63b05fabe45acefb12d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -73,6 +73,8 @@ 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]))
+AC_CHECK_LIB([uuid], [uuid_unparse], [],
+	AC_MSG_ERROR([Install UUID library development files]))
 
 # Check version of libdns
 AC_MSG_CHECKING([libdns version])
diff --git a/src/Makefile.am b/src/Makefile.am
index 73aa8a3afa1bea0e63a0ac04ca13f58e4ad512cf..68ddba87582e0e590e51ad05782d18a8fdcfbcd0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,6 +13,7 @@ HDRS =				\
 	ldap_helper.h		\
 	lock.h			\
 	log.h			\
+	mldap.h			\
 	rbt_helper.h		\
 	rdlist.h		\
 	semaphore.h		\
@@ -38,6 +39,7 @@ ldap_la_SOURCES =		\
 	ldap_helper.c		\
 	lock.c			\
 	log.c			\
+	mldap.c			\
 	rbt_helper.c		\
 	rdlist.c		\
 	semaphore.c		\
diff --git a/src/mldap.c b/src/mldap.c
new file mode 100644
index 0000000000000000000000000000000000000000..0b2d0db43624131fc569b05e1492fbc6a7f68c30
--- /dev/null
+++ b/src/mldap.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015  bind-dyndb-ldap authors; see COPYING for license
+ *
+ * Meta-database for LDAP-specific information which are not represented in
+ * DNS data.
+ */
+
+#include <ldap.h>
+#include <stddef.h>
+#include <uuid/uuid.h>
+
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <dns/name.h>
+
+#include "mldap.h"
+#include "util.h"
+
+/* name "ldap.uuid." */
+static unsigned char uuid_rootname_ndata[]
+	= { 4, 'u', 'u', 'i', 'd', 4, 'l', 'd', 'a', 'p', 0 };
+static unsigned char uuid_rootname_offsets[] = { 0, 5, 10 };
+static dns_name_t uuid_rootname =
+{
+	DNS_NAME_MAGIC,
+	uuid_rootname_ndata,
+	sizeof(uuid_rootname_ndata),
+	sizeof(uuid_rootname_offsets),
+	DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+	uuid_rootname_offsets,
+	NULL,
+	{ (void *)-1, (void *)-1 },
+	{ NULL, NULL }
+};
+
+/**
+ * Convert UUID to "01234567-89ab-cdef-0123-456789abcdef.uuid.ldap." DNS name.
+ *
+ * @param[in]  beruuid
+ * @param[out] nameuuid
+ */
+void
+ldap_uuid_to_mname(struct berval *beruuid, dns_name_t *nameuuid) {
+	/* UUID string representation according to RFC 4122 section 3 */
+	char label_buf[sizeof("01234567-89ab-cdef-0123-456789abcdef") + 1];
+	/* uncompressed label format, length 36 octets; RFC 1034 section 3.1 */
+	label_buf[0] = 36;
+
+	isc_region_t label_reg;
+	label_reg.base = (unsigned char *)label_buf;
+	label_reg.length = sizeof(label_buf) - 1; /* omit final \0 */
+
+	dns_name_t relative_name;
+	DNS_NAME_INIT(&relative_name, NULL);
+
+	/* RFC 4530 section 2.1 format = 16 octets is required */
+	REQUIRE(beruuid != NULL && beruuid->bv_len == 16);
+
+	/* fill-in string representation into label buffer */
+	uuid_unparse((*(const uuid_t *) beruuid->bv_val), label_buf + 1);
+	dns_name_fromregion(&relative_name, &label_reg);
+
+	INSIST(dns_name_concatenate(&relative_name, &uuid_rootname,
+				    nameuuid, NULL) == ISC_R_SUCCESS);
+
+	return;
+}
diff --git a/src/mldap.h b/src/mldap.h
new file mode 100644
index 0000000000000000000000000000000000000000..dcf2556326ccea5037b32e71ab5da216f0f44ba4
--- /dev/null
+++ b/src/mldap.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright (C) 2015  bind-dyndb-ldap authors; see COPYING for license
+ */
+
+#ifndef SRC_MLDAP_H_
+#define SRC_MLDAP_H_
+
+void
+ldap_uuid_to_mname(struct berval *beruuid, dns_name_t *nameuuid);
+
+#endif /* SRC_MLDAP_H_ */
-- 
2.1.0

From 7c556a58ff4fb919c089f3f65ad2ed8d415a1fa0 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 12 May 2015 13:04:41 +0200
Subject: [PATCH] Add basic infratructure for generic meta-database.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/Makefile.am |   2 +
 src/metadb.c    | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/metadb.h    |  52 ++++++++++++
 3 files changed, 310 insertions(+)
 create mode 100644 src/metadb.c
 create mode 100644 src/metadb.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 68ddba87582e0e590e51ad05782d18a8fdcfbcd0..aaa72063230a34d9aa0fca4b799309a89815db09 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,6 +13,7 @@ HDRS =				\
 	ldap_helper.h		\
 	lock.h			\
 	log.h			\
+	metadb.h		\
 	mldap.h			\
 	rbt_helper.h		\
 	rdlist.h		\
@@ -39,6 +40,7 @@ ldap_la_SOURCES =		\
 	ldap_helper.c		\
 	lock.c			\
 	log.c			\
+	metadb.c		\
 	mldap.c			\
 	rbt_helper.c		\
 	rdlist.c		\
diff --git a/src/metadb.c b/src/metadb.c
new file mode 100644
index 0000000000000000000000000000000000000000..bbde3a85fed233ad35a2c81f0c0dbf0b530638df
--- /dev/null
+++ b/src/metadb.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2015  bind-dyndb-ldap authors; see COPYING for license
+ *
+ * Meta-database for information which are not represented in DNS data.
+ */
+
+#include <isc/mutex.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/rdatalist.h>
+
+#include "metadb.h"
+#include "util.h"
+
+struct metadb {
+	isc_mem_t			*mctx;
+	dns_db_t			*rbtdb;
+
+	/** Upcoming RBTDB version. */
+	dns_dbversion_t			*newversion;
+
+	/**
+	 * Guard for newversion. Only one RBTDB version can be open
+	 * for writing at any time. See functions newversion and closeversion.
+	 */
+	isc_mutex_t			newversion_lock;
+};
+
+/**
+ * Initialize new empty meta-database backed by RBT DB.
+ */
+isc_result_t
+metadb_new(isc_mem_t *mctx, metadb_t **mdbp) {
+	isc_result_t result;
+	metadb_t *mdb = NULL;
+	isc_boolean_t lock_ready = ISC_FALSE;
+
+	REQUIRE(mdbp != NULL && *mdbp == NULL);
+
+	CHECKED_MEM_GET_PTR(mctx, mdb);
+	ZERO_PTR(mdb);
+
+	isc_mem_attach(mctx, &mdb->mctx);
+
+	CHECK(isc_mutex_init(&mdb->newversion_lock));
+	lock_ready = ISC_TRUE;
+	CHECK(dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
+			    dns_rdataclass_in, 0, NULL, &mdb->rbtdb));
+
+	*mdbp = mdb;
+	return result;
+
+cleanup:
+	if (mdb != NULL) {
+		if (lock_ready == ISC_TRUE)
+			RUNTIME_CHECK(isc_mutex_destroy(&mdb->newversion_lock)
+				      == ISC_R_SUCCESS);
+		MEM_PUT_AND_DETACH(mdb);
+	}
+	return result;
+}
+
+/**
+ * Destroy meta-database.
+ * All write-able versions have to be closed before calling destroy().
+ */
+void
+metadb_destroy(metadb_t **mdbp) {
+	metadb_t *mdb;
+
+	REQUIRE(mdbp != NULL && *mdbp != NULL);
+
+	mdb = *mdbp;
+
+#ifdef METADB_DEBUG
+	dns_db_dump(mdb->rbtdb, NULL, "/tmp/mdb.db");
+#endif
+	dns_db_detach(&mdb->rbtdb);
+	RUNTIME_CHECK(isc_mutex_destroy(&mdb->newversion_lock) == ISC_R_SUCCESS);
+	MEM_PUT_AND_DETACH(mdb);
+
+	*mdbp = NULL;
+}
+
+/**
+ * Open new metaDB version for writing.
+ *
+ * @warning metaDB should be modified only from single thread!
+ *
+ * @waning Only one writeable version can be open at any time. Purpose of the
+ *         lock is to detect misuse and prevent immediate crashes
+ *         but it does not change properties of underlying RBT DB.
+ */
+isc_result_t
+metadb_newversion(metadb_t *mdb) {
+	isc_result_t result;
+
+	if (isc_mutex_trylock(&mdb->newversion_lock) != ISC_R_SUCCESS) {
+		log_bug("mdb newversion_lock is not open");
+		LOCK(&mdb->newversion_lock);
+	}
+	CHECK(dns_db_newversion(mdb->rbtdb, &mdb->newversion));
+
+cleanup:
+	if (result != ISC_R_SUCCESS)
+		UNLOCK(&mdb->newversion_lock);
+	return result;
+}
+
+/**
+ * Close writeable metaDB version and commit/discard all changes.
+ *
+ * @pre All metaDB nodes have to be closed before calling
+ *      closeversion(commit = ISC_TRUE).
+ */
+void
+metadb_closeversion(metadb_t *mdb, isc_boolean_t commit) {
+	UNLOCK(&mdb->newversion_lock);
+	dns_db_closeversion(mdb->rbtdb, &mdb->newversion, commit);
+}
+
+/**
+ * Close metaDB node and detach associated DB version. All changes will be lost
+ * if this was the last reference to particular metaDB version.
+ */
+void
+metadb_node_close(metadb_node_t **nodep) {
+	metadb_node_t *node;
+
+	REQUIRE(nodep != NULL);
+
+	node = *nodep;
+	if (node == NULL)
+		return;
+
+	if (node->rbtdb != NULL) {
+		if (node->dbnode != NULL)
+			dns_db_detachnode(node->rbtdb, &node->dbnode);
+		if (node->version != NULL)
+			dns_db_closeversion(node->rbtdb, &node->version,
+					    ISC_FALSE);
+		dns_db_detach(&node->rbtdb);
+	}
+	MEM_PUT_AND_DETACH(node);
+	*nodep = NULL;
+}
+
+/**
+ * Create new "metaDB node" structure and attach underlying RBT DB node to it.
+ *
+ * @param[in]  version Underlying RBTDB version to use.
+ * @param[in]  mname   Name of the node in metaDB. E.g. '1234.uuid.ldap.'
+ * @param[in]  create  RBTDB node will be created if it does not exist.
+ * @param[out] nodep   Resulting "metaDB node" structure. It has to be freed
+ *                     using metadb_node_close().
+ */
+static isc_result_t
+metadb_node_init(metadb_t *mdb, dns_dbversion_t *ver, dns_name_t *mname,
+		 isc_boolean_t create, metadb_node_t **nodep) {
+	isc_result_t result;
+	metadb_node_t *node = NULL;
+
+	REQUIRE(nodep != NULL && *nodep == NULL);
+
+	CHECKED_MEM_GET_PTR(mdb->mctx, node);
+	ZERO_PTR(node);
+
+	isc_mem_attach(mdb->mctx, &node->mctx);
+	dns_db_attach(mdb->rbtdb, &node->rbtdb);
+	dns_db_attachversion(mdb->rbtdb, ver, &node->version);
+	CHECK(dns_db_findnode(mdb->rbtdb, mname, create, &node->dbnode));
+
+	*nodep = node;
+	return ISC_R_SUCCESS;
+
+cleanup:
+	metadb_node_close(&node);
+	return result;
+}
+
+/**
+ * Create new "metaDB node" structure and attach current read-only version of
+ * RBT DB to it.
+ *
+ * @param[in]  mname Name of the node in metaDB. E.g. '1234.uuid.ldap.'
+ * @param[out] nodep Resulting "metaDB node" structure. Node has to be freed
+ *                   using metadb_node_close().
+ */
+isc_result_t
+metadb_readnode_open(metadb_t *mdb, dns_name_t *mname, metadb_node_t **nodep) {
+	isc_result_t result;
+	dns_dbversion_t *ver = NULL;
+
+	dns_db_currentversion(mdb->rbtdb, &ver);
+	CHECK(metadb_node_init(mdb, ver, mname, ISC_FALSE, nodep));
+
+cleanup:
+	dns_db_closeversion(mdb->rbtdb, &ver, ISC_FALSE);
+	return result;
+}
+
+/**
+ * Create new "metaDB node" structure and attach current writeable version of
+ * RBT DB to it.
+ *
+ * @param[in]  mname Name of the node in metaDB. E.g. '1234.uuid.ldap.'
+ * @param[out] nodep Resulting "metaDB node" structure. Node has to be freed
+ *                   using metadb_node_close().
+ *
+ * @pre MetaDB was opened by newversion().
+ */
+isc_result_t
+metadb_writenode_create(metadb_t *mdb, dns_name_t *mname, metadb_node_t **nodep) {
+	isc_result_t result;
+	dns_dbversion_t *ver = NULL;
+
+	INSIST(mdb->newversion != NULL);
+	dns_db_attachversion(mdb->rbtdb, mdb->newversion, &ver);
+	CHECK(metadb_node_init(mdb, ver, mname, ISC_TRUE, nodep));
+
+cleanup:
+	dns_db_closeversion(mdb->rbtdb, &ver, ISC_FALSE);
+	return result;
+}
+
+/**
+ * Store rdata into metaDB node and overwrite all existing values for RR type
+ * specified in rdata.
+ *
+ * @pre Node was created by metadb_writenode_create().
+ */
+isc_result_t
+metadb_rdata_store(dns_rdata_t *rdata, metadb_node_t *node) {
+	isc_result_t result;
+	dns_rdatalist_t rdatalist;
+	dns_rdataset_t rdataset;
+
+	dns_rdatalist_init(&rdatalist);
+	rdatalist.rdclass = rdata->rdclass;
+	rdatalist.type = rdata->type;
+	dns_rdataset_init(&rdataset);
+	APPEND(rdatalist.rdata, rdata, link);
+
+	RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset)
+		      == ISC_R_SUCCESS);
+	/* DNS_DBADD_MERGE flag is not set - old rdataset will be replaced. */
+	CHECK(dns_db_addrdataset(node->rbtdb, node->dbnode, node->version, 0, &rdataset, 0, NULL));
+
+cleanup:
+	if (dns_rdataset_isassociated(&rdataset))
+		dns_rdataset_disassociate(&rdataset);
+	if (result == DNS_R_UNCHANGED)
+		result = ISC_R_SUCCESS;
+	return result;
+}
diff --git a/src/metadb.h b/src/metadb.h
new file mode 100644
index 0000000000000000000000000000000000000000..c49ac0dc2db46b8e62820d2e907b77bf82e59c2f
--- /dev/null
+++ b/src/metadb.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015  bind-dyndb-ldap authors; see COPYING for license
+ *
+ * Meta-database for information which are not represented in DNS data.
+ */
+
+#ifndef SRC_METADB_H_
+#define SRC_METADB_H_
+
+#include "util.h"
+
+
+/**
+ * All-in-one structure for metaDB operations. Version guarantees that node
+ * content visible to metadb_node user will not change asynchronously
+ * as long as metaDB 'version' is modified in the same thread.
+ */
+struct metadb_node {
+	isc_mem_t			*mctx;
+	dns_db_t			*rbtdb;
+	dns_dbversion_t			*version;
+	dns_dbnode_t			*dbnode;
+};
+
+typedef struct metadb_node metadb_node_t;
+typedef struct metadb metadb_t;
+
+isc_result_t
+metadb_new(isc_mem_t *mctx, metadb_t **dbp) ATTR_CHECKRESULT ATTR_NONNULLS;
+
+void
+metadb_destroy(metadb_t **dbp);
+
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+metadb_newversion(metadb_t *mdb);
+
+void ATTR_NONNULLS
+metadb_closeversion(metadb_t *mdb, isc_boolean_t commit);
+
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+metadb_readnode_open(metadb_t *mdb, dns_name_t *mname, metadb_node_t **nodep);
+
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+metadb_writenode_create(metadb_t *mdb, dns_name_t *mname, metadb_node_t **nodep);
+
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+metadb_rdata_store(dns_rdata_t *rdata, metadb_node_t *node);
+
+void ATTR_NONNULLS
+metadb_node_close(metadb_node_t **nodep);
+
+#endif /* SRC_METADB_H_ */
-- 
2.1.0

From 3c49145a7834c9913deb076cb74d18ecb8992a65 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 12 May 2015 13:25:18 +0200
Subject: [PATCH] Add static (compile-time) assert macro.

---
 src/util.h | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/src/util.h b/src/util.h
index 69b5d2a0a0803d8194a255638777d06654fa80ea..1f92df8e900bc0871cec5245ad51967d8642c537 100644
--- a/src/util.h
+++ b/src/util.h
@@ -127,4 +127,38 @@ extern isc_boolean_t verbose_checks; /* from settings.c */
 #define ATTR_CHECKRESULT
 #endif
 
+/*
+ * Static (compile-time) assert for C:
+ * C99 doesn't require support for "sizeof" in preprocessor conditionals so
+ * we can't do something like #if (sizeof(my_struct) != 512).
+ *
+ * This macro has no runtime side affects as it just defines an enum whose name
+ * depends on the current line, and whose value will give a divide by zero error
+ * at compile time if the assertion is false.
+ *
+ * Taken from
+ * http://www.pixelbeat.org/programming/gcc/static_assert.html
+ * version 10 Feb 2015. Padraig Brady told me that it is licensed under
+ * "GNU All-Permissive License":
+ *
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright notice
+ * and this notice are preserved. This code is offered as-is,
+ * without any warranty.
+ */
+#define ASSERT_CONCAT_(a, b) a##b
+#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
+/* These can't be used after statements in c89. */
+#ifdef __COUNTER__
+  #define STATIC_ASSERT(e, m) \
+    ;enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1/(!!(e)) }
+#else
+  /* This can't be used twice on the same line so ensure if using in headers
+   * that the headers are not included twice (by wrapping in #ifndef...#endif)
+   * Note it doesn't cause an issue when used on same line of separate modules
+   * compiled with gcc -combine -fwhole-program.  */
+  #define STATIC_ASSERT(e, m) \
+    ;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }
+#endif
+
 #endif /* !_LD_UTIL_H_ */
-- 
2.1.0

From 3f05f0378bc9d7ae273cc7b707e39165f457c960 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 12 May 2015 13:27:43 +0200
Subject: [PATCH] Add basic infratructure for LDAP meta-database.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/mldap.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/mldap.h | 16 +++++++++++++++-
 2 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/src/mldap.c b/src/mldap.c
index 0b2d0db43624131fc569b05e1492fbc6a7f68c30..057247497366e20ce19c008bae4495ca96ee1ee6 100644
--- a/src/mldap.c
+++ b/src/mldap.c
@@ -12,8 +12,12 @@
 #include <isc/result.h>
 #include <isc/util.h>
 
+#include <dns/db.h>
+#include <dns/enumclass.h>
 #include <dns/name.h>
+#include <dns/types.h>
 
+#include "metadb.h"
 #include "mldap.h"
 #include "util.h"
 
@@ -34,6 +38,63 @@ static dns_name_t uuid_rootname =
 	{ NULL, NULL }
 };
 
+struct mldapdb {
+	isc_mem_t	*mctx;
+	metadb_t	*mdb;
+	isc_uint32_t	generation;
+};
+
+
+isc_result_t
+mldap_new(isc_mem_t *mctx, mldapdb_t **mldapp) {
+	isc_result_t result;
+	mldapdb_t *mldap = NULL;
+
+	REQUIRE(mldapp != NULL && *mldapp == NULL);
+
+	CHECKED_MEM_GET_PTR(mctx, mldap);
+	ZERO_PTR(mldap);
+	isc_mem_attach(mctx, &mldap->mctx);
+
+	CHECK(metadb_new(mctx, &mldap->mdb));
+	mldap->generation = 0;
+
+	*mldapp = mldap;
+	return result;
+
+cleanup:
+	metadb_destroy(&mldap->mdb);
+	MEM_PUT_AND_DETACH(mldap);
+	return result;
+}
+
+void
+mldap_destroy(mldapdb_t **mldapp) {
+	mldapdb_t *mldap;
+
+	REQUIRE(mldapp != NULL && *mldapp != NULL);
+
+	mldap = *mldapp;
+	if (mldap == NULL)
+		return;
+
+	metadb_destroy(&mldap->mdb);
+	MEM_PUT_AND_DETACH(mldap);
+
+	*mldapp = NULL;
+}
+
+
+isc_result_t
+mldap_newversion(mldapdb_t *mldap) {
+	return metadb_newversion(mldap->mdb);
+}
+
+void
+mldap_closeversion(mldapdb_t *mldap, isc_boolean_t commit) {
+	return metadb_closeversion(mldap->mdb, commit);
+}
+
 /**
  * Convert UUID to "01234567-89ab-cdef-0123-456789abcdef.uuid.ldap." DNS name.
  *
diff --git a/src/mldap.h b/src/mldap.h
index dcf2556326ccea5037b32e71ab5da216f0f44ba4..e14964619a7ac50a248d00ff414cf11d5b056989 100644
--- a/src/mldap.h
+++ b/src/mldap.h
@@ -5,7 +5,21 @@
 #ifndef SRC_MLDAP_H_
 #define SRC_MLDAP_H_
 
+#include "metadb.h"
+#include "util.h"
+
+typedef struct mldapdb mldapdb_t;
+
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+mldap_new(isc_mem_t *mctx, mldapdb_t **dbp);
+
 void
-ldap_uuid_to_mname(struct berval *beruuid, dns_name_t *nameuuid);
+mldap_destroy(mldapdb_t **dbp);
+
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+mldap_newversion(mldapdb_t *mldap);
+
+void ATTR_NONNULLS
+mldap_closeversion(mldapdb_t *mldap, isc_boolean_t commit);
 
 #endif /* SRC_MLDAP_H_ */
-- 
2.1.0

From f6cf9e49d5f5c9a8863e872c80a2bb3cae2fe1f4 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 12 May 2015 13:28:32 +0200
Subject: [PATCH] Add functions for populating LDAP meta-database.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/mldap.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/mldap.h |   6 ++++
 2 files changed, 116 insertions(+), 1 deletion(-)

diff --git a/src/mldap.c b/src/mldap.c
index 057247497366e20ce19c008bae4495ca96ee1ee6..2b06ec6a11d6ada37aea1bee177b3201d16be7e2 100644
--- a/src/mldap.c
+++ b/src/mldap.c
@@ -9,14 +9,16 @@
 #include <stddef.h>
 #include <uuid/uuid.h>
 
+#include <isc/boolean.h>
+#include <isc/net.h>
 #include <isc/result.h>
-#include <isc/util.h>
 
 #include <dns/db.h>
 #include <dns/enumclass.h>
 #include <dns/name.h>
 #include <dns/types.h>
 
+#include "ldap_entry.h"
 #include "metadb.h"
 #include "mldap.h"
 #include "util.h"
@@ -127,3 +129,110 @@ ldap_uuid_to_mname(struct berval *beruuid, dns_name_t *nameuuid) {
 
 	return;
 }
+
+STATIC_ASSERT((sizeof(ldap_entryclass_t) <= sizeof(struct in6_addr)), \
+		"ldap_entryclass_t is too big for AAAA rdata type");
+/**
+ * ldap_entryclass_t is stored inside AAAA record type
+ */
+static isc_result_t
+mldap_class_store(ldap_entryclass_t class, metadb_node_t *node) {
+	unsigned char buff[sizeof(struct in6_addr)];
+	isc_region_t region = { .base = buff, .length = sizeof(buff) };
+	dns_rdata_t rdata;
+
+	dns_rdata_init(&rdata);
+	memset(buff, 0, sizeof(buff));
+
+	/* Bytes should be in network-order but we do not care because:
+	 * 1) It is used only internally.  2) Class is unsigned char. */
+	memcpy(buff, &class, sizeof(class));
+	dns_rdata_fromregion(&rdata, dns_rdataclass_in, dns_rdatatype_aaaa,
+			     &region);
+
+	return metadb_rdata_store(&rdata, node);
+}
+
+
+STATIC_ASSERT((sizeof(((mldapdb_t *)0)->generation) == sizeof(struct in_addr)), \
+		"mldapdb_t->generation is too big for A rdata type");
+/**
+ * mldapdb_t->generation is stored inside A record type
+ */
+static isc_result_t
+mldap_generation_store(mldapdb_t *mldap, metadb_node_t *node) {
+	isc_result_t result;
+	unsigned char buff[sizeof(mldap->generation)];
+	isc_region_t region = { .base = buff, .length = sizeof(buff) };
+	dns_rdata_t rdata;
+
+	dns_rdata_init(&rdata);
+
+	/* Bytes should be in network-order but we do not care because:
+	 * 1) It is used only internally and always compared on this machine. */
+	memcpy(buff, &mldap->generation, sizeof(mldap->generation));
+	dns_rdata_fromregion(&rdata, dns_rdataclass_in, dns_rdatatype_a, &region);
+	CHECK(metadb_rdata_store(&rdata, node));
+
+cleanup:
+	return result;
+}
+
+/**
+ * FQDN and zone name are stored inside RP record type
+ */
+isc_result_t
+mldap_dnsname_store(dns_name_t *fqdn, dns_name_t *zone, metadb_node_t *node) {
+	isc_result_t result;
+	dns_rdata_rp_t rp;
+	dns_rdata_t rdata;
+	unsigned char wirebuf[2 * DNS_NAME_MAXWIRE];
+	isc_buffer_t rdatabuf;
+
+	REQUIRE(fqdn != NULL);
+	REQUIRE(zone != NULL);
+
+	dns_rdata_init(&rdata);
+	DNS_RDATACOMMON_INIT(&rp, dns_rdatatype_rp, dns_rdataclass_in);
+	isc_buffer_init(&rdatabuf, wirebuf, sizeof(wirebuf));
+
+	/* Bytes should be in network-order but we do not care because:
+	 * 1) It is used only internally and always compared on this machine. */
+	rp.mail = *fqdn;
+	rp.text = *zone;
+	CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_in, dns_rdatatype_rp,
+				   &rp, &rdatabuf));
+	CHECK(metadb_rdata_store(&rdata, node));
+
+cleanup:
+	return result;
+}
+
+/**
+ * Store information from LDAP entry into meta-database.
+ */
+isc_result_t
+mldap_entry_create(ldap_entry_t *entry, mldapdb_t *mldap, metadb_node_t **nodep) {
+	isc_result_t result;
+	ldap_entryclass_t class;
+	metadb_node_t *node = NULL;
+	DECLARE_BUFFERED_NAME(mname);
+
+	REQUIRE(nodep != NULL && *nodep == NULL);
+
+	INIT_BUFFERED_NAME(mname);
+
+	ldap_uuid_to_mname(entry->uuid, &mname);
+	CHECK(metadb_writenode_create(mldap->mdb, &mname, &node));
+
+	CHECK(ldap_entry_getclass(entry, &class));
+	CHECK(mldap_class_store(class, node));
+	CHECK(mldap_generation_store(mldap, node));
+
+	*nodep = node;
+
+cleanup:
+	if (result != ISC_R_SUCCESS)
+		metadb_node_close(&node);
+	return result;
+}
diff --git a/src/mldap.h b/src/mldap.h
index e14964619a7ac50a248d00ff414cf11d5b056989..a0e9b7372ea8d114178ced1d1e2ffcfd4eb00bfc 100644
--- a/src/mldap.h
+++ b/src/mldap.h
@@ -22,4 +22,10 @@ mldap_newversion(mldapdb_t *mldap);
 void ATTR_NONNULLS
 mldap_closeversion(mldapdb_t *mldap, isc_boolean_t commit);
 
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+mldap_entry_create(ldap_entry_t *entry, mldapdb_t *mldap, metadb_node_t **nodep);
+
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+mldap_dnsname_store(dns_name_t *fqdn, dns_name_t *zone, metadb_node_t *node);
+
 #endif /* SRC_MLDAP_H_ */
-- 
2.1.0

From 8a84ac99110164e00d44d158dc4ee375a77004f0 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 12 May 2015 14:01:47 +0200
Subject: [PATCH] Add meta-LDAP database to LDAP instance.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_helper.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index be64f8207f3f35a4f639e4ebebe30319aad06e67..a25cad855fd088e04692198a3ce5e98c6dd55010 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -80,6 +80,7 @@
 #include "ldap_helper.h"
 #include "lock.h"
 #include "log.h"
+#include "mldap.h"
 #include "rdlist.h"
 #include "semaphore.h"
 #include "settings.h"
@@ -182,6 +183,7 @@ struct ldap_instance {
 	dns_forwarders_t	orig_global_forwarders; /* from named.conf */
 
 	sync_ctx_t		*sctx;
+	mldapdb_t		*mldapdb;
 };
 
 struct ldap_pool {
@@ -559,6 +561,7 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name,
 	CHECK(zr_create(mctx, ldap_inst, ldap_inst->global_settings,
 			&ldap_inst->zone_register));
 	CHECK(fwdr_create(ldap_inst->mctx, &ldap_inst->fwd_register));
+	CHECK(mldap_new(mctx, &ldap_inst->mldapdb));
 
 	CHECK(isc_mutex_init(&ldap_inst->kinit_lock));
 
@@ -652,6 +655,7 @@ destroy_ldap_instance(ldap_instance_t **ldap_instp)
 	/* Unregister all zones already registered in BIND. */
 	zr_destroy(&ldap_inst->zone_register);
 	fwdr_destroy(&ldap_inst->fwd_register);
+	mldap_destroy(&ldap_inst->mldapdb);
 
 	ldap_pool_destroy(&ldap_inst->pool);
 	dns_view_detach(&ldap_inst->view);
-- 
2.1.0

From 77418d2a585d41f1bc3743db100203c662a6cdc8 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 12 May 2015 14:03:47 +0200
Subject: [PATCH] Add LDAP UUID to LDAP entry structure.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_entry.c  | 6 ++++--
 src/ldap_entry.h  | 4 ++--
 src/ldap_helper.c | 2 +-
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/ldap_entry.c b/src/ldap_entry.c
index 5551e664255f029aefe276ec5bbdee7e6add7e8b..e11c6f17ca3920582e272d0b8a9fa54ad05797be 100644
--- a/src/ldap_entry.c
+++ b/src/ldap_entry.c
@@ -137,7 +137,7 @@ cleanup:
  */
 isc_result_t
 ldap_entry_create(isc_mem_t *mctx, LDAP *ld, LDAPMessage *ldap_entry,
-		  ldap_entry_t **entryp)
+		  struct berval	*uuid, ldap_entry_t **entryp)
 {
 	isc_result_t result;
 	ldap_attribute_t *attr = NULL;
@@ -151,7 +151,6 @@ ldap_entry_create(isc_mem_t *mctx, LDAP *ld, LDAPMessage *ldap_entry,
 	REQUIRE(*entryp == NULL);
 
 	CHECK(ldap_entry_init(mctx, &entry));
-	entry->ldap_entry = ldap_entry;
 
 	for (attribute = ldap_first_attribute(ld, ldap_entry, &ber);
 	     attribute != NULL;
@@ -173,6 +172,7 @@ ldap_entry_create(isc_mem_t *mctx, LDAP *ld, LDAPMessage *ldap_entry,
 		log_ldap_error(ld, "unable to get entry DN");
 		CLEANUP_WITH(ISC_R_FAILURE);
 	}
+	entry->uuid = ber_dupbv(NULL, uuid);
 
 	*entryp = entry;
 
@@ -202,6 +202,8 @@ ldap_entry_destroy(isc_mem_t *mctx, ldap_entry_t **entryp)
 	ldap_attributelist_destroy(mctx, &entry->attrs);
 	if (entry->dn != NULL)
 		ldap_memfree(entry->dn);
+	if (entry->uuid != NULL)
+		ber_bvfree(entry->uuid);
 	if (entry->lex != NULL) {
 		isc_lex_close(entry->lex);
 		isc_lex_destroy(&entry->lex);
diff --git a/src/ldap_entry.h b/src/ldap_entry.h
index 635b58f235e4bf43cb0195833c87acc9618fabf6..1f8748988775e8f446179abab6af9c2f9952d30f 100644
--- a/src/ldap_entry.h
+++ b/src/ldap_entry.h
@@ -49,8 +49,8 @@ typedef LIST(ldap_attribute_t)	ldap_attributelist_t;
 typedef struct ldap_entry	ldap_entry_t;
 typedef LIST(ldap_entry_t)	ldap_entrylist_t;
 struct ldap_entry {
-	LDAPMessage		*ldap_entry;
 	char			*dn;
+	struct berval		*uuid;
 	ldap_attribute_t	*lastattr;
 	ldap_attributelist_t	attrs;
 	LINK(ldap_entry_t)	link;
@@ -104,7 +104,7 @@ ldap_entrylist_append(isc_mem_t *mctx, LDAP *ld, LDAPMessage *msg,
  */
 isc_result_t
 ldap_entry_create(isc_mem_t *mctx, LDAP *ld, LDAPMessage *ldap_entry,
-		  ldap_entry_t **entryp) ATTR_NONNULLS ATTR_CHECKRESULT;
+		  struct berval	*uuid, ldap_entry_t **entryp) ATTR_NONNULLS ATTR_CHECKRESULT;
 
 void
 ldap_entry_destroy(isc_mem_t *mctx, ldap_entry_t **entryp) ATTR_NONNULLS;
diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index a25cad855fd088e04692198a3ce5e98c6dd55010..9046353351038cd06f90a59a13c96309cc18c42c 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -4368,7 +4368,7 @@ int ldap_sync_search_entry (
 		return LDAP_SUCCESS;
 
 	CHECK(sync_concurr_limit_wait(inst->sctx));
-	CHECK(ldap_entry_create(inst->mctx, ls->ls_ld, msg, &entry));
+	CHECK(ldap_entry_create(inst->mctx, ls->ls_ld, msg, entryUUID, &entry));
 	syncrepl_update(inst, entry, phase);
 #ifdef RBTDB_DEBUG
 	if (++count % 100 == 0)
-- 
2.1.0

From efb2b01d9080ca2314e74bf4313b7f45c18ddf57 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Wed, 13 May 2015 14:00:34 +0200
Subject: [PATCH] Store object class, generation number, and DNS names into
 meta-LDAP DB.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_helper.c | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index 9046353351038cd06f90a59a13c96309cc18c42c..0f089169852b7c74f9ee3ef655bd14f2a5fa091a 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -80,6 +80,7 @@
 #include "ldap_helper.h"
 #include "lock.h"
 #include "log.h"
+#include "metadb.h"
 #include "mldap.h"
 #include "rdlist.h"
 #include "semaphore.h"
@@ -4357,31 +4358,56 @@ int ldap_sync_search_entry (
 	ldap_instance_t *inst = ls->ls_private;
 	ldap_entry_t *entry = NULL;
 	isc_result_t result;
+	metadb_node_t *node = NULL;
+	isc_boolean_t mdb_write = ISC_FALSE;
+	ldap_entryclass_t class;
+	DECLARE_BUFFERED_NAME(fqdn);
+	DECLARE_BUFFERED_NAME(zone_name);
+
 #ifdef RBTDB_DEBUG
 	static unsigned int count = 0;
 #endif
 
-	/* TODO: Use this for UUID->DN mapping and MODDN detection. */
-	UNUSED(entryUUID);
-
 	if (inst->exiting)
 		return LDAP_SUCCESS;
 
+	INIT_BUFFERED_NAME(fqdn);
+	INIT_BUFFERED_NAME(zone_name);
+
 	CHECK(sync_concurr_limit_wait(inst->sctx));
 	CHECK(ldap_entry_create(inst->mctx, ls->ls_ld, msg, entryUUID, &entry));
+	if (phase == LDAP_SYNC_CAPI_ADD || phase == LDAP_SYNC_CAPI_MODIFY) {
+		CHECK(mldap_newversion(inst->mldapdb));
+		mdb_write = ISC_TRUE;
+		CHECK(mldap_entry_create(entry, inst->mldapdb, &node));
+		CHECK(ldap_entry_getclass(entry, &class));
+		if ((class & LDAP_ENTRYCLASS_CONFIG) == 0) {
+			CHECK(dn_to_dnsname(inst->mctx, entry->dn,
+					    &fqdn, &zone_name, NULL));
+			CHECK(mldap_dnsname_store(&fqdn, &zone_name, node));
+		}
+		metadb_node_close(&node);
+		mldap_closeversion(inst->mldapdb, ISC_TRUE);
+	}
 	syncrepl_update(inst, entry, phase);
 #ifdef RBTDB_DEBUG
 	if (++count % 100 == 0)
 		log_info("ldap_sync_search_entry: %u entries read; inuse: %zd",
 			 count, isc_mem_inuse(inst->mctx));
 #endif
 
 cleanup:
 	if (result != ISC_R_SUCCESS) {
+		if (mdb_write == ISC_TRUE)
+			mldap_closeversion(inst->mldapdb, ISC_FALSE);
 		log_error_r("ldap_sync_search_entry failed");
 		sync_concurr_limit_signal(inst->sctx);
 		/* TODO: Add 'tainted' flag to the LDAP instance. */
 	}
+	if (dns_name_dynamic(&fqdn))
+		dns_name_free(&fqdn, inst->mctx);
+	if (dns_name_dynamic(&zone_name))
+		dns_name_free(&zone_name, inst->mctx);
 
 	/* Following return code will never reach upper layers.
 	 * It is limitation in ldap_sync_init() and ldap_sync_poll()
-- 
2.1.0

From da3a3ad4c184ec5d6bb99caf3955eae56a3e3995 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Thu, 14 May 2015 11:35:02 +0200
Subject: [PATCH] Move typedefs to types.h to avoid cross-include problems.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/acl.h          | 1 -
 src/ldap_convert.h | 3 ++-
 src/ldap_driver.c  | 1 +
 src/ldap_entry.c   | 3 +++
 src/ldap_entry.h   | 2 +-
 src/ldap_helper.h  | 4 ++--
 src/lock.c         | 1 +
 src/lock.h         | 2 +-
 src/mldap.h        | 4 +++-
 src/settings.h     | 1 -
 src/types.h        | 3 +++
 src/zone_manager.h | 2 +-
 12 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/src/acl.h b/src/acl.h
index e438132f623b4efb2c3e2d595b1d83065f8583dc..b6603a2a5e2ad4cf57311160f80754a434c68cff 100644
--- a/src/acl.h
+++ b/src/acl.h
@@ -21,7 +21,6 @@
 #ifndef _LD_ACL_H_
 #define _LD_ACL_H_
 
-#include "ldap_entry.h"
 #include "types.h"
 
 #include <dns/acl.h>
diff --git a/src/ldap_convert.h b/src/ldap_convert.h
index daa0db0b311dd51c05ade688715550d9f70759ac..112aaac4426f7e2229c040e1202df324278bbfb6 100644
--- a/src/ldap_convert.h
+++ b/src/ldap_convert.h
@@ -22,10 +22,11 @@
 #define _LD_LDAP_CONVERT_H_
 
 #include <dns/types.h>
+#include <dns/rbt.h>
 #include <dns/rdatatype.h>
 
 #include "str.h"
-#include "zone_register.h"
+#include "types.h"
 
 #define LDAP_ATTR_FORMATSIZE 32 /* "expected" maximum attribute name length */
 #define LDAP_RDATATYPE_SUFFIX     "Record"
diff --git a/src/ldap_driver.c b/src/ldap_driver.c
index 8b78c960cfb05cc0f4c0fb50e3fbdaa9cfdcae50..931f57324211a2cefdfbd3a620a31a75340a82a7 100644
--- a/src/ldap_driver.c
+++ b/src/ldap_driver.c
@@ -54,6 +54,7 @@
 #include "rdlist.h"
 #include "util.h"
 #include "zone_manager.h"
+#include "zone_register.h"
 
 #ifdef HAVE_VISIBILITY
 #define VISIBLE __attribute__((__visibility__("default")))
diff --git a/src/ldap_entry.c b/src/ldap_entry.c
index e11c6f17ca3920582e272d0b8a9fa54ad05797be..49bc2f0865ebad53841f592da63be977b3c1aca0 100644
--- a/src/ldap_entry.c
+++ b/src/ldap_entry.c
@@ -32,8 +32,11 @@
 
 #include "ldap_convert.h"
 #include "ldap_entry.h"
+#include "mldap.h"
+#include "metadb.h"
 #include "str.h"
 #include "util.h"
+#include "zone_register.h"
 
 /* Represents values associated with LDAP attribute */
 static void ATTR_NONNULLS
diff --git a/src/ldap_entry.h b/src/ldap_entry.h
index 1f8748988775e8f446179abab6af9c2f9952d30f..6fc3cbd8e31141d3deff606d6831f5797c3d8be3 100644
--- a/src/ldap_entry.h
+++ b/src/ldap_entry.h
@@ -29,6 +29,7 @@
 #include "fwd_register.h"
 #include "util.h"
 #include "str.h"
+#include "types.h"
 
 #define LDAP_DEPRECATED 1
 #include <ldap.h>
@@ -46,7 +47,6 @@ typedef struct ldap_attribute	ldap_attribute_t;
 typedef LIST(ldap_attribute_t)	ldap_attributelist_t;
 
 /* Represents LDAP entry and it's attributes */
-typedef struct ldap_entry	ldap_entry_t;
 typedef LIST(ldap_entry_t)	ldap_entrylist_t;
 struct ldap_entry {
 	char			*dn;
diff --git a/src/ldap_helper.h b/src/ldap_helper.h
index 834b30d5b5b4bf61ebee561734998ce0b442f081..7e328226eb34c956b8e17015ad1a3516a2a11dd3 100644
--- a/src/ldap_helper.h
+++ b/src/ldap_helper.h
@@ -22,13 +22,13 @@
 #ifndef _LD_LDAP_HELPER_H_
 #define _LD_LDAP_HELPER_H_
 
-#include "settings.h"
 #include "types.h"
-#include "zone_register.h"
 
 #include <isc/eventclass.h>
 #include <isc/util.h>
 
+#include <ldap.h>
+
 #define LDAPDB_EVENTCLASS 		ISC_EVENTCLASS(0xDDDD)
 
 isc_result_t ldapdb_rdatalist_findrdatatype(ldapdb_rdatalist_t *rdatalist,
diff --git a/src/lock.c b/src/lock.c
index b6b2e9fe828bee54f7c2637eafdb9b15080ba663..fb00927843de2e24d7a63d0ef0be7200341cc691 100644
--- a/src/lock.c
+++ b/src/lock.c
@@ -22,6 +22,7 @@
 #include <isc/util.h>
 
 #include "lock.h"
+#include "ldap_helper.h"
 
 /**
  * Lock BIND dispatcher and allow only single task to run.
diff --git a/src/lock.h b/src/lock.h
index ed271646703115126dbea184a406fd0a6405ccdc..2d0ebbd6af7647944553452e93cb5523e9887c1a 100644
--- a/src/lock.h
+++ b/src/lock.h
@@ -21,8 +21,8 @@
 #ifndef LOCK_H_
 #define LOCK_H_
 
-#include "ldap_helper.h"
 #include "util.h"
+#include "types.h"
 
 void ATTR_NONNULLS
 run_exclusive_enter(ldap_instance_t *inst, isc_result_t *statep);
diff --git a/src/mldap.h b/src/mldap.h
index a0e9b7372ea8d114178ced1d1e2ffcfd4eb00bfc..a44c2648c5aa16d97c04babd55951af25e608d29 100644
--- a/src/mldap.h
+++ b/src/mldap.h
@@ -5,10 +5,12 @@
 #ifndef SRC_MLDAP_H_
 #define SRC_MLDAP_H_
 
+#include <ldap.h>
+
 #include "metadb.h"
+#include "types.h"
 #include "util.h"
 
-typedef struct mldapdb mldapdb_t;
 
 isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
 mldap_new(isc_mem_t *mctx, mldapdb_t **dbp);
diff --git a/src/settings.h b/src/settings.h
index 610e4283254873ae63cfd7059d64f125ebe74ad9..300b714d922c7caa8cfe7bda553e709e5b41db32 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -33,7 +33,6 @@
 #define SETTING_SET_NAME_ZONE   "LDAP idnsZone object"
 
 typedef struct setting	setting_t;
-typedef struct settings_set	settings_set_t;
 
 /* Make sure that cases in get_value_ptr() are synchronized */
 typedef enum {
diff --git a/src/types.h b/src/types.h
index 1ca1411d1d29ce1e8475a3f9fa888519e08a730a..047612f30c875b731c320fd1e540f5c5cb39b206 100644
--- a/src/types.h
+++ b/src/types.h
@@ -48,5 +48,8 @@ typedef struct enum_txt_assoc {
 
 typedef struct ldap_instance	ldap_instance_t;
 typedef struct zone_register	zone_register_t;
+typedef struct mldapdb		mldapdb_t;
+typedef struct ldap_entry	ldap_entry_t;
+typedef struct settings_set	settings_set_t;
 
 #endif /* !_LD_TYPES_H_ */
diff --git a/src/zone_manager.h b/src/zone_manager.h
index 556e66c25e3e0ef4cc74bc870a510e7f302ed2c3..ee4a094594b0ea9bb0650a41edaba6dd4571bae7 100644
--- a/src/zone_manager.h
+++ b/src/zone_manager.h
@@ -24,7 +24,7 @@
 
 #include <dns/types.h>
 
-#include "ldap_helper.h"
+#include "types.h"
 
 typedef struct db_instance db_instance_t;
 
-- 
2.1.0

From f05db549465129588469d274f4d30e7223f8b3ce Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Thu, 14 May 2015 12:33:24 +0200
Subject: [PATCH] Add functions for reading from generic meta-database.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/metadb.c | 34 ++++++++++++++++++++++++++++++++++
 src/metadb.h |  4 ++++
 2 files changed, 38 insertions(+)

diff --git a/src/metadb.c b/src/metadb.c
index bbde3a85fed233ad35a2c81f0c0dbf0b530638df..b9caf24b261139add9bd0e003c7878fb188b4803 100644
--- a/src/metadb.c
+++ b/src/metadb.c
@@ -254,3 +254,37 @@ cleanup:
 		result = ISC_R_SUCCESS;
 	return result;
 }
+
+/**
+ * Get rdataset of given type from metaDB.
+ *
+ * Caller has to call dns_rdataset_dissociate() on the returned rdataset.
+ * Rdata will become invalid after dns_rdataset_dissociate() call.
+ *
+ * Note: It is not possible to directly return rdata without rdataset because
+ *       there would be no way how to dissociate rdataset.
+ *
+ * @pre Node was created by metadb_writenode_create() or metadb_readnode_open().
+ * @pre rdatataset is valid diassociated rdataset.
+ *
+ * @post Rdataset is an associated rdataset with exactly one rdata instance.
+ *       Rdata can be obtained using dns_rdadaset_current().
+ */
+isc_result_t
+metadb_rdataset_get(metadb_node_t *node, dns_rdatatype_t rrtype,
+		    dns_rdataset_t *rdataset) {
+	isc_result_t result;
+
+	REQUIRE(dns_rdataset_isassociated(rdataset) == ISC_FALSE);
+
+	CHECK(dns_db_findrdataset(node->rbtdb, node->dbnode, node->version,
+				  rrtype, 0, 0, rdataset, NULL));
+	/* Exactly one RR is expected in metaDB. */
+	INSIST(dns_rdataset_count(rdataset) == 1);
+	INSIST(dns_rdataset_first(rdataset) == ISC_R_SUCCESS);
+
+cleanup:
+	if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(rdataset))
+		dns_rdataset_disassociate(rdataset);
+	return result;
+}
diff --git a/src/metadb.h b/src/metadb.h
index c49ac0dc2db46b8e62820d2e907b77bf82e59c2f..f1869d87b72f2c3dad8c0b1a7311b3578673c135 100644
--- a/src/metadb.h
+++ b/src/metadb.h
@@ -46,6 +46,10 @@ metadb_writenode_create(metadb_t *mdb, dns_name_t *mname, metadb_node_t **nodep)
 isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
 metadb_rdata_store(dns_rdata_t *rdata, metadb_node_t *node);
 
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+metadb_rdataset_get(metadb_node_t *node, dns_rdatatype_t rrtype,
+		    dns_rdataset_t *rdataset);
+
 void ATTR_NONNULLS
 metadb_node_close(metadb_node_t **nodep);
 
-- 
2.1.0

From 71a5e1133c6e4db0cf8831b6300a111af4e91a28 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Thu, 14 May 2015 12:36:12 +0200
Subject: [PATCH] Add functions for reading from meta-LDAP database.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/mldap.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/mldap.h |  9 ++++++++
 2 files changed, 82 insertions(+)

diff --git a/src/mldap.c b/src/mldap.c
index 2b06ec6a11d6ada37aea1bee177b3201d16be7e2..4eea4b6588ea7df4d14405ed8349add7ac911d48 100644
--- a/src/mldap.c
+++ b/src/mldap.c
@@ -153,6 +153,31 @@ mldap_class_store(ldap_entryclass_t class, metadb_node_t *node) {
 	return metadb_rdata_store(&rdata, node);
 }
 
+isc_result_t
+mldap_class_get(metadb_node_t *node, ldap_entryclass_t *classp) {
+	isc_result_t result;
+	dns_rdataset_t rdataset;
+	dns_rdata_t rdata;
+	isc_region_t region;
+
+	REQUIRE(classp != NULL);
+
+	dns_rdata_init(&rdata);
+	dns_rdataset_init(&rdataset);
+
+	CHECK(metadb_rdataset_get(node, dns_rdatatype_aaaa, &rdataset));
+	dns_rdataset_current(&rdataset, &rdata);
+	dns_rdata_toregion(&rdata, &region);
+	/* Bytes should be in network-order but we do not care because:
+	 * 1) It is used only internally.  2) Class is unsigned char. */
+	memcpy(classp, region.base, sizeof(*classp));
+
+cleanup:
+	if (dns_rdataset_isassociated(&rdataset))
+		dns_rdataset_disassociate(&rdataset);
+	return result;
+}
+
 
 STATIC_ASSERT((sizeof(((mldapdb_t *)0)->generation) == sizeof(struct in_addr)), \
 		"mldapdb_t->generation is too big for A rdata type");
@@ -209,6 +234,39 @@ cleanup:
 }
 
 /**
+ * Retrieve FQDN and zone name from RP record in metaDB.
+ * @param[in]  node
+ * @param[out] fqdn
+ * @param[out] zone
+ *
+ * @pre DNS names fqdn and zone have dedicated buffer.
+ */
+isc_result_t
+mldap_dnsname_get(metadb_node_t *node, dns_name_t *fqdn, dns_name_t *zone) {
+	isc_result_t result;
+	dns_rdata_rp_t rp;
+	dns_rdataset_t rdataset;
+	dns_rdata_t rdata;
+
+	REQUIRE(fqdn != NULL);
+	REQUIRE(zone != NULL);
+
+	dns_rdataset_init(&rdataset);
+	dns_rdata_init(&rdata);
+
+	CHECK(metadb_rdataset_get(node, dns_rdatatype_rp, &rdataset));
+	dns_rdataset_current(&rdataset, &rdata);
+	CHECK(dns_rdata_tostruct(&rdata, &rp, NULL));
+	CHECK(dns_name_copy(&rp.mail, fqdn, NULL));
+	CHECK(dns_name_copy(&rp.text, zone, NULL));
+
+cleanup:
+	if (dns_rdataset_isassociated(&rdataset))
+		dns_rdataset_disassociate(&rdataset);
+	return result;
+}
+
+/**
  * Store information from LDAP entry into meta-database.
  */
 isc_result_t
@@ -236,3 +294,18 @@ cleanup:
 		metadb_node_close(&node);
 	return result;
 }
+
+/**
+ * Open metaLDAP entry for reading.
+ * All notes about metadb_readnode_open() apply equally here.
+ */
+isc_result_t
+mldap_entry_read(mldapdb_t *mldap, struct berval *uuid, metadb_node_t **nodep) {
+	DECLARE_BUFFERED_NAME(mname);
+
+	INIT_BUFFERED_NAME(mname);
+
+	ldap_uuid_to_mname(uuid, &mname);
+
+	return metadb_readnode_open(mldap->mdb, &mname, nodep);
+}
diff --git a/src/mldap.h b/src/mldap.h
index a44c2648c5aa16d97c04babd55951af25e608d29..8312a638416c1f8b17b7293c32b071f1b3f71665 100644
--- a/src/mldap.h
+++ b/src/mldap.h
@@ -25,9 +25,18 @@ void ATTR_NONNULLS
 mldap_closeversion(mldapdb_t *mldap, isc_boolean_t commit);
 
 isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+mldap_entry_read(mldapdb_t *mldap, struct berval *uuid, metadb_node_t **nodep);
+
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
 mldap_entry_create(ldap_entry_t *entry, mldapdb_t *mldap, metadb_node_t **nodep);
 
 isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+mldap_class_get(metadb_node_t *node, ldap_entryclass_t *class);
+
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+mldap_dnsname_get(metadb_node_t *node, dns_name_t *fqdn, dns_name_t *zone);
+
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
 mldap_dnsname_store(dns_name_t *fqdn, dns_name_t *zone, metadb_node_t *node);
 
 #endif /* SRC_MLDAP_H_ */
-- 
2.1.0

From 6556ea2034300cc41b24d5593b6773b623f54cf7 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Thu, 14 May 2015 13:35:27 +0200
Subject: [PATCH] Use information from metaDB for LDAP object deletion.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_entry.c  | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/ldap_entry.h  |  5 ++++
 src/ldap_helper.c | 15 +++++++++++-
 3 files changed, 87 insertions(+), 1 deletion(-)

diff --git a/src/ldap_entry.c b/src/ldap_entry.c
index 49bc2f0865ebad53841f592da63be977b3c1aca0..7e77cc2bd73e3ffad0c62dddf9978779fbf6dada 100644
--- a/src/ldap_entry.c
+++ b/src/ldap_entry.c
@@ -136,6 +136,74 @@ cleanup:
 }
 
 /**
+ * Create fake LDAP entry with values from metaDB. No attributes will be
+ * present in the fake entry.
+ *
+ * @param[in]  mldap
+ * @param[in]  uuid   LDAP entry UUID
+ * @param[out] entryp Resulting entry. Caller has to free it.
+ *
+ * @warning fake entry->dn might be inaccurate
+ */
+isc_result_t
+ldap_entry_reconstruct(isc_mem_t *mctx, zone_register_t *zr,
+		       const char *ldap_base, mldapdb_t *mldap,
+		       struct berval *uuid, ldap_entry_t **entryp) {
+	isc_result_t result;
+	ldap_entry_t *entry = NULL;
+	ld_string_t *str = NULL;
+	metadb_node_t *node = NULL;
+	ldap_entryclass_t class;
+	DECLARE_BUFFERED_NAME(fqdn);
+	DECLARE_BUFFERED_NAME(zone_name);
+
+	INIT_BUFFERED_NAME(fqdn);
+	INIT_BUFFERED_NAME(zone_name);
+
+	CHECK(str_new(mctx, &str));
+	result = mldap_entry_read(mldap, uuid, &node);
+	if (result != ISC_R_SUCCESS) {
+		log_bug("protocol violation: "
+			"attempt to reconstruct non-existing entry");
+		goto cleanup;
+	}
+	CHECK(ldap_entry_init(mctx, &entry));
+
+	entry->uuid = ber_dupbv(NULL, uuid);
+	if (entry->uuid == NULL)
+		CLEANUP_WITH(ISC_R_NOMEMORY);
+
+	CHECK(mldap_class_get(node, &class));
+	/* create fake DN from remembered DNS names and object class */
+	if ((class & LDAP_ENTRYCLASS_CONFIG) != 0) {
+		/* idnsConfig objects do not have DNS name */
+		CHECK(str_cat_char(str, ldap_base));
+	} else {
+		CHECK(mldap_dnsname_get(node, &fqdn, &zone_name));
+		if ((class &
+		     (LDAP_ENTRYCLASS_MASTER | LDAP_ENTRYCLASS_FORWARD)) != 0) {
+			INSIST(dns_name_equal(dns_rootname, &zone_name)
+			       == ISC_TRUE);
+			CHECK(dnsname_to_dn(zr, &fqdn, &fqdn, str));
+		} else if ((class & LDAP_ENTRYCLASS_RR) != 0) {
+			CHECK(dnsname_to_dn(zr, &fqdn, &zone_name, str));
+		}
+	}
+	entry->dn = ldap_strdup(str_buf(str));
+	if (entry->dn == NULL)
+		CLEANUP_WITH(ISC_R_NOMEMORY);
+
+	*entryp = entry;
+
+cleanup:
+	if (result != ISC_R_SUCCESS)
+		ldap_entry_destroy(mctx, &entry);
+	metadb_node_close(&node);
+	str_destroy(&str);
+	return result;
+}
+
+/**
  * Allocate new ldap_entry and fill it with data from LDAPMessage.
  */
 isc_result_t
diff --git a/src/ldap_entry.h b/src/ldap_entry.h
index 6fc3cbd8e31141d3deff606d6831f5797c3d8be3..ac7d1ee537232052e4fbdbcfd3016c1f72a74489 100644
--- a/src/ldap_entry.h
+++ b/src/ldap_entry.h
@@ -106,6 +106,11 @@ isc_result_t
 ldap_entry_create(isc_mem_t *mctx, LDAP *ld, LDAPMessage *ldap_entry,
 		  struct berval	*uuid, ldap_entry_t **entryp) ATTR_NONNULLS ATTR_CHECKRESULT;
 
+isc_result_t
+ldap_entry_reconstruct(isc_mem_t *mctx, zone_register_t *zr, const char *ldap_base,
+		       mldapdb_t *mldap, struct berval *uuid,
+		       ldap_entry_t **entryp) ATTR_NONNULLS ATTR_CHECKRESULT;
+
 void
 ldap_entry_destroy(isc_mem_t *mctx, ldap_entry_t **entryp) ATTR_NONNULLS;
 
diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index 0f089169852b7c74f9ee3ef655bd14f2a5fa091a..1c8e49ed8983f7d016f2cdb73f06c8bac783fba1 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -4361,6 +4361,7 @@ int ldap_sync_search_entry (
 	metadb_node_t *node = NULL;
 	isc_boolean_t mdb_write = ISC_FALSE;
 	ldap_entryclass_t class;
+	const char *ldap_base = NULL;
 	DECLARE_BUFFERED_NAME(fqdn);
 	DECLARE_BUFFERED_NAME(zone_name);
 
@@ -4375,8 +4376,9 @@ int ldap_sync_search_entry (
 	INIT_BUFFERED_NAME(zone_name);
 
 	CHECK(sync_concurr_limit_wait(inst->sctx));
-	CHECK(ldap_entry_create(inst->mctx, ls->ls_ld, msg, entryUUID, &entry));
 	if (phase == LDAP_SYNC_CAPI_ADD || phase == LDAP_SYNC_CAPI_MODIFY) {
+		CHECK(ldap_entry_create(inst->mctx, ls->ls_ld, msg, entryUUID,
+					&entry));
 		CHECK(mldap_newversion(inst->mldapdb));
 		mdb_write = ISC_TRUE;
 		CHECK(mldap_entry_create(entry, inst->mldapdb, &node));
@@ -4388,6 +4390,16 @@ int ldap_sync_search_entry (
 		}
 		metadb_node_close(&node);
 		mldap_closeversion(inst->mldapdb, ISC_TRUE);
+
+	} else if (phase == LDAP_SYNC_CAPI_DELETE) {
+		INSIST(setting_get_str("base", inst->local_settings,
+				       &ldap_base) == ISC_R_SUCCESS);
+		CHECK(ldap_entry_reconstruct(inst->mctx, inst->zone_register,
+					     ldap_base, inst->mldapdb, entryUUID,
+					     &entry));
+	} else {
+		log_bug("syncrepl phase %x is not supported", phase);
+		CLEANUP_WITH(ISC_R_NOTIMPLEMENTED);
 	}
 	syncrepl_update(inst, entry, phase);
 #ifdef RBTDB_DEBUG
@@ -4404,6 +4416,7 @@ cleanup:
 		sync_concurr_limit_signal(inst->sctx);
 		/* TODO: Add 'tainted' flag to the LDAP instance. */
 	}
+	metadb_node_close(&node);
 	if (dns_name_dynamic(&fqdn))
 		dns_name_free(&fqdn, inst->mctx);
 	if (dns_name_dynamic(&zone_name))
-- 
2.1.0

From 4fb7bd42609c2b6a4ffbdf6f3a1e58e00d84fa1e Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 12 May 2015 14:22:25 +0200
Subject: [PATCH] Rename ldap_entry_create() to ldap_entry_parse().

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_entry.c  | 2 +-
 src/ldap_entry.h  | 2 +-
 src/ldap_helper.c | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/ldap_entry.c b/src/ldap_entry.c
index 7e77cc2bd73e3ffad0c62dddf9978779fbf6dada..dc986c6771c28ab8a4c4c3d50b6f9f6c8593358b 100644
--- a/src/ldap_entry.c
+++ b/src/ldap_entry.c
@@ -207,7 +207,7 @@ cleanup:
  * Allocate new ldap_entry and fill it with data from LDAPMessage.
  */
 isc_result_t
-ldap_entry_create(isc_mem_t *mctx, LDAP *ld, LDAPMessage *ldap_entry,
+ldap_entry_parse(isc_mem_t *mctx, LDAP *ld, LDAPMessage *ldap_entry,
 		  struct berval	*uuid, ldap_entry_t **entryp)
 {
 	isc_result_t result;
diff --git a/src/ldap_entry.h b/src/ldap_entry.h
index ac7d1ee537232052e4fbdbcfd3016c1f72a74489..5953aaef9f994ae9323aa4fca9c35aa5611a75e4 100644
--- a/src/ldap_entry.h
+++ b/src/ldap_entry.h
@@ -103,7 +103,7 @@ ldap_entrylist_append(isc_mem_t *mctx, LDAP *ld, LDAPMessage *msg,
  * Creates ldap_entry_t from message "result" received via "ld" connection
  */
 isc_result_t
-ldap_entry_create(isc_mem_t *mctx, LDAP *ld, LDAPMessage *ldap_entry,
+ldap_entry_parse(isc_mem_t *mctx, LDAP *ld, LDAPMessage *ldap_entry,
 		  struct berval	*uuid, ldap_entry_t **entryp) ATTR_NONNULLS ATTR_CHECKRESULT;
 
 isc_result_t
diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index 1c8e49ed8983f7d016f2cdb73f06c8bac783fba1..4294488589f0f24fd88e1d05a1c1d9e7c11f8a9c 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -4377,7 +4377,7 @@ int ldap_sync_search_entry (
 
 	CHECK(sync_concurr_limit_wait(inst->sctx));
 	if (phase == LDAP_SYNC_CAPI_ADD || phase == LDAP_SYNC_CAPI_MODIFY) {
-		CHECK(ldap_entry_create(inst->mctx, ls->ls_ld, msg, entryUUID,
+		CHECK(ldap_entry_parse(inst->mctx, ls->ls_ld, msg, entryUUID,
 					&entry));
 		CHECK(mldap_newversion(inst->mldapdb));
 		mdb_write = ISC_TRUE;
@@ -4401,6 +4401,7 @@ int ldap_sync_search_entry (
 		log_bug("syncrepl phase %x is not supported", phase);
 		CLEANUP_WITH(ISC_R_NOTIMPLEMENTED);
 	}
+
 	syncrepl_update(inst, entry, phase);
 #ifdef RBTDB_DEBUG
 	if (++count % 100 == 0)
-- 
2.1.0

From 3f11f82f2d2c88f50417d75c2d4d70a9563daabf Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 12 May 2015 15:21:00 +0200
Subject: [PATCH] Replace ldap_entry_parseclass() by LDAP entry struct member
 variable.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_entry.c  | 21 +++++++++++++++------
 src/ldap_entry.h  | 13 ++-----------
 src/ldap_helper.c | 16 +++++-----------
 src/mldap.c       |  4 +---
 4 files changed, 23 insertions(+), 31 deletions(-)

diff --git a/src/ldap_entry.c b/src/ldap_entry.c
index dc986c6771c28ab8a4c4c3d50b6f9f6c8593358b..6156bd09c95ef451d68638137a978baffea84849 100644
--- a/src/ldap_entry.c
+++ b/src/ldap_entry.c
@@ -38,6 +38,15 @@
 #include "util.h"
 #include "zone_register.h"
 
+/*
+ * ldap_entry_parseclass
+ *
+ * Get entry class (bitwise OR of the LDAP_ENTRYCLASS_*). Note that
+ * you must ldap_search for objectClass attribute!
+ */
+static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT
+ldap_entry_parseclass(ldap_entry_t *entry, ldap_entryclass_t *class);
+
 /* Represents values associated with LDAP attribute */
 static void ATTR_NONNULLS
 ldap_valuelist_destroy(isc_mem_t *mctx, ldap_valuelist_t *values)
@@ -153,7 +162,6 @@ ldap_entry_reconstruct(isc_mem_t *mctx, zone_register_t *zr,
 	ldap_entry_t *entry = NULL;
 	ld_string_t *str = NULL;
 	metadb_node_t *node = NULL;
-	ldap_entryclass_t class;
 	DECLARE_BUFFERED_NAME(fqdn);
 	DECLARE_BUFFERED_NAME(zone_name);
 
@@ -173,19 +181,19 @@ ldap_entry_reconstruct(isc_mem_t *mctx, zone_register_t *zr,
 	if (entry->uuid == NULL)
 		CLEANUP_WITH(ISC_R_NOMEMORY);
 
-	CHECK(mldap_class_get(node, &class));
+	CHECK(mldap_class_get(node, &entry->class));
 	/* create fake DN from remembered DNS names and object class */
-	if ((class & LDAP_ENTRYCLASS_CONFIG) != 0) {
+	if ((entry->class & LDAP_ENTRYCLASS_CONFIG) != 0) {
 		/* idnsConfig objects do not have DNS name */
 		CHECK(str_cat_char(str, ldap_base));
 	} else {
 		CHECK(mldap_dnsname_get(node, &fqdn, &zone_name));
-		if ((class &
+		if ((entry->class &
 		     (LDAP_ENTRYCLASS_MASTER | LDAP_ENTRYCLASS_FORWARD)) != 0) {
 			INSIST(dns_name_equal(dns_rootname, &zone_name)
 			       == ISC_TRUE);
 			CHECK(dnsname_to_dn(zr, &fqdn, &fqdn, str));
-		} else if ((class & LDAP_ENTRYCLASS_RR) != 0) {
+		} else if ((entry->class & LDAP_ENTRYCLASS_RR) != 0) {
 			CHECK(dnsname_to_dn(zr, &fqdn, &zone_name, str));
 		}
 	}
@@ -244,6 +252,7 @@ ldap_entry_parse(isc_mem_t *mctx, LDAP *ld, LDAPMessage *ldap_entry,
 		CLEANUP_WITH(ISC_R_FAILURE);
 	}
 	entry->uuid = ber_dupbv(NULL, uuid);
+	CHECK(ldap_entry_parseclass(entry, &entry->class));
 
 	*entryp = entry;
 
@@ -426,7 +435,7 @@ cleanup:
 }
 
 isc_result_t
-ldap_entry_getclass(ldap_entry_t *entry, ldap_entryclass_t *class)
+ldap_entry_parseclass(ldap_entry_t *entry, ldap_entryclass_t *class)
 {
 	ldap_valuelist_t values;
 	ldap_value_t *val;
diff --git a/src/ldap_entry.h b/src/ldap_entry.h
index 5953aaef9f994ae9323aa4fca9c35aa5611a75e4..9c0d882c2e0e26d947f6881721f7450bca9a1068 100644
--- a/src/ldap_entry.h
+++ b/src/ldap_entry.h
@@ -47,10 +47,12 @@ typedef struct ldap_attribute	ldap_attribute_t;
 typedef LIST(ldap_attribute_t)	ldap_attributelist_t;
 
 /* Represents LDAP entry and it's attributes */
+typedef unsigned char		ldap_entryclass_t;
 typedef LIST(ldap_entry_t)	ldap_entrylist_t;
 struct ldap_entry {
 	char			*dn;
 	struct berval		*uuid;
+	ldap_entryclass_t	class;
 	ldap_attribute_t	*lastattr;
 	ldap_attributelist_t	attrs;
 	LINK(ldap_entry_t)	link;
@@ -78,8 +80,6 @@ struct ldap_attribute {
 
 #define DEFAULT_TTL 86400
 
-typedef unsigned char		ldap_entryclass_t;
-
 /* Max type length definitions, from lib/dns/master.c */
 #define TOKENSIZ (8*1024)
 
@@ -136,15 +136,6 @@ isc_result_t
 ldap_entry_getfakesoa(ldap_entry_t *entry, const char *fake_mname,
 		      ld_string_t *target) ATTR_NONNULLS ATTR_CHECKRESULT;
 
-/*
- * ldap_entry_getclass
- *
- * Get entry class (bitwise OR of the LDAP_ENTRYCLASS_*). Note that
- * you must ldap_search for objectClass attribute!
- */
-isc_result_t
-ldap_entry_getclass(ldap_entry_t *entry, ldap_entryclass_t *class) ATTR_NONNULLS ATTR_CHECKRESULT;
-
 isc_result_t
 ldap_entry_guessclass(dns_name_t *entry_name, isc_boolean_t iszone,
 		      fwd_register_t *fwd_register, ldap_entryclass_t *class)
diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index 4294488589f0f24fd88e1d05a1c1d9e7c11f8a9c..72823cedec32b6a895c1f2da126896d466f4211f 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -2589,7 +2589,6 @@ ldap_parse_rrentry(isc_mem_t *mctx, ldap_entry_t *entry, dns_name_t *origin,
 {
 	isc_result_t result;
 	dns_rdataclass_t rdclass;
-	ldap_entryclass_t objclass;
 	dns_ttl_t ttl;
 	dns_rdatatype_t rdtype;
 	dns_rdata_t *rdata = NULL;
@@ -2602,8 +2601,7 @@ ldap_parse_rrentry(isc_mem_t *mctx, ldap_entry_t *entry, dns_name_t *origin,
 	REQUIRE(EMPTY(*rdatalist));
 
 	CHECK(str_new(mctx, &data_buf));
-	CHECK(ldap_entry_getclass(entry, &objclass));
-	if ((objclass & LDAP_ENTRYCLASS_MASTER) != 0)
+	if ((entry->class & LDAP_ENTRYCLASS_MASTER) != 0)
 		CHECK(add_soa_record(mctx, origin, entry, rdatalist, fake_mname));
 
 	rdclass = ldap_entry_getrdclass(entry);
@@ -3705,7 +3703,6 @@ update_zone(isc_task_t *task, isc_event_t *event)
 	ldap_syncreplevent_t *pevent = (ldap_syncreplevent_t *)event;
 	isc_result_t result ;
 	ldap_instance_t *inst = NULL;
-	ldap_entryclass_t objclass;
 	isc_mem_t *mctx;
 	dns_name_t prevname;
 	dns_name_t currname;
@@ -3724,11 +3721,10 @@ update_zone(isc_task_t *task, isc_event_t *event)
 	if (SYNCREPL_DEL(pevent->chgtype)) {
 		CHECK(ldap_delete_zone(inst, pevent->dn, ISC_TRUE, ISC_FALSE));
 	} else {
-		CHECK(ldap_entry_getclass(entry, &objclass));
-		if (objclass & LDAP_ENTRYCLASS_MASTER)
+		if (entry->class & LDAP_ENTRYCLASS_MASTER)
 			CHECK(ldap_parse_master_zoneentry(entry, NULL, inst,
 							  task));
-		else if (objclass & LDAP_ENTRYCLASS_FORWARD)
+		else if (entry->class & LDAP_ENTRYCLASS_FORWARD)
 			CHECK(ldap_parse_fwd_zoneentry(entry, inst));
 	}
 
@@ -4146,7 +4142,7 @@ syncrepl_update(ldap_instance_t *inst, ldap_entry_t *entry, int chgtype)
 		switch (chgtype) {
 		case LDAP_SYNC_CAPI_ADD:
 		case LDAP_SYNC_CAPI_MODIFY:
-			CHECK(ldap_entry_getclass(entry, &class));
+			class = entry->class;
 			break;
 
 		default:
@@ -4360,7 +4356,6 @@ int ldap_sync_search_entry (
 	isc_result_t result;
 	metadb_node_t *node = NULL;
 	isc_boolean_t mdb_write = ISC_FALSE;
-	ldap_entryclass_t class;
 	const char *ldap_base = NULL;
 	DECLARE_BUFFERED_NAME(fqdn);
 	DECLARE_BUFFERED_NAME(zone_name);
@@ -4382,8 +4377,7 @@ int ldap_sync_search_entry (
 		CHECK(mldap_newversion(inst->mldapdb));
 		mdb_write = ISC_TRUE;
 		CHECK(mldap_entry_create(entry, inst->mldapdb, &node));
-		CHECK(ldap_entry_getclass(entry, &class));
-		if ((class & LDAP_ENTRYCLASS_CONFIG) == 0) {
+		if ((entry->class & LDAP_ENTRYCLASS_CONFIG) == 0) {
 			CHECK(dn_to_dnsname(inst->mctx, entry->dn,
 					    &fqdn, &zone_name, NULL));
 			CHECK(mldap_dnsname_store(&fqdn, &zone_name, node));
diff --git a/src/mldap.c b/src/mldap.c
index 4eea4b6588ea7df4d14405ed8349add7ac911d48..3195ad89f1eb51d72bb0e2487a913a6e871466b4 100644
--- a/src/mldap.c
+++ b/src/mldap.c
@@ -272,7 +272,6 @@ cleanup:
 isc_result_t
 mldap_entry_create(ldap_entry_t *entry, mldapdb_t *mldap, metadb_node_t **nodep) {
 	isc_result_t result;
-	ldap_entryclass_t class;
 	metadb_node_t *node = NULL;
 	DECLARE_BUFFERED_NAME(mname);
 
@@ -283,8 +282,7 @@ mldap_entry_create(ldap_entry_t *entry, mldapdb_t *mldap, metadb_node_t **nodep)
 	ldap_uuid_to_mname(entry->uuid, &mname);
 	CHECK(metadb_writenode_create(mldap->mdb, &mname, &node));
 
-	CHECK(ldap_entry_getclass(entry, &class));
-	CHECK(mldap_class_store(class, node));
+	CHECK(mldap_class_store(entry->class, node));
 	CHECK(mldap_generation_store(mldap, node));
 
 	*nodep = node;
-- 
2.1.0

From 31eca2f3971368e0fb7c75722ea47c23d18cd8d7 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 12 May 2015 15:49:27 +0200
Subject: [PATCH] Add pre-parsed DNS names to LDAP entry structure.

All LDAP objects except idnsConfig need a DNS name anyway.

This is a step towards removal of dependency on entry->dn field
which is unavailable for deleted objects.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_entry.c | 34 +++++++++++++++++++++++++---------
 src/ldap_entry.h |  3 +++
 2 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/src/ldap_entry.c b/src/ldap_entry.c
index 6156bd09c95ef451d68638137a978baffea84849..165d034cc4a15b0867b2dbbef74f16d6b9a97d51 100644
--- a/src/ldap_entry.c
+++ b/src/ldap_entry.c
@@ -131,6 +131,8 @@ ldap_entry_init(isc_mem_t *mctx, ldap_entry_t **entryp) {
 	ZERO_PTR(entry);
 	INIT_LIST(entry->attrs);
 	INIT_LINK(entry, link);
+	INIT_BUFFERED_NAME(entry->fqdn);
+	INIT_BUFFERED_NAME(entry->zone_name);
 
 	CHECKED_MEM_GET(mctx, entry->rdata_target_mem, DNS_RDATA_MAXLENGTH);
 	CHECK(isc_lex_create(mctx, TOKENSIZ, &entry->lex));
@@ -162,11 +164,6 @@ ldap_entry_reconstruct(isc_mem_t *mctx, zone_register_t *zr,
 	ldap_entry_t *entry = NULL;
 	ld_string_t *str = NULL;
 	metadb_node_t *node = NULL;
-	DECLARE_BUFFERED_NAME(fqdn);
-	DECLARE_BUFFERED_NAME(zone_name);
-
-	INIT_BUFFERED_NAME(fqdn);
-	INIT_BUFFERED_NAME(zone_name);
 
 	CHECK(str_new(mctx, &str));
 	result = mldap_entry_read(mldap, uuid, &node);
@@ -187,14 +184,15 @@ ldap_entry_reconstruct(isc_mem_t *mctx, zone_register_t *zr,
 		/* idnsConfig objects do not have DNS name */
 		CHECK(str_cat_char(str, ldap_base));
 	} else {
-		CHECK(mldap_dnsname_get(node, &fqdn, &zone_name));
+		CHECK(mldap_dnsname_get(node, &entry->fqdn, &entry->zone_name));
 		if ((entry->class &
 		     (LDAP_ENTRYCLASS_MASTER | LDAP_ENTRYCLASS_FORWARD)) != 0) {
-			INSIST(dns_name_equal(dns_rootname, &zone_name)
+			INSIST(dns_name_equal(dns_rootname, &entry->zone_name)
 			       == ISC_TRUE);
-			CHECK(dnsname_to_dn(zr, &fqdn, &fqdn, str));
+			CHECK(dnsname_to_dn(zr, &entry->fqdn, &entry->fqdn, str));
 		} else if ((entry->class & LDAP_ENTRYCLASS_RR) != 0) {
-			CHECK(dnsname_to_dn(zr, &fqdn, &zone_name, str));
+			CHECK(dnsname_to_dn(zr, &entry->fqdn, &entry->zone_name,
+					    str));
 		}
 	}
 	entry->dn = ldap_strdup(str_buf(str));
@@ -223,6 +221,8 @@ ldap_entry_parse(isc_mem_t *mctx, LDAP *ld, LDAPMessage *ldap_entry,
 	char *attribute;
 	BerElement *ber = NULL;
 	ldap_entry_t *entry = NULL;
+	isc_boolean_t has_zone_dn;
+	isc_boolean_t has_zone_class;
 
 	REQUIRE(ld != NULL);
 	REQUIRE(ldap_entry != NULL);
@@ -254,6 +254,18 @@ ldap_entry_parse(isc_mem_t *mctx, LDAP *ld, LDAPMessage *ldap_entry,
 	entry->uuid = ber_dupbv(NULL, uuid);
 	CHECK(ldap_entry_parseclass(entry, &entry->class));
 
+	if ((entry->class &
+	    (LDAP_ENTRYCLASS_MASTER | LDAP_ENTRYCLASS_FORWARD
+	     | LDAP_ENTRYCLASS_RR)) != 0)
+		CHECK(dn_to_dnsname(mctx, entry->dn, &entry->fqdn,
+				    &entry->zone_name, &has_zone_dn));
+	else
+		has_zone_dn = ISC_FALSE;
+	has_zone_class = ISC_TF(entry->class & (LDAP_ENTRYCLASS_MASTER
+						| LDAP_ENTRYCLASS_FORWARD));
+	CHECK(dn_want_zone(__func__, entry->dn, has_zone_dn, has_zone_class));
+
+
 	*entryp = entry;
 
 cleanup:
@@ -284,6 +296,10 @@ ldap_entry_destroy(isc_mem_t *mctx, ldap_entry_t **entryp)
 		ldap_memfree(entry->dn);
 	if (entry->uuid != NULL)
 		ber_bvfree(entry->uuid);
+	if (dns_name_dynamic(&entry->fqdn))
+		dns_name_free(&entry->fqdn, mctx);
+	if (dns_name_dynamic(&entry->zone_name))
+		dns_name_free(&entry->zone_name, mctx);
 	if (entry->lex != NULL) {
 		isc_lex_close(entry->lex);
 		isc_lex_destroy(&entry->lex);
diff --git a/src/ldap_entry.h b/src/ldap_entry.h
index 9c0d882c2e0e26d947f6881721f7450bca9a1068..606fe8894579dc527e3a1723de51d5f9b700dd5d 100644
--- a/src/ldap_entry.h
+++ b/src/ldap_entry.h
@@ -53,6 +53,9 @@ struct ldap_entry {
 	char			*dn;
 	struct berval		*uuid;
 	ldap_entryclass_t	class;
+	DECLARE_BUFFERED_NAME(fqdn);
+	DECLARE_BUFFERED_NAME(zone_name);
+
 	ldap_attribute_t	*lastattr;
 	ldap_attributelist_t	attrs;
 	LINK(ldap_entry_t)	link;
-- 
2.1.0

From 6187b1a4f1179d4d98d29a40d7e293c2f5ef2089 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Wed, 13 May 2015 11:06:09 +0200
Subject: [PATCH] Adapt update_record() to use pre-parsed DNS names in LDAP
 entry.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_helper.c | 23 ++++++-----------------
 1 file changed, 6 insertions(+), 17 deletions(-)

diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index 72823cedec32b6a895c1f2da126896d466f4211f..97ef857e01cf8a463bde885042319378389cdbb7 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -3833,7 +3833,6 @@ update_record(isc_task_t *task, isc_event_t *event)
 	isc_boolean_t zone_reloaded = ISC_FALSE;
 	isc_uint32_t serial;
 	ldap_entry_t *entry = pevent->entry;
-	isc_boolean_t iszone;
 	const char *fake_mname = NULL;
 
 	dns_db_t *rbtdb = NULL;
@@ -3859,29 +3858,23 @@ update_record(isc_task_t *task, isc_event_t *event)
 	INIT_LIST(rdatalist);
 
 	/* 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(manager_get_ldap_instance(pevent->dbname, &inst));
-	CHECK(dn_to_dnsname(mctx, pevent->dn, &name, &origin, &iszone));
-	INSIST(iszone == ISC_FALSE);
-	CHECK(zr_get_zone_ptr(inst->zone_register, &origin, &raw, &secure));
+	CHECK(zr_get_zone_ptr(inst->zone_register, &entry->zone_name, &raw, &secure));
 	zone_found = ISC_TRUE;
 
 update_restart:
 	rbtdb = NULL;
 	ldapdb = NULL;
 	ldapdb_rdatalist_destroy(mctx, &rdatalist);
-	CHECK(zr_get_zone_dbs(inst->zone_register, &origin, &ldapdb, &rbtdb));
+	CHECK(zr_get_zone_dbs(inst->zone_register, &entry->zone_name, &ldapdb, &rbtdb));
 	CHECK(dns_db_newversion(ldapdb, &version));
 
-	CHECK(dns_db_findnode(rbtdb, &name, ISC_TRUE, &node));
+	CHECK(dns_db_findnode(rbtdb, &entry->fqdn, ISC_TRUE, &node));
 	result = dns_db_allrdatasets(rbtdb, node, version, 0, &rbt_rds_iterator);
 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
 		goto cleanup;
@@ -3931,12 +3924,12 @@ update_restart:
 		          pevent->dn);
 		CHECK(setting_get_str("fake_mname", inst->local_settings,
 				      &fake_mname));
-		CHECK(ldap_parse_rrentry(mctx, entry, &origin, fake_mname,
+		CHECK(ldap_parse_rrentry(mctx, entry, &entry->zone_name, fake_mname,
 					 &rdatalist));
 	}
 
 	if (rbt_rds_iterator != NULL) {
-		CHECK(diff_ldap_rbtdb(mctx, &name, &rdatalist,
+		CHECK(diff_ldap_rbtdb(mctx, &entry->fqdn, &rdatalist,
 				      rbt_rds_iterator, &diff));
 		dns_rdatasetiter_destroy(&rbt_rds_iterator);
 	}
@@ -3950,7 +3943,7 @@ update_restart:
 			dns_zone_log(raw, ISC_LOG_DEBUG(5),
 				     "writing new zone serial %u to LDAP",
 				     serial);
-			result = ldap_replace_serial(inst, &origin, serial);
+			result = ldap_replace_serial(inst, &entry->zone_name, serial);
 			if (result != ISC_R_SUCCESS)
 				dns_zone_log(raw, ISC_LOG_ERROR,
 					     "serial (%u) write back to LDAP failed",
@@ -4032,12 +4025,8 @@ cleanup:
 
 	if (inst != NULL) {
 		sync_concurr_limit_signal(inst->sctx);
-		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);
 	}
-- 
2.1.0

From cc4dda573db838e4bf26f194984f92309e8c8923 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Wed, 13 May 2015 11:16:01 +0200
Subject: [PATCH] Adapt ldap_parse_fwd_zoneentry() to use pre-parsed DNS names
 in LDAP entry.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_helper.c | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index 97ef857e01cf8a463bde885042319378389cdbb7..6454f9817977b832becd27b3aeaec97d3c640052 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -1769,52 +1769,44 @@ static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT
 ldap_parse_fwd_zoneentry(ldap_entry_t *entry, ldap_instance_t *inst)
 {
 	const char *dn;
-	dns_name_t name;
 	ldap_valuelist_t values;
-	isc_boolean_t iszone;
 	char name_txt[DNS_NAME_FORMATSIZE];
 	isc_result_t result;
 
 	REQUIRE(entry != NULL);
 	REQUIRE(inst != NULL);
 
-	dns_name_init(&name, NULL);
-
 	/* Derive the DNS name of the zone from the DN. */
 	dn = entry->dn;
-	CHECK(dn_to_dnsname(inst->mctx, dn, &name, NULL, &iszone));
-	INSIST(iszone == ISC_TRUE);
 
 	CHECK(ldap_entry_getvalues(entry, "idnsZoneActive", &values));
 	if (HEAD(values) != NULL &&
 	    strcasecmp(HEAD(values)->value, "TRUE") != 0) {
 		/* Zone is not active */
-		result = ldap_delete_zone2(inst, &name, ISC_TRUE, ISC_FALSE);
+		result = ldap_delete_zone2(inst, &entry->fqdn,
+					   ISC_TRUE, ISC_FALSE);
 		goto cleanup;
 	}
 
 	/* Zone is active */
-	result = configure_zone_forwarders(entry, inst, &name);
+	result = configure_zone_forwarders(entry, inst, &entry->fqdn);
 	if (result != ISC_R_DISABLED && result != ISC_R_SUCCESS) {
 		log_error_r("forward zone '%s': could not configure forwarding", dn);
 		goto cleanup;
 	}
 
-	result = fwdr_add_zone(inst->fwd_register, &name);
+	result = fwdr_add_zone(inst->fwd_register, &entry->fqdn);
 	if (result != ISC_R_EXISTS && result != ISC_R_SUCCESS) {
-		dns_name_format(&name, name_txt, DNS_NAME_FORMATSIZE);
+		dns_name_format(&entry->fqdn, name_txt, DNS_NAME_FORMATSIZE);
 		log_error_r("failed to add forward zone '%s' "
 			    "to the forwarding register", name_txt);
 		goto cleanup;
 	}
 	result = ISC_R_SUCCESS;
-	dns_name_format(&name, name_txt, DNS_NAME_FORMATSIZE);
+	dns_name_format(&entry->fqdn, name_txt, DNS_NAME_FORMATSIZE);
 	log_info("forward zone '%s': loaded", name_txt);
 
 cleanup:
-	if (dns_name_dynamic(&name))
-		dns_name_free(&name, inst->mctx);
-
 	return result;
 }
 
-- 
2.1.0

From 4bce8e6c64e527e47e5bb51adedc04e05695c5ce Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Wed, 13 May 2015 11:28:11 +0200
Subject: [PATCH] Adapt update_zone() to use pre-parsed DNS names in LDAP
 entry.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_helper.c | 32 ++------------------------------
 1 file changed, 2 insertions(+), 30 deletions(-)

diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index 6454f9817977b832becd27b3aeaec97d3c640052..38bf37736beabb6f5246bbca9c5bed9c85fb2b0e 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -1387,28 +1387,6 @@ cleanup:
 	return result;
 }
 
-/* Delete zone */
-static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT
-ldap_delete_zone(ldap_instance_t *inst, const char *dn, isc_boolean_t lock,
-		 isc_boolean_t preserve_forwarding)
-{
-	isc_result_t result;
-	isc_boolean_t iszone;
-	dns_name_t name;
-	dns_name_init(&name, NULL);
-	
-	CHECK(dn_to_dnsname(inst->mctx, dn, &name, NULL, &iszone));
-	INSIST(iszone == ISC_TRUE);
-
-	result = ldap_delete_zone2(inst, &name, lock, preserve_forwarding);
-
-cleanup:
-	if (dns_name_dynamic(&name))
-		dns_name_free(&name, inst->mctx);
-
-	return result;
-}
-
 /**
  * Remove zone from view but let the zone object intact. The same zone object
  * can be re-published later using publish_zone().
@@ -3697,21 +3675,17 @@ update_zone(isc_task_t *task, isc_event_t *event)
 	ldap_instance_t *inst = NULL;
 	isc_mem_t *mctx;
 	dns_name_t prevname;
-	dns_name_t currname;
 	ldap_entry_t *entry = pevent->entry;
-	isc_boolean_t iszone;
 
 	mctx = pevent->mctx;
-	dns_name_init(&currname, NULL);
 	dns_name_init(&prevname, NULL);
 
 	CHECK(manager_get_ldap_instance(pevent->dbname, &inst));
 	INSIST(task == inst->task); /* For task-exclusive mode */
-	CHECK(dn_to_dnsname(inst->mctx, pevent->dn, &currname, NULL, &iszone));
-	INSIST(iszone == ISC_TRUE);
 
 	if (SYNCREPL_DEL(pevent->chgtype)) {
-		CHECK(ldap_delete_zone(inst, pevent->dn, ISC_TRUE, ISC_FALSE));
+		CHECK(ldap_delete_zone2(inst, &entry->fqdn,
+					ISC_TRUE, ISC_FALSE));
 	} else {
 		if (entry->class & LDAP_ENTRYCLASS_MASTER)
 			CHECK(ldap_parse_master_zoneentry(entry, NULL, inst,
@@ -3750,8 +3724,6 @@ cleanup:
 	if (inst != NULL) {
 		sync_concurr_limit_signal(inst->sctx);
 		sync_event_signal(inst->sctx, event);
-		if (dns_name_dynamic(&currname))
-			dns_name_free(&currname, inst->mctx);
 		if (dns_name_dynamic(&prevname))
 			dns_name_free(&prevname, inst->mctx);
 	}
-- 
2.1.0

From 3641ce90df42da414fe62b87be569224afc1bdc6 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Wed, 13 May 2015 11:38:49 +0200
Subject: [PATCH] Adapt ldap_parse_master_zoneentry() to use pre-parsed DNS
 names in LDAP entry.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_helper.c | 30 +++++++++++++-----------------
 1 file changed, 13 insertions(+), 17 deletions(-)

diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index 38bf37736beabb6f5246bbca9c5bed9c85fb2b0e..8d21fbf839bca9c28b7bfbce65b9aa76038cacd7 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -2284,17 +2284,15 @@ ldap_parse_master_zoneentry(ldap_entry_t * const entry, dns_db_t * const olddb,
 {
 	const char *dn;
 	ldap_valuelist_t values;
-	dns_name_t name;
 	dns_zone_t *raw = NULL;
 	dns_zone_t *secure = NULL;
 	dns_zone_t *toview = NULL;
 	isc_result_t result;
 	isc_result_t lock_state = ISC_R_IGNORE;
 	isc_boolean_t new_zone = ISC_FALSE;
 	isc_boolean_t want_secure = ISC_FALSE;
 	isc_boolean_t configured = ISC_FALSE;
 	isc_boolean_t activity_changed;
-	isc_boolean_t iszone;
 	isc_boolean_t isactive = ISC_FALSE;
 	settings_set_t *zone_settings = NULL;
 	isc_boolean_t ldap_writeback;
@@ -2312,16 +2310,13 @@ ldap_parse_master_zoneentry(ldap_entry_t * const entry, dns_db_t * const olddb,
 	REQUIRE(task == inst->task); /* For task-exclusive mode */
 
 	dns_diff_init(inst->mctx, &diff);
-	dns_name_init(&name, NULL);
 
 	/* Derive the dns name of the zone from the DN. */
 	dn = entry->dn;
-	CHECK(dn_to_dnsname(inst->mctx, dn, &name, NULL, &iszone));
-	INSIST(iszone == ISC_TRUE);
 
 	run_exclusive_enter(inst, &lock_state);
 
-	result = configure_zone_forwarders(entry, inst, &name);
+	result = configure_zone_forwarders(entry, inst, &entry->fqdn);
 	if (result != ISC_R_SUCCESS && result != ISC_R_DISABLED)
 		goto cleanup;
 
@@ -2333,9 +2328,10 @@ ldap_parse_master_zoneentry(ldap_entry_t * const entry, dns_db_t * const olddb,
 				     == 0);
 
 	/* Check if we are already serving given zone */
-	result = zr_get_zone_ptr(inst->zone_register, &name, &raw, &secure);
+	result = zr_get_zone_ptr(inst->zone_register, &entry->fqdn,
+				 &raw, &secure);
 	if (result == ISC_R_NOTFOUND || result == DNS_R_PARTIALMATCH) {
-		CHECK(create_zone(inst, dn, &name, olddb, want_secure,
+		CHECK(create_zone(inst, dn, &entry->fqdn, olddb, want_secure,
 				  &raw, &secure));
 		new_zone = ISC_TRUE;
 		log_debug(2, "created zone %s: raw %p; secure %p", dn, raw,
@@ -2349,20 +2345,21 @@ ldap_parse_master_zoneentry(ldap_entry_t * const entry, dns_db_t * const olddb,
 		else
 			dns_zone_log(secure, ISC_LOG_INFO,
 				     "downgrading zone to insecure");
-		CHECK(zone_security_change(entry, &name, inst, task));
+		CHECK(zone_security_change(entry, &entry->fqdn, inst, task));
 		goto cleanup;
 	} else { /* Zone exists and it's security status is unchanged. */
 		INSIST(olddb == NULL);
 	}
 
-	CHECK(zr_get_zone_settings(inst->zone_register, &name, &zone_settings));
+	CHECK(zr_get_zone_settings(inst->zone_register, &entry->fqdn,
+				   &zone_settings));
 	CHECK(zone_master_reconfigure(entry, zone_settings, raw, secure, task));
 
 	/* synchronize zone origin with LDAP */
-	CHECK(zr_get_zone_dbs(inst->zone_register, &name, &ldapdb, &rbtdb));
+	CHECK(zr_get_zone_dbs(inst->zone_register, &entry->fqdn, &ldapdb, &rbtdb));
 	CHECK(dns_db_newversion(ldapdb, &version));
 	sync_state_get(inst->sctx, &sync_state);
-	CHECK(zone_sync_apex(inst, entry, name, sync_state, new_zone,
+	CHECK(zone_sync_apex(inst, entry, entry->fqdn, sync_state, new_zone,
 			     ldapdb, rbtdb, version,
 			     &diff, &new_serial, &ldap_writeback,
 			     &data_changed));
@@ -2375,7 +2372,7 @@ ldap_parse_master_zoneentry(ldap_entry_t * const entry, dns_db_t * const olddb,
 	if (ldap_writeback == ISC_TRUE) {
 		dns_zone_log(raw, ISC_LOG_DEBUG(5), "writing new zone serial "
 			     "%u to LDAP", new_serial);
-		result = ldap_replace_serial(inst, &name, new_serial);
+		result = ldap_replace_serial(inst, &entry->fqdn, new_serial);
 		if (result != ISC_R_SUCCESS)
 			dns_zone_log(raw, ISC_LOG_ERROR,
 				     "serial (%u) write back to LDAP failed",
@@ -2421,7 +2418,7 @@ ldap_parse_master_zoneentry(ldap_entry_t * const entry, dns_db_t * const olddb,
 			CHECK(publish_zone(task, inst, toview));
 		CHECK(load_zone(toview, ISC_FALSE));
 	} else if (activity_changed == ISC_TRUE) { /* Zone was deactivated */
-		CHECK(unpublish_zone(inst, &name, entry->dn));
+		CHECK(unpublish_zone(inst, &entry->fqdn, entry->dn));
 		dns_zone_log(toview, ISC_LOG_INFO, "zone deactivated "
 			     "and removed from view");
 	}
@@ -2439,13 +2436,12 @@ cleanup:
 		log_error_r("zone '%s': publishing failed, rolling back due to",
 			    entry->dn);
 		/* TODO: verify this */
-		result = ldap_delete_zone2(inst, &name, ISC_TRUE, ISC_FALSE);
+		result = ldap_delete_zone2(inst, &entry->fqdn,
+					   ISC_TRUE, ISC_FALSE);
 		if (result != ISC_R_SUCCESS)
 			log_error_r("zone '%s': rollback failed: ", entry->dn);
 	}
 	run_exclusive_exit(inst, lock_state);
-	if (dns_name_dynamic(&name))
-		dns_name_free(&name, inst->mctx);
 	if (raw != NULL)
 		dns_zone_detach(&raw);
 	if (secure != NULL)
-- 
2.1.0

From aac8522b32405c0f37c6d12aa50033bd604f7e43 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Thu, 14 May 2015 14:02:41 +0200
Subject: [PATCH] Adapt ldap_sync_search_entry() to use pre-parsed DNS names in
 LDAP entry.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_helper.c | 17 +++--------------
 1 file changed, 3 insertions(+), 14 deletions(-)

diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index 8d21fbf839bca9c28b7bfbce65b9aa76038cacd7..951e873832e273165fe25c2f9d7b0fd5c9168bc7 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -4306,31 +4306,24 @@ int ldap_sync_search_entry (
 	metadb_node_t *node = NULL;
 	isc_boolean_t mdb_write = ISC_FALSE;
 	const char *ldap_base = NULL;
-	DECLARE_BUFFERED_NAME(fqdn);
-	DECLARE_BUFFERED_NAME(zone_name);
 
 #ifdef RBTDB_DEBUG
 	static unsigned int count = 0;
 #endif
 
 	if (inst->exiting)
 		return LDAP_SUCCESS;
 
-	INIT_BUFFERED_NAME(fqdn);
-	INIT_BUFFERED_NAME(zone_name);
-
 	CHECK(sync_concurr_limit_wait(inst->sctx));
 	if (phase == LDAP_SYNC_CAPI_ADD || phase == LDAP_SYNC_CAPI_MODIFY) {
 		CHECK(ldap_entry_parse(inst->mctx, ls->ls_ld, msg, entryUUID,
 					&entry));
 		CHECK(mldap_newversion(inst->mldapdb));
 		mdb_write = ISC_TRUE;
 		CHECK(mldap_entry_create(entry, inst->mldapdb, &node));
-		if ((entry->class & LDAP_ENTRYCLASS_CONFIG) == 0) {
-			CHECK(dn_to_dnsname(inst->mctx, entry->dn,
-					    &fqdn, &zone_name, NULL));
-			CHECK(mldap_dnsname_store(&fqdn, &zone_name, node));
-		}
+		if ((entry->class & LDAP_ENTRYCLASS_CONFIG) == 0)
+			CHECK(mldap_dnsname_store(&entry->fqdn,
+						  &entry->zone_name, node));
 		metadb_node_close(&node);
 		mldap_closeversion(inst->mldapdb, ISC_TRUE);
 
@@ -4361,10 +4354,6 @@ cleanup:
 		/* TODO: Add 'tainted' flag to the LDAP instance. */
 	}
 	metadb_node_close(&node);
-	if (dns_name_dynamic(&fqdn))
-		dns_name_free(&fqdn, inst->mctx);
-	if (dns_name_dynamic(&zone_name))
-		dns_name_free(&zone_name, inst->mctx);
 
 	/* Following return code will never reach upper layers.
 	 * It is limitation in ldap_sync_init() and ldap_sync_poll()
-- 
2.1.0

From f095fdf2c81037e4d4ceb4bd2eda6662be0e4530 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Thu, 14 May 2015 17:17:30 +0200
Subject: [PATCH] Adapt syncrepl_update() to use pre-parsed DNS names and
 metadata in LDAP entry.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_entry.c  | 26 ------------------------
 src/ldap_entry.h  |  5 -----
 src/ldap_helper.c | 60 ++++++++++---------------------------------------------
 3 files changed, 11 insertions(+), 80 deletions(-)

diff --git a/src/ldap_entry.c b/src/ldap_entry.c
index 165d034cc4a15b0867b2dbbef74f16d6b9a97d51..437b31dcca974ee9341560a72b48d69d0ec9b8b9 100644
--- a/src/ldap_entry.c
+++ b/src/ldap_entry.c
@@ -498,32 +498,6 @@ ldap_entry_parseclass(ldap_entry_t *entry, ldap_entryclass_t *class)
 	return ISC_R_SUCCESS;
 }
 
-/**
- * Infer entry class from auxiliary information.
- *
- * This is a fallback method for cases where objectClass values
- * are not available.
- *
- * TODO: Object class information should be stored in UUID database
- * 	 (once we have it).
- */
-isc_result_t
-ldap_entry_guessclass(dns_name_t *entry_name, isc_boolean_t iszone,
-		      fwd_register_t *fwd_register, ldap_entryclass_t *class) {
-	REQUIRE(class != NULL);
-
-	if (iszone == ISC_TRUE) {
-		if (fwdr_zone_ispresent(fwd_register, entry_name)
-		    == ISC_R_SUCCESS)
-			*class = LDAP_ENTRYCLASS_FORWARD;
-		else /* master zone */
-			*class = (LDAP_ENTRYCLASS_MASTER | LDAP_ENTRYCLASS_RR);
-	} else
-		*class = LDAP_ENTRYCLASS_RR;
-
-	return ISC_R_SUCCESS;
-}
-
 isc_result_t
 ldap_attr_firstvalue(ldap_attribute_t *attr, ld_string_t *str)
 {
diff --git a/src/ldap_entry.h b/src/ldap_entry.h
index 606fe8894579dc527e3a1723de51d5f9b700dd5d..2ccdcc42a5b5196791f0842c35f2b6a60155e3a7 100644
--- a/src/ldap_entry.h
+++ b/src/ldap_entry.h
@@ -140,11 +140,6 @@ ldap_entry_getfakesoa(ldap_entry_t *entry, const char *fake_mname,
 		      ld_string_t *target) ATTR_NONNULLS ATTR_CHECKRESULT;
 
 isc_result_t
-ldap_entry_guessclass(dns_name_t *entry_name, isc_boolean_t iszone,
-		      fwd_register_t *fwd_register, ldap_entryclass_t *class)
-		      ATTR_NONNULLS ATTR_CHECKRESULT;
-
-isc_result_t
 ldap_attr_firstvalue(ldap_attribute_t *attr, ld_string_t *str) ATTR_NONNULLS ATTR_CHECKRESULT;
 
 /*
diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index 951e873832e273165fe25c2f9d7b0fd5c9168bc7..592eadb9911f90bbdc58149eb62edcbedef34795 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -4050,72 +4050,40 @@ cleanup:
 static void ATTR_NONNULLS
 syncrepl_update(ldap_instance_t *inst, ldap_entry_t *entry, int chgtype)
 {
-	ldap_entryclass_t class = LDAP_ENTRYCLASS_NONE;
 	isc_result_t result = ISC_R_SUCCESS;
 	ldap_syncreplevent_t *pevent = NULL;
 	isc_event_t *wait_event = NULL;
-	dns_name_t entry_name;
-	dns_name_t entry_origin;
 	dns_name_t *zone_name = NULL;
 	dns_zone_t *zone_ptr = NULL;
 	char *dn = NULL;
 	char *dbname = NULL;
-	const char *ldap_base = NULL;
-	isc_boolean_t isbase;
-	isc_boolean_t iszone;
 	isc_mem_t *mctx = NULL;
 	isc_taskaction_t action = NULL;
 	isc_task_t *task = NULL;
 	sync_state_t sync_state;
 
+	REQUIRE(entry->class != LDAP_ENTRYCLASS_NONE);
+
 	log_debug(20, "syncrepl change type: " /*"none%d,"*/ "add%d, del%d, mod%d", /* moddn%d", */
 		  /* !SYNCREPL_ANY(chgtype), */ SYNCREPL_ADD(chgtype),
 		  SYNCREPL_DEL(chgtype), SYNCREPL_MOD(chgtype)/*, SYNCREPL_MODDN(chgtype) */ );
 
 	isc_mem_attach(inst->mctx, &mctx);
-	dns_name_init(&entry_name, NULL);
-	dns_name_init(&entry_origin, NULL);
 
 	CHECKED_MEM_STRDUP(mctx, entry->dn, dn);
 	CHECKED_MEM_STRDUP(mctx, inst->db_name, dbname);
 
-	/* TODO: handle object class inference properly - via UUID database */
-	CHECK(setting_get_str("base", inst->local_settings, &ldap_base));
-	CHECK(ldap_dn_compare(ldap_base, entry->dn, &isbase));
-	if (isbase == ISC_TRUE) {
-		class = LDAP_ENTRYCLASS_CONFIG;
-		iszone = ISC_FALSE;
-	} else {
-		CHECK(dn_to_dnsname(inst->mctx, dn, &entry_name, &entry_origin,
-				    &iszone));
-		switch (chgtype) {
-		case LDAP_SYNC_CAPI_ADD:
-		case LDAP_SYNC_CAPI_MODIFY:
-			class = entry->class;
-			break;
 
-		default:
-			/* deleted entry doesn't contain objectClass, so
-			 * we need to find if the entry is zone or not
-			 * in other way */
-			CHECK(ldap_entry_guessclass(&entry_name, iszone,
-						    inst->fwd_register,
-						    &class));
-			break;
-		}
-	}
-	REQUIRE(class != LDAP_ENTRYCLASS_NONE);
-
-	if (class & LDAP_ENTRYCLASS_MASTER)
-		zone_name = &entry_name;
+	if (entry->class & LDAP_ENTRYCLASS_MASTER)
+		zone_name = &entry->fqdn;
 	else
-		zone_name = &entry_origin;
+		zone_name = &entry->zone_name;
 
 	/* Process ordinary records in parallel but serialize operations on
 	 * master zone objects.
 	 * See discussion about run_exclusive_begin() function in lock.c. */
-	if ((class & LDAP_ENTRYCLASS_RR) != 0 &&
-	    (class & LDAP_ENTRYCLASS_MASTER) == 0) {
+	if ((entry->class & LDAP_ENTRYCLASS_RR) != 0 &&
+	    (entry->class & LDAP_ENTRYCLASS_MASTER) == 0) {
 		result = zr_get_zone_ptr(inst->zone_register, zone_name,
 					 &zone_ptr, NULL);
 		if (result == ISC_R_SUCCESS && dns_zone_getmgr(zone_ptr) != NULL)
@@ -4141,21 +4109,19 @@ syncrepl_update(ldap_instance_t *inst, ldap_entry_t *entry, int chgtype)
 	}
 	*/
 
-	if ((class & LDAP_ENTRYCLASS_CONFIG) != 0)
+	if ((entry->class & LDAP_ENTRYCLASS_CONFIG) != 0)
 		action = update_config;
-	else if ((class & LDAP_ENTRYCLASS_MASTER) != 0)
+	else if ((entry->class & LDAP_ENTRYCLASS_MASTER) != 0)
 		action = update_zone;
-	else if ((class & LDAP_ENTRYCLASS_FORWARD) != 0)
+	else if ((entry->class & LDAP_ENTRYCLASS_FORWARD) != 0)
 		action = update_zone;
-	else if ((class & LDAP_ENTRYCLASS_RR) != 0)
+	else if ((entry->class & LDAP_ENTRYCLASS_RR) != 0)
 		action = update_record;
 	else {
 		log_error("unsupported objectClass: dn '%s'", dn);
 		result = ISC_R_NOTIMPLEMENTED;
 		goto cleanup;
 	}
-	CHECK(dn_want_zone(__func__, dn, iszone,
-			   ISC_TF(class & (LDAP_ENTRYCLASS_MASTER | LDAP_ENTRYCLASS_FORWARD))));
 
 	/* All events for single zone are handled by one task, so we don't
 	 * need to spend time with normal records. */
@@ -4191,10 +4157,6 @@ syncrepl_update(ldap_instance_t *inst, ldap_entry_t *entry, int chgtype)
 		CHECK(sync_event_wait(inst->sctx, wait_event));
 
 cleanup:
-	if (dns_name_dynamic(&entry_name))
-		dns_name_free(&entry_name, inst->mctx);
-	if (dns_name_dynamic(&entry_origin))
-		dns_name_free(&entry_origin, inst->mctx);
 	if (zone_ptr != NULL)
 		dns_zone_detach(&zone_ptr);
 	if (result != ISC_R_SUCCESS)
-- 
2.1.0

From aed476b4f9b0a3a340a386ae74487f0fa35ac1a4 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Thu, 14 May 2015 18:13:55 +0200
Subject: [PATCH] Add function for node deletion from generic meta-database.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/metadb.c | 40 ++++++++++++++++++++++++++++++++++++++++
 src/metadb.h |  3 +++
 2 files changed, 43 insertions(+)

diff --git a/src/metadb.c b/src/metadb.c
index b9caf24b261139add9bd0e003c7878fb188b4803..e36f28190cf16527715320d876feab7089f54e83 100644
--- a/src/metadb.c
+++ b/src/metadb.c
@@ -9,6 +9,7 @@
 
 #include <dns/db.h>
 #include <dns/rdatalist.h>
+#include <dns/rdatasetiter.h>
 
 #include "metadb.h"
 #include "util.h"
@@ -147,6 +148,45 @@ metadb_node_close(metadb_node_t **nodep) {
 }
 
 /**
+ * Delete all RRsets in given metaDB node.
+ */
+isc_result_t
+metadb_node_delete(metadb_node_t **nodep) {
+	isc_result_t result;
+	metadb_node_t *node;
+	dns_rdatasetiter_t *iter = NULL;
+	dns_rdataset_t rdataset;
+
+	REQUIRE(nodep != NULL && *nodep != NULL);
+	node = *nodep;
+
+	dns_rdataset_init(&rdataset);
+	CHECK(dns_db_allrdatasets(node->rbtdb, node->dbnode, node->version, 0,
+				  &iter));
+
+	for (result = dns_rdatasetiter_first(iter);
+	     result == ISC_R_SUCCESS;
+	     result = dns_rdatasetiter_next(iter)) {
+
+		dns_rdatasetiter_current(iter, &rdataset);
+		CHECK(dns_db_deleterdataset(node->rbtdb, node->dbnode,
+					    node->version, rdataset.type, 0));
+		dns_rdataset_disassociate(&rdataset);
+	}
+	if (result == ISC_R_NOMORE)
+		result = ISC_R_SUCCESS;
+
+cleanup:
+	if (dns_rdataset_isassociated(&rdataset))
+		dns_rdataset_disassociate(&rdataset);
+	if (iter != NULL)
+		dns_rdatasetiter_destroy(&iter);
+	if (result == ISC_R_SUCCESS)
+		metadb_node_close(nodep);
+	return result;
+}
+
+/**
  * Create new "metaDB node" structure and attach underlying RBT DB node to it.
  *
  * @param[in]  version Underlying RBTDB version to use.
diff --git a/src/metadb.h b/src/metadb.h
index f1869d87b72f2c3dad8c0b1a7311b3578673c135..681535d26b56692e422c44f40ffd7d43880ba406 100644
--- a/src/metadb.h
+++ b/src/metadb.h
@@ -53,4 +53,7 @@ metadb_rdataset_get(metadb_node_t *node, dns_rdatatype_t rrtype,
 void ATTR_NONNULLS
 metadb_node_close(metadb_node_t **nodep);
 
+isc_result_t ATTR_NONNULLS
+metadb_node_delete(metadb_node_t **nodep);
+
 #endif /* SRC_METADB_H_ */
-- 
2.1.0

From 7cd3861c0cee6709d54c94af7514ca9280aed617 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Thu, 14 May 2015 18:14:38 +0200
Subject: [PATCH] Add ability to open existing metaDB node for writing.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/metadb.c | 30 ++++++++++++++++++++++++++----
 src/metadb.h |  3 +++
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/src/metadb.c b/src/metadb.c
index e36f28190cf16527715320d876feab7089f54e83..610df5a50d5b4ce02d584e8b78f7a9bf74ab159a 100644
--- a/src/metadb.c
+++ b/src/metadb.c
@@ -220,8 +220,8 @@ cleanup:
 }
 
 /**
- * Create new "metaDB node" structure and attach current read-only version of
- * RBT DB to it.
+ * Associate "metaDB node" structure with existing node in current read-only
+ * version of RBT DB.
  *
  * @param[in]  mname Name of the node in metaDB. E.g. '1234.uuid.ldap.'
  * @param[out] nodep Resulting "metaDB node" structure. Node has to be freed
@@ -241,8 +241,7 @@ cleanup:
 }
 
 /**
- * Create new "metaDB node" structure and attach current writeable version of
- * RBT DB to it.
+ * Create new "metaDB node" in current writeable version of metaDB.
  *
  * @param[in]  mname Name of the node in metaDB. E.g. '1234.uuid.ldap.'
  * @param[out] nodep Resulting "metaDB node" structure. Node has to be freed
@@ -265,6 +264,29 @@ cleanup:
 }
 
 /**
+ * Open existing "metaDB node" in current writeable version of metaDB.
+ *
+ * @param[in]  mname Name of the node in metaDB. E.g. '1234.uuid.ldap.'
+ * @param[out] nodep Resulting "metaDB node" structure. Node has to be freed
+ *                   using metadb_node_close().
+ *
+ * @pre MetaDB was opened by newversion().
+ */
+isc_result_t
+metadb_writenode_open(metadb_t *mdb, dns_name_t *mname, metadb_node_t **nodep) {
+	isc_result_t result;
+	dns_dbversion_t *ver = NULL;
+
+	INSIST(mdb->newversion != NULL);
+	dns_db_attachversion(mdb->rbtdb, mdb->newversion, &ver);
+	CHECK(metadb_node_init(mdb, ver, mname, ISC_FALSE, nodep));
+
+cleanup:
+	dns_db_closeversion(mdb->rbtdb, &ver, ISC_FALSE);
+	return result;
+}
+
+/**
  * Store rdata into metaDB node and overwrite all existing values for RR type
  * specified in rdata.
  *
diff --git a/src/metadb.h b/src/metadb.h
index 681535d26b56692e422c44f40ffd7d43880ba406..d6e3490f65a4bdd616e7567f86a875415b9d4c10 100644
--- a/src/metadb.h
+++ b/src/metadb.h
@@ -44,6 +44,9 @@ isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
 metadb_writenode_create(metadb_t *mdb, dns_name_t *mname, metadb_node_t **nodep);
 
 isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+metadb_writenode_open(metadb_t *mdb, dns_name_t *mname, metadb_node_t **nodep);
+
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
 metadb_rdata_store(dns_rdata_t *rdata, metadb_node_t *node);
 
 isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
-- 
2.1.0

From ce007b262a6fad987491a25a9f57772ee1237c54 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Thu, 14 May 2015 18:20:06 +0200
Subject: [PATCH] Add function for node deletion to meta-LDAP database API.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/mldap.c | 21 +++++++++++++++++++++
 src/mldap.h |  3 +++
 2 files changed, 24 insertions(+)

diff --git a/src/mldap.c b/src/mldap.c
index 3195ad89f1eb51d72bb0e2487a913a6e871466b4..71de3c58d9816bc91dc4311f73433e278ffac312 100644
--- a/src/mldap.c
+++ b/src/mldap.c
@@ -307,3 +307,24 @@ mldap_entry_read(mldapdb_t *mldap, struct berval *uuid, metadb_node_t **nodep) {
 
 	return metadb_readnode_open(mldap->mdb, &mname, nodep);
 }
+
+/**
+ * Delete metaLDAP entry.
+ * All notes about metadb_writenode_open() apply equally here.
+ */
+isc_result_t
+mldap_entry_delete(mldapdb_t *mldap, struct berval *uuid) {
+	isc_result_t result;
+	metadb_node_t *node = NULL;
+	DECLARE_BUFFERED_NAME(mname);
+
+	INIT_BUFFERED_NAME(mname);
+
+	ldap_uuid_to_mname(uuid, &mname);
+
+	CHECK(metadb_writenode_open(mldap->mdb, &mname, &node));
+	CHECK(metadb_node_delete(&node));
+
+cleanup:
+	return result;
+}
diff --git a/src/mldap.h b/src/mldap.h
index 8312a638416c1f8b17b7293c32b071f1b3f71665..752ab28b2da956817ad27c9c928863bc9e601c0c 100644
--- a/src/mldap.h
+++ b/src/mldap.h
@@ -31,6 +31,9 @@ isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
 mldap_entry_create(ldap_entry_t *entry, mldapdb_t *mldap, metadb_node_t **nodep);
 
 isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
+mldap_entry_delete(mldapdb_t *mldap, struct berval *uuid);
+
+isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
 mldap_class_get(metadb_node_t *node, ldap_entryclass_t *class);
 
 isc_result_t ATTR_CHECKRESULT ATTR_NONNULLS
-- 
2.1.0

From 0b405088eaf00a79bb02aec854785054f13eec23 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Thu, 14 May 2015 18:21:12 +0200
Subject: [PATCH] Delete metadata about objects deleted from LDAP.

https://fedorahosted.org/bind-dyndb-ldap/ticket/151
---
 src/ldap_helper.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index 592eadb9911f90bbdc58149eb62edcbedef34795..8922141724c4351db9435fd73e91756d60606390 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -4047,7 +4047,7 @@ cleanup:
 	return result;
 }
 
-static void ATTR_NONNULLS
+static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT
 syncrepl_update(ldap_instance_t *inst, ldap_entry_t *entry, int chgtype)
 {
 	isc_result_t result = ISC_R_SUCCESS;
@@ -4176,6 +4176,7 @@ cleanup:
 		if (task != NULL)
 			isc_task_detach(&task);
 	}
+	return result;
 }
 
 #define CHECK_EXIT \
@@ -4266,56 +4267,63 @@ int ldap_sync_search_entry (
 	ldap_entry_t *entry = NULL;
 	isc_result_t result;
 	metadb_node_t *node = NULL;
-	isc_boolean_t mdb_write = ISC_FALSE;
+	isc_boolean_t mldap_open = ISC_FALSE;
 	const char *ldap_base = NULL;
 
 #ifdef RBTDB_DEBUG
 	static unsigned int count = 0;
 #endif
 
 	if (inst->exiting)
 		return LDAP_SUCCESS;
 
+	CHECK(mldap_newversion(inst->mldapdb));
+	mldap_open = ISC_TRUE;
+
 	CHECK(sync_concurr_limit_wait(inst->sctx));
 	if (phase == LDAP_SYNC_CAPI_ADD || phase == LDAP_SYNC_CAPI_MODIFY) {
 		CHECK(ldap_entry_parse(inst->mctx, ls->ls_ld, msg, entryUUID,
 					&entry));
-		CHECK(mldap_newversion(inst->mldapdb));
-		mdb_write = ISC_TRUE;
 		CHECK(mldap_entry_create(entry, inst->mldapdb, &node));
 		if ((entry->class & LDAP_ENTRYCLASS_CONFIG) == 0)
 			CHECK(mldap_dnsname_store(&entry->fqdn,
 						  &entry->zone_name, node));
+		/* commit new entry into metaLDAP DB before something breaks */
 		metadb_node_close(&node);
 		mldap_closeversion(inst->mldapdb, ISC_TRUE);
+		mldap_open = ISC_FALSE;
 
 	} else if (phase == LDAP_SYNC_CAPI_DELETE) {
 		INSIST(setting_get_str("base", inst->local_settings,
 				       &ldap_base) == ISC_R_SUCCESS);
 		CHECK(ldap_entry_reconstruct(inst->mctx, inst->zone_register,
 					     ldap_base, inst->mldapdb, entryUUID,
 					     &entry));
+		CHECK(mldap_entry_delete(inst->mldapdb, entryUUID));
+		/* do not commit into DB until syncrepl_update finished */
 	} else {
 		log_bug("syncrepl phase %x is not supported", phase);
 		CLEANUP_WITH(ISC_R_NOTIMPLEMENTED);
 	}
 
-	syncrepl_update(inst, entry, phase);
+	CHECK(syncrepl_update(inst, entry, phase));
+	/* commit eventual deletion if the syncrepl event was sent */
+
 #ifdef RBTDB_DEBUG
 	if (++count % 100 == 0)
 		log_info("ldap_sync_search_entry: %u entries read; inuse: %zd",
 			 count, isc_mem_inuse(inst->mctx));
 #endif
 
 cleanup:
+	metadb_node_close(&node);
+	if (mldap_open == ISC_TRUE)
+		mldap_closeversion(inst->mldapdb, ISC_TF(result == ISC_R_SUCCESS));
 	if (result != ISC_R_SUCCESS) {
-		if (mdb_write == ISC_TRUE)
-			mldap_closeversion(inst->mldapdb, ISC_FALSE);
 		log_error_r("ldap_sync_search_entry failed");
 		sync_concurr_limit_signal(inst->sctx);
 		/* TODO: Add 'tainted' flag to the LDAP instance. */
 	}
-	metadb_node_close(&node);
 
 	/* Following return code will never reach upper layers.
 	 * It is limitation in ldap_sync_init() and ldap_sync_poll()
-- 
2.1.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to