ldb patches (version 1.1.26)

Stefan Metzmacher metze at samba.org
Tue Feb 2 13:25:23 UTC 2016


Am 02.02.2016 um 11:37 schrieb Stefan Metzmacher:
> Hi,
> 
> here're some patches for ldb, which add the following features:
> 
> * let a timeout of -1 indicate no timeout for a given request
> * fix memory leaks in pyldb ldb.search()
> * improve pyldb ldb.search() help message
> * add pyldb ldb.search_iterator() api
> * add client support for LDB_CONTROL_DIRSYNC_EX
> 
> Please review and push:-)

And here comes the patchset, sorry:-)

metze
-------------- next part --------------
From 60bb53b122745e69eda589336d059fb8aa6820a7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 14 Jan 2016 03:14:26 +0100
Subject: [PATCH 01/12] ldb:ABI: add missing pyldb-util.py3-1.1.25.sigs

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/ldb/ABI/pyldb-util.py3-1.1.25.sigs | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 lib/ldb/ABI/pyldb-util.py3-1.1.25.sigs

diff --git a/lib/ldb/ABI/pyldb-util.py3-1.1.25.sigs b/lib/ldb/ABI/pyldb-util.py3-1.1.25.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util.py3-1.1.25.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
-- 
1.9.1


From ed5e4f33ae7bb8146efbd6f25e851a65eea3f543 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 1 Feb 2016 11:00:14 +0100
Subject: [PATCH 02/12] s4:libcli/ldap: send AbandonRequests for cancelled
 requests

This happens on a local timeout of an talloc_free() of the request.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/ldap/ldap_client.c | 50 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c
index 4b8f951..97a83ce 100644
--- a/source4/libcli/ldap/ldap_client.c
+++ b/source4/libcli/ldap/ldap_client.c
@@ -662,15 +662,50 @@ static void ldap_reconnect(struct ldap_connection *conn)
 	}
 }
 
+static void ldap_request_destructor_abandon(struct ldap_request *abandon)
+{
+	TALLOC_FREE(abandon);
+}
+
 /* destroy an open ldap request */
 static int ldap_request_destructor(struct ldap_request *req)
 {
 	if (req->state == LDAP_REQUEST_PENDING) {
+		struct ldap_message msg = {
+			.type = LDAP_TAG_AbandonRequest,
+			.r.AbandonRequest.messageid = req->messageid,
+		};
+		struct ldap_request *abandon = NULL;
+
 		DLIST_REMOVE(req->conn->pending, req);
+
+		abandon = ldap_request_send(req->conn, &msg);
+		if (abandon == NULL) {
+			ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
+			return 0;
+		}
+		abandon->async.fn = ldap_request_destructor_abandon;
+		abandon->async.private_data = NULL;
 	}
+
 	return 0;
 }
 
+static void ldap_request_timeout_abandon(struct ldap_request *abandon)
+{
+	struct ldap_request *req =
+		talloc_get_type_abort(abandon->async.private_data,
+		struct ldap_request);
+
+	if (req->state == LDAP_REQUEST_PENDING) {
+		DLIST_REMOVE(req->conn->pending, req);
+	}
+	req->state = LDAP_REQUEST_DONE;
+	if (req->async.fn) {
+		req->async.fn(req);
+	}
+}
+
 /*
   called on timeout of a ldap request
 */
@@ -683,7 +718,22 @@ static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer
 
 	req->status = NT_STATUS_IO_TIMEOUT;
 	if (req->state == LDAP_REQUEST_PENDING) {
+		struct ldap_message msg = {
+			.type = LDAP_TAG_AbandonRequest,
+			.r.AbandonRequest.messageid = req->messageid,
+		};
+		struct ldap_request *abandon = NULL;
+
+		abandon = ldap_request_send(req->conn, &msg);
+		if (abandon == NULL) {
+			ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
+			return;
+		}
+		talloc_reparent(req->conn, req, abandon);
+		abandon->async.fn = ldap_request_timeout_abandon;
+		abandon->async.private_data = req;
 		DLIST_REMOVE(req->conn->pending, req);
+		return;
 	}
 	req->state = LDAP_REQUEST_DONE;
 	if (req->async.fn) {
-- 
1.9.1


From d4acd1e72e764d6a02686d42a5b9a89eff5219fd Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 22 Jan 2016 08:53:57 +0100
Subject: [PATCH 03/12] ldb-samba: fix the timeout setup in ildb_request_send()

We need to use the startime as reference not the current time.

We also allow timeout == -1 to indicate no timeout at all.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/ldb-samba/ldb_ildap.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/lib/ldb-samba/ldb_ildap.c b/lib/ldb-samba/ldb_ildap.c
index 6ec363d..65f11db 100644
--- a/lib/ldb-samba/ldb_ildap.c
+++ b/lib/ldb-samba/ldb_ildap.c
@@ -418,11 +418,13 @@ static int ildb_request_send(struct ildb_context *ac, struct ldap_message *msg)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	talloc_free(req->time_event);
-	req->time_event = NULL;
-	if (ac->req->timeout) {
-		req->time_event = tevent_add_timer(ac->ildb->event_ctx, ac,
-						   timeval_current_ofs(ac->req->timeout, 0),
+	TALLOC_FREE(req->time_event);
+	if (ac->req->timeout > 0) {
+		struct timeval tv = {
+			.tv_sec = ac->req->starttime + ac->req->timeout,
+		};
+
+		req->time_event = tevent_add_timer(ac->ildb->event_ctx, ac, tv,
 						   ildb_request_timeout, ac);
 	}
 
-- 
1.9.1


From a1fdb2f311e7cc9cf9a4c062d8c1d35704484771 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 22 Jan 2016 08:53:57 +0100
Subject: [PATCH 04/12] ldb: allow a timeout of -1 result in no timeout timer
 at all.

This is required in order to have long running async searches,
e.g. with LDB_CONTROL_NOTIFICATION_OID.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/ldb/ldb_ldap/ldb_ldap.c       | 18 +++++++++++-------
 lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 11 +++++++----
 lib/ldb/ldb_tdb/ldb_tdb.c         | 14 +++++++++-----
 3 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/lib/ldb/ldb_ldap/ldb_ldap.c b/lib/ldb/ldb_ldap/ldb_ldap.c
index 7e6ac90..29f8938 100644
--- a/lib/ldb/ldb_ldap/ldb_ldap.c
+++ b/lib/ldb/ldb_ldap/ldb_ldap.c
@@ -252,8 +252,11 @@ static int lldb_search(struct lldb_context *lldb_ac)
 		break;
 	}
 
-	tv.tv_sec = req->timeout;
+	tv.tv_sec = 0;
 	tv.tv_usec = 0;
+	if (req->timeout > 0) {
+		tv.tv_sec = req->timeout;
+	}
 
 	ret = ldap_search_ext(lldb->ldap, search_base, ldap_scope, 
 			      expression, 
@@ -836,12 +839,13 @@ static int lldb_handle_request(struct ldb_module *module, struct ldb_request *re
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-
-	tv.tv_sec = req->starttime + req->timeout;
-	tv.tv_usec = 0;
-	te = tevent_add_timer(ev, ac, tv, lldb_timeout, ac);
-	if (NULL == te) {
-		return LDB_ERR_OPERATIONS_ERROR;
+	if (req->timeout > 0) {
+		tv.tv_sec = req->starttime + req->timeout;
+		tv.tv_usec = 0;
+		te = tevent_add_timer(ev, ac, tv, lldb_timeout, ac);
+		if (NULL == te) {
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
 	}
 
 	return LDB_SUCCESS;
diff --git a/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
index 223868a..60b39e8 100644
--- a/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
+++ b/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
@@ -1566,10 +1566,13 @@ static int lsql_handle_request(struct ldb_module *module, struct ldb_request *re
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	tv.tv_sec = req->starttime + req->timeout;
-	ac->timeout_event = tevent_add_timer(ev, ac, tv, lsql_timeout, ac);
-	if (NULL == ac->timeout_event) {
-		return LDB_ERR_OPERATIONS_ERROR;
+	if (req->timeout > 0) {
+		tv.tv_sec = req->starttime + req->timeout;
+		tv.tv_usec = 0;
+		ac->timeout_event = tevent_add_timer(ev, ac, tv, lsql_timeout, ac);
+		if (NULL == ac->timeout_event) {
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
 	}
 
 	return LDB_SUCCESS;
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index bcb8f0f..8d1fd36 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -1469,11 +1469,15 @@ static int ltdb_handle_request(struct ldb_module *module,
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	tv.tv_sec = req->starttime + req->timeout;
-	ac->timeout_event = tevent_add_timer(ev, ac, tv, ltdb_timeout, ac);
-	if (NULL == ac->timeout_event) {
-		talloc_free(ac);
-		return LDB_ERR_OPERATIONS_ERROR;
+	if (req->timeout > 0) {
+		tv.tv_sec = req->starttime + req->timeout;
+		tv.tv_usec = 0;
+		ac->timeout_event = tevent_add_timer(ev, ac, tv,
+						     ltdb_timeout, ac);
+		if (NULL == ac->timeout_event) {
+			talloc_free(ac);
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
 	}
 
 	/* set a spy so that we do not try to use the request context
-- 
1.9.1


From 92de6ddc8a3676df141435f6335771e4790bf930 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Tue, 5 Jan 2016 17:59:32 +1300
Subject: [PATCH 05/12] pyldb: Free correct context when pyldb_Object_AsDn()
 fails

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

diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index 3daed96..8c3162a 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -1808,7 +1808,7 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar
 		base = ldb_get_default_basedn(ldb_ctx);
 	} else {
 		if (!pyldb_Object_AsDn(ldb_ctx, py_base, ldb_ctx, &base)) {
-			talloc_free(attrs);
+			talloc_free(mem_ctx);
 			return NULL;
 		}
 	}
-- 
1.9.1


From 12e60fded31541db1c3cff0899fb81059b278dbf Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 22 Jan 2016 00:05:09 +0100
Subject: [PATCH 06/12] pyldb: fix memory leak in py_ldb_search()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/ldb/pyldb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index 8c3162a..dcd6cc5 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -1807,7 +1807,7 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar
 	if (py_base == Py_None) {
 		base = ldb_get_default_basedn(ldb_ctx);
 	} else {
-		if (!pyldb_Object_AsDn(ldb_ctx, py_base, ldb_ctx, &base)) {
+		if (!pyldb_Object_AsDn(mem_ctx, py_base, ldb_ctx, &base)) {
 			talloc_free(mem_ctx);
 			return NULL;
 		}
-- 
1.9.1


From 473c6d4a105b81fa06997c5c4021dffe3f1c615a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 22 Jan 2016 00:06:04 +0100
Subject: [PATCH 07/12] pyldb: fix help message for ldb.search()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/ldb/pyldb.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index dcd6cc5..9d9d1e3 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -2003,7 +2003,7 @@ static PyMethodDef py_ldb_methods[] = {
 		"S.rename(old_dn, new_dn, controls=None) -> None\n"
 		"Rename an entry." },
 	{ "search", (PyCFunction)py_ldb_search, METH_VARARGS|METH_KEYWORDS,
-		"S.search(base=None, scope=None, expression=None, attrs=None, controls=None) -> msgs\n"
+		"S.search(base=None, scope=None, expression=None, attrs=None, controls=None) -> result\n"
 		"Search in a database.\n"
 		"\n"
 		":param base: Optional base DN to search\n"
@@ -2011,7 +2011,7 @@ static PyMethodDef py_ldb_methods[] = {
 		":param expression: Optional search expression\n"
 		":param attrs: Attributes to return (defaults to all)\n"
 		":param controls: Optional list of controls\n"
-		":return: Iterator over Message objects\n"
+		":return: ldb.Result object\n"
 	},
 	{ "schema_attribute_remove", (PyCFunction)py_ldb_schema_attribute_remove, METH_VARARGS,
 		NULL },
-- 
1.9.1


From 6be40ea41be8cb182c2569902fefe2d74613c530 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 22 Jan 2016 00:06:45 +0100
Subject: [PATCH 08/12] pyldb: add ldb.search_iterator()

This is able to handle async requests, e.g. with a notification control
and processes results as they arrive instead of waiting for all results
before returning.

search_handle = ldb.search_iterator(...)

for e in search_handle:
    if not isinstance(msg, ldb.Message):
        # referral
        continue

    name = e["name"][0]

result = search_handle.result()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/ldb/pyldb.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 372 insertions(+)

diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index 9d9d1e3..c8b842c 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -32,6 +32,27 @@
 #include "ldb_private.h"
 #include "ldb_handlers.h"
 #include "pyldb.h"
+#include "dlinklist.h"
+
+struct py_ldb_search_iterator_reply;
+
+typedef struct {
+	PyObject_HEAD
+	TALLOC_CTX *mem_ctx;
+	PyLdbObject *ldb;
+	struct {
+		struct ldb_request *req;
+		struct py_ldb_search_iterator_reply *next;
+		struct py_ldb_search_iterator_reply *result;
+		PyObject *exception;
+	} state;
+} PyLdbSearchIteratorObject;
+
+struct py_ldb_search_iterator_reply {
+	struct py_ldb_search_iterator_reply *prev, *next;
+	PyLdbSearchIteratorObject *py_iter;
+	PyObject *obj;
+};
 
 void initldb(void);
 static PyObject *PyLdbMessage_FromMessage(struct ldb_message *msg);
@@ -39,6 +60,7 @@ static PyObject *PyExc_LdbError;
 
 static PyTypeObject PyLdbControl;
 static PyTypeObject PyLdbResult;
+static PyTypeObject PyLdbSearchIterator;
 static PyTypeObject PyLdbMessage;
 #define PyLdbMessage_Check(ob) PyObject_TypeCheck(ob, &PyLdbMessage)
 static PyTypeObject PyLdbModule;
@@ -1869,6 +1891,200 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar
 	return py_ret;
 }
 
+static int py_ldb_search_iterator_reply_destructor(struct py_ldb_search_iterator_reply *reply)
+{
+	if (reply->py_iter != NULL) {
+		DLIST_REMOVE(reply->py_iter->state.next, reply);
+		if (reply->py_iter->state.result == reply) {
+			reply->py_iter->state.result = NULL;
+		}
+		reply->py_iter = NULL;
+	}
+
+	if (reply->obj != NULL) {
+		Py_DECREF(reply->obj);
+		reply->obj = NULL;
+	}
+
+	return 0;
+}
+
+static int py_ldb_search_iterator_callback(struct ldb_request *req,
+					   struct ldb_reply *ares)
+{
+	PyLdbSearchIteratorObject *py_iter = (PyLdbSearchIteratorObject *)req->context;
+	struct ldb_result result = { .msgs = NULL };
+	struct py_ldb_search_iterator_reply *reply = NULL;
+
+	if (ares == NULL) {
+		return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+	}
+
+	if (ares->error != LDB_SUCCESS) {
+		int ret = ares->error;
+		TALLOC_FREE(ares);
+		return ldb_request_done(req, ret);
+	}
+
+	reply = talloc_zero(py_iter->mem_ctx,
+			    struct py_ldb_search_iterator_reply);
+	if (reply == NULL) {
+		TALLOC_FREE(ares);
+		return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+	}
+	reply->py_iter = py_iter;
+	talloc_set_destructor(reply, py_ldb_search_iterator_reply_destructor);
+
+	switch (ares->type) {
+	case LDB_REPLY_ENTRY:
+		reply->obj = PyLdbMessage_FromMessage(ares->message);
+		if (reply->obj == NULL) {
+			TALLOC_FREE(ares);
+			return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+		}
+		DLIST_ADD_END(py_iter->state.next, reply, NULL);
+		TALLOC_FREE(ares);
+		return LDB_SUCCESS;
+
+	case LDB_REPLY_REFERRAL:
+		reply->obj = PyStr_FromString(ares->referral);
+		if (reply->obj == NULL) {
+			TALLOC_FREE(ares);
+			return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+		}
+		DLIST_ADD_END(py_iter->state.next, reply, NULL);
+		TALLOC_FREE(ares);
+		return LDB_SUCCESS;
+
+	case LDB_REPLY_DONE:
+		result = (struct ldb_result) { .controls = ares->controls };
+		reply->obj = PyLdbResult_FromResult(&result);
+		if (reply->obj == NULL) {
+			TALLOC_FREE(ares);
+			return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+		}
+		py_iter->state.result = reply;
+		TALLOC_FREE(ares);
+		return ldb_request_done(req, LDB_SUCCESS);
+	}
+
+	TALLOC_FREE(ares);
+	return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+}
+
+static PyObject *py_ldb_search_iterator(PyLdbObject *self, PyObject *args, PyObject *kwargs)
+{
+	PyObject *py_base = Py_None;
+	int scope = LDB_SCOPE_DEFAULT;
+	int timeout = 0;
+	char *expr = NULL;
+	PyObject *py_attrs = Py_None;
+	PyObject *py_controls = Py_None;
+	const char * const kwnames[] = { "base", "scope", "expression", "attrs", "controls", "timeout", NULL };
+	int ret;
+	const char **attrs;
+	struct ldb_context *ldb_ctx;
+	struct ldb_control **parsed_controls;
+	struct ldb_dn *base;
+	PyLdbSearchIteratorObject *py_iter;
+
+	/* type "int" rather than "enum" for "scope" is intentional */
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OizOOi",
+					 discard_const_p(char *, kwnames),
+					 &py_base, &scope, &expr, &py_attrs, &py_controls, &timeout))
+		return NULL;
+
+	py_iter = (PyLdbSearchIteratorObject *)PyLdbSearchIterator.tp_alloc(&PyLdbSearchIterator, 0);
+	if (py_iter == NULL) {
+		PyErr_NoMemory();
+		return NULL;
+	}
+	py_iter->ldb = self;
+	Py_INCREF(self);
+	ZERO_STRUCT(py_iter->state);
+	py_iter->mem_ctx = talloc_new(NULL);
+	if (py_iter->mem_ctx == NULL) {
+		Py_DECREF(py_iter);
+		PyErr_NoMemory();
+		return NULL;
+	}
+
+	ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+
+	if (py_attrs == Py_None) {
+		attrs = NULL;
+	} else {
+		attrs = PyList_AsStrList(py_iter->mem_ctx, py_attrs, "attrs");
+		if (attrs == NULL) {
+			Py_DECREF(py_iter);
+			PyErr_NoMemory();
+			return NULL;
+		}
+	}
+
+	if (py_base == Py_None) {
+		base = ldb_get_default_basedn(ldb_ctx);
+	} else {
+		if (!pyldb_Object_AsDn(py_iter->mem_ctx, py_base, ldb_ctx, &base)) {
+			Py_DECREF(py_iter);
+			PyErr_NoMemory();
+			return NULL;
+		}
+	}
+
+	if (py_controls == Py_None) {
+		parsed_controls = NULL;
+	} else {
+		const char **controls = NULL;
+
+		controls = PyList_AsStrList(py_iter->mem_ctx,
+					    py_controls, "controls");
+		if (controls == NULL) {
+			Py_DECREF(py_iter);
+			PyErr_NoMemory();
+			return NULL;
+		}
+
+		parsed_controls = ldb_parse_control_strings(ldb_ctx,
+							    py_iter->mem_ctx,
+							    controls);
+		if (controls[0] != NULL && parsed_controls == NULL) {
+			Py_DECREF(py_iter);
+			PyErr_NoMemory();
+			return NULL;
+		}
+		talloc_free(controls);
+	}
+
+	ret = ldb_build_search_req(&py_iter->state.req,
+				   ldb_ctx,
+				   py_iter->mem_ctx,
+				   base,
+				   scope,
+				   expr,
+				   attrs,
+				   parsed_controls,
+				   py_iter,
+				   py_ldb_search_iterator_callback,
+				   NULL);
+	if (ret != LDB_SUCCESS) {
+		Py_DECREF(py_iter);
+		PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+		return NULL;
+	}
+
+	ldb_set_timeout(ldb_ctx, py_iter->state.req, timeout);
+
+	ret = ldb_request(ldb_ctx, py_iter->state.req);
+	if (ret != LDB_SUCCESS) {
+		Py_DECREF(py_iter);
+		PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+		return NULL;
+	}
+
+	return (PyObject *)py_iter;
+}
+
 static PyObject *py_ldb_get_opaque(PyLdbObject *self, PyObject *args)
 {
 	char *name;
@@ -2013,6 +2229,18 @@ static PyMethodDef py_ldb_methods[] = {
 		":param controls: Optional list of controls\n"
 		":return: ldb.Result object\n"
 	},
+	{ "search_iterator", (PyCFunction)py_ldb_search_iterator, METH_VARARGS|METH_KEYWORDS,
+		"S.search_iterator(base=None, scope=None, expression=None, attrs=None, controls=None, timeout=None) -> iterator\n"
+		"Search in a database.\n"
+		"\n"
+		":param base: Optional base DN to search\n"
+		":param scope: Search scope (SCOPE_BASE, SCOPE_ONELEVEL or SCOPE_SUBTREE)\n"
+		":param expression: Optional search expression\n"
+		":param attrs: Attributes to return (defaults to all)\n"
+		":param controls: Optional list of controls\n"
+		":param timeout: Optional timeout in seconds (defaults to 300), 0 means the default, -1 no timeout\n"
+		":return: ldb.SearchIterator object that provides results when they arrive\n"
+	},
 	{ "schema_attribute_remove", (PyCFunction)py_ldb_schema_attribute_remove, METH_VARARGS,
 		NULL },
 	{ "schema_attribute_add", (PyCFunction)py_ldb_schema_attribute_add, METH_VARARGS,
@@ -2235,6 +2463,147 @@ static PyTypeObject PyLdbResult = {
 	.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
 };
 
+static void py_ldb_search_iterator_dealloc(PyLdbSearchIteratorObject *self)
+{
+	Py_XDECREF(self->state.exception);
+	TALLOC_FREE(self->mem_ctx);
+	ZERO_STRUCT(self->state);
+	Py_DECREF(self->ldb);
+	Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *py_ldb_search_iterator_next(PyLdbSearchIteratorObject *self)
+{
+	PyObject *py_ret = NULL;
+
+	if (self->state.req == NULL) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"ldb.SearchIterator request already finished");
+		return NULL;
+	}
+
+	/*
+	 * TODO: do we want a non-blocking mode?
+	 * In future we may add an optional 'nonblocking'
+	 * argument to search_iterator().
+	 *
+	 * For now we keep it simple and wait for at
+	 * least one reply.
+	 */
+
+	while (self->state.next == NULL) {
+		int ret;
+
+		if (self->state.result != NULL) {
+			/*
+			 * We (already) got a final result from the server.
+			 *
+			 * We stop the iteration and let
+			 * py_ldb_search_iterator_result() will deliver
+			 * the result details.
+			 */
+			TALLOC_FREE(self->state.req);
+			PyErr_SetNone(PyExc_StopIteration);
+			return NULL;
+		}
+
+		ret = ldb_wait(self->state.req->handle, LDB_WAIT_NONE);
+		if (ret != LDB_SUCCESS) {
+			struct ldb_context *ldb_ctx;
+			TALLOC_FREE(self->state.req);
+			ldb_ctx = pyldb_Ldb_AsLdbContext(self->ldb);
+			/*
+			 * We stop the iteration and let
+			 * py_ldb_search_iterator_result() will deliver
+			 * the exception.
+			 */
+			self->state.exception = Py_BuildValue(discard_const_p(char, "(i,s)"),
+						ret, ldb_errstring(ldb_ctx));
+			PyErr_SetNone(PyExc_StopIteration);
+			return NULL;
+		}
+	}
+
+	py_ret = self->state.next->obj;
+	self->state.next->obj = NULL;
+	/* no TALLOC_FREE() as self->state.next is a list */
+	talloc_free(self->state.next);
+	return py_ret;
+}
+
+static PyObject *py_ldb_search_iterator_result(PyLdbSearchIteratorObject *self)
+{
+	PyObject *py_ret = NULL;
+
+	if (self->state.req != NULL) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"ldb.SearchIterator request running");
+		return NULL;
+	}
+
+	if (self->state.next != NULL) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"ldb.SearchIterator not fully consumed.");
+		return NULL;
+	}
+
+	if (self->state.exception != NULL) {
+		PyErr_SetObject(PyExc_LdbError, self->state.exception);
+		self->state.exception = NULL;
+		return NULL;
+	}
+
+	if (self->state.result == NULL) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"ldb.SearchIterator result already consumed");
+		return NULL;
+	}
+
+	py_ret = self->state.result->obj;
+	self->state.result->obj = NULL;
+	TALLOC_FREE(self->state.result);
+	return py_ret;
+}
+
+static PyObject *py_ldb_search_iterator_abandon(PyLdbSearchIteratorObject *self)
+{
+	if (self->state.req == NULL) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"ldb.SearchIterator request already finished");
+		return NULL;
+	}
+
+	Py_XDECREF(self->state.exception);
+	TALLOC_FREE(self->mem_ctx);
+	ZERO_STRUCT(self->state);
+	Py_RETURN_NONE;
+}
+
+static PyMethodDef py_ldb_search_iterator_methods[] = {
+	{ "result", (PyCFunction)py_ldb_search_iterator_result, METH_NOARGS,
+		"S.result() -> ldb.Result (without msgs and referrals)\n" },
+	{ "abandon", (PyCFunction)py_ldb_search_iterator_abandon, METH_NOARGS,
+		"S.abandon()\n" },
+	{ NULL }
+};
+
+static PyObject *py_ldb_search_iterator_repr(PyLdbSearchIteratorObject *self)
+{
+	return PyStr_FromString("<ldb search iterator>");
+}
+
+static PyTypeObject PyLdbSearchIterator = {
+	.tp_name = "ldb.SearchIterator",
+	.tp_repr = (reprfunc)py_ldb_search_iterator_repr,
+	.tp_dealloc = (destructor)py_ldb_search_iterator_dealloc,
+	.tp_iter = PyObject_SelfIter,
+	.tp_iternext = (iternextfunc)py_ldb_search_iterator_next,
+	.tp_methods = py_ldb_search_iterator_methods,
+	.tp_basicsize = sizeof(PyLdbSearchIteratorObject),
+	.tp_doc = "LDB search_iterator.",
+	.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+};
+
 static PyObject *py_ldb_module_repr(PyLdbModuleObject *self)
 {
 	return PyStr_FromFormat("<ldb module '%s'>",
@@ -3745,6 +4114,9 @@ static PyObject* module_init(void)
 	if (PyType_Ready(&PyLdbResult) < 0)
 		return NULL;
 
+	if (PyType_Ready(&PyLdbSearchIterator) < 0)
+		return NULL;
+
 	if (PyType_Ready(&PyLdbControl) < 0)
 		return NULL;
 
-- 
1.9.1


From 5b288b5ff69c59b202c44d2485fb2d5d14b46200 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 1 Feb 2016 02:30:56 +0100
Subject: [PATCH 09/12] pyldb: add api tests for search_iterator()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/ldb/tests/python/api.py | 100 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/lib/ldb/tests/python/api.py b/lib/ldb/tests/python/api.py
index af1ff03..98381fe 100755
--- a/lib/ldb/tests/python/api.py
+++ b/lib/ldb/tests/python/api.py
@@ -167,6 +167,106 @@ class SimpleLdb(TestCase):
         finally:
             l.delete(ldb.Dn(l, "dc=foo4"))
 
+    def test_search_iterator(self):
+        l = ldb.Ldb(filename())
+        s = l.search_iterator()
+        s.abandon()
+        try:
+            for me in s:
+                self.fail()
+            self.fail()
+        except RuntimeError as re:
+            pass
+        try:
+            s.abandon()
+            self.fail()
+        except RuntimeError as re:
+            pass
+        try:
+            s.result()
+            self.fail()
+        except RuntimeError as re:
+            pass
+
+        s = l.search_iterator()
+        count = 0
+        for me in s:
+            self.assertTrue(isinstance(me, ldb.Message))
+            count += 1
+        r = s.result()
+        self.assertEqual(len(r), 0)
+        self.assertEqual(count, 0)
+
+        m1 = ldb.Message()
+        m1.dn = ldb.Dn(l, "dc=foo4")
+        m1["bla"] = b"bla"
+        l.add(m1)
+        try:
+            s = l.search_iterator()
+            msgs = []
+            for me in s:
+                self.assertTrue(isinstance(me, ldb.Message))
+                count += 1
+                msgs.append(me)
+            r = s.result()
+            self.assertEqual(len(r), 0)
+            self.assertEqual(len(msgs), 1)
+            self.assertEqual(msgs[0].dn, m1.dn)
+
+            m2 = ldb.Message()
+            m2.dn = ldb.Dn(l, "dc=foo5")
+            m2["bla"] = b"bla"
+            l.add(m2)
+
+            s = l.search_iterator()
+            msgs = []
+            for me in s:
+                self.assertTrue(isinstance(me, ldb.Message))
+                count += 1
+                msgs.append(me)
+            r = s.result()
+            self.assertEqual(len(r), 0)
+            self.assertEqual(len(msgs), 2)
+            if msgs[0].dn == m1.dn:
+                self.assertEqual(msgs[0].dn, m1.dn)
+                self.assertEqual(msgs[1].dn, m2.dn)
+            else:
+                self.assertEqual(msgs[0].dn, m2.dn)
+                self.assertEqual(msgs[1].dn, m1.dn)
+
+            s = l.search_iterator()
+            msgs = []
+            for me in s:
+                self.assertTrue(isinstance(me, ldb.Message))
+                count += 1
+                msgs.append(me)
+                break
+            try:
+                s.result()
+                self.fail()
+            except RuntimeError as re:
+                pass
+            for me in s:
+                self.assertTrue(isinstance(me, ldb.Message))
+                count += 1
+                msgs.append(me)
+                break
+            for me in s:
+                self.fail()
+
+            r = s.result()
+            self.assertEqual(len(r), 0)
+            self.assertEqual(len(msgs), 2)
+            if msgs[0].dn == m1.dn:
+                self.assertEqual(msgs[0].dn, m1.dn)
+                self.assertEqual(msgs[1].dn, m2.dn)
+            else:
+                self.assertEqual(msgs[0].dn, m2.dn)
+                self.assertEqual(msgs[1].dn, m1.dn)
+        finally:
+            l.delete(ldb.Dn(l, "dc=foo4"))
+            l.delete(ldb.Dn(l, "dc=foo5"))
+
     def test_add_text(self):
         l = ldb.Ldb(filename())
         m = ldb.Message()
-- 
1.9.1


From a30ff9ff674017ff01dcb0a0e6e51c33ea4b719a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 26 Jan 2016 09:36:56 +0100
Subject: [PATCH 10/12] ldb: add support for LDB_CONTROL_DIRSYNC_EX

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/ldb/common/ldb_controls.c | 65 +++++++++++++++++++++++++++++++++++++++++++
 lib/ldb/include/ldb.h         |  2 ++
 lib/ldb/tools/cmdline.c       | 33 ++++++++++++++++++++++
 3 files changed, 100 insertions(+)

diff --git a/lib/ldb/common/ldb_controls.c b/lib/ldb/common/ldb_controls.c
index 7346326..af056d0 100644
--- a/lib/ldb/common/ldb_controls.c
+++ b/lib/ldb/common/ldb_controls.c
@@ -367,6 +367,26 @@ char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *contr
 		talloc_free(cookie);
 		return res;
 	}
+	if (strcmp(control->oid, LDB_CONTROL_DIRSYNC_EX_OID) == 0) {
+		char *cookie;
+		struct ldb_dirsync_control *rep_control = talloc_get_type(control->data,
+								struct ldb_dirsync_control);
+
+		cookie = ldb_base64_encode(mem_ctx, rep_control->cookie,
+				rep_control->cookie_len);
+		if (cookie == NULL) {
+			return NULL;
+		}
+		res = talloc_asprintf(mem_ctx, "%s:%d:%d:%d:%s",
+					LDB_CONTROL_DIRSYNC_EX_NAME,
+					control->critical,
+					rep_control->flags,
+					rep_control->max_attributes,
+					cookie);
+
+		talloc_free(cookie);
+		return res;
+	}
 
 	if (strcmp(control->oid, LDB_CONTROL_VERIFY_NAME_OID) == 0) {
 		struct ldb_verify_name_control *rep_control = talloc_get_type(control->data, struct ldb_verify_name_control);
@@ -525,6 +545,51 @@ struct ldb_control *ldb_parse_control_from_string(struct ldb_context *ldb, TALLO
 
 		return ctrl;
 	}
+	if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_DIRSYNC_EX_NAME) == 0) {
+		struct ldb_dirsync_control *control;
+		const char *p;
+		char cookie[1024];
+		int crit, max_attrs, ret;
+		uint32_t flags;
+
+		cookie[0] = '\0';
+		p = &(control_strings[sizeof(LDB_CONTROL_DIRSYNC_EX_NAME)]);
+		ret = sscanf(p, "%d:%u:%d:%1023[^$]", &crit, &flags, &max_attrs, cookie);
+
+		if ((ret < 3) || (crit < 0) || (crit > 1) || (max_attrs < 0)) {
+			error_string = talloc_asprintf(mem_ctx, "invalid %s control syntax\n",
+						       LDB_CONTROL_DIRSYNC_EX_NAME);
+			error_string = talloc_asprintf_append(error_string, " syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n");
+			error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number, o = b64 binary blob");
+			ldb_set_errstring(ldb, error_string);
+			talloc_free(error_string);
+			talloc_free(ctrl);
+			return NULL;
+		}
+
+		/* w2k3 seems to ignore the parameter,
+		 * but w2k sends a wrong cookie when this value is to small
+		 * this would cause looping forever, while getting
+		 * the same data and same cookie forever
+		 */
+		if (max_attrs == 0) max_attrs = 0x0FFFFFFF;
+
+		ctrl->oid = LDB_CONTROL_DIRSYNC_EX_OID;
+		ctrl->critical = crit;
+		control = talloc(ctrl, struct ldb_dirsync_control);
+		control->flags = flags;
+		control->max_attributes = max_attrs;
+		if (*cookie) {
+			control->cookie_len = ldb_base64_decode(cookie);
+			control->cookie = (char *)talloc_memdup(control, cookie, control->cookie_len);
+		} else {
+			control->cookie = NULL;
+			control->cookie_len = 0;
+		}
+		ctrl->data = control;
+
+		return ctrl;
+	}
 
 	if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_ASQ_NAME) == 0) {
 		struct ldb_asq_control *control;
diff --git a/lib/ldb/include/ldb.h b/lib/ldb/include/ldb.h
index f48f753..cedb56d 100644
--- a/lib/ldb/include/ldb.h
+++ b/lib/ldb/include/ldb.h
@@ -652,6 +652,8 @@ typedef int (*ldb_qsort_cmp_fn_t) (void *v1, void *v2, void *opaque);
 */
 #define LDB_CONTROL_DIRSYNC_OID		"1.2.840.113556.1.4.841"
 #define LDB_CONTROL_DIRSYNC_NAME	"dirsync"
+#define LDB_CONTROL_DIRSYNC_EX_OID	"1.2.840.113556.1.4.2090"
+#define LDB_CONTROL_DIRSYNC_EX_NAME	"dirsync_ex"
 
 
 /**
diff --git a/lib/ldb/tools/cmdline.c b/lib/ldb/tools/cmdline.c
index a06445f..6d0a406 100644
--- a/lib/ldb/tools/cmdline.c
+++ b/lib/ldb/tools/cmdline.c
@@ -459,6 +459,39 @@ int handle_controls_reply(struct ldb_control **reply, struct ldb_control **reque
 
 			continue;
 		}
+		if (strcmp(LDB_CONTROL_DIRSYNC_EX_OID, reply[i]->oid) == 0) {
+			struct ldb_dirsync_control *rep_control, *req_control;
+			char *cookie;
+
+			rep_control = talloc_get_type(reply[i]->data, struct ldb_dirsync_control);
+			if (rep_control->cookie_len == 0) /* we are done */
+				break;
+
+			/* more processing required */
+			/* let's fill in the request control with the new cookie */
+
+			for (j = 0; request[j]; j++) {
+				if (strcmp(LDB_CONTROL_DIRSYNC_EX_OID, request[j]->oid) == 0)
+					break;
+			}
+			/* if there's a reply control we must find a request
+			 * control matching it */
+			if (! request[j]) return -1;
+
+			req_control = talloc_get_type(request[j]->data, struct ldb_dirsync_control);
+
+			if (req_control->cookie)
+				talloc_free(req_control->cookie);
+			req_control->cookie = (char *)talloc_memdup(
+				req_control, rep_control->cookie,
+				rep_control->cookie_len);
+			req_control->cookie_len = rep_control->cookie_len;
+
+			cookie = ldb_base64_encode(req_control, rep_control->cookie, rep_control->cookie_len);
+			printf("# DIRSYNC_EX cookie returned was:\n# %s\n", cookie);
+
+			continue;
+		}
 
 		/* no controls matched, throw a warning */
 		fprintf(stderr, "Unknown reply control oid: %s\n", reply[i]->oid);
-- 
1.9.1


From 40485b5f5bda2c0da938e5fe620dcf41e056c966 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 2 Feb 2016 10:04:20 +0100
Subject: [PATCH 11/12] ldb: version 1.1.26

* let a timeout of -1 indicate no timeout for a given request
* fix memory leaks in pyldb ldb.search()
* build fixes
* improve pyldb ldb.search() help message
* add pyldb ldb.search_iterator() api
* add client support for LDB_CONTROL_DIRSYNC_EX

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/ldb/ABI/ldb-1.1.26.sigs            | 265 +++++++++++++++++++++++++++++++++
 lib/ldb/ABI/pyldb-util-1.1.26.sigs     |   2 +
 lib/ldb/ABI/pyldb-util.py3-1.1.26.sigs |   2 +
 lib/ldb/wscript                        |   2 +-
 4 files changed, 270 insertions(+), 1 deletion(-)
 create mode 100644 lib/ldb/ABI/ldb-1.1.26.sigs
 create mode 100644 lib/ldb/ABI/pyldb-util-1.1.26.sigs
 create mode 100644 lib/ldb/ABI/pyldb-util.py3-1.1.26.sigs

diff --git a/lib/ldb/ABI/ldb-1.1.26.sigs b/lib/ldb/ABI/ldb-1.1.26.sigs
new file mode 100644
index 0000000..3f33df9
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.1.26.sigs
@@ -0,0 +1,265 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.26.sigs b/lib/ldb/ABI/pyldb-util-1.1.26.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.1.26.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util.py3-1.1.26.sigs b/lib/ldb/ABI/pyldb-util.py3-1.1.26.sigs
new file mode 100644
index 0000000..74d6719
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util.py3-1.1.26.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/wscript b/lib/ldb/wscript
index b7dd4aa..2398ff7 100755
--- a/lib/ldb/wscript
+++ b/lib/ldb/wscript
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'ldb'
-VERSION = '1.1.25'
+VERSION = '1.1.26'
 
 blddir = 'bin'
 
-- 
1.9.1


From ab970af25e34c371f7221f5985b556eae92b4a37 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 26 Jan 2016 09:37:13 +0100
Subject: [PATCH 12/12] s4:libcli/ldap: add support for
 LDB_CONTROL_DIRSYNC_EX_OID

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/ldap/ldap_controls.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source4/libcli/ldap/ldap_controls.c b/source4/libcli/ldap/ldap_controls.c
index 448a263..14a80af 100644
--- a/source4/libcli/ldap/ldap_controls.c
+++ b/source4/libcli/ldap/ldap_controls.c
@@ -1256,6 +1256,7 @@ static const struct ldap_control_handler ldap_known_controls[] = {
 	{ LDB_CONTROL_SORT_RESP_OID, decode_server_sort_response, encode_server_sort_response },
 	{ LDB_CONTROL_ASQ_OID, decode_asq_control, encode_asq_control },
 	{ LDB_CONTROL_DIRSYNC_OID, decode_dirsync_request, encode_dirsync_request },
+	{ LDB_CONTROL_DIRSYNC_EX_OID, decode_dirsync_request, encode_dirsync_request },
 	{ LDB_CONTROL_VLV_REQ_OID, decode_vlv_request, encode_vlv_request },
 	{ LDB_CONTROL_VLV_RESP_OID, decode_vlv_response, encode_vlv_response },
 	{ LDB_CONTROL_PERMISSIVE_MODIFY_OID, decode_flag_request, encode_flag_request },
-- 
1.9.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20160202/b06bc7eb/signature.sig>


More information about the samba-technical mailing list