[WIP][PATCH] GUID index for LDB

Andrew Bartlett abartlet at samba.org
Tue Aug 15 08:21:25 UTC 2017


This is a heads-up about a work I have in progress.

I know that this is a topic around which many folks will have great
ideas, but if we can keep those to small fixes and practical
improvements, that would be really awesome.  We can always make further
changes once we finish and measure this initial set of work.

I know I'm not going to win any awards for this improvement, but my aim
is to make adding users to Samba a little bit faster (because the index
records, for objectclass=user in particular, will be smaller), and to
optimise searching by removing the need to casefold all DNs between the
index and TDB key.

If successful this will make large domains more practical. 

The design is quite simple.  Where we keep records in TDB under a key
of DN=DC=SAMBA,DC=EXAMPLE,DC=COM, instead use the GUID.  Then put that
GUID in the index records. 

The patches as is use the raw GUID except for special records, but of
course that means some @ record could match an unlucky GUID, so I'll
rework it tomorrow to use a GUID= prefix.  

One question, should I use:

GUID=9515e108-3b76-41fb-be2a-956cc90f644a
or
GUID=<binary GUID as raw 16 bytes>

as the key?

To do a base search, the DN -> GUID index in @IDXDN is consulted.  To
offset the cost of that, I optimise the base search not to fetch the
record twice. 

TODO/ideas:
 - make it work (the DN -> GUID index write needs work)
 - use a GUID for linked attribute equality (eg memberOf) /
   rework the extended_dn_in module to prefer GUIDs for the query
 - sort index records
 - use sorted index records for faster intersection calculations.
 - always use the IDXONE index for SCOPE_ONE searches and trust that
result.

The saving from this change is primarily expected to be in the record
page in and parse time by reducing it from variable length strings to
fixed size GUIDs.  'perf' suggests that reading and parsing the index
records is around 10% of the CPU time to add a user, and grows with the
number of users. 

Not included are the full set of tasks to allow O(1) subtree rename, as
that would require re-working the DN->GUID index rather than re-using
the existing code.  

I'm told a B-tree may be a much better structure, in particular a
structure were we don't need to page in and read a large index like
objectclass=user.  I see this kind of a rework as a second stage.

The patches are at:

https://git.samba.org/?p=abartlet/samba.git/.git;a=shortlog;h=refs/heads/GUID-index

The current WIP patches are attached for your interest.

Thanks, 

Andrew Bartlett

-- 
Andrew Bartlett                       http://samba.org/~abartlet/
Authentication Developer, Samba Team  http://samba.org
Samba Developer, Catalyst IT          http://catalyst.net.nz/services/samba
-------------- next part --------------
From e4c04047227774715a91b66a911fa24c87afbe5a Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 15 Aug 2017 17:21:28 +1200
Subject: [PATCH 01/39] ldb_tdb: Add helper function
 ltdb_search_and_return_base()

This avoids an extra DB lookup for the base, when that is the only record we will return

This also avoids looking in the index records for special DNs like @MODULES

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_search.c | 82 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 5 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c
index 53355e0..0cc03bd 100644
--- a/lib/ldb/ldb_tdb/ldb_search.c
+++ b/lib/ldb/ldb_tdb/ldb_search.c
@@ -502,6 +502,66 @@ static int ltdb_search_full(struct ltdb_context *ctx)
 	return ctx->error;
 }
 
+static int ltdb_search_and_return_base(struct ltdb_context *ctx)
+{
+	struct ldb_message *msg, *filtered_msg;
+	struct ldb_context *ldb = ldb_module_get_ctx(ctx->module);
+	int ret;
+	bool matched;
+	
+	msg = ldb_msg_new(ctx);
+	if (!msg) {
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	ret = ltdb_search_dn1(ctx->module, ctx->base, msg,
+			      LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC|
+			      LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC);
+	
+	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+		ldb_asprintf_errstring(ldb, 
+				       "No such Base DN: %s", 
+				       ldb_dn_get_linearized(ctx->base));
+	}
+	if (ret != LDB_SUCCESS) {
+		talloc_free(msg);
+		return ret;
+	}
+
+	ret = ldb_match_msg_error(ldb, msg,
+				  ctx->tree,
+				  ctx->base,
+				  ctx->scope,
+				  &matched);
+	if (ret != LDB_SUCCESS) {
+		talloc_free(msg);
+		return ret;
+	}
+	if (!matched) {
+		talloc_free(msg);
+		return LDB_SUCCESS;
+	}
+
+	/* filter the attributes that the user wants */
+	ret = ltdb_filter_attrs(ctx, msg, ctx->attrs, &filtered_msg);
+	
+	talloc_free(msg);
+
+	if (ret == -1) {
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	
+	ret = ldb_module_send_entry(ctx->req, filtered_msg, NULL);
+	if (ret != LDB_SUCCESS) {
+		/* Regardless of success or failure, the msg
+		 * is the callbacks responsiblity, and should
+		 * not be talloc_free()'ed */
+		ctx->request_terminated = true;
+		return ret;
+	}
+
+	return LDB_SUCCESS;
+}
+
 /*
   search the database with a LDAP-like expression.
   choses a search method
@@ -533,6 +593,11 @@ int ltdb_search(struct ltdb_context *ctx)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
+	ctx->tree = req->op.search.tree;
+	ctx->scope = req->op.search.scope;
+	ctx->base = req->op.search.base;
+	ctx->attrs = req->op.search.attrs;
+
 	if ((req->op.search.base == NULL) || (ldb_dn_is_null(req->op.search.base) == true)) {
 
 		/* Check what we should do with a NULL dn */
@@ -560,6 +625,18 @@ int ltdb_search(struct ltdb_context *ctx)
 				       ldb_dn_get_linearized(req->op.search.base));
 		ret = LDB_ERR_INVALID_DN_SYNTAX;
 
+	} else if (ltdb->check_base && req->op.search.scope == LDB_SCOPE_BASE) {
+
+		/* 
+		 * If we are LDB_SCOPE_BASE, do just one search and 
+		 * return early
+		 */
+		ret = ltdb_search_and_return_base(ctx);
+
+		ltdb_unlock_read(module);
+		
+		return ret;
+
 	} else if (ltdb->check_base) {
 		/* This database has been marked as 'checkBaseOnSearch', so do a spot check of the base dn */
 		ret = ltdb_search_base(module, req->op.search.base);
@@ -575,11 +652,6 @@ int ltdb_search(struct ltdb_context *ctx)
 		ret = LDB_SUCCESS;
 	}
 
-	ctx->tree = req->op.search.tree;
-	ctx->scope = req->op.search.scope;
-	ctx->base = req->op.search.base;
-	ctx->attrs = req->op.search.attrs;
-
 	if (ret == LDB_SUCCESS) {
 		uint32_t match_count = 0;
 
-- 
2.9.4


From 632b86957da3262f136ce10e1e322c602f3e5fe3 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 15 Aug 2017 14:25:59 +1200
Subject: [PATCH 02/39] ldb_tdb: Use memcmp() to compare TDB keys in re_index()

The keys will soon not always be a null terminated string, they can be a binary GUID

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 232bb4c..fbc05bd 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -1620,7 +1620,8 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
 		talloc_free(msg);
 		return 0;
 	}
-	if (strcmp((char *)key2.dptr, (char *)key.dptr) != 0) {
+	if (key.dsize != key2.dsize ||
+	    (memcmp(key.dptr, key2.dptr, key.dsize) != 0)) {
 		tdb_delete(tdb, key);
 		tdb_store(tdb, key2, data, 0);
 	}
-- 
2.9.4


From fb85d4a6e610d83fdac6d3f0f93d38b057a2001e Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 14:31:18 +1200
Subject: [PATCH 03/39] ldb_tdb: provide ldb_key_dn() and ldb_key_msg()

This will in time allow us to generate a TDB key from
the msg, eg from an objectGUID.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c  |  2 +-
 lib/ldb/ldb_tdb/ldb_search.c |  4 ++--
 lib/ldb/ldb_tdb/ldb_tdb.c    | 25 +++++++++++++++++++------
 lib/ldb/ldb_tdb/ldb_tdb.h    |  3 ++-
 4 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index fbc05bd..8e71053 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -1612,7 +1612,7 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
 
 	/* check if the DN key has changed, perhaps due to the
 	   case insensitivity of an element changing */
-	key2 = ltdb_key(module, msg->dn);
+	key2 = ltdb_key_dn(module, msg->dn);
 	if (key2.dptr == NULL) {
 		/* probably a corrupt record ... darn */
 		ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s",
diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c
index 0cc03bd..271cdd8 100644
--- a/lib/ldb/ldb_tdb/ldb_search.c
+++ b/lib/ldb/ldb_tdb/ldb_search.c
@@ -125,7 +125,7 @@ static int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn)
 	}
 
 	/* form the key */
-	tdb_key = ltdb_key(module, dn);
+	tdb_key = ltdb_key_dn(module, dn);
 	if (!tdb_key.dptr) {
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
@@ -214,7 +214,7 @@ int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_mes
 	};
 
 	/* form the key */
-	tdb_key = ltdb_key(module, dn);
+	tdb_key = ltdb_key_dn(module, dn);
 	if (!tdb_key.dptr) {
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index 2ac1967..edf0f60 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -134,7 +134,7 @@ int ltdb_unlock_read(struct ldb_module *module)
   note that the key for a record can depend on whether the
   dn refers to a case sensitive index record or not
 */
-TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn)
+TDB_DATA ltdb_key_dn(struct ldb_module *module, struct ldb_dn *dn)
 {
 	struct ldb_context *ldb = ldb_module_get_ctx(module);
 	TDB_DATA key;
@@ -181,6 +181,19 @@ failed:
 }
 
 /*
+  form a TDB_DATA for a record key
+  caller frees
+
+  note that the key for a record can depend on whether the
+  dn refers to a case sensitive index record or not
+*/
+TDB_DATA ltdb_key_msg(struct ldb_module *module,
+		      const struct ldb_message *msg)
+{
+	return ltdb_key_dn(module, msg->dn);
+}
+
+/*
   check special dn's have valid attributes
   currently only @ATTRIBUTES is checked
 */
@@ -268,7 +281,7 @@ int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flg
 	struct ldb_val ldb_data;
 	int ret = LDB_SUCCESS;
 
-	tdb_key = ltdb_key(module, msg->dn);
+	tdb_key = ltdb_key_msg(module, msg);
 	if (tdb_key.dptr == NULL) {
 		return LDB_ERR_OTHER;
 	}
@@ -436,7 +449,7 @@ int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn)
 	TDB_DATA tdb_key;
 	int ret;
 
-	tdb_key = ltdb_key(module, dn);
+	tdb_key = ltdb_key_dn(module, dn);
 	if (!tdb_key.dptr) {
 		return LDB_ERR_OTHER;
 	}
@@ -700,7 +713,7 @@ int ltdb_modify_internal(struct ldb_module *module,
 					LDB_CONTROL_PERMISSIVE_MODIFY_OID);
 	}
 
-	tdb_key = ltdb_key(module, msg->dn);
+	tdb_key = ltdb_key_msg(module, msg);
 	if (!tdb_key.dptr) {
 		return LDB_ERR_OTHER;
 	}
@@ -1082,13 +1095,13 @@ static int ltdb_rename(struct ltdb_context *ctx)
 	/* We need to, before changing the DB, check if the new DN
 	 * exists, so we can return this error to the caller with an
 	 * unmodified DB */
-	tdb_key = ltdb_key(module, req->op.rename.newdn);
+	tdb_key = ltdb_key_dn(module, req->op.rename.newdn);
 	if (!tdb_key.dptr) {
 		talloc_free(msg);
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	tdb_key_old = ltdb_key(module, req->op.rename.olddn);
+	tdb_key_old = ltdb_key_dn(module, req->op.rename.olddn);
 	if (!tdb_key_old.dptr) {
 		talloc_free(msg);
 		talloc_free(tdb_key.dptr);
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index 26ae68e..e489bcc 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -110,7 +110,8 @@ int ltdb_search(struct ltdb_context *ctx);
 /* The following definitions come from lib/ldb/ldb_tdb/ldb_tdb.c  */
 int ltdb_lock_read(struct ldb_module *module);
 int ltdb_unlock_read(struct ldb_module *module);
-TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn);
+TDB_DATA ltdb_key_dn(struct ldb_module *module, struct ldb_dn *dn);
+TDB_DATA ltdb_key_msg(struct ldb_module *module, const struct ldb_message *msg);
 int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs);
 int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg, struct ldb_request *req);
 int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn);
-- 
2.9.4


From 76442c4e00eb4cd30d12b230121d403ae3b2bf86 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 16:01:12 +1200
Subject: [PATCH 04/39] ldb_tdb: Use ltdb_key_msg() in re_index()

This will allow changing to a GUID tdb key in the future

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 8e71053..6bf1d9e 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -1610,9 +1610,10 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
 		return -1;
 	}
 
-	/* check if the DN key has changed, perhaps due to the
-	   case insensitivity of an element changing */
-	key2 = ltdb_key_dn(module, msg->dn);
+	/* check if the DN key has changed, perhaps due to the case
+	   insensitivity of an element changing, or a change from DN
+	   to GUID keys */
+	key2 = ltdb_key_msg(module, msg);
 	if (key2.dptr == NULL) {
 		/* probably a corrupt record ... darn */
 		ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s",
-- 
2.9.4


From 3a897ae79e153d634f7fec39575a726a703ec36e Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 16:06:08 +1200
Subject: [PATCH 05/39] ldb_tdb: Add ltdb_search_key()

This allows us to slowly split out the tdb key in the DB from being the DN

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_search.c | 41 +++++++++++++++++++++++++++++++----------
 lib/ldb/ldb_tdb/ldb_tdb.h    |  4 ++++
 2 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c
index 271cdd8..499cf1b 100644
--- a/lib/ldb/ldb_tdb/ldb_search.c
+++ b/lib/ldb/ldb_tdb/ldb_search.c
@@ -200,25 +200,18 @@ static int ltdb_parse_data_unpack(TDB_DATA key, TDB_DATA data,
   return LDB_ERR_NO_SUCH_OBJECT on record-not-found
   and LDB_SUCCESS on success
 */
-int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg,
+int ltdb_search_key(struct ldb_module *module, struct ltdb_private *ltdb,
+		    struct TDB_DATA tdb_key,
+		    struct ldb_message *msg,
 		    unsigned int unpack_flags)
 {
-	void *data = ldb_module_get_private(module);
-	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
 	int ret;
-	TDB_DATA tdb_key;
 	struct ltdb_parse_data_unpack_ctx ctx = {
 		.msg = msg,
 		.module = module,
 		.unpack_flags = unpack_flags
 	};
 
-	/* form the key */
-	tdb_key = ltdb_key_dn(module, dn);
-	if (!tdb_key.dptr) {
-		return LDB_ERR_OPERATIONS_ERROR;
-	}
-
 	memset(msg, 0, sizeof(*msg));
 
 	msg->num_elements = 0;
@@ -237,6 +230,34 @@ int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_mes
 		return ret;
 	}
 
+	return LDB_SUCCESS;
+}
+
+/*
+  search the database for a single simple dn, returning all attributes
+  in a single message
+
+  return LDB_ERR_NO_SUCH_OBJECT on record-not-found
+  and LDB_SUCCESS on success
+*/
+int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg,
+		    unsigned int unpack_flags)
+{
+	void *data = ldb_module_get_private(module);
+	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
+	int ret;
+	TDB_DATA tdb_key;
+	/* form the key */
+	tdb_key = ltdb_key_dn(module, dn);
+	if (!tdb_key.dptr) {
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+
+	ret = ltdb_search_key(module, ltdb, tdb_key, msg, unpack_flags);
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
+	
 	if ((unpack_flags & LDB_UNPACK_DATA_FLAG_NO_DN) == 0) {
 		if (!msg->dn) {
 			msg->dn = ldb_dn_copy(msg, dn);
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index e489bcc..0a82df3 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -102,6 +102,10 @@ int ltdb_has_wildcard(struct ldb_module *module, const char *attr_name,
 void ltdb_search_dn1_free(struct ldb_module *module, struct ldb_message *msg);
 int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg,
 		    unsigned int unpack_flags);
+int ltdb_search_key(struct ldb_module *module, struct ltdb_private *ltdb,
+		    struct TDB_DATA tdb_key,
+		    struct ldb_message *msg,
+		    unsigned int unpack_flags);
 int ltdb_filter_attrs(TALLOC_CTX *mem_ctx,
 		      const struct ldb_message *msg, const char * const *attrs,
 		      struct ldb_message **filtered_msg);
-- 
2.9.4


From 6719643662d779e9d58ee0d5e972ff6dfe5b59e3 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 16:09:31 +1200
Subject: [PATCH 06/39] ldb_tdb: Use braces in ltdb_dn_list_find_val()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 6bf1d9e..592649f 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -83,7 +83,9 @@ static int ltdb_dn_list_find_val(const struct dn_list *list, const struct ldb_va
 {
 	unsigned int i;
 	for (i=0; i<list->count; i++) {
-		if (dn_list_cmp(&list->dn[i], v) == 0) return i;
+		if (dn_list_cmp(&list->dn[i], v) == 0) {
+			return i;
+		}
 	}
 	return -1;
 }
-- 
2.9.4


From a17c413bd730306e9dffdc8a37c0c6f43ceabb49 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 16:23:33 +1200
Subject: [PATCH 07/39] ldb_tdb: Provide struct ltdb_private to index routines

This will make it easier to switch the GUID index mode on and off

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 91 +++++++++++++++++++++++++++++----------------
 lib/ldb/ldb_tdb/ldb_tdb.c   | 36 ++++++++++++------
 lib/ldb/ldb_tdb/ldb_tdb.h   | 16 ++++++--
 3 files changed, 96 insertions(+), 47 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 592649f..38de508 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -79,7 +79,9 @@ static int dn_list_cmp(const struct ldb_val *v1, const struct ldb_val *v2)
   find a entry in a dn_list, using a ldb_val. Uses a case sensitive
   comparison with the dn returns -1 if not found
  */
-static int ltdb_dn_list_find_val(const struct dn_list *list, const struct ldb_val *v)
+static int ltdb_dn_list_find_val(struct ltdb_private *ltdb,
+				 const struct dn_list *list,
+				 const struct ldb_val *v)
 {
 	unsigned int i;
 	for (i=0; i<list->count; i++) {
@@ -94,12 +96,14 @@ static int ltdb_dn_list_find_val(const struct dn_list *list, const struct ldb_va
   find a entry in a dn_list. Uses a case sensitive comparison with the dn
   returns -1 if not found
  */
-static int ltdb_dn_list_find_str(struct dn_list *list, const char *dn)
+static int ltdb_dn_list_find_str(struct ltdb_private *ltdb,
+				 struct dn_list *list,
+				 const char *dn)
 {
 	struct ldb_val v;
 	v.data = discard_const_p(unsigned char, dn);
 	v.length = strlen(dn);
-	return ltdb_dn_list_find_val(list, &v);
+	return ltdb_dn_list_find_val(ltdb, list, &v);
 }
 
 /*
@@ -219,7 +223,9 @@ normal_index:
 /*
   save a dn_list into a full @IDX style record
  */
-static int ltdb_dn_list_store_full(struct ldb_module *module, struct ldb_dn *dn,
+static int ltdb_dn_list_store_full(struct ldb_module *module,
+				   struct ltdb_private *ltdb,
+				   struct ldb_dn *dn,
 				   struct dn_list *list)
 {
 	struct ldb_message *msg;
@@ -274,7 +280,8 @@ static int ltdb_dn_list_store(struct ldb_module *module, struct ldb_dn *dn,
 	struct dn_list *list2;
 
 	if (ltdb->idxptr == NULL) {
-		return ltdb_dn_list_store_full(module, dn, list);
+		return ltdb_dn_list_store_full(module, ltdb,
+					       dn, list);
 	}
 
 	if (ltdb->idxptr->itdb == NULL) {
@@ -345,7 +352,8 @@ static int ltdb_index_traverse_store(struct tdb_context *tdb, TDB_DATA key, TDB_
 		return -1;
 	}
 
-	ltdb->idxptr->error = ltdb_dn_list_store_full(module, dn, list);
+	ltdb->idxptr->error = ltdb_dn_list_store_full(module, ltdb,
+						      dn, list);
 	talloc_free(dn);
 	if (ltdb->idxptr->error != 0) {
 		return -1;
@@ -575,6 +583,7 @@ static int ltdb_index_dn_leaf(struct ldb_module *module,
   list = list & list2
 */
 static bool list_intersect(struct ldb_context *ldb,
+			   struct ltdb_private *ltdb,
 			   struct dn_list *list, const struct dn_list *list2)
 {
 	struct dn_list *list3;
@@ -622,7 +631,8 @@ static bool list_intersect(struct ldb_context *ldb,
 	list3->count = 0;
 
 	for (i=0;i<list->count;i++) {
-		if (ltdb_dn_list_find_val(list2, &list->dn[i]) != -1) {
+		if (ltdb_dn_list_find_val(ltdb, list2,
+					  &list->dn[i]) != -1) {
 			list3->dn[list3->count] = list->dn[i];
 			list3->count++;
 		}
@@ -846,7 +856,8 @@ static int ltdb_index_dn_and(struct ldb_module *module,
 			list->dn = list2->dn;
 			list->count = list2->count;
 			found = true;
-		} else if (!list_intersect(ldb, list, list2)) {
+		} else if (!list_intersect(ldb, ltdb,
+					   list, list2)) {
 			talloc_free(list2);
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
@@ -952,7 +963,8 @@ static int ltdb_index_dn(struct ldb_module *module,
   filter a candidate dn_list from an indexed search into a set of results
   extracting just the given attributes
 */
-static int ltdb_index_filter(const struct dn_list *dn_list,
+static int ltdb_index_filter(struct ltdb_private *ltdb,
+			     const struct dn_list *dn_list,
 			     struct ltdb_context *ac,
 			     uint32_t *match_count)
 {
@@ -978,7 +990,7 @@ static int ltdb_index_filter(const struct dn_list *dn_list,
 			talloc_free(msg);
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
-
+		
 		ret = ltdb_search_dn1(ac->module, dn, msg,
 				      LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC|
 				      LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC);
@@ -1123,7 +1135,7 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
 		break;
 	}
 
-	ret = ltdb_index_filter(dn_list, ac, match_count);
+	ret = ltdb_index_filter(ltdb, dn_list, ac, match_count);
 	talloc_free(dn_list);
 	return ret;
 }
@@ -1148,7 +1160,9 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
  *
  * @return                  An ldb error code
  */
-static int ltdb_index_add1(struct ldb_module *module, const char *dn,
+static int ltdb_index_add1(struct ldb_module *module,
+			   struct ltdb_private *ltdb,
+			   const char *dn,
 			   struct ldb_message_element *el, int v_idx,
 			   bool is_new)
 {
@@ -1204,7 +1218,7 @@ static int ltdb_index_add1(struct ldb_module *module, const char *dn,
 	   as it was not already in the database, and this has already been
 	   checked because the store succeeded */
 	if (! is_new) {
-		if (ltdb_dn_list_find_str(list, dn) != -1) {
+		if (ltdb_dn_list_find_str(ltdb, list, dn) != -1) {
 			talloc_free(list);
 			return LDB_SUCCESS;
 		}
@@ -1232,12 +1246,15 @@ static int ltdb_index_add1(struct ldb_module *module, const char *dn,
 /*
   add index entries for one elements in a message
  */
-static int ltdb_index_add_el(struct ldb_module *module, const char *dn,
+static int ltdb_index_add_el(struct ldb_module *module,
+			     struct ltdb_private *ltdb,
+			     const char *dn,
 			     struct ldb_message_element *el, bool is_new)
 {
 	unsigned int i;
 	for (i = 0; i < el->num_values; i++) {
-		int ret = ltdb_index_add1(module, dn, el, i, is_new);
+		int ret = ltdb_index_add1(module, ltdb,
+					  dn, el, i, is_new);
 		if (ret != LDB_SUCCESS) {
 			return ret;
 		}
@@ -1249,12 +1266,13 @@ static int ltdb_index_add_el(struct ldb_module *module, const char *dn,
 /*
   add index entries for all elements in a message
  */
-static int ltdb_index_add_all(struct ldb_module *module, const char *dn,
+static int ltdb_index_add_all(struct ldb_module *module,
+			      struct ltdb_private *ltdb,
+			      const char *dn,
 			      struct ldb_message_element *elements,
 			      unsigned int num_el,
 			      bool is_new)
 {
-	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
 	unsigned int i;
 
 	if (dn[0] == '@') {
@@ -1271,7 +1289,7 @@ static int ltdb_index_add_all(struct ldb_module *module, const char *dn,
 		if (!ltdb_is_indexed(module, ltdb, elements[i].name)) {
 			continue;
 		}
-		ret = ltdb_index_add_el(module, dn, &elements[i], is_new);
+		ret = ltdb_index_add_el(module, ltdb, dn, &elements[i], is_new);
 		if (ret != LDB_SUCCESS) {
 			struct ldb_context *ldb = ldb_module_get_ctx(module);
 			ldb_asprintf_errstring(ldb,
@@ -1325,9 +1343,9 @@ static int ltdb_index_onelevel(struct ldb_module *module, const struct ldb_messa
 	el.num_values = 1;
 
 	if (add) {
-		ret = ltdb_index_add1(module, dn, &el, 0, add);
+		ret = ltdb_index_add1(module, ltdb, dn, &el, 0, add);
 	} else { /* delete */
-		ret = ltdb_index_del_value(module, msg->dn, &el, 0);
+		ret = ltdb_index_del_value(module, ltdb, msg->dn, &el, 0);
 	}
 
 	talloc_free(pdn);
@@ -1339,23 +1357,26 @@ static int ltdb_index_onelevel(struct ldb_module *module, const struct ldb_messa
   add the index entries for a new element in a record
   The caller guarantees that these element values are not yet indexed
 */
-int ltdb_index_add_element(struct ldb_module *module, struct ldb_dn *dn,
+int ltdb_index_add_element(struct ldb_module *module,
+			   struct ltdb_private *ltdb,
+			   struct ldb_dn *dn,
 			   struct ldb_message_element *el)
 {
-	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
 	if (ldb_dn_is_special(dn)) {
 		return LDB_SUCCESS;
 	}
 	if (!ltdb_is_indexed(module, ltdb, el->name)) {
 		return LDB_SUCCESS;
 	}
-	return ltdb_index_add_el(module, ldb_dn_get_linearized(dn), el, true);
+	return ltdb_index_add_el(module, ltdb, ldb_dn_get_linearized(dn), el, true);
 }
 
 /*
   add the index entries for a new record
 */
-int ltdb_index_add_new(struct ldb_module *module, const struct ldb_message *msg)
+int ltdb_index_add_new(struct ldb_module *module,
+		       struct ltdb_private *ltdb,
+		       const struct ldb_message *msg)
 {
 	const char *dn;
 	int ret;
@@ -1369,7 +1390,7 @@ int ltdb_index_add_new(struct ldb_module *module, const struct ldb_message *msg)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	ret = ltdb_index_add_all(module, dn, msg->elements, msg->num_elements,
+	ret = ltdb_index_add_all(module, ltdb, dn, msg->elements, msg->num_elements,
 				 true);
 	if (ret != LDB_SUCCESS) {
 		return ret;
@@ -1382,7 +1403,9 @@ int ltdb_index_add_new(struct ldb_module *module, const struct ldb_message *msg)
 /*
   delete an index entry for one message element
 */
-int ltdb_index_del_value(struct ldb_module *module, struct ldb_dn *dn,
+int ltdb_index_del_value(struct ldb_module *module,
+			 struct ltdb_private *ltdb,
+			 struct ldb_dn *dn,
 			 struct ldb_message_element *el, unsigned int v_idx)
 {
 	struct ldb_context *ldb;
@@ -1427,7 +1450,7 @@ int ltdb_index_del_value(struct ldb_module *module, struct ldb_dn *dn,
 		return ret;
 	}
 
-	i = ltdb_dn_list_find_str(list, dn_str);
+	i = ltdb_dn_list_find_str(ltdb, list, dn_str);
 	if (i == -1) {
 		/* nothing to delete */
 		talloc_free(dn_key);
@@ -1457,10 +1480,11 @@ int ltdb_index_del_value(struct ldb_module *module, struct ldb_dn *dn,
   delete the index entries for a element
   return -1 on failure
 */
-int ltdb_index_del_element(struct ldb_module *module, struct ldb_dn *dn,
+int ltdb_index_del_element(struct ldb_module *module,
+			   struct ltdb_private *ltdb,
+			   struct ldb_dn *dn,
 			   struct ldb_message_element *el)
 {
-	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
 	const char *dn_str;
 	int ret;
 	unsigned int i;
@@ -1483,7 +1507,7 @@ int ltdb_index_del_element(struct ldb_module *module, struct ldb_dn *dn,
 		return LDB_SUCCESS;
 	}
 	for (i = 0; i < el->num_values; i++) {
-		ret = ltdb_index_del_value(module, dn, el, i);
+		ret = ltdb_index_del_value(module, ltdb, dn, el, i);
 		if (ret != LDB_SUCCESS) {
 			return ret;
 		}
@@ -1517,7 +1541,8 @@ int ltdb_index_delete(struct ldb_module *module, const struct ldb_message *msg)
 	}
 
 	for (i = 0; i < msg->num_elements; i++) {
-		ret = ltdb_index_del_element(module, msg->dn, &msg->elements[i]);
+		ret = ltdb_index_del_element(module, ltdb,
+					     msg->dn, &msg->elements[i]);
 		if (ret != LDB_SUCCESS) {
 			return ret;
 		}
@@ -1578,6 +1603,7 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
 	struct ldb_context *ldb;
 	struct ltdb_reindex_context *ctx = (struct ltdb_reindex_context *)state;
 	struct ldb_module *module = ctx->module;
+	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
 	struct ldb_message *msg;
 	unsigned int nb_elements_in_db;
 	const struct ldb_val val = {
@@ -1645,7 +1671,8 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
 		return -1;
 	}
 
-	ret = ltdb_index_add_all(module, dn, msg->elements, msg->num_elements,
+	ret = ltdb_index_add_all(module, ltdb, dn,
+				 msg->elements, msg->num_elements,
 				 false);
 
 	if (ret != LDB_SUCCESS) {
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index edf0f60..5d0e397 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -339,6 +339,7 @@ static bool ldb_tdb_single_valued(const struct ldb_schema_attribute *a,
 }
 
 static int ltdb_add_internal(struct ldb_module *module,
+			     struct ltdb_private *ltdb,
 			     const struct ldb_message *msg,
 			     bool check_single_value)
 {
@@ -403,7 +404,7 @@ static int ltdb_add_internal(struct ldb_module *module,
 		return ret;
 	}
 
-	ret = ltdb_index_add_new(module, msg);
+	ret = ltdb_index_add_new(module, ltdb, msg);
 	if (ret != LDB_SUCCESS) {
 		return ret;
 	}
@@ -420,6 +421,8 @@ static int ltdb_add(struct ltdb_context *ctx)
 {
 	struct ldb_module *module = ctx->module;
 	struct ldb_request *req = ctx->req;
+	void *data = ldb_module_get_private(module);
+	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
 	int ret = LDB_SUCCESS;
 
 	ret = ltdb_check_special_dn(module, req->op.add.message);
@@ -433,7 +436,8 @@ static int ltdb_add(struct ltdb_context *ctx)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	ret = ltdb_add_internal(module, req->op.add.message, true);
+	ret = ltdb_add_internal(module, ltdb,
+				req->op.add.message, true);
 
 	return ret;
 }
@@ -593,6 +597,7 @@ static int ltdb_msg_add_element(struct ldb_message *msg,
   delete all elements having a specified attribute name
 */
 static int msg_delete_attribute(struct ldb_module *module,
+				struct ltdb_private *ltdb,
 				struct ldb_message *msg, const char *name)
 {
 	unsigned int i;
@@ -605,7 +610,7 @@ static int msg_delete_attribute(struct ldb_module *module,
 	}
 	i = el - msg->elements;
 
-	ret = ltdb_index_del_element(module, msg->dn, el);
+	ret = ltdb_index_del_element(module, ltdb, msg->dn, el);
 	if (ret != LDB_SUCCESS) {
 		return ret;
 	}
@@ -627,6 +632,7 @@ static int msg_delete_attribute(struct ldb_module *module,
   return LDB Error on failure
 */
 static int msg_delete_element(struct ldb_module *module,
+			      struct ltdb_private *ltdb,
 			      struct ldb_message *msg,
 			      const char *name,
 			      const struct ldb_val *val)
@@ -659,10 +665,11 @@ static int msg_delete_element(struct ldb_module *module,
 		}
 		if (matched) {
 			if (el->num_values == 1) {
-				return msg_delete_attribute(module, msg, name);
+				return msg_delete_attribute(module,
+							    ltdb, msg, name);
 			}
 
-			ret = ltdb_index_del_value(module, msg->dn, el, i);
+			ret = ltdb_index_del_value(module, ltdb, msg->dn, el, i);
 			if (ret != LDB_SUCCESS) {
 				return ret;
 			}
@@ -802,7 +809,8 @@ int ltdb_modify_internal(struct ldb_module *module,
 					ret = LDB_ERR_OTHER;
 					goto done;
 				}
-				ret = ltdb_index_add_element(module, msg2->dn,
+				ret = ltdb_index_add_element(module, ltdb,
+							     msg2->dn,
 							     el);
 				if (ret != LDB_SUCCESS) {
 					goto done;
@@ -883,7 +891,8 @@ int ltdb_modify_internal(struct ldb_module *module,
 				el2->values = vals;
 				el2->num_values += el->num_values;
 
-				ret = ltdb_index_add_element(module, msg2->dn, el);
+				ret = ltdb_index_add_element(module, ltdb,
+							     msg2->dn, el);
 				if (ret != LDB_SUCCESS) {
 					goto done;
 				}
@@ -947,7 +956,8 @@ int ltdb_modify_internal(struct ldb_module *module,
 				}
 
 				/* Delete the attribute if it exists in the DB */
-				if (msg_delete_attribute(module, msg2,
+				if (msg_delete_attribute(module, ltdb,
+							 msg2,
 							 el->name) != 0) {
 					ret = LDB_ERR_OTHER;
 					goto done;
@@ -960,7 +970,8 @@ int ltdb_modify_internal(struct ldb_module *module,
 				goto done;
 			}
 
-			ret = ltdb_index_add_element(module, msg2->dn, el);
+			ret = ltdb_index_add_element(module, ltdb,
+						     msg2->dn, el);
 			if (ret != LDB_SUCCESS) {
 				goto done;
 			}
@@ -976,7 +987,9 @@ int ltdb_modify_internal(struct ldb_module *module,
 
 			if (msg->elements[i].num_values == 0) {
 				/* Delete the whole attribute */
-				ret = msg_delete_attribute(module, msg2,
+				ret = msg_delete_attribute(module,
+							   ltdb, 
+							   msg2,
 							   msg->elements[i].name);
 				if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE &&
 				    control_permissive) {
@@ -993,6 +1006,7 @@ int ltdb_modify_internal(struct ldb_module *module,
 				/* Delete specified values from an attribute */
 				for (j=0; j < msg->elements[i].num_values; j++) {
 					ret = msg_delete_element(module,
+								 ltdb, 
 							         msg2,
 							         msg->elements[i].name,
 							         &msg->elements[i].values[j]);
@@ -1144,7 +1158,7 @@ static int ltdb_rename(struct ltdb_context *ctx)
 	 * deleted attributes. We could go through all elements but that's
 	 * maybe not the most efficient way
 	 */
-	ret = ltdb_add_internal(module, msg, false);
+	ret = ltdb_add_internal(module, ltdb, msg, false);
 
 	talloc_free(msg);
 
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index 0a82df3..8ab56d3 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -82,13 +82,21 @@ int ltdb_check_at_attributes_values(const struct ldb_val *value);
 struct ldb_parse_tree;
 
 int ltdb_search_indexed(struct ltdb_context *ctx, uint32_t *);
-int ltdb_index_add_new(struct ldb_module *module, const struct ldb_message *msg);
+int ltdb_index_add_new(struct ldb_module *module,
+		       struct ltdb_private *ltdb,
+		       const struct ldb_message *msg);
 int ltdb_index_delete(struct ldb_module *module, const struct ldb_message *msg);
-int ltdb_index_del_element(struct ldb_module *module, struct ldb_dn *dn,
+int ltdb_index_del_element(struct ldb_module *module,
+			   struct ltdb_private *ltdb,
+			   struct ldb_dn *dn,
 			   struct ldb_message_element *el);
-int ltdb_index_add_element(struct ldb_module *module, struct ldb_dn *dn, 
+int ltdb_index_add_element(struct ldb_module *module,
+			   struct ltdb_private *ltdb,
+			   struct ldb_dn *dn,
 			   struct ldb_message_element *el);
-int ltdb_index_del_value(struct ldb_module *module, struct ldb_dn *dn,
+int ltdb_index_del_value(struct ldb_module *module,
+			 struct ltdb_private *ltdb,
+			 struct ldb_dn *dn,
 			 struct ldb_message_element *el, unsigned int v_idx);
 int ltdb_reindex(struct ldb_module *module);
 int ltdb_index_transaction_start(struct ldb_module *module);
-- 
2.9.4


From d83b10bc7ef4e2ef71966fc1e2cb9a5604867293 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 14:44:27 +1200
Subject: [PATCH 08/39] ldb_tdb: Check for talloc_strdup() failure in
 ltdb_index_add1()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 38de508..dfea8d7 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -1232,7 +1232,13 @@ static int ltdb_index_add1(struct ldb_module *module,
 		talloc_free(list);
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
-	list->dn[list->count].data = (uint8_t *)talloc_strdup(list->dn, dn);
+
+	list->dn[list->count].data
+		= (uint8_t *)talloc_strdup(list->dn, dn);
+	if (list->dn[list->count].data == NULL) {
+		talloc_free(list);
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
 	list->dn[list->count].length = strlen(dn);
 	list->count++;
 
-- 
2.9.4


From bee47822a896c7bd520237bc0da2aebf1ede2f8c Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 17:13:48 +1200
Subject: [PATCH 09/39] ldb_tdb: Add GUID_index_attribute to ltdb_private

This will be used to determine if we are in GUID index mode

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_tdb.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index 8ab56d3..0f1b3f9 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -20,6 +20,7 @@ struct ltdb_private {
 		struct ldb_message *indexlist;
 		bool one_level_indexes;
 		bool attribute_indexes;
+		const char *GUID_index_attribute;
 	} *cache;
 
 	int in_transaction;
-- 
2.9.4


From 4fca7bfaf6373d7122e3f86e9419eb288ed9ba64 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 17:00:48 +1200
Subject: [PATCH 10/39] ldb_tdb: If the GUID index is in use, use
 ldb_val_equal_exact()

We do not need or want a case-insenstive compare for a GUID index

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index dfea8d7..67b5b4c 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -84,8 +84,17 @@ static int ltdb_dn_list_find_val(struct ltdb_private *ltdb,
 				 const struct ldb_val *v)
 {
 	unsigned int i;
+	if (ltdb->cache->GUID_index_attribute == NULL) {
+		for (i=0; i<list->count; i++) {
+			if (dn_list_cmp(&list->dn[i], v) == 0) {
+				return i;
+			}
+		}
+		return -1;
+	}
+
 	for (i=0; i<list->count; i++) {
-		if (dn_list_cmp(&list->dn[i], v) == 0) {
+		if (ldb_val_equal_exact(&list->dn[i], v) == 1) {
 			return i;
 		}
 	}
-- 
2.9.4


From 46c4a190ce8983fc17fd5f512947e9234cd282a7 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 17:02:14 +1200
Subject: [PATCH 11/39] ldb_tdb: Store binaries index values in one packed ldb
 attribute

This should make them more memory efficient

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 55 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 47 insertions(+), 8 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 67b5b4c..073796f 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -220,9 +220,26 @@ normal_index:
 	 * value with LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC above
 	 */
 	talloc_steal(el->values, msg);
-	list->dn = talloc_steal(list, el->values);
-	list->count = el->num_values;
+	if (ltdb->cache->GUID_index_attribute == NULL) {
+		list->dn = talloc_steal(list, el->values);
+		list->count = el->num_values;
+	} else {
+		unsigned int i;
+		static const size_t GUID_val_size = 16;
+		if (el->num_values != 1) {
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		
+		list->dn = talloc_array_size(list, GUID_val_size,
+					     el->values[0].length / GUID_val_size);
+		list->count = el->values[0].length / GUID_val_size;
 
+		for (i = 0; i < list->count; i++) {
+			list->dn[i].data = &el->values[0].data[i * GUID_val_size];
+			list->dn[i].length = GUID_val_size;
+		}
+	}
+	
 	/* We don't need msg->elements any more */
 	talloc_free(msg->elements);
 	return LDB_SUCCESS;
@@ -262,14 +279,36 @@ static int ltdb_dn_list_store_full(struct ldb_module *module,
 	msg->dn = dn;
 	if (list->count > 0) {
 		struct ldb_message_element *el;
+		
+		if (ltdb->cache->GUID_index_attribute == NULL) {
+			ret = ldb_msg_add_empty(msg, LTDB_IDX,
+						LDB_FLAG_MOD_ADD, &el);
+		
+			if (ret != LDB_SUCCESS) {
+				talloc_free(msg);
+				return ldb_module_oom(module);
+			}
+			el->values = list->dn;
+			el->num_values = list->count;
+		} else {
+			size_t GUID_val_size = list->dn[0].length;
+			struct ldb_val v;
+			unsigned int i;
+			v.data = talloc_array_size(el, list->count,
+						   GUID_val_size);
+			if (v.data == NULL) {
+				talloc_free(msg);
+				return ldb_module_oom(module);
+			}
+			
+			v.length = talloc_get_size(v.data);
 
-		ret = ldb_msg_add_empty(msg, LTDB_IDX, LDB_FLAG_MOD_ADD, &el);
-		if (ret != LDB_SUCCESS) {
-			talloc_free(msg);
-			return ldb_module_oom(module);
+			for (i = 0; i < list->count; i++) {
+				memcpy(&v.data[GUID_val_size*i],
+				       list->dn[i].data,
+				       GUID_val_size);
+			}
 		}
-		el->values = list->dn;
-		el->num_values = list->count;
 	}
 
 	ret = ltdb_store(module, msg, TDB_REPLACE);
-- 
2.9.4


From 53b5baa48877a81265c50eedaf9aa8fe0270f96f Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 17:04:23 +1200
Subject: [PATCH 12/39] ldb_tdb: Write GUID index values as version 3

Nothing reads these currently, but we should refuse to load a mixed up index
in the future

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 073796f..048599a 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -49,6 +49,8 @@ struct ltdb_idxptr {
 */
 #define LTDB_INDEXING_VERSION 2
 
+#define LTDB_GUID_INDEXING_VERSION 3
+
 /* enable the idxptr mode when transactions start */
 int ltdb_index_transaction_start(struct ldb_module *module)
 {
@@ -270,10 +272,20 @@ static int ltdb_dn_list_store_full(struct ldb_module *module,
 		return ldb_module_oom(module);
 	}
 
-	ret = ldb_msg_add_fmt(msg, LTDB_IDXVERSION, "%u", LTDB_INDEXING_VERSION);
-	if (ret != LDB_SUCCESS) {
-		talloc_free(msg);
-		return ldb_module_oom(module);
+	if (ltdb->cache->GUID_index_attribute == NULL) {
+		ret = ldb_msg_add_fmt(msg, LTDB_IDXVERSION, "%u",
+				      LTDB_INDEXING_VERSION);
+		if (ret != LDB_SUCCESS) {
+			talloc_free(msg);
+			return ldb_module_oom(module);
+		}
+	} else {
+		ret = ldb_msg_add_fmt(msg, LTDB_IDXVERSION, "%u",
+				      LTDB_GUID_INDEXING_VERSION);
+		if (ret != LDB_SUCCESS) {
+			talloc_free(msg);
+			return ldb_module_oom(module);
+		}
 	}
 
 	msg->dn = dn;
-- 
2.9.4


From 3a5319413bb027c0dc2833e1959ee0cb76bb37b5 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 17:05:37 +1200
Subject: [PATCH 13/39] ldb_tdb: Optionally use GUID index values a direct TDB
 keys

This will makes the index work again, once we move the
TDB key for records to be the objectGUID

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 048599a..ec16938 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -1045,16 +1045,28 @@ static int ltdb_index_filter(struct ltdb_private *ltdb,
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
 
-		dn = ldb_dn_from_ldb_val(msg, ldb, &dn_list->dn[i]);
-		if (dn == NULL) {
-			talloc_free(msg);
-			return LDB_ERR_OPERATIONS_ERROR;
+		if (ltdb->cache->GUID_index_attribute == NULL) {
+			dn = ldb_dn_from_ldb_val(msg, ldb, &dn_list->dn[i]);
+			if (dn == NULL) {
+				talloc_free(msg);
+				return LDB_ERR_OPERATIONS_ERROR;
+			}
+
+			ret = ltdb_search_dn1(ac->module, dn, msg,
+					      LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC|
+					      LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC);
+			talloc_free(dn);
+		} else {
+			TDB_DATA tdb_key;
+			tdb_key.dptr = dn_list->dn[i].data;
+			tdb_key.dsize = dn_list->dn[i].length;
+
+			ret = ltdb_search_key(ac->module, ltdb,
+					      tdb_key, msg,
+					      LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC|
+					      LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC);
+			
 		}
-		
-		ret = ltdb_search_dn1(ac->module, dn, msg,
-				      LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC|
-				      LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC);
-		talloc_free(dn);
 		if (ret == LDB_ERR_NO_SUCH_OBJECT) {
 			/* the record has disappeared? yes, this can happen */
 			talloc_free(msg);
-- 
2.9.4


From b96ffb6389f7dbd6c3f1f826d36499ce175d681a Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 17:06:37 +1200
Subject: [PATCH 14/39] ldb_tdb: For now, remove the new unique index error
 message

The DN is no longer a printable string.  We need to parse it as a GUID and print that.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index ec16938..e328fa9 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -1272,14 +1272,16 @@ static int ltdb_index_add1(struct ldb_module *module,
 		 * confidential DN that the conflict was with in the
 		 * user-visible error string
 		 */
-		ldb_debug(ldb, LDB_DEBUG_WARNING,
-			  __location__ ": unique index violation on %s in %s, "
-			  "conficts with %*.*s in %s",
-			  el->name, dn,
-			  (int)list->dn[0].length,
-			  (int)list->dn[0].length,
-			  list->dn[0].data,
-			  ldb_dn_get_linearized(dn_key));
+		if (ltdb->cache->GUID_index_attribute == NULL) {
+			ldb_debug(ldb, LDB_DEBUG_WARNING,
+				  __location__ ": unique index violation on %s in %s, "
+				  "conficts with %*.*s in %s",
+				  el->name, dn,
+				  (int)list->dn[0].length,
+				  (int)list->dn[0].length,
+				  list->dn[0].data,
+				  ldb_dn_get_linearized(dn_key));
+		}
 		ldb_asprintf_errstring(ldb, __location__ ": unique index violation on %s in %s",
 				       el->name, dn);
 		talloc_free(list);
-- 
2.9.4


From bafd8f398e3c2110c16bb943b70bcde971c1180c Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 17:08:54 +1200
Subject: [PATCH 15/39] ldb_tdb: Refuse to re-index very old database with no
 DN in the record

These are not found on any AD DC.  However do check for errors parsing the key as a DN, so we do not
somehow parse a GUID as a key

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index e328fa9..dfe44f8 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -1737,6 +1737,15 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
 	talloc_free(key2.dptr);
 
 	if (msg->dn == NULL) {
+		if (ltdb->cache->GUID_index_attribute != NULL) {
+			ldb_debug(ldb, LDB_DEBUG_ERROR,
+				  "Refusing to re-index as GUID "
+				  "key %*.*s with no DN\n",
+				  (int)key.dsize, (int)key.dsize,
+				  (char *)key.dptr);
+			talloc_free(msg);
+			return -1;
+		}
 		dn = (char *)key.dptr + 3;
 	} else {
 		dn = ldb_dn_get_linearized(msg->dn);
-- 
2.9.4


From 110763ada96db528e6252ececc9b4a279fa99ca3 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 17:11:13 +1200
Subject: [PATCH 16/39] ldb_tdb: Use the objectGUID (or similar) as the TDB key
 in ltdb_key_msg()

When we have the full ldb_message we can read the objectGUID as the TDB key

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_tdb.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index 5d0e397..e1749eb 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -190,7 +190,33 @@ failed:
 TDB_DATA ltdb_key_msg(struct ldb_module *module,
 		      const struct ldb_message *msg)
 {
-	return ltdb_key_dn(module, msg->dn);
+	void *data = ldb_module_get_private(module);
+	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
+	TDB_DATA key;
+	const struct ldb_val *key_val;
+
+	if (ltdb->cache->GUID_index_attribute == NULL) {
+		return ltdb_key_dn(module, msg->dn);
+	}
+
+	if (ldb_dn_is_special(msg->dn)) {
+		return ltdb_key_dn(module, msg->dn);
+	}
+
+	key_val = ldb_msg_find_ldb_val(msg,
+				       ltdb->cache->GUID_index_attribute);
+	if (key_val == NULL) {
+		errno = EINVAL;
+		key.dptr = NULL;
+		key.dsize = 0;
+		return key;
+	}
+
+	key.dptr = key_val->data;
+	key.dsize = key_val->length;
+	
+	return key;
+
 }
 
 /*
-- 
2.9.4


From 2c494b5f8c8c8b364441a23e288d4800b16d5586 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 17:13:05 +1200
Subject: [PATCH 17/39] ldb_tdb: Use GUID index in ltdb_delete_internal()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_tdb.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index e1749eb..a094a34 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -496,6 +496,7 @@ int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn)
 
 static int ltdb_delete_internal(struct ldb_module *module, struct ldb_dn *dn)
 {
+	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
 	struct ldb_message *msg;
 	int ret = LDB_SUCCESS;
 
@@ -512,9 +513,25 @@ static int ltdb_delete_internal(struct ldb_module *module, struct ldb_dn *dn)
 		goto done;
 	}
 
-	ret = ltdb_delete_noindex(module, dn);
-	if (ret != LDB_SUCCESS) {
-		goto done;
+	if (ltdb->cache->GUID_index_attribute == NULL) {
+		ret = ltdb_delete_noindex(module, dn);
+		if (ret != LDB_SUCCESS) {
+			goto done;
+		}
+	} else {
+		TDB_DATA tdb_key = ltdb_key_msg(module, msg);
+		if (!tdb_key.dptr) {
+			ret = LDB_ERR_OTHER;
+			goto done;
+		}
+
+		ret = tdb_delete(ltdb->tdb, tdb_key);
+		talloc_free(tdb_key.dptr);
+		
+		if (ret != 0) {
+			ret = ltdb_err_map(tdb_error(ltdb->tdb));
+			goto done;
+		}
 	}
 
 	/* remove any indexed attributes */
-- 
2.9.4


From 0af298b9f0a5048b42155e8d9157dacc3caf13b4 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 11 Aug 2017 10:54:54 +1200
Subject: [PATCH 18/39] ldb_tdb: Add comment explaining how
 ltdb_dn_list_find_val now works

We do not want to be using strncmp() on a GUID value

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index dfe44f8..822fd9c 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -80,6 +80,10 @@ static int dn_list_cmp(const struct ldb_val *v1, const struct ldb_val *v2)
 /*
   find a entry in a dn_list, using a ldb_val. Uses a case sensitive
   comparison with the dn returns -1 if not found
+
+  or
+
+  find a entry in a dn_list, using a ldb_val for an exact match. 
  */
 static int ltdb_dn_list_find_val(struct ltdb_private *ltdb,
 				 const struct dn_list *list,
-- 
2.9.4


From 845e38daf1c2673d170da477bdf9e73c8a4243f4 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 15 Aug 2017 13:08:42 +1200
Subject: [PATCH 19/39] ldb_tdb: Pass the full ldb_message to ldb index
 funtions

This allows the objectGUID, rather than the DN, to be the index key

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 111 +++++++++++++++++++++++++-------------------
 lib/ldb/ldb_tdb/ldb_tdb.c   |  10 ++--
 lib/ldb/ldb_tdb/ldb_tdb.h   |   6 +--
 3 files changed, 71 insertions(+), 56 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 822fd9c..fcb8247 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -111,13 +111,15 @@ static int ltdb_dn_list_find_val(struct ltdb_private *ltdb,
   find a entry in a dn_list. Uses a case sensitive comparison with the dn
   returns -1 if not found
  */
-static int ltdb_dn_list_find_str(struct ltdb_private *ltdb,
+static int ltdb_dn_list_find_msg(struct ltdb_private *ltdb,
 				 struct dn_list *list,
-				 const char *dn)
+				 const struct ldb_message *msg)
 {
 	struct ldb_val v;
-	v.data = discard_const_p(unsigned char, dn);
-	v.length = strlen(dn);
+	const struct ldb_val *key_val;
+	const char *dn_str = ldb_dn_get_linearized(msg->dn);
+	v.data = discard_const_p(unsigned char, dn_str);
+	v.length = strlen(dn_str);
 	return ltdb_dn_list_find_val(ltdb, list, &v);
 }
 
@@ -1238,7 +1240,7 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
  */
 static int ltdb_index_add1(struct ldb_module *module,
 			   struct ltdb_private *ltdb,
-			   const char *dn,
+			   const struct ldb_message *msg,
 			   struct ldb_message_element *el, int v_idx,
 			   bool is_new)
 {
@@ -1248,7 +1250,8 @@ static int ltdb_index_add1(struct ldb_module *module,
 	const struct ldb_schema_attribute *a;
 	struct dn_list *list;
 	unsigned alloc_len;
-
+	const char *dn_str;
+	
 	ldb = ldb_module_get_ctx(module);
 
 	list = talloc_zero(module, struct dn_list);
@@ -1276,18 +1279,20 @@ static int ltdb_index_add1(struct ldb_module *module,
 		 * confidential DN that the conflict was with in the
 		 * user-visible error string
 		 */
+
 		if (ltdb->cache->GUID_index_attribute == NULL) {
 			ldb_debug(ldb, LDB_DEBUG_WARNING,
 				  __location__ ": unique index violation on %s in %s, "
 				  "conficts with %*.*s in %s",
-				  el->name, dn,
+				  el->name, ldb_dn_get_linearized(msg->dn),
 				  (int)list->dn[0].length,
 				  (int)list->dn[0].length,
 				  list->dn[0].data,
 				  ldb_dn_get_linearized(dn_key));
 		}
 		ldb_asprintf_errstring(ldb, __location__ ": unique index violation on %s in %s",
-				       el->name, dn);
+				       el->name,
+				       ldb_dn_get_linearized(msg->dn));
 		talloc_free(list);
 		return LDB_ERR_ENTRY_ALREADY_EXISTS;
 	}
@@ -1296,7 +1301,7 @@ static int ltdb_index_add1(struct ldb_module *module,
 	   as it was not already in the database, and this has already been
 	   checked because the store succeeded */
 	if (! is_new) {
-		if (ltdb_dn_list_find_str(ltdb, list, dn) != -1) {
+		if (ltdb_dn_list_find_msg(ltdb, list, msg) != -1) {
 			talloc_free(list);
 			return LDB_SUCCESS;
 		}
@@ -1311,13 +1316,14 @@ static int ltdb_index_add1(struct ldb_module *module,
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
+	dn_str = ldb_dn_get_linearized(msg->dn);
 	list->dn[list->count].data
-		= (uint8_t *)talloc_strdup(list->dn, dn);
+		= (uint8_t *)talloc_strdup(list->dn, dn_str);
 	if (list->dn[list->count].data == NULL) {
 		talloc_free(list);
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
-	list->dn[list->count].length = strlen(dn);
+	list->dn[list->count].length = strlen(dn_str);
 	list->count++;
 
 	ret = ltdb_dn_list_store(module, dn_key, list);
@@ -1332,13 +1338,13 @@ static int ltdb_index_add1(struct ldb_module *module,
  */
 static int ltdb_index_add_el(struct ldb_module *module,
 			     struct ltdb_private *ltdb,
-			     const char *dn,
+			     const struct ldb_message *msg,
 			     struct ldb_message_element *el, bool is_new)
 {
 	unsigned int i;
 	for (i = 0; i < el->num_values; i++) {
 		int ret = ltdb_index_add1(module, ltdb,
-					  dn, el, i, is_new);
+					  msg, el, i, is_new);
 		if (ret != LDB_SUCCESS) {
 			return ret;
 		}
@@ -1352,15 +1358,20 @@ static int ltdb_index_add_el(struct ldb_module *module,
  */
 static int ltdb_index_add_all(struct ldb_module *module,
 			      struct ltdb_private *ltdb,
-			      const char *dn,
-			      struct ldb_message_element *elements,
-			      unsigned int num_el,
+			      const struct ldb_message *msg,
 			      bool is_new)
 {
+	struct ldb_message_element *elements = msg->elements;
 	unsigned int i;
-
-	if (dn[0] == '@') {
-		return LDB_SUCCESS;
+	const char *dn_str;
+	
+       if (ldb_dn_is_special(msg->dn)) {
+               return LDB_SUCCESS;
+       }
+       
+	dn_str = ldb_dn_get_linearized(msg->dn);
+	if (dn_str == NULL) {
+		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
 	if (!ltdb->cache->attribute_indexes) {
@@ -1368,17 +1379,19 @@ static int ltdb_index_add_all(struct ldb_module *module,
 		return LDB_SUCCESS;
 	}
 
-	for (i = 0; i < num_el; i++) {
+	for (i = 0; i < msg->num_elements; i++) {
 		int ret;
 		if (!ltdb_is_indexed(module, ltdb, elements[i].name)) {
 			continue;
 		}
-		ret = ltdb_index_add_el(module, ltdb, dn, &elements[i], is_new);
+		ret = ltdb_index_add_el(module, ltdb,
+					msg, &elements[i], is_new);
 		if (ret != LDB_SUCCESS) {
 			struct ldb_context *ldb = ldb_module_get_ctx(module);
 			ldb_asprintf_errstring(ldb,
 					       __location__ ": Failed to re-index %s in %s - %s",
-					       elements[i].name, dn, ldb_errstring(ldb));
+					       elements[i].name, dn_str,
+					       ldb_errstring(ldb));
 			return ret;
 		}
 	}
@@ -1390,7 +1403,8 @@ static int ltdb_index_add_all(struct ldb_module *module,
 /*
   insert a one level index for a message
 */
-static int ltdb_index_onelevel(struct ldb_module *module, const struct ldb_message *msg, int add)
+static int ltdb_index_onelevel(struct ldb_module *module,
+			       const struct ldb_message *msg, int add)
 {
 	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
 	struct ldb_message_element el;
@@ -1427,9 +1441,9 @@ static int ltdb_index_onelevel(struct ldb_module *module, const struct ldb_messa
 	el.num_values = 1;
 
 	if (add) {
-		ret = ltdb_index_add1(module, ltdb, dn, &el, 0, add);
+		ret = ltdb_index_add1(module, ltdb, msg, &el, 0, add);
 	} else { /* delete */
-		ret = ltdb_index_del_value(module, ltdb, msg->dn, &el, 0);
+		ret = ltdb_index_del_value(module, ltdb, msg, &el, 0);
 	}
 
 	talloc_free(pdn);
@@ -1443,16 +1457,16 @@ static int ltdb_index_onelevel(struct ldb_module *module, const struct ldb_messa
 */
 int ltdb_index_add_element(struct ldb_module *module,
 			   struct ltdb_private *ltdb,
-			   struct ldb_dn *dn,
+			   const struct ldb_message *msg,
 			   struct ldb_message_element *el)
 {
-	if (ldb_dn_is_special(dn)) {
+	if (ldb_dn_is_special(msg->dn)) {
 		return LDB_SUCCESS;
 	}
 	if (!ltdb_is_indexed(module, ltdb, el->name)) {
 		return LDB_SUCCESS;
 	}
-	return ltdb_index_add_el(module, ltdb, ldb_dn_get_linearized(dn), el, true);
+	return ltdb_index_add_el(module, ltdb, msg, el, true);
 }
 
 /*
@@ -1462,19 +1476,13 @@ int ltdb_index_add_new(struct ldb_module *module,
 		       struct ltdb_private *ltdb,
 		       const struct ldb_message *msg)
 {
-	const char *dn;
 	int ret;
 
 	if (ldb_dn_is_special(msg->dn)) {
 		return LDB_SUCCESS;
 	}
 
-	dn = ldb_dn_get_linearized(msg->dn);
-	if (dn == NULL) {
-		return LDB_ERR_OPERATIONS_ERROR;
-	}
-
-	ret = ltdb_index_add_all(module, ltdb, dn, msg->elements, msg->num_elements,
+	ret = ltdb_index_add_all(module, ltdb, msg,
 				 true);
 	if (ret != LDB_SUCCESS) {
 		return ret;
@@ -1489,7 +1497,7 @@ int ltdb_index_add_new(struct ldb_module *module,
 */
 int ltdb_index_del_value(struct ldb_module *module,
 			 struct ltdb_private *ltdb,
-			 struct ldb_dn *dn,
+			 const struct ldb_message *msg,
 			 struct ldb_message_element *el, unsigned int v_idx)
 {
 	struct ldb_context *ldb;
@@ -1498,7 +1506,8 @@ int ltdb_index_del_value(struct ldb_module *module,
 	int ret, i;
 	unsigned int j;
 	struct dn_list *list;
-
+	struct ldb_dn *dn = msg->dn;
+	
 	ldb = ldb_module_get_ctx(module);
 
 	dn_str = ldb_dn_get_linearized(dn);
@@ -1534,7 +1543,7 @@ int ltdb_index_del_value(struct ldb_module *module,
 		return ret;
 	}
 
-	i = ltdb_dn_list_find_str(ltdb, list, dn_str);
+	i = ltdb_dn_list_find_msg(ltdb, list, msg);
 	if (i == -1) {
 		/* nothing to delete */
 		talloc_free(dn_key);
@@ -1566,7 +1575,7 @@ int ltdb_index_del_value(struct ldb_module *module,
 */
 int ltdb_index_del_element(struct ldb_module *module,
 			   struct ltdb_private *ltdb,
-			   struct ldb_dn *dn,
+			   const struct ldb_message *msg,
 			   struct ldb_message_element *el)
 {
 	const char *dn_str;
@@ -1578,7 +1587,7 @@ int ltdb_index_del_element(struct ldb_module *module,
 		return LDB_SUCCESS;
 	}
 
-	dn_str = ldb_dn_get_linearized(dn);
+	dn_str = ldb_dn_get_linearized(msg->dn);
 	if (dn_str == NULL) {
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
@@ -1591,7 +1600,7 @@ int ltdb_index_del_element(struct ldb_module *module,
 		return LDB_SUCCESS;
 	}
 	for (i = 0; i < el->num_values; i++) {
-		ret = ltdb_index_del_value(module, ltdb, dn, el, i);
+		ret = ltdb_index_del_value(module, ltdb, msg, el, i);
 		if (ret != LDB_SUCCESS) {
 			return ret;
 		}
@@ -1626,7 +1635,7 @@ int ltdb_index_delete(struct ldb_module *module, const struct ldb_message *msg)
 
 	for (i = 0; i < msg->num_elements; i++) {
 		ret = ltdb_index_del_element(module, ltdb,
-					     msg->dn, &msg->elements[i]);
+					     msg, &msg->elements[i]);
 		if (ret != LDB_SUCCESS) {
 			return ret;
 		}
@@ -1694,7 +1703,6 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
 		.data = data.dptr,
 		.length = data.dsize,
 	};
-	const char *dn = NULL;
 	int ret;
 	TDB_DATA key2;
 
@@ -1750,9 +1758,17 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
 			talloc_free(msg);
 			return -1;
 		}
-		dn = (char *)key.dptr + 3;
-	} else {
-		dn = ldb_dn_get_linearized(msg->dn);
+		msg->dn = ldb_dn_new(msg, ldb, (char *)key.dptr + 3);
+		if (msg->dn == NULL) {
+			ldb_debug(ldb, LDB_DEBUG_ERROR,
+				  "Parse of %*.*s as a DN during re-index failed!",
+				  (int)key.dsize - 3,
+				  (int)key.dsize - 3,
+				  (char *)key.dptr + 3);
+				  
+			talloc_free(msg);
+			return -1;
+		}
 	}
 
 	ret = ltdb_index_onelevel(module, msg, 1);
@@ -1764,8 +1780,7 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
 		return -1;
 	}
 
-	ret = ltdb_index_add_all(module, ltdb, dn,
-				 msg->elements, msg->num_elements,
+	ret = ltdb_index_add_all(module, ltdb, msg,
 				 false);
 
 	if (ret != LDB_SUCCESS) {
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index a094a34..c173a62 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -653,7 +653,7 @@ static int msg_delete_attribute(struct ldb_module *module,
 	}
 	i = el - msg->elements;
 
-	ret = ltdb_index_del_element(module, ltdb, msg->dn, el);
+	ret = ltdb_index_del_element(module, ltdb, msg, el);
 	if (ret != LDB_SUCCESS) {
 		return ret;
 	}
@@ -712,7 +712,7 @@ static int msg_delete_element(struct ldb_module *module,
 							    ltdb, msg, name);
 			}
 
-			ret = ltdb_index_del_value(module, ltdb, msg->dn, el, i);
+			ret = ltdb_index_del_value(module, ltdb, msg, el, i);
 			if (ret != LDB_SUCCESS) {
 				return ret;
 			}
@@ -853,7 +853,7 @@ int ltdb_modify_internal(struct ldb_module *module,
 					goto done;
 				}
 				ret = ltdb_index_add_element(module, ltdb,
-							     msg2->dn,
+							     msg2,
 							     el);
 				if (ret != LDB_SUCCESS) {
 					goto done;
@@ -935,7 +935,7 @@ int ltdb_modify_internal(struct ldb_module *module,
 				el2->num_values += el->num_values;
 
 				ret = ltdb_index_add_element(module, ltdb,
-							     msg2->dn, el);
+							     msg2, el);
 				if (ret != LDB_SUCCESS) {
 					goto done;
 				}
@@ -1014,7 +1014,7 @@ int ltdb_modify_internal(struct ldb_module *module,
 			}
 
 			ret = ltdb_index_add_element(module, ltdb,
-						     msg2->dn, el);
+						     msg2, el);
 			if (ret != LDB_SUCCESS) {
 				goto done;
 			}
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index 0f1b3f9..ea9ccb6 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -89,15 +89,15 @@ int ltdb_index_add_new(struct ldb_module *module,
 int ltdb_index_delete(struct ldb_module *module, const struct ldb_message *msg);
 int ltdb_index_del_element(struct ldb_module *module,
 			   struct ltdb_private *ltdb,
-			   struct ldb_dn *dn,
+			   const struct ldb_message *msg,
 			   struct ldb_message_element *el);
 int ltdb_index_add_element(struct ldb_module *module,
 			   struct ltdb_private *ltdb,
-			   struct ldb_dn *dn,
+			   const struct ldb_message *msg,
 			   struct ldb_message_element *el);
 int ltdb_index_del_value(struct ldb_module *module,
 			 struct ltdb_private *ltdb,
-			 struct ldb_dn *dn,
+			 const struct ldb_message *msg,
 			 struct ldb_message_element *el, unsigned int v_idx);
 int ltdb_reindex(struct ldb_module *module);
 int ltdb_index_transaction_start(struct ldb_module *module);
-- 
2.9.4


From 2e11b4605b08ce94f344f71cd589c53e303abd6f Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 15 Aug 2017 14:13:32 +1200
Subject: [PATCH 20/39] ldb_tdb: Optionally use a GUID index key in
 ltdb_dn_list_find_msg()

This function is used to find an existing index value and this
change allows it to find the value by GUID rather than by DN once
the GUID index is enabled.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index fcb8247..cf0cdc1 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -117,9 +117,18 @@ static int ltdb_dn_list_find_msg(struct ltdb_private *ltdb,
 {
 	struct ldb_val v;
 	const struct ldb_val *key_val;
-	const char *dn_str = ldb_dn_get_linearized(msg->dn);
-	v.data = discard_const_p(unsigned char, dn_str);
-	v.length = strlen(dn_str);
+	if (ltdb->cache->GUID_index_attribute == NULL) {
+		const char *dn_str = ldb_dn_get_linearized(msg->dn);
+		v.data = discard_const_p(unsigned char, dn_str);
+		v.length = strlen(dn_str);
+	} else {
+		key_val = ldb_msg_find_ldb_val(msg,
+					       ltdb->cache->GUID_index_attribute);
+		if (key_val == NULL) {
+			return -1;
+		}
+		v = *key_val;
+	}
 	return ltdb_dn_list_find_val(ltdb, list, &v);
 }
 
-- 
2.9.4


From 76ef86f9771660d82900fb2fbfb04069f5135cd3 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 15 Aug 2017 14:18:19 +1200
Subject: [PATCH 21/39] ldb_tdb: Optionally store a GUID as the index record

This allows, when enabled, the index record to contain (say) the objectGUID, not the DN
of the record.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 32 +++++++++++++++++++++++---------
 1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index cf0cdc1..a733980 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -1259,8 +1259,7 @@ static int ltdb_index_add1(struct ldb_module *module,
 	const struct ldb_schema_attribute *a;
 	struct dn_list *list;
 	unsigned alloc_len;
-	const char *dn_str;
-	
+
 	ldb = ldb_module_get_ctx(module);
 
 	list = talloc_zero(module, struct dn_list);
@@ -1325,14 +1324,29 @@ static int ltdb_index_add1(struct ldb_module *module,
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	dn_str = ldb_dn_get_linearized(msg->dn);
-	list->dn[list->count].data
-		= (uint8_t *)talloc_strdup(list->dn, dn_str);
-	if (list->dn[list->count].data == NULL) {
-		talloc_free(list);
-		return LDB_ERR_OPERATIONS_ERROR;
+	if (ltdb->cache->GUID_index_attribute == NULL) {
+		const char *dn_str = ldb_dn_get_linearized(msg->dn);
+		list->dn[list->count].data
+			= (uint8_t *)talloc_strdup(list->dn, dn_str);
+		if (list->dn[list->count].data == NULL) {
+			talloc_free(list);
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		list->dn[list->count].length = strlen(dn_str);
+	} else {
+		const struct ldb_val *key_val;
+		key_val = ldb_msg_find_ldb_val(msg,
+					       ltdb->cache->GUID_index_attribute);
+		if (key_val == NULL) {
+			talloc_free(list);
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		list->dn[list->count] = ldb_val_dup(list->dn, key_val);
+		if (list->dn[list->count].data == NULL) {
+			talloc_free(list);
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
 	}
-	list->dn[list->count].length = strlen(dn_str);
 	list->count++;
 
 	ret = ltdb_dn_list_store(module, dn_key, list);
-- 
2.9.4


From a715d7937efc42ea1262e7e3cc3e76331854e101 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 11 Aug 2017 11:31:05 +1200
Subject: [PATCH 22/39] ldb: Add LDB_UNPACK_DATA_FLAG_NO_ATTRS

This will allow us to avoid a full unpack in situations where we just want to confirm
if the DN exists

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/common/ldb_pack.c    | 5 +++++
 lib/ldb/include/ldb_module.h | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c
index 1f1688a..448c577 100644
--- a/lib/ldb/common/ldb_pack.c
+++ b/lib/ldb/common/ldb_pack.c
@@ -301,6 +301,11 @@ int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
 		goto failed;
 	}
 
+	
+	if (flags & LDB_UNPACK_DATA_FLAG_NO_ATTRS) {
+		return 0;
+	}
+	
 	if (message->num_elements == 0) {
 		return 0;
 	}
diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h
index 8ad212a..71b4074 100644
--- a/lib/ldb/include/ldb_module.h
+++ b/lib/ldb/include/ldb_module.h
@@ -518,6 +518,10 @@ int ldb_unpack_data(struct ldb_context *ldb,
  * LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC is also specified.
  *
  * Likewise if LDB_UNPACK_DATA_FLAG_NO_DN is specified, the DN is omitted.
+ *
+ * If LDB_UNPACK_DATA_FLAG_NO_ATTRS is specified, then no attributes
+ * are unpacked or returned.
+ *
  */
 int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
 					 const struct ldb_val *data,
@@ -530,6 +534,7 @@ int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
 #define LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC   0x0001
 #define LDB_UNPACK_DATA_FLAG_NO_DN           0x0002
 #define LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC 0x0004
+#define LDB_UNPACK_DATA_FLAG_NO_ATTRS        0x0008
 
 /**
  Forces a specific ldb handle to use the global event context.
-- 
2.9.4


From 1e021895312496b13f5a2c9430a14899d75b8c82 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 15 Aug 2017 14:39:08 +1200
Subject: [PATCH 23/39] ldb_tdb: Implement ltdb_search_base() for a GUID index

The GUID index case can not directly use ltdb_key_dn() and tdb_exists() to
show that a records exists.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_search.c | 42 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 34 insertions(+), 8 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c
index 499cf1b..95077b1 100644
--- a/lib/ldb/ldb_tdb/ldb_search.c
+++ b/lib/ldb/ldb_tdb/ldb_search.c
@@ -124,15 +124,41 @@ static int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn)
 		return LDB_ERR_NO_SUCH_OBJECT;
 	}
 
-	/* form the key */
-	tdb_key = ltdb_key_dn(module, dn);
-	if (!tdb_key.dptr) {
-		return LDB_ERR_OPERATIONS_ERROR;
-	}
-
-	exists = tdb_exists(ltdb->tdb, tdb_key);
-	talloc_free(tdb_key.dptr);
+	if (ltdb->cache->GUID_index_attribute == NULL) {
+		/* form the key */
+		tdb_key = ltdb_key_dn(module, dn);
+		if (!tdb_key.dptr) {
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
 		
+		exists = tdb_exists(ltdb->tdb, tdb_key);
+		talloc_free(tdb_key.dptr);
+	} else {
+		/*
+		 * We can't use tdb_exists() as in this case
+		 * the in-DB key is the GUID one, not the DN
+		 * based one.  So we just do a normal
+		 * search 
+		 */
+		int ret;
+		struct ldb_message *msg = ldb_msg_new(module);
+		if (msg == NULL) {
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		
+		ret = ltdb_search_dn1(module, dn,
+				      msg,
+				      LDB_UNPACK_DATA_FLAG_NO_DN|
+				      LDB_UNPACK_DATA_FLAG_NO_ATTRS);
+		talloc_free(msg);
+		if (ret == LDB_SUCCESS) {
+			exists = true;
+		} else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+			exists = false;
+		} else {
+			return ret;
+		}
+	}
 	if (exists) {
 		return LDB_SUCCESS;
 	}
-- 
2.9.4


From 064b1f9f357c1bebd8b1793c5c8d935be40757f4 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 11 Aug 2017 11:33:17 +1200
Subject: [PATCH 24/39] ldb_tdb: Prepare to handle rename with GUID index by
 using ltdb_search_base()

This allows a check if the target DN exists even when the direct DN -> key
link is broken.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_search.c |  2 +-
 lib/ldb/ldb_tdb/ldb_tdb.c    | 48 +++++++++++++++++++++++++++++++++-----------
 lib/ldb/ldb_tdb/ldb_tdb.h    |  1 +
 3 files changed, 38 insertions(+), 13 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c
index 95077b1..fd48445 100644
--- a/lib/ldb/ldb_tdb/ldb_search.c
+++ b/lib/ldb/ldb_tdb/ldb_search.c
@@ -113,7 +113,7 @@ static int msg_add_distinguished_name(struct ldb_message *msg)
   return LDB_ERR_NO_SUCH_OBJECT on record-not-found
   and LDB_SUCCESS on success
 */
-static int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn)
+int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn)
 {
 	void *data = ldb_module_get_private(module);
 	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index c173a62..2e53b09 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -1151,7 +1151,11 @@ static int ltdb_rename(struct ltdb_context *ctx)
 
 	/* We need to, before changing the DB, check if the new DN
 	 * exists, so we can return this error to the caller with an
-	 * unmodified DB */
+	 * unmodified DB 
+	 * 
+	 * Even in GUID index mode we use ltdb_key_dn() as we are
+	 * trying to figure out if this is just a case rename
+	 */
 	tdb_key = ltdb_key_dn(module, req->op.rename.newdn);
 	if (!tdb_key.dptr) {
 		talloc_free(msg);
@@ -1165,19 +1169,39 @@ static int ltdb_rename(struct ltdb_context *ctx)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	/* Only declare a conflict if the new DN already exists, and it isn't a case change on the old DN */
-	if (tdb_key_old.dsize != tdb_key.dsize || memcmp(tdb_key.dptr, tdb_key_old.dptr, tdb_key.dsize) != 0) {
-		if (tdb_exists(ltdb->tdb, tdb_key)) {
-			talloc_free(tdb_key_old.dptr);
-			talloc_free(tdb_key.dptr);
-			ldb_asprintf_errstring(ldb_module_get_ctx(module),
-					       "Entry %s already exists",
-					       ldb_dn_get_linearized(req->op.rename.newdn));
-			/* finding the new record already in the DB is an error */
-			talloc_free(msg);
-			return LDB_ERR_ENTRY_ALREADY_EXISTS;
+	/*
+	 * Only declare a conflict if the new DN already exists, 
+	 * and it isn't a case change on the old DN 
+	 */
+	if (tdb_key_old.dsize != tdb_key.dsize
+	    || memcmp(tdb_key.dptr, tdb_key_old.dptr, tdb_key.dsize) != 0) {
+		if (ltdb->cache->GUID_index_attribute == NULL) {
+			if (tdb_exists(ltdb->tdb, tdb_key)) {
+				ret = LDB_ERR_ENTRY_ALREADY_EXISTS;
+			}
+		} else {
+			ret = ltdb_search_base(module,
+					       req->op.rename.newdn);
+			if (ret == LDB_SUCCESS) {
+				ret = LDB_ERR_ENTRY_ALREADY_EXISTS;
+			}
 		}
 	}
+
+	/* finding the new record already in the DB is an error */
+
+	if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+		ldb_asprintf_errstring(ldb_module_get_ctx(module),
+				       "Entry %s already exists",
+				       ldb_dn_get_linearized(req->op.rename.newdn));
+	}
+	if (ret != LDB_SUCCESS) {
+		talloc_free(tdb_key_old.dptr);
+		talloc_free(tdb_key.dptr);
+		talloc_free(msg);
+		return ret;
+	}
+	
 	talloc_free(tdb_key_old.dptr);
 	talloc_free(tdb_key.dptr);
 
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index ea9ccb6..e8c4dad 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -111,6 +111,7 @@ int ltdb_has_wildcard(struct ldb_module *module, const char *attr_name,
 void ltdb_search_dn1_free(struct ldb_module *module, struct ldb_message *msg);
 int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg,
 		    unsigned int unpack_flags);
+int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn);
 int ltdb_search_key(struct ldb_module *module, struct ltdb_private *ltdb,
 		    struct TDB_DATA tdb_key,
 		    struct ldb_message *msg,
-- 
2.9.4


From 4897920fb18027c50961527c96b4eecae5d09bc9 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 11 Aug 2017 12:25:42 +1200
Subject: [PATCH 25/39] ldb_tdb: Add a GUID index of the DN during
 ltdb_index_add_all()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 31 +++++++++++++++++++++++++++++++
 lib/ldb/ldb_tdb/ldb_tdb.h   |  1 +
 2 files changed, 32 insertions(+)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index a733980..3baa2e6 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -1397,6 +1397,37 @@ static int ltdb_index_add_all(struct ldb_module *module,
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
+	if (ltdb->cache->GUID_index_attribute != NULL) {
+		int ret;
+		const char *casefold_dn = ldb_dn_get_casefold(msg->dn);
+		struct ldb_val val = {
+			.data = (uint8_t *)((uintptr_t)casefold_dn)
+		};
+		struct ldb_message_element dn_el = {
+			.name = LTDB_IDXDN,
+			.num_values = 1,
+			.values = &val
+		};
+		
+		if (casefold_dn == NULL) {
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		val.length = strlen(casefold_dn);
+		
+		ret = ltdb_index_add1(module, ltdb, msg,
+				      &dn_el, 1, is_new);
+		if (ret != LDB_SUCCESS) {
+			struct ldb_context *ldb = ldb_module_get_ctx(module);
+			ldb_asprintf_errstring(ldb,
+					       __location__
+					       ": Failed to re-index DN "
+					       "against %s in %s - %s",
+					       ltdb->cache->GUID_index_attribute,
+					       dn_str, ldb_errstring(ldb));
+			return ret;
+		}
+	}
+	
 	if (!ltdb->cache->attribute_indexes) {
 		/* no indexed fields */
 		return LDB_SUCCESS;
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index e8c4dad..c11b0e1 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -60,6 +60,7 @@ struct ltdb_context {
 #define LTDB_IDXVERSION "@IDXVERSION"
 #define LTDB_IDXATTR    "@IDXATTR"
 #define LTDB_IDXONE     "@IDXONE"
+#define LTDB_IDXDN     "@IDXDN"
 #define LTDB_BASEINFO   "@BASEINFO"
 #define LTDB_OPTIONS    "@OPTIONS"
 #define LTDB_ATTRIBUTES "@ATTRIBUTES"
-- 
2.9.4


From 306bc31ebd89d2cbd467c77527c5b132544cbd37 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 11 Aug 2017 13:26:30 +1200
Subject: [PATCH 26/39] ldb_tdb: Pass ltdb_private to ltdb_dn_list_load()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 3baa2e6..b010f8f 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -170,12 +170,12 @@ static struct dn_list *ltdb_index_idxptr(struct ldb_module *module, TDB_DATA rec
   struct dn_list
  */
 static int ltdb_dn_list_load(struct ldb_module *module,
+			     struct ltdb_private *ltdb,
 			     struct ldb_dn *dn, struct dn_list *list)
 {
 	struct ldb_message *msg;
 	int ret;
 	struct ldb_message_element *el;
-	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
 	TDB_DATA rec;
 	struct dn_list *list2;
 	TDB_DATA key;
@@ -616,7 +616,7 @@ static int ltdb_index_dn_simple(struct ldb_module *module,
 	dn = ltdb_index_key(ldb, tree->u.equality.attr, &tree->u.equality.value, NULL);
 	if (!dn) return LDB_ERR_OPERATIONS_ERROR;
 
-	ret = ltdb_dn_list_load(module, dn, list);
+	ret = ltdb_dn_list_load(module, ltdb, dn, list);
 	talloc_free(dn);
 	return ret;
 }
@@ -960,6 +960,7 @@ static int ltdb_index_dn_and(struct ldb_module *module,
   return a list of matching objects using a one-level index
  */
 static int ltdb_index_dn_one(struct ldb_module *module,
+			     struct ltdb_private *ltdb,
 			     struct ldb_dn *parent_dn,
 			     struct dn_list *list)
 {
@@ -979,7 +980,7 @@ static int ltdb_index_dn_one(struct ldb_module *module,
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	ret = ltdb_dn_list_load(module, key, list);
+	ret = ltdb_dn_list_load(module, ltdb, key, list);
 	talloc_free(key);
 	if (ret != LDB_SUCCESS) {
 		return ret;
@@ -1200,7 +1201,7 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
 			talloc_free(dn_list);
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
-		ret = ltdb_index_dn_one(ac->module, ac->base, dn_list);
+		ret = ltdb_index_dn_one(ac->module, ltdb, ac->base, dn_list);
 		if (ret != LDB_SUCCESS) {
 			talloc_free(dn_list);
 			return ret;
@@ -1274,7 +1275,7 @@ static int ltdb_index_add1(struct ldb_module *module,
 	}
 	talloc_steal(list, dn_key);
 
-	ret = ltdb_dn_list_load(module, dn_key, list);
+	ret = ltdb_dn_list_load(module, ltdb, dn_key, list);
 	if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
 		talloc_free(list);
 		return ret;
@@ -1584,7 +1585,7 @@ int ltdb_index_del_value(struct ldb_module *module,
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	ret = ltdb_dn_list_load(module, dn_key, list);
+	ret = ltdb_dn_list_load(module, ltdb, dn_key, list);
 	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
 		/* it wasn't indexed. Did we have an earlier error? If we did then
 		   its gone now */
-- 
2.9.4


From 8c0180f12ccced2773cd9ac1f9cee06aa2637b81 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 11 Aug 2017 17:51:40 +1200
Subject: [PATCH 27/39] ldb_tdb: Do not directly assign DN into the index
 result list

With the GUID index option, the values in the index result list may not be a DN
but the objectGUID.  We look up the @IDXDN index to get that if required.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 91 +++++++++++++++++++++++++++++++++------------
 1 file changed, 68 insertions(+), 23 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index b010f8f..dccfda5 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -632,6 +632,8 @@ static int ltdb_index_dn_leaf(struct ldb_module *module,
 			      const struct ldb_parse_tree *tree,
 			      struct dn_list *list)
 {
+	/* Must be at the same scope as the ltdb_index_dn_simple */
+	struct ldb_parse_tree dn_tree;
 	if (ltdb->disallow_dn_filter &&
 	    (ldb_attr_cmp(tree->u.equality.attr, "dn") == 0)) {
 		/* in AD mode we do not support "(dn=...)" search filters */
@@ -640,14 +642,21 @@ static int ltdb_index_dn_leaf(struct ldb_module *module,
 		return LDB_SUCCESS;
 	}
 	if (ldb_attr_dn(tree->u.equality.attr) == 0) {
-		list->dn = talloc_array(list, struct ldb_val, 1);
-		if (list->dn == NULL) {
-			ldb_module_oom(module);
-			return LDB_ERR_OPERATIONS_ERROR;
+		if (ltdb->cache->GUID_index_attribute == NULL) {
+			list->dn = talloc_array(list, struct ldb_val, 1);
+			if (list->dn == NULL) {
+				ldb_module_oom(module);
+				return LDB_ERR_OPERATIONS_ERROR;
+			}
+			list->dn[0] = tree->u.equality.value;
+			list->count = 1;
+			return LDB_SUCCESS;
 		}
-		list->dn[0] = tree->u.equality.value;
-		list->count = 1;
-		return LDB_SUCCESS;
+
+		/* Overwrite the attr with @IDXDN */
+		dn_tree = *tree;
+		dn_tree.u.equality.attr = LTDB_IDXDN;
+		tree = &dn_tree;
 	}
 	return ltdb_index_dn_simple(module, ltdb, tree, list);
 }
@@ -959,10 +968,11 @@ static int ltdb_index_dn_and(struct ldb_module *module,
 /*
   return a list of matching objects using a one-level index
  */
-static int ltdb_index_dn_one(struct ldb_module *module,
-			     struct ltdb_private *ltdb,
-			     struct ldb_dn *parent_dn,
-			     struct dn_list *list)
+static int ltdb_index_dn_attr(struct ldb_module *module,
+			      struct ltdb_private *ltdb,
+			      const char *attr,
+			      struct ldb_dn *dn,
+			      struct dn_list *list)
 {
 	struct ldb_context *ldb;
 	struct ldb_dn *key;
@@ -972,9 +982,9 @@ static int ltdb_index_dn_one(struct ldb_module *module,
 	ldb = ldb_module_get_ctx(module);
 
 	/* work out the index key from the parent DN */
-	val.data = (uint8_t *)((uintptr_t)ldb_dn_get_casefold(parent_dn));
+	val.data = (uint8_t *)((uintptr_t)ldb_dn_get_casefold(dn));
 	val.length = strlen((char *)val.data);
-	key = ltdb_index_key(ldb, LTDB_IDXONE, &val, NULL);
+	key = ltdb_index_key(ldb, attr, &val, NULL);
 	if (!key) {
 		ldb_oom(ldb);
 		return LDB_ERR_OPERATIONS_ERROR;
@@ -994,6 +1004,47 @@ static int ltdb_index_dn_one(struct ldb_module *module,
 }
 
 /*
+  return a list of matching objects using a one-level index
+ */
+static int ltdb_index_dn_one(struct ldb_module *module,
+			     struct ltdb_private *ltdb,
+			     struct ldb_dn *parent_dn,
+			     struct dn_list *list)
+{
+	return ltdb_index_dn_attr(module, ltdb,
+				  LTDB_IDXONE, parent_dn, list);
+}
+
+/*
+  return a list of matching objects using the DN index
+ */
+static int ltdb_index_dn_base_dn(struct ldb_module *module,
+				 struct ltdb_private *ltdb,
+				 struct ldb_dn *base_dn,
+				 struct dn_list *dn_list)
+{
+	if (ltdb->cache->GUID_index_attribute != NULL) {
+		return ltdb_index_dn_attr(module, ltdb,
+					  LTDB_IDXDN, base_dn, dn_list);
+	}
+	
+	dn_list->dn = talloc_array(dn_list, struct ldb_val, 1);
+	if (dn_list->dn == NULL) {
+		talloc_free(dn_list);
+		return ldb_module_oom(module);
+	}
+	dn_list->dn[0].data = discard_const_p(unsigned char,
+					      ldb_dn_get_linearized(base_dn));
+	if (dn_list->dn[0].data == NULL) {
+		talloc_free(dn_list);
+		return ldb_module_oom(module);
+	}
+	dn_list->dn[0].length = strlen((char *)dn_list->dn[0].data);
+	dn_list->count = 1;
+	return LDB_SUCCESS;
+}
+
+/*
   return a list of dn's that might match a indexed search or
   an error. return LDB_ERR_NO_SUCH_OBJECT for no matches, or LDB_SUCCESS for matches
  */
@@ -1182,18 +1233,12 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
 
 	switch (ac->scope) {
 	case LDB_SCOPE_BASE:
-		dn_list->dn = talloc_array(dn_list, struct ldb_val, 1);
-		if (dn_list->dn == NULL) {
-			talloc_free(dn_list);
-			return ldb_module_oom(ac->module);
-		}
-		dn_list->dn[0].data = discard_const_p(unsigned char, ldb_dn_get_linearized(ac->base));
-		if (dn_list->dn[0].data == NULL) {
+		ret = ltdb_index_dn_base_dn(ac->module, ltdb,
+					    ac->base, dn_list);
+		if (ret != LDB_SUCCESS) {
 			talloc_free(dn_list);
-			return ldb_module_oom(ac->module);
+			return ret;
 		}
-		dn_list->dn[0].length = strlen((char *)dn_list->dn[0].data);
-		dn_list->count = 1;
 		break;
 
 	case LDB_SCOPE_ONELEVEL:
-- 
2.9.4


From e6f1a89308163ccdbd11583e2fe202201145d861 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 11 Aug 2017 18:09:01 +1200
Subject: [PATCH 28/39] ldb_tdb: Add a function to get the GUID key for a DN

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 38 ++++++++++++++++++++++++++++++++++++++
 lib/ldb/ldb_tdb/ldb_tdb.h   |  5 +++++
 2 files changed, 43 insertions(+)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index dccfda5..2fea58b 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -44,6 +44,11 @@ struct ltdb_idxptr {
 	int error;
 };
 
+static int ltdb_index_dn_base_dn(struct ldb_module *module,
+				 struct ltdb_private *ltdb,
+				 struct ldb_dn *base_dn,
+				 struct dn_list *dn_list);
+
 /* we put a @IDXVERSION attribute on index entries. This
    allows us to tell if it was written by an older version
 */
@@ -262,6 +267,39 @@ normal_index:
 	return LDB_SUCCESS;
 }
 
+int ltdb_key_dn_from_idx(struct ldb_module *module,
+			 struct ltdb_private *ltdb,
+			 TALLOC_CTX *mem_ctx,
+			 struct ldb_dn *dn,
+			 TDB_DATA *tdb_key)
+{
+	struct ldb_context *ldb = ldb_module_get_ctx(module);
+	int ret;
+	struct dn_list *list = talloc(mem_ctx, struct dn_list);
+	if (list == NULL) {
+		ldb_oom(ldb);
+		return LDB_ERR_OPERATIONS_ERROR;
+	}		
+	 
+	ret = ltdb_index_dn_base_dn(module, ltdb, dn, list);
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
+
+	if (list->count == 0) {
+		return LDB_ERR_NO_SUCH_OBJECT;
+	}
+	if (list->count > 1) {
+		return LDB_ERR_CONSTRAINT_VIOLATION;
+	}
+
+	tdb_key->dptr = list->dn[0].data;
+	tdb_key->dsize = list->dn[0].length;
+	
+	return LDB_SUCCESS;
+}
+
+
 
 /*
   save a dn_list into a full @IDX style record
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index c11b0e1..13ac001 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -104,6 +104,11 @@ int ltdb_reindex(struct ldb_module *module);
 int ltdb_index_transaction_start(struct ldb_module *module);
 int ltdb_index_transaction_commit(struct ldb_module *module);
 int ltdb_index_transaction_cancel(struct ldb_module *module);
+int ltdb_key_dn_from_idx(struct ldb_module *module,
+			 struct ltdb_private *ltdb,
+			 TALLOC_CTX *mem_ctx,
+			 struct ldb_dn *dn,
+			 TDB_DATA *tdb_key);
 
 /* The following definitions come from lib/ldb/ldb_tdb/ldb_search.c  */
 
-- 
2.9.4


From 09c7aa7adb17e0a90f175e943e6190c10ba54d9e Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 14 Aug 2017 16:13:42 +1200
Subject: [PATCH 29/39] ldb_tdb: Add an index shortcut for a <GUID= DN

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 49 ++++++++++++++++++++++++++++++---------------
 lib/ldb/ldb_tdb/ldb_tdb.h   |  1 +
 2 files changed, 34 insertions(+), 16 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 2fea58b..edeb6a7 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -1061,25 +1061,42 @@ static int ltdb_index_dn_base_dn(struct ldb_module *module,
 				 struct ldb_dn *base_dn,
 				 struct dn_list *dn_list)
 {
-	if (ltdb->cache->GUID_index_attribute != NULL) {
-		return ltdb_index_dn_attr(module, ltdb,
-					  LTDB_IDXDN, base_dn, dn_list);
+	const struct ldb_val *guid_val = NULL;
+	if (ltdb->cache->GUID_index_attribute == NULL) {
+		dn_list->dn = talloc_array(dn_list, struct ldb_val, 1);
+		if (dn_list->dn == NULL) {
+			return ldb_module_oom(module);
+		}
+		dn_list->dn[0].data = discard_const_p(unsigned char,
+						      ldb_dn_get_linearized(base_dn));
+		if (dn_list->dn[0].data == NULL) {
+			return ldb_module_oom(module);
+		}
+		dn_list->dn[0].length = strlen((char *)dn_list->dn[0].data);
+		dn_list->count = 1;
+
+		return LDB_SUCCESS;
 	}
-	
-	dn_list->dn = talloc_array(dn_list, struct ldb_val, 1);
-	if (dn_list->dn == NULL) {
-		talloc_free(dn_list);
-		return ldb_module_oom(module);
+
+	if (ltdb->cache->GUID_index_dn_component != NULL) {
+		guid_val = ldb_dn_get_extended_component(base_dn,
+							 ltdb->cache->GUID_index_dn_component);
 	}
-	dn_list->dn[0].data = discard_const_p(unsigned char,
-					      ldb_dn_get_linearized(base_dn));
-	if (dn_list->dn[0].data == NULL) {
-		talloc_free(dn_list);
-		return ldb_module_oom(module);
+	
+	if (guid_val != NULL) {
+		dn_list->dn = talloc_array(dn_list, struct ldb_val, 1);
+		if (dn_list->dn == NULL) {
+			return ldb_module_oom(module);
+		}
+		dn_list->dn[0].data = guid_val->data;
+		dn_list->dn[0].length = guid_val->length;
+		dn_list->count = 1;
+
+		return LDB_SUCCESS;
 	}
-	dn_list->dn[0].length = strlen((char *)dn_list->dn[0].data);
-	dn_list->count = 1;
-	return LDB_SUCCESS;
+		
+	return ltdb_index_dn_attr(module, ltdb,
+				  LTDB_IDXDN, base_dn, dn_list);
 }
 
 /*
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index 13ac001..8c25a82 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -21,6 +21,7 @@ struct ltdb_private {
 		bool one_level_indexes;
 		bool attribute_indexes;
 		const char *GUID_index_attribute;
+		const char *GUID_index_dn_component;
 	} *cache;
 
 	int in_transaction;
-- 
2.9.4


From 4879399ae1127a5ccaedad83a2b6e87d0d537dd7 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 14 Aug 2017 10:54:18 +1200
Subject: [PATCH 30/39] ldb_tdb: Check version number on index

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index edeb6a7..678b037 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -179,7 +179,7 @@ static int ltdb_dn_list_load(struct ldb_module *module,
 			     struct ldb_dn *dn, struct dn_list *list)
 {
 	struct ldb_message *msg;
-	int ret;
+	int ret, version;
 	struct ldb_message_element *el;
 	TDB_DATA rec;
 	struct dn_list *list2;
@@ -227,13 +227,13 @@ normal_index:
 		return ret;
 	}
 
-	/* TODO: check indexing version number */
-
 	el = ldb_msg_find_element(msg, LTDB_IDX);
 	if (!el) {
 		talloc_free(msg);
 		return LDB_SUCCESS;
 	}
+	
+	version = ldb_msg_find_attr_as_int(msg, LTDB_IDXVERSION, 0);
 
 	/*
 	 * we avoid copying the strings by stealing the list.  We have
@@ -243,11 +243,34 @@ normal_index:
 	 */
 	talloc_steal(el->values, msg);
 	if (ltdb->cache->GUID_index_attribute == NULL) {
+		/* check indexing version number */
+		if (version != LTDB_INDEXING_VERSION) {
+			ldb_debug_set(ldb_module_get_ctx(module),
+				      LDB_DEBUG_ERROR,
+				      "Wrong DN index version %d "
+				      "expected %d for %s",
+				      version, LTDB_INDEXING_VERSION, 
+				      ldb_dn_get_linearized(dn));
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		
 		list->dn = talloc_steal(list, el->values);
 		list->count = el->num_values;
 	} else {
 		unsigned int i;
 		static const size_t GUID_val_size = 16;
+		if (version != LTDB_GUID_INDEXING_VERSION) {
+			/* This is quite likely during the DB startup
+			   on first upgrade to using a GUID index */
+			ldb_debug_set(ldb_module_get_ctx(module),
+				      LDB_DEBUG_ERROR,
+				      "Wrong GUID index version %d "
+				      "expected %d for %s",
+				      version, LTDB_GUID_INDEXING_VERSION, 
+				      ldb_dn_get_linearized(dn));
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		
 		if (el->num_values != 1) {
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
-- 
2.9.4


From 98537985f130f2bf72f6ac176fd5bd3b96f13772 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 14 Aug 2017 15:47:15 +1200
Subject: [PATCH 31/39] ldb_tdb: Add mem_ctx to ltdb_key_dn() and
 ltdb_key_msg()

This allows ltdb_key_msg() to safely return a GUID index values
from the msg parameter, for example the objectGUID attribute

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c  |  2 +-
 lib/ldb/ldb_tdb/ldb_search.c | 23 ++++++++++++++----
 lib/ldb/ldb_tdb/ldb_tdb.c    | 56 ++++++++++++++++++++++++++++----------------
 lib/ldb/ldb_tdb/ldb_tdb.h    |  6 +++--
 4 files changed, 59 insertions(+), 28 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 678b037..5b658d1 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -1911,7 +1911,7 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
 	/* check if the DN key has changed, perhaps due to the case
 	   insensitivity of an element changing, or a change from DN
 	   to GUID keys */
-	key2 = ltdb_key_msg(module, msg);
+	key2 = ltdb_key_msg(module, msg, msg);
 	if (key2.dptr == NULL) {
 		/* probably a corrupt record ... darn */
 		ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s",
diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c
index fd48445..537c7d0 100644
--- a/lib/ldb/ldb_tdb/ldb_search.c
+++ b/lib/ldb/ldb_tdb/ldb_search.c
@@ -125,14 +125,18 @@ int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn)
 	}
 
 	if (ltdb->cache->GUID_index_attribute == NULL) {
+		TALLOC_CTX *tdb_key_ctx = talloc_new(module);
+		if (tdb_key_ctx == NULL) {
+			return ldb_oom(ldb_module_get_ctx(module));
+		}
 		/* form the key */
-		tdb_key = ltdb_key_dn(module, dn);
+		tdb_key = ltdb_key_dn(module, tdb_key_ctx, dn);
 		if (!tdb_key.dptr) {
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
 		
 		exists = tdb_exists(ltdb->tdb, tdb_key);
-		talloc_free(tdb_key.dptr);
+		talloc_free(tdb_key_ctx);
 	} else {
 		/*
 		 * We can't use tdb_exists() as in this case
@@ -227,7 +231,7 @@ static int ltdb_parse_data_unpack(TDB_DATA key, TDB_DATA data,
   and LDB_SUCCESS on success
 */
 int ltdb_search_key(struct ldb_module *module, struct ltdb_private *ltdb,
-		    struct TDB_DATA tdb_key,
+		    const struct TDB_DATA tdb_key,
 		    struct ldb_message *msg,
 		    unsigned int unpack_flags)
 {
@@ -245,7 +249,6 @@ int ltdb_search_key(struct ldb_module *module, struct ltdb_private *ltdb,
 
 	ret = tdb_parse_record(ltdb->tdb, tdb_key, 
 			       ltdb_parse_data_unpack, &ctx); 
-	talloc_free(tdb_key.dptr);
 	
 	if (ret == -1) {
 		if (tdb_error(ltdb->tdb) == TDB_ERR_NOEXIST) {
@@ -273,13 +276,23 @@ int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_mes
 	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
 	int ret;
 	TDB_DATA tdb_key;
+
+	TALLOC_CTX *tdb_key_ctx = talloc_new(msg);
+	if (!tdb_key_ctx) {
+		return ldb_module_oom(module);
+	}
+
 	/* form the key */
-	tdb_key = ltdb_key_dn(module, dn);
+	tdb_key = ltdb_key_dn(module, tdb_key_ctx, dn);
 	if (!tdb_key.dptr) {
+		TALLOC_FREE(tdb_key_ctx);
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
 	ret = ltdb_search_key(module, ltdb, tdb_key, msg, unpack_flags);
+
+	TALLOC_FREE(tdb_key_ctx);
+
 	if (ret != LDB_SUCCESS) {
 		return ret;
 	}
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index 2e53b09..7e495c5 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -134,7 +134,8 @@ int ltdb_unlock_read(struct ldb_module *module)
   note that the key for a record can depend on whether the
   dn refers to a case sensitive index record or not
 */
-TDB_DATA ltdb_key_dn(struct ldb_module *module, struct ldb_dn *dn)
+TDB_DATA ltdb_key_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx,
+		     struct ldb_dn *dn)
 {
 	struct ldb_context *ldb = ldb_module_get_ctx(module);
 	TDB_DATA key;
@@ -182,12 +183,13 @@ failed:
 
 /*
   form a TDB_DATA for a record key
-  caller frees
+  caller frees mem_ctx, which may or may not have the key
+  as a child.
 
-  note that the key for a record can depend on whether the
-  dn refers to a case sensitive index record or not
+  note that the key for a record can depend on whether a
+  GUID index is in use, or the DN is used as the key
 */
-TDB_DATA ltdb_key_msg(struct ldb_module *module,
+TDB_DATA ltdb_key_msg(struct ldb_module *module, TALLOC_CTX *mem_ctx,
 		      const struct ldb_message *msg)
 {
 	void *data = ldb_module_get_private(module);
@@ -196,11 +198,11 @@ TDB_DATA ltdb_key_msg(struct ldb_module *module,
 	const struct ldb_val *key_val;
 
 	if (ltdb->cache->GUID_index_attribute == NULL) {
-		return ltdb_key_dn(module, msg->dn);
+		return ltdb_key_dn(module, mem_ctx, msg->dn);
 	}
 
 	if (ldb_dn_is_special(msg->dn)) {
-		return ltdb_key_dn(module, msg->dn);
+		return ltdb_key_dn(module, mem_ctx, msg->dn);
 	}
 
 	key_val = ldb_msg_find_ldb_val(msg,
@@ -306,16 +308,22 @@ int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flg
 	TDB_DATA tdb_key, tdb_data;
 	struct ldb_val ldb_data;
 	int ret = LDB_SUCCESS;
+	TALLOC_CTX *tdb_key_ctx = talloc_new(module);
 
-	tdb_key = ltdb_key_msg(module, msg);
+	if (tdb_key_ctx == NULL) {
+		return ldb_module_oom(module);
+	}
+	
+	tdb_key = ltdb_key_msg(module, tdb_key_ctx, msg);
 	if (tdb_key.dptr == NULL) {
+		TALLOC_FREE(tdb_key_ctx);
 		return LDB_ERR_OTHER;
 	}
 
 	ret = ldb_pack_data(ldb_module_get_ctx(module),
 			    msg, &ldb_data);
 	if (ret == -1) {
-		talloc_free(tdb_key.dptr);
+		TALLOC_FREE(tdb_key_ctx);
 		return LDB_ERR_OTHER;
 	}
 
@@ -329,7 +337,7 @@ int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flg
 	}
 
 done:
-	talloc_free(tdb_key.dptr);
+	TALLOC_FREE(tdb_key_ctx);
 	talloc_free(ldb_data.data);
 
 	return ret;
@@ -478,14 +486,20 @@ int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn)
 	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
 	TDB_DATA tdb_key;
 	int ret;
+	TALLOC_CTX *tdb_key_ctx = talloc_new(module);
 
-	tdb_key = ltdb_key_dn(module, dn);
+	if (tdb_key_ctx == NULL) {
+		return ldb_module_oom(module);
+	}
+	
+	tdb_key = ltdb_key_dn(module, tdb_key_ctx, dn);
 	if (!tdb_key.dptr) {
+		TALLOC_FREE(tdb_key_ctx);
 		return LDB_ERR_OTHER;
 	}
 
 	ret = tdb_delete(ltdb->tdb, tdb_key);
-	talloc_free(tdb_key.dptr);
+	TALLOC_FREE(tdb_key_ctx);
 
 	if (ret != 0) {
 		ret = ltdb_err_map(tdb_error(ltdb->tdb));
@@ -519,7 +533,7 @@ static int ltdb_delete_internal(struct ldb_module *module, struct ldb_dn *dn)
 			goto done;
 		}
 	} else {
-		TDB_DATA tdb_key = ltdb_key_msg(module, msg);
+		TDB_DATA tdb_key = ltdb_key_msg(module, msg, msg);
 		if (!tdb_key.dptr) {
 			ret = LDB_ERR_OTHER;
 			goto done;
@@ -757,24 +771,26 @@ int ltdb_modify_internal(struct ldb_module *module,
 	unsigned int i, j;
 	int ret = LDB_SUCCESS, idx;
 	struct ldb_control *control_permissive = NULL;
-
+	TALLOC_CTX *mem_ctx = talloc_new(req);
+	
 	if (req) {
 		control_permissive = ldb_request_get_control(req,
 					LDB_CONTROL_PERMISSIVE_MODIFY_OID);
 	}
 
-	tdb_key = ltdb_key_msg(module, msg);
+	tdb_key = ltdb_key_msg(module, mem_ctx, msg);
 	if (!tdb_key.dptr) {
+		TALLOC_FREE(mem_ctx);
 		return LDB_ERR_OTHER;
 	}
 
 	tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
 	if (!tdb_data.dptr) {
-		talloc_free(tdb_key.dptr);
+		TALLOC_FREE(mem_ctx);
 		return ltdb_err_map(tdb_error(ltdb->tdb));
 	}
 
-	msg2 = ldb_msg_new(tdb_key.dptr);
+	msg2 = ldb_msg_new(mem_ctx);
 	if (msg2 == NULL) {
 		free(tdb_data.dptr);
 		ret = LDB_ERR_OTHER;
@@ -1088,7 +1104,7 @@ int ltdb_modify_internal(struct ldb_module *module,
 	}
 
 done:
-	talloc_free(tdb_key.dptr);
+	TALLOC_FREE(mem_ctx);
 	return ret;
 }
 
@@ -1156,13 +1172,13 @@ static int ltdb_rename(struct ltdb_context *ctx)
 	 * Even in GUID index mode we use ltdb_key_dn() as we are
 	 * trying to figure out if this is just a case rename
 	 */
-	tdb_key = ltdb_key_dn(module, req->op.rename.newdn);
+	tdb_key = ltdb_key_dn(module, msg, req->op.rename.newdn);
 	if (!tdb_key.dptr) {
 		talloc_free(msg);
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	tdb_key_old = ltdb_key_dn(module, req->op.rename.olddn);
+	tdb_key_old = ltdb_key_dn(module, msg, req->op.rename.olddn);
 	if (!tdb_key_old.dptr) {
 		talloc_free(msg);
 		talloc_free(tdb_key.dptr);
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index 8c25a82..bd43320 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -131,8 +131,10 @@ int ltdb_search(struct ltdb_context *ctx);
 /* The following definitions come from lib/ldb/ldb_tdb/ldb_tdb.c  */
 int ltdb_lock_read(struct ldb_module *module);
 int ltdb_unlock_read(struct ldb_module *module);
-TDB_DATA ltdb_key_dn(struct ldb_module *module, struct ldb_dn *dn);
-TDB_DATA ltdb_key_msg(struct ldb_module *module, const struct ldb_message *msg);
+TDB_DATA ltdb_key_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx,
+		     struct ldb_dn *dn);
+TDB_DATA ltdb_key_msg(struct ldb_module *module, TALLOC_CTX *mem_ctx,
+		      const struct ldb_message *msg);
 int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs);
 int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg, struct ldb_request *req);
 int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn);
-- 
2.9.4


From ba9b5c067b9cbf90130eb33f67342abe65fce1f5 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 17:12:30 +1200
Subject: [PATCH 32/39] ldb_tdb: Optionally use GUID index in ltdb_search_dn1()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_search.c | 27 ++++++++++++++++++++++-----
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c
index 537c7d0..26f0381 100644
--- a/lib/ldb/ldb_tdb/ldb_search.c
+++ b/lib/ldb/ldb_tdb/ldb_search.c
@@ -282,11 +282,28 @@ int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_mes
 		return ldb_module_oom(module);
 	}
 
-	/* form the key */
-	tdb_key = ltdb_key_dn(module, tdb_key_ctx, dn);
-	if (!tdb_key.dptr) {
-		TALLOC_FREE(tdb_key_ctx);
-		return LDB_ERR_OPERATIONS_ERROR;
+	if (ltdb->cache->GUID_index_attribute == NULL) {
+		/* form the key */
+		tdb_key = ltdb_key_dn(module, tdb_key_ctx, dn);
+		if (!tdb_key.dptr) {
+			TALLOC_FREE(tdb_key_ctx);
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+	} else if (ldb_dn_is_special(dn)) {
+		/* form the key */
+		tdb_key = ltdb_key_dn(module, tdb_key_ctx, dn);
+		if (!tdb_key.dptr) {
+			TALLOC_FREE(tdb_key_ctx);
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+	} else {
+		/* Look in the index to find the key for this DN */
+		ret = ltdb_key_dn_from_idx(module, ltdb, tdb_key_ctx,
+					   dn, &tdb_key);
+		if (ret != LDB_SUCCESS) {
+			TALLOC_FREE(tdb_key_ctx);
+			return ret;
+		}
 	}
 
 	ret = ltdb_search_key(module, ltdb, tdb_key, msg, unpack_flags);
-- 
2.9.4


From 1a2fab07382e39b6a5a0ac8705249949b85538b5 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 14 Aug 2017 16:27:46 +1200
Subject: [PATCH 33/39] ldb_tdb: Do not add or query an index on the
 GUID_index_attribute

The objectGUID (or similar) is already the record key, it is not in the index

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 5b658d1..2f15f17 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -603,6 +603,12 @@ static bool ltdb_is_indexed(struct ldb_module *module,
 	unsigned int i;
 	struct ldb_message_element *el;
 
+	if ((ltdb->cache->GUID_index_attribute != NULL) && 
+	    (ldb_attr_cmp(attr,
+			  ltdb->cache->GUID_index_attribute) == 0)) {
+		/* Implicity covered, this is the index key */
+		return false;
+	}
 	if (ldb->schema.index_handler_override) {
 		const struct ldb_schema_attribute *a
 			= ldb_schema_attribute_by_name(ldb, attr);
@@ -718,7 +724,20 @@ static int ltdb_index_dn_leaf(struct ldb_module *module,
 		dn_tree = *tree;
 		dn_tree.u.equality.attr = LTDB_IDXDN;
 		tree = &dn_tree;
+	} else if (ltdb->cache->GUID_index_attribute != NULL) {
+		/*
+		 * If (for example) the search is for objectGUID=
+		 * and that is our GUID attribute, 
+		 * we have our key already
+		 */
+		if (ldb_attr_cmp(tree->u.equality.attr,
+				 ltdb->cache->GUID_index_attribute) == 0) {
+			list->dn[0] = tree->u.equality.value;
+			list->count = 1;
+			return LDB_SUCCESS;
+		}
 	}
+			
 	return ltdb_index_dn_simple(module, ltdb, tree, list);
 }
 
-- 
2.9.4


From 43d8a98d01786cc142bba20a130cc4eb15ac3dd9 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 15 Aug 2017 15:33:24 +1200
Subject: [PATCH 34/39] ldb_tdb: add control points for the new GUID index mode

The @IDXGUID attribute in the @INDEXLIST will be objectGUID
in Samba.

The @IDX_DN_GUID attribute in the @INDEXLIST will be GUID
in Samba.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_tdb.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index bd43320..7ac4651 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -62,6 +62,8 @@ struct ltdb_context {
 #define LTDB_IDXATTR    "@IDXATTR"
 #define LTDB_IDXONE     "@IDXONE"
 #define LTDB_IDXDN     "@IDXDN"
+#define LTDB_IDXGUID    "@IDXGUID"
+#define LTDB_IDX_DN_GUID "@IDX_DN_GUID"
 #define LTDB_BASEINFO   "@BASEINFO"
 #define LTDB_OPTIONS    "@OPTIONS"
 #define LTDB_ATTRIBUTES "@ATTRIBUTES"
-- 
2.9.4


From 8d7ebe4b79fbac63ddf9962ad39d04707a094c94 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 15 Aug 2017 15:57:57 +1200
Subject: [PATCH 35/39] ldb_tdb: Read from @INDEXLIST or an override if we are
 using a GUID index

This allows all the previous patches to be enabled.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/common/ldb_attributes.c | 14 ++++++++++++++
 lib/ldb/include/ldb_module.h    | 16 ++++++++++++++++
 lib/ldb/include/ldb_private.h   |  3 +++
 lib/ldb/ldb_tdb/ldb_cache.c     | 10 ++++++++++
 4 files changed, 43 insertions(+)

diff --git a/lib/ldb/common/ldb_attributes.c b/lib/ldb/common/ldb_attributes.c
index 98ec5a4..3eeb9c6 100644
--- a/lib/ldb/common/ldb_attributes.c
+++ b/lib/ldb/common/ldb_attributes.c
@@ -395,3 +395,17 @@ void ldb_schema_set_override_indexlist(struct ldb_context *ldb,
 	ldb->schema.index_handler_override = true;
 	ldb->schema.one_level_indexes = one_level_indexes;
 }
+
+/*
+ * set that the GUID index mode is in operation
+ *
+ * The caller must ensure the supplied strings do not go out of
+ * scope (they are typically constant memory). 
+ */
+void ldb_schema_set_override_GUID_index(struct ldb_context *ldb,
+					const char *GUID_index_attribute,
+					const char *GUID_index_dn_component)
+{
+	ldb->schema.GUID_index_attribute = GUID_index_attribute;
+	ldb->schema.GUID_index_dn_component = GUID_index_dn_component;
+}
diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h
index 71b4074..0ac689c 100644
--- a/lib/ldb/include/ldb_module.h
+++ b/lib/ldb/include/ldb_module.h
@@ -183,6 +183,22 @@ void ldb_schema_attribute_set_override_handler(struct ldb_context *ldb,
 void ldb_schema_set_override_indexlist(struct ldb_context *ldb,
 				       bool one_level_indexes);
 
+/**
+
+  \param ldb The ldb context
+  \param GUID_index_attribute The globally attribute (eg objectGUID) 
+         on each entry
+  \param GUID_index_attribute The DN component matching the
+         globally attribute on each entry (eg GUID)
+
+ The caller must ensure the supplied strings do not go out of
+ scope (they are typically constant memory). 
+
+*/
+void ldb_schema_set_override_GUID_index(struct ldb_context *ldb,
+					const char *GUID_index_attribute,
+					const char *GUID_index_dn_component);
+	
 /* A useful function to build comparison functions with */
 int ldb_any_comparison(struct ldb_context *ldb, void *mem_ctx, 
 		       ldb_attr_handler_t canonicalise_fn, 
diff --git a/lib/ldb/include/ldb_private.h b/lib/ldb/include/ldb_private.h
index ae7ec3c..ca24b39 100644
--- a/lib/ldb/include/ldb_private.h
+++ b/lib/ldb/include/ldb_private.h
@@ -98,6 +98,9 @@ struct ldb_schema {
 	 */
 	bool index_handler_override;
 	bool one_level_indexes;
+	
+	const char *GUID_index_attribute;
+	const char *GUID_index_dn_component;
 };
 
 /*
diff --git a/lib/ldb/ldb_tdb/ldb_cache.c b/lib/ldb/ldb_tdb/ldb_cache.c
index f08e073..163e1d8 100644
--- a/lib/ldb/ldb_tdb/ldb_cache.c
+++ b/lib/ldb/ldb_tdb/ldb_cache.c
@@ -243,6 +243,10 @@ static int ltdb_index_load(struct ldb_module *module,
 		 */
 		ltdb->cache->attribute_indexes = true;
 		ltdb->cache->one_level_indexes = ldb->schema.one_level_indexes;
+		ltdb->cache->GUID_index_attribute
+			= ldb->schema.GUID_index_attribute;
+		ltdb->cache->GUID_index_dn_component
+			= ldb->schema.GUID_index_dn_component;
 		return 0;
 	}
 
@@ -276,6 +280,12 @@ static int ltdb_index_load(struct ldb_module *module,
 	if (ldb_msg_find_element(ltdb->cache->indexlist, LTDB_IDXATTR) != NULL) {
 		ltdb->cache->attribute_indexes = true;
 	}
+	ltdb->cache->GUID_index_attribute
+		= ldb_msg_find_attr_as_string(ltdb->cache->indexlist,
+					      LTDB_IDXGUID, NULL);
+	ltdb->cache->GUID_index_dn_component
+		= ldb_msg_find_attr_as_string(ltdb->cache->indexlist,
+					      LTDB_IDX_DN_GUID, NULL);
 
 	return 0;
 }
-- 
2.9.4


From e9b0771979f946e332664c2e8713de6e0c7dba0a Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 15 Aug 2017 15:54:00 +1200
Subject: [PATCH 36/39] TODO: Release ldb 1.2.1 with GUID index support

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/wscript | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/ldb/wscript b/lib/ldb/wscript
index 6f3b326..bd17b7b 100644
--- a/lib/ldb/wscript
+++ b/lib/ldb/wscript
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'ldb'
-VERSION = '1.2.1'
+VERSION = '1.2.2'
 
 blddir = 'bin'
 
-- 
2.9.4


From f5b644409620eb578b845b9caaf71be3072ebb9a Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 15 Aug 2017 15:58:57 +1200
Subject: [PATCH 37/39] dsdb: Set that Samba uses the GUID index in LDB

This is not made optional, as that would require us to test and maintain multiple code paths
and not optimise queries to be GUID centric.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/dsdb/schema/schema_set.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c
index cfd320b..364042d 100644
--- a/source4/dsdb/schema/schema_set.c
+++ b/source4/dsdb/schema/schema_set.c
@@ -72,7 +72,8 @@ int dsdb_schema_set_indices_and_attributes(struct ldb_context *ldb,
 	/* setup our own attribute name to schema handler */
 	ldb_schema_attribute_set_override_handler(ldb, dsdb_attribute_handler_override, schema);
 	ldb_schema_set_override_indexlist(ldb, true);
-
+	ldb_schema_set_override_GUID_index(ldb, "objectGUID", "GUID");
+	
 	if (!write_indices_and_attributes) {
 		return ret;
 	}
@@ -108,6 +109,16 @@ int dsdb_schema_set_indices_and_attributes(struct ldb_context *ldb,
 		goto op_error;
 	}
 
+	ret = ldb_msg_add_string(msg_idx, "@IDXGUID", "objectGUID");
+	if (ret != LDB_SUCCESS) {
+		goto op_error;
+	}
+
+	ret = ldb_msg_add_string(msg_idx, "@IDX_DN_GUID", "GUID");
+	if (ret != LDB_SUCCESS) {
+		goto op_error;
+	}
+
 
 	ret = ldb_msg_add_string(msg_idx, "@IDXVERSION", SAMDB_INDEXING_VERSION);
 	if (ret != LDB_SUCCESS) {
-- 
2.9.4


From dc3696b96c5f3bf582933e696bde8b9f8192b4f4 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 15 Aug 2017 17:19:32 +1200
Subject: [PATCH 38/39] ldb_tdb: Ensure that special DNs do not use a GUID
 index in ltdb_search_base()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_search.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c
index 26f0381..e7931a5 100644
--- a/lib/ldb/ldb_tdb/ldb_search.c
+++ b/lib/ldb/ldb_tdb/ldb_search.c
@@ -119,12 +119,13 @@ int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn)
 	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
 	TDB_DATA tdb_key;
 	int exists;
-
+	bool is_special = ldb_dn_is_special(dn);
+	
 	if (ldb_dn_is_null(dn)) {
 		return LDB_ERR_NO_SUCH_OBJECT;
 	}
 
-	if (ltdb->cache->GUID_index_attribute == NULL) {
+	if (is_special || ltdb->cache->GUID_index_attribute == NULL) {
 		TALLOC_CTX *tdb_key_ctx = talloc_new(module);
 		if (tdb_key_ctx == NULL) {
 			return ldb_oom(ldb_module_get_ctx(module));
-- 
2.9.4


From a058024f437fee307f98d5d203df05a9360a2a59 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 15 Aug 2017 17:20:09 +1200
Subject: [PATCH 39/39] ldb_tdb: Explain we we shortcut to a tdb_exists() in
 ltdb_search_base()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_search.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c
index e7931a5..5b70235 100644
--- a/lib/ldb/ldb_tdb/ldb_search.c
+++ b/lib/ldb/ldb_tdb/ldb_search.c
@@ -135,7 +135,11 @@ int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn)
 		if (!tdb_key.dptr) {
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
-		
+
+		/*
+		 * This is a little less expensive than a full
+		 * ltdb_search_dn1()
+		 */
 		exists = tdb_exists(ltdb->tdb, tdb_key);
 		talloc_free(tdb_key_ctx);
 	} else {
-- 
2.9.4



More information about the samba-technical mailing list