[PATCHES v2] Re: [PATCHES] fix bugs in the python bindings

Douglas Bagnall douglas.bagnall at catalyst.net.nz
Thu May 3 05:36:46 UTC 2018


There was a mistake lurking in there. New version attached.

On 03/05/18 16:40, William Brown wrote:
> On Thu, 2018-05-03 at 16:12 +1200, Douglas Bagnall via samba-technical
> wrote:
>> Procrastinating again, I found a number of segfaults and a seemingly
>> endless series of memory leaks and unchecked allocations in the
>> Python
>> bindings. I managed to stop myself after the attached patches.
>>
>> Douglas
> 
> Most of this looks sane to me. It's a pretty big patch though. I'd want
> to run it with ASAN to be sure, but that may highlight more outstanding
> cases.

Yep. There are also about a million outstanding cases I don't think it
will catch, namely the lack of Py_DECREF()s and failures to consider
NULL values from Python allocations. Given the way we use Python in
short-lived little processes, those are annoying but not really interesting.

Douglas
-------------- next part --------------
From 63d30532803955bec9df5845573cc44614287a73 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Fri, 20 Apr 2018 16:28:29 +1200
Subject: [PATCH 01/22] Tests for segfaults in python bindings

These tests run in a child process and are regarded as succeeding if they
don't die by signal.

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 python/samba/tests/segfault.py        | 128 ++++++++++++++++++++++++++++++++++
 selftest/knownfail.d/python-segfaults |   8 +++
 source4/selftest/tests.py             |   3 +
 3 files changed, 139 insertions(+)
 create mode 100644 python/samba/tests/segfault.py
 create mode 100644 selftest/knownfail.d/python-segfaults

diff --git a/python/samba/tests/segfault.py b/python/samba/tests/segfault.py
new file mode 100644
index 00000000000..dbcd78bfc64
--- /dev/null
+++ b/python/samba/tests/segfault.py
@@ -0,0 +1,128 @@
+# Unix SMB/CIFS implementation.
+#
+# Copyright (C) Catalyst.Net Ltd. 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""Test whether various python calls segfault when given unexpected input.
+"""
+
+import samba.tests
+import os
+import sys
+from samba.net import Net, LIBNET_JOIN_AUTOMATIC
+from samba.credentials import DONT_USE_KERBEROS
+from samba import NTSTATUSError, ntstatus
+from samba.dcerpc import misc, drsuapi
+from samba import auth, gensec
+from samba.samdb import SamDB
+from samba import netbios
+from samba import registry
+from samba import ldb
+
+import traceback
+
+def segfault_detector(f):
+    def wrapper(*args, **kwargs):
+        pid = os.fork()
+        if pid == 0:
+            try:
+                f(*args, **kwargs)
+            except Exception as e:
+                traceback.print_exc()
+            sys.stderr.flush()
+            sys.stdout.flush()
+            os._exit(0)
+
+        pid2, status = os.waitpid(pid, 0)
+        signal = status & 255
+        if os.WIFSIGNALED(status):
+            signal = os.WTERMSIG(status)
+            raise AssertionError("Failed with signal %d" % signal)
+
+    return wrapper
+
+
+class SegfaultTests(samba.tests.TestCase):
+    def get_lp_et_al(self):
+        server = os.environ["SERVER"]
+        lp = self.get_loadparm()
+        #lp.set("private dir", self.tempdir)
+        #lp.set("lock dir", self.tempdir)
+        #lp.set("state directory", self.tempdir)
+
+        creds = self.insta_creds(template=self.get_credentials(),
+                                 kerberos_state=DONT_USE_KERBEROS)
+        return lp, creds, server
+
+    def get_samdb(self):
+        lp, creds, server = self.get_lp_et_al()
+        url = 'ldap://' + server
+        ldb = SamDB(url, credentials=creds, lp=lp)
+        return ldb
+
+    @segfault_detector
+    def test_net_replicate_init__1(self):
+        lp, creds, server = self.get_lp_et_al()
+        net = Net(creds, lp, server=server)
+        net.replicate_init(42, lp, None, misc.GUID())
+
+    @segfault_detector
+    def test_net_replicate_init__3(self):
+        # third argument is also unchecked
+        lp, creds, server = self.get_lp_et_al()
+        net = Net(creds, lp, server=server)
+        net.replicate_init(None, lp, 42, misc.GUID())
+
+    @segfault_detector
+    def test_net_replicate_chunk_1(self):
+        lp, creds, server = self.get_lp_et_al()
+        ctr = drsuapi.DsGetNCChangesCtr6()
+        net = Net(creds, lp, server=server)
+        net.replicate_chunk(42, 1, ctr)
+
+    @segfault_detector
+    def test_auth_context_gensec_start_server(self):
+        a = auth.AuthContext(ldb=42, methods=['sam'])
+        # there is no failure yet because the ldb is not actually
+        # dereferenced.
+        g = gensec.Security.start_server(auth_context=a)
+        # and still the ldb is not dereferenced...
+
+    @segfault_detector
+    def test_auth_user_session(self):
+        s = auth.user_session(ldb=42, principal='foo')
+
+    @segfault_detector
+    def test_gensec_start_server(self):
+        gensec.Security.start_server(auth_context=42)
+
+    @segfault_detector
+    def test_netbios_query_name(self):
+        n = netbios.Node()
+        t = n.query_name((42, 'foo'), 'localhost')
+
+    @segfault_detector
+    def test_encrypt_netr_crypt_password(self):
+        lp, creds, server = self.get_lp_et_al()
+        creds.encrypt_netr_crypt_password(42)
+
+    @segfault_detector
+    def test_hive_open_ldb(self):
+        # we don't need to provide a valid path because we segfault first
+        try:
+            registry.open_ldb('', credentials=42)
+        except ldb.LdbError as e:
+            print("failed with %s" % e)
diff --git a/selftest/knownfail.d/python-segfaults b/selftest/knownfail.d/python-segfaults
new file mode 100644
index 00000000000..b1938cd1702
--- /dev/null
+++ b/selftest/knownfail.d/python-segfaults
@@ -0,0 +1,8 @@
+samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_auth_user_session
+samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_encrypt_netr_crypt_password
+samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_gensec_start_server
+samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_hive_open_ldb
+samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_chunk_1
+samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_init__1
+samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_init__3
+samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_netbios_query_name
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index d1e5bc6a509..521bb152559 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -680,6 +680,9 @@ planoldpythontestsuite("ad_dc",
 planoldpythontestsuite("ad_dc",
                        "samba.tests.net_join",
                        extra_args=['-U"$USERNAME%$PASSWORD"'])
+planoldpythontestsuite("ad_dc",
+                       "samba.tests.segfault",
+                       extra_args=['-U"$USERNAME%$PASSWORD"'])
 # Need to test the password hashing in multiple environments to ensure that
 # all the possible options are covered
 #
-- 
2.14.1


From 273213ac4e470bfff2850e79df31fde85967d960 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Fri, 20 Apr 2018 16:23:42 +1200
Subject: [PATCH 02/22] pyldb: rename pyldb_Ldb_AsLdbContext macro to reflect
 unsafeness

In the Python/C API, conversion functions which check the types of their arguments
have names like:

double PyFloat_AsDouble(PyObject *pyfloat);

while conversion macros that don't check have names like:

PyFloat_AS_DOUBLE(pyfloat)

The pyldb_Ldb_AsLdbContext() macro looks like one of the checking functions
but it actually isn't. This has fooled us more than once.

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 lib/ldb-samba/pyldb.c | 12 ++++-----
 lib/ldb/pyldb.c       | 75 +++++++++++++++++++++++++--------------------------
 lib/ldb/pyldb.h       |  2 +-
 source4/dsdb/pydsdb.c |  2 +-
 4 files changed, 45 insertions(+), 46 deletions(-)

diff --git a/lib/ldb-samba/pyldb.c b/lib/ldb-samba/pyldb.c
index dfcb5510e6d..64fd91d1cb2 100644
--- a/lib/ldb-samba/pyldb.c
+++ b/lib/ldb-samba/pyldb.c
@@ -54,7 +54,7 @@ static PyObject *py_ldb_set_loadparm(PyObject *self, PyObject *args)
 	if (!PyArg_ParseTuple(args, "O", &py_lp_ctx))
 		return NULL;
 
-	ldb = pyldb_Ldb_AsLdbContext(self);
+	ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
 
 	lp_ctx = lpcfg_from_py_object(ldb, py_lp_ctx);
 	if (lp_ctx == NULL) {
@@ -82,7 +82,7 @@ static PyObject *py_ldb_set_credentials(PyObject *self, PyObject *args)
 		return NULL;
 	}
 
-	ldb = pyldb_Ldb_AsLdbContext(self);
+	ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
 
 	ldb_set_opaque(ldb, "credentials", creds);
 
@@ -102,7 +102,7 @@ static PyObject *py_ldb_set_opaque_integer(PyObject *self, PyObject *args)
 	if (!PyArg_ParseTuple(args, "si", &py_opaque_name, &value))
 		return NULL;
 
-	ldb = pyldb_Ldb_AsLdbContext(self);
+	ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
 
 	/* see if we have a cached copy */
 	old_val = (int *)ldb_get_opaque(ldb, py_opaque_name);
@@ -158,7 +158,7 @@ static PyObject *py_ldb_set_utf8_casefold(PyObject *self)
 {
 	struct ldb_context *ldb;
 
-	ldb = pyldb_Ldb_AsLdbContext(self);
+	ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
 
 	ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
 
@@ -190,7 +190,7 @@ static PyObject *py_ldb_set_session_info(PyObject *self, PyObject *args)
 	if (!ret)
 		return NULL;
 
-	ldb = pyldb_Ldb_AsLdbContext(self);
+	ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
 
 	info = PyAuthSession_AsSession(py_session_info);
 
@@ -206,7 +206,7 @@ static PyObject *py_ldb_register_samba_handlers(PyObject *self)
 
 	/* XXX: Perhaps call this from PySambaLdb's init function ? */
 
-	ldb = pyldb_Ldb_AsLdbContext(self);
+	ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
 	ret = ldb_register_samba_handlers(ldb);
 
 	PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_error, ret, ldb);
diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index 110ec8e60ad..084363abe6c 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -214,7 +214,7 @@ static PyObject *py_ldb_control_new(PyTypeObject *type, PyObject *args, PyObject
 		return NULL;
 	}
 
-	ldb_ctx = pyldb_Ldb_AsLdbContext(py_ldb);
+	ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(py_ldb);
 	parsed_controls = ldb_parse_control_from_string(ldb_ctx, mem_ctx, data);
 
 	if (!parsed_controls) {
@@ -874,8 +874,7 @@ static PyObject *py_ldb_dn_new(PyTypeObject *type, PyObject *args, PyObject *kwa
 		PyErr_SetString(PyExc_TypeError, "Expected Ldb");
 		return NULL;
 	}
-
-	ldb_ctx = pyldb_Ldb_AsLdbContext(py_ldb);
+	ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(py_ldb);
 
 	mem_ctx = talloc_new(NULL);
 	if (mem_ctx == NULL) {
@@ -946,7 +945,7 @@ static PyObject *py_ldb_set_debug(PyObject *self, PyObject *args)
 	Py_INCREF(cb);
 	/* FIXME: DECREF cb when exiting program */
 	py_ldb_debug_func = cb;
-	ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 	PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError,
 		ldb_set_debug(ldb_ctx, py_ldb_debug, cb),
 		ldb_ctx);
@@ -960,7 +959,7 @@ static PyObject *py_ldb_set_create_perms(PyTypeObject *self, PyObject *args)
 	if (!PyArg_ParseTuple(args, "I", &perms))
 		return NULL;
 
-	ldb_set_create_perms(pyldb_Ldb_AsLdbContext(self), perms);
+	ldb_set_create_perms(pyldb_Ldb_AS_LDBCONTEXT(self), perms);
 
 	Py_RETURN_NONE;
 }
@@ -971,14 +970,14 @@ static PyObject *py_ldb_set_modules_dir(PyTypeObject *self, PyObject *args)
 	if (!PyArg_ParseTuple(args, "s", &modules_dir))
 		return NULL;
 
-	ldb_set_modules_dir(pyldb_Ldb_AsLdbContext(self), modules_dir);
+	ldb_set_modules_dir(pyldb_Ldb_AS_LDBCONTEXT(self), modules_dir);
 
 	Py_RETURN_NONE;
 }
 
 static PyObject *py_ldb_transaction_start(PyLdbObject *self)
 {
-	struct ldb_context *ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 	int ldb_err;
 	ldb_err = ldb_transaction_start(ldb_ctx);
 	PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
@@ -987,7 +986,7 @@ static PyObject *py_ldb_transaction_start(PyLdbObject *self)
 
 static PyObject *py_ldb_transaction_commit(PyLdbObject *self)
 {
-	struct ldb_context *ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 	int ldb_err;
 	ldb_err = ldb_transaction_commit(ldb_ctx);
 	PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
@@ -996,7 +995,7 @@ static PyObject *py_ldb_transaction_commit(PyLdbObject *self)
 
 static PyObject *py_ldb_transaction_prepare_commit(PyLdbObject *self)
 {
-	struct ldb_context *ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 	int ldb_err;
 	ldb_err = ldb_transaction_prepare_commit(ldb_ctx);
 	PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
@@ -1005,7 +1004,7 @@ static PyObject *py_ldb_transaction_prepare_commit(PyLdbObject *self)
 
 static PyObject *py_ldb_transaction_cancel(PyLdbObject *self)
 {
-	struct ldb_context *ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 	int ldb_err;
 	ldb_err = ldb_transaction_cancel(ldb_ctx);
 	PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
@@ -1014,7 +1013,7 @@ static PyObject *py_ldb_transaction_cancel(PyLdbObject *self)
 
 static PyObject *py_ldb_setup_wellknown_attributes(PyLdbObject *self)
 {
-	struct ldb_context *ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 	int ldb_err;
 	ldb_err = ldb_setup_wellknown_attributes(ldb_ctx);
 	PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
@@ -1028,7 +1027,7 @@ static PyObject *py_ldb_repr(PyLdbObject *self)
 
 static PyObject *py_ldb_get_root_basedn(PyLdbObject *self)
 {
-	struct ldb_dn *dn = ldb_get_root_basedn(pyldb_Ldb_AsLdbContext(self));
+	struct ldb_dn *dn = ldb_get_root_basedn(pyldb_Ldb_AS_LDBCONTEXT(self));
 	if (dn == NULL)
 		Py_RETURN_NONE;
 	return py_ldb_dn_copy(dn);
@@ -1037,7 +1036,7 @@ static PyObject *py_ldb_get_root_basedn(PyLdbObject *self)
 
 static PyObject *py_ldb_get_schema_basedn(PyLdbObject *self)
 {
-	struct ldb_dn *dn = ldb_get_schema_basedn(pyldb_Ldb_AsLdbContext(self));
+	struct ldb_dn *dn = ldb_get_schema_basedn(pyldb_Ldb_AS_LDBCONTEXT(self));
 	if (dn == NULL)
 		Py_RETURN_NONE;
 	return py_ldb_dn_copy(dn);
@@ -1045,7 +1044,7 @@ static PyObject *py_ldb_get_schema_basedn(PyLdbObject *self)
 
 static PyObject *py_ldb_get_config_basedn(PyLdbObject *self)
 {
-	struct ldb_dn *dn = ldb_get_config_basedn(pyldb_Ldb_AsLdbContext(self));
+	struct ldb_dn *dn = ldb_get_config_basedn(pyldb_Ldb_AS_LDBCONTEXT(self));
 	if (dn == NULL)
 		Py_RETURN_NONE;
 	return py_ldb_dn_copy(dn);
@@ -1053,7 +1052,7 @@ static PyObject *py_ldb_get_config_basedn(PyLdbObject *self)
 
 static PyObject *py_ldb_get_default_basedn(PyLdbObject *self)
 {
-	struct ldb_dn *dn = ldb_get_default_basedn(pyldb_Ldb_AsLdbContext(self));
+	struct ldb_dn *dn = ldb_get_default_basedn(pyldb_Ldb_AS_LDBCONTEXT(self));
 	if (dn == NULL)
 		Py_RETURN_NONE;
 	return py_ldb_dn_copy(dn);
@@ -1109,7 +1108,7 @@ static int py_ldb_init(PyLdbObject *self, PyObject *args, PyObject *kwargs)
 					 &url, &flags, &py_options))
 		return -1;
 
-	ldb = pyldb_Ldb_AsLdbContext(self);
+	ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
 
 	if (py_options == Py_None) {
 		options = NULL;
@@ -1175,7 +1174,7 @@ static PyObject *py_ldb_connect(PyLdbObject *self, PyObject *args, PyObject *kwa
 			return NULL;
 	}
 
-	ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 	ret = ldb_connect(ldb_ctx, url, flags, options);
 	talloc_free(options);
 
@@ -1207,7 +1206,7 @@ static PyObject *py_ldb_modify(PyLdbObject *self, PyObject *args, PyObject *kwar
 		PyErr_NoMemory();
 		return NULL;
 	}
-	ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 
 	if (py_controls == Py_None) {
 		parsed_controls = NULL;
@@ -1356,7 +1355,7 @@ static PyObject *py_ldb_add(PyLdbObject *self, PyObject *args, PyObject *kwargs)
 		PyErr_NoMemory();
 		return NULL;
 	}
-	ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 
 	if (py_controls == Py_None) {
 		parsed_controls = NULL;
@@ -1449,7 +1448,7 @@ static PyObject *py_ldb_delete(PyLdbObject *self, PyObject *args, PyObject *kwar
 		PyErr_NoMemory();
 		return NULL;
 	}
-	ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 
 	if (py_controls == Py_None) {
 		parsed_controls = NULL;
@@ -1515,7 +1514,7 @@ static PyObject *py_ldb_rename(PyLdbObject *self, PyObject *args, PyObject *kwar
 	struct ldb_request *req;
 	const char * const kwnames[] = { "dn1", "dn2", "controls", NULL };
 
-	ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|O",
 					 discard_const_p(char *, kwnames),
@@ -1593,7 +1592,7 @@ static PyObject *py_ldb_schema_attribute_remove(PyLdbObject *self, PyObject *arg
 	if (!PyArg_ParseTuple(args, "s", &name))
 		return NULL;
 
-	ldb_schema_attribute_remove(pyldb_Ldb_AsLdbContext(self), name);
+	ldb_schema_attribute_remove(pyldb_Ldb_AS_LDBCONTEXT(self), name);
 
 	Py_RETURN_NONE;
 }
@@ -1608,7 +1607,7 @@ static PyObject *py_ldb_schema_attribute_add(PyLdbObject *self, PyObject *args)
 	if (!PyArg_ParseTuple(args, "sIs", &attribute, &flags, &syntax))
 		return NULL;
 
-	ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 	ret = ldb_schema_attribute_add(ldb_ctx, attribute, flags, syntax);
 
 	PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
@@ -1651,7 +1650,7 @@ static PyObject *py_ldb_write_ldif(PyLdbObject *self, PyObject *args)
 
 	mem_ctx = talloc_new(NULL);
 
-	string = ldb_ldif_write_string(pyldb_Ldb_AsLdbContext(self), mem_ctx, &ldif);
+	string = ldb_ldif_write_string(pyldb_Ldb_AS_LDBCONTEXT(self), mem_ctx, &ldif);
 	if (!string) {
 		PyErr_SetString(PyExc_KeyError, "Failed to generate LDIF");
 		return NULL;
@@ -1742,7 +1741,7 @@ static PyObject *py_ldb_msg_diff(PyLdbObject *self, PyObject *args)
 		return NULL;
 	}
 
-	ldb = pyldb_Ldb_AsLdbContext(self);
+	ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
 	ldb_ret = ldb_msg_difference(ldb, ldb,
 	                             pyldb_Message_AsMessage(py_msg_old),
 	                             pyldb_Message_AsMessage(py_msg_new),
@@ -1782,7 +1781,7 @@ static PyObject *py_ldb_schema_format_value(PyLdbObject *self, PyObject *args)
 		return NULL;
 	}
 
-	a = ldb_schema_attribute_by_name(pyldb_Ldb_AsLdbContext(self), element_name);
+	a = ldb_schema_attribute_by_name(pyldb_Ldb_AS_LDBCONTEXT(self), element_name);
 
 	if (a == NULL) {
 		Py_RETURN_NONE;
@@ -1794,7 +1793,7 @@ static PyObject *py_ldb_schema_format_value(PyLdbObject *self, PyObject *args)
 		return NULL;
 	}
 
-	if (a->syntax->ldif_write_fn(pyldb_Ldb_AsLdbContext(self), mem_ctx, &old_val, &new_val) != 0) {
+	if (a->syntax->ldif_write_fn(pyldb_Ldb_AS_LDBCONTEXT(self), mem_ctx, &old_val, &new_val) != 0) {
 		talloc_free(mem_ctx);
 		Py_RETURN_NONE;
 	}
@@ -1836,7 +1835,7 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar
 		PyErr_NoMemory();
 		return NULL;
 	}
-	ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 
 	if (py_attrs == Py_None) {
 		attrs = NULL;
@@ -2031,7 +2030,7 @@ static PyObject *py_ldb_search_iterator(PyLdbObject *self, PyObject *args, PyObj
 		return NULL;
 	}
 
-	ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 
 	if (py_attrs == Py_None) {
 		attrs = NULL;
@@ -2115,7 +2114,7 @@ static PyObject *py_ldb_get_opaque(PyLdbObject *self, PyObject *args)
 	if (!PyArg_ParseTuple(args, "s", &name))
 		return NULL;
 
-	data = ldb_get_opaque(pyldb_Ldb_AsLdbContext(self), name);
+	data = ldb_get_opaque(pyldb_Ldb_AS_LDBCONTEXT(self), name);
 
 	if (data == NULL)
 		Py_RETURN_NONE;
@@ -2135,14 +2134,14 @@ static PyObject *py_ldb_set_opaque(PyLdbObject *self, PyObject *args)
 
 	/* FIXME: More interpretation */
 
-	ldb_set_opaque(pyldb_Ldb_AsLdbContext(self), name, data);
+	ldb_set_opaque(pyldb_Ldb_AS_LDBCONTEXT(self), name, data);
 
 	Py_RETURN_NONE;
 }
 
 static PyObject *py_ldb_modules(PyLdbObject *self)
 {
-	struct ldb_context *ldb = pyldb_Ldb_AsLdbContext(self);
+	struct ldb_context *ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
 	PyObject *ret = PyList_New(0);
 	struct ldb_module *mod;
 
@@ -2155,7 +2154,7 @@ static PyObject *py_ldb_modules(PyLdbObject *self)
 
 static PyObject *py_ldb_sequence_number(PyLdbObject *self, PyObject *args)
 {
-	struct ldb_context *ldb = pyldb_Ldb_AsLdbContext(self);
+	struct ldb_context *ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
 	int type, ret;
 	uint64_t value;
 
@@ -2181,7 +2180,7 @@ static const struct ldb_dn_extended_syntax test_dn_syntax = {
 
 static PyObject *py_ldb_register_test_extensions(PyLdbObject *self)
 {
-	struct ldb_context *ldb = pyldb_Ldb_AsLdbContext(self);
+	struct ldb_context *ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
 	int ret;
 
 	ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &test_dn_syntax);
@@ -2315,7 +2314,7 @@ static PyObject *PyLdbModule_FromModule(struct ldb_module *mod)
 
 static PyObject *py_ldb_get_firstmodule(PyLdbObject *self, void *closure)
 {
-	struct ldb_module *mod = pyldb_Ldb_AsLdbContext(self)->modules;
+	struct ldb_module *mod = pyldb_Ldb_AS_LDBCONTEXT(self)->modules;
 	if (mod == NULL) {
 		Py_RETURN_NONE;
 	}
@@ -2329,7 +2328,7 @@ static PyGetSetDef py_ldb_getset[] = {
 
 static int py_ldb_contains(PyLdbObject *self, PyObject *obj)
 {
-	struct ldb_context *ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+	struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
 	struct ldb_dn *dn;
 	struct ldb_result *result;
 	unsigned int count;
@@ -2533,7 +2532,7 @@ static PyObject *py_ldb_search_iterator_next(PyLdbSearchIteratorObject *self)
 		if (ret != LDB_SUCCESS) {
 			struct ldb_context *ldb_ctx;
 			TALLOC_FREE(self->state.req);
-			ldb_ctx = pyldb_Ldb_AsLdbContext(self->ldb);
+			ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self->ldb);
 			/*
 			 * We stop the iteration and let
 			 * py_ldb_search_iterator_result() will deliver
@@ -3247,7 +3246,7 @@ static PyObject *py_ldb_msg_from_dict(PyTypeObject *type, PyObject *args)
 		return NULL;
 	}
 
-	ldb_ctx = pyldb_Ldb_AsLdbContext(py_ldb);
+	ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(py_ldb);
 
 	msg = PyDict_AsMessage(ldb_ctx, py_dict, ldb_ctx, mod_flags);
 	if (!msg) {
diff --git a/lib/ldb/pyldb.h b/lib/ldb/pyldb.h
index 4fc89ec4814..27611833ad6 100644
--- a/lib/ldb/pyldb.h
+++ b/lib/ldb/pyldb.h
@@ -34,7 +34,7 @@ typedef struct {
 	struct ldb_context *ldb_ctx;
 } PyLdbObject;
 
-#define pyldb_Ldb_AsLdbContext(pyobj) ((PyLdbObject *)pyobj)->ldb_ctx
+#define pyldb_Ldb_AS_LDBCONTEXT(pyobj) ((PyLdbObject *)pyobj)->ldb_ctx
 
 typedef struct {
 	PyObject_HEAD
diff --git a/source4/dsdb/pydsdb.c b/source4/dsdb/pydsdb.c
index d9177bbd1d7..031b8a82e32 100644
--- a/source4/dsdb/pydsdb.c
+++ b/source4/dsdb/pydsdb.c
@@ -40,7 +40,7 @@
 		PyErr_SetString(PyExc_TypeError, "Ldb connection object required"); \
 		return NULL; \
 	} \
-	ldb = pyldb_Ldb_AsLdbContext(py_ldb);
+	ldb = pyldb_Ldb_AS_LDBCONTEXT(py_ldb);
 
 #define PyErr_LDB_DN_OR_RAISE(py_ldb_dn, dn) \
 	if (!py_check_dcerpc_type(py_ldb_dn, "ldb", "Dn")) { \
-- 
2.14.1


From 03de9326d5cb746dc147a3fb93e4e6754f4f66dd Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu, 3 May 2018 12:10:21 +1200
Subject: [PATCH 03/22] pyldb: add pyldb_check_type(), used by
 pyldb_Ldb_AsLdbContext()

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 lib/ldb/pyldb.h      |  8 ++++++++
 lib/ldb/pyldb_util.c | 10 ++++++++++
 2 files changed, 18 insertions(+)

diff --git a/lib/ldb/pyldb.h b/lib/ldb/pyldb.h
index 27611833ad6..56e0f5e19c0 100644
--- a/lib/ldb/pyldb.h
+++ b/lib/ldb/pyldb.h
@@ -34,8 +34,14 @@ typedef struct {
 	struct ldb_context *ldb_ctx;
 } PyLdbObject;
 
+/* pyldb_Ldb_AS_LDBCONTEXT() does not check argument validity,
+   pyldb_Ldb_AsLdbContext() does */
 #define pyldb_Ldb_AS_LDBCONTEXT(pyobj) ((PyLdbObject *)pyobj)->ldb_ctx
 
+#define pyldb_Ldb_AsLdbContext(pyobj)		\
+	(pyldb_check_type(pyobj, "Ldb") ?	\
+	 pyldb_Ldb_AS_LDBCONTEXT(pyobj) : NULL)
+
 typedef struct {
 	PyObject_HEAD
 	TALLOC_CTX *mem_ctx;
@@ -46,6 +52,8 @@ PyObject *pyldb_Dn_FromDn(struct ldb_dn *);
 bool pyldb_Object_AsDn(TALLOC_CTX *mem_ctx, PyObject *object, struct ldb_context *ldb_ctx, struct ldb_dn **dn);
 #define pyldb_Dn_AsDn(pyobj) ((PyLdbDnObject *)pyobj)->dn
 
+bool pyldb_check_type(PyObject *obj, const char *type_name);
+
 typedef struct {
 	PyObject_HEAD
 	TALLOC_CTX *mem_ctx;
diff --git a/lib/ldb/pyldb_util.c b/lib/ldb/pyldb_util.c
index 46ee4034122..0260aa98cde 100644
--- a/lib/ldb/pyldb_util.c
+++ b/lib/ldb/pyldb_util.c
@@ -54,6 +54,16 @@ static PyTypeObject * PyLdb_GetPyType(const char *typename)
 	py_obj = PyObject_GetAttrString(ldb_module, typename);
 
 	return (PyTypeObject*)py_obj;
+
+bool pyldb_check_type(PyObject *obj, const char *typename)
+{
+	bool ok = false;
+	PyTypeObject *type = PyLdb_GetPyType(typename);
+	if (type != NULL) {
+		ok = PyObject_TypeCheck(obj, type);
+		Py_DECREF(type);
+	}
+	return ok;
 }
 
 /**
-- 
2.14.1


From 452b96c47ede486ee5c33007167206854dd4e6a9 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu, 3 May 2018 15:47:13 +1200
Subject: [PATCH 04/22] ldb: 1.3.3

 * Add a helper function to the Python/C bindings to check types.

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 lib/ldb/ABI/ldb-1.3.3.sigs            | 279 ++++++++++++++++++++++++++++++++++
 lib/ldb/ABI/pyldb-util-1.3.3.sigs     |   3 +
 lib/ldb/ABI/pyldb-util.py3-1.3.3.sigs |   3 +
 lib/ldb/wscript                       |   2 +-
 4 files changed, 286 insertions(+), 1 deletion(-)
 create mode 100644 lib/ldb/ABI/ldb-1.3.3.sigs
 create mode 100644 lib/ldb/ABI/pyldb-util-1.3.3.sigs
 create mode 100644 lib/ldb/ABI/pyldb-util.py3-1.3.3.sigs

diff --git a/lib/ldb/ABI/ldb-1.3.3.sigs b/lib/ldb/ABI/ldb-1.3.3.sigs
new file mode 100644
index 00000000000..a31b84ef4b5
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.3.3.sigs
@@ -0,0 +1,279 @@
+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_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+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_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+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_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+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_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_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_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: 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_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+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_require_private_event_context: void (struct ldb_context *)
+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_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, 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.3.3.sigs b/lib/ldb/ABI/pyldb-util-1.3.3.sigs
new file mode 100644
index 00000000000..164a806b2ff
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.3.3.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/ABI/pyldb-util.py3-1.3.3.sigs b/lib/ldb/ABI/pyldb-util.py3-1.3.3.sigs
new file mode 100644
index 00000000000..164a806b2ff
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util.py3-1.3.3.sigs
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/wscript b/lib/ldb/wscript
index aab4da132d5..08f293a75bd 100644
--- a/lib/ldb/wscript
+++ b/lib/ldb/wscript
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'ldb'
-VERSION = '1.3.2'
+VERSION = '1.3.3'
 
 blddir = 'bin'
 
-- 
2.14.1


From 2ceebc57f52cea3382d4a07dfcff83348021dbfa Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu, 3 May 2018 11:17:55 +1200
Subject: [PATCH 05/22] pyldb: check for errors in PyLdb_GetPyType()

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 lib/ldb/pyldb_util.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/lib/ldb/pyldb_util.c b/lib/ldb/pyldb_util.c
index 0260aa98cde..4e44d0a3744 100644
--- a/lib/ldb/pyldb_util.c
+++ b/lib/ldb/pyldb_util.c
@@ -42,7 +42,8 @@ static PyObject *ldb_module = NULL;
  */
 static PyTypeObject * PyLdb_GetPyType(const char *typename)
 {
-	PyObject *py_obj = NULL;
+	PyTypeObject *type = NULL;
+	bool ok;
 
 	if (ldb_module == NULL) {
 		ldb_module = PyImport_ImportModule("ldb");
@@ -51,9 +52,28 @@ static PyTypeObject * PyLdb_GetPyType(const char *typename)
 		}
 	}
 
-	py_obj = PyObject_GetAttrString(ldb_module, typename);
+	type = (PyTypeObject *)PyObject_GetAttrString(ldb_module, typename);
+
+
+	if (type == NULL) {
+		PyErr_Format(PyExc_NameError,
+			     "Unable to find type %s in ldb module",
+			     typename);
+		return NULL;
+	}
+
+	ok = PyType_Check(type);
+	if (! ok) {
+		PyErr_Format(PyExc_TypeError,
+			     "Expected type ldb.%s, not %s",
+			     typename, Py_TYPE(type)->tp_name);
+		Py_DECREF(type);
+		return NULL;
+	}
+
+	return type;
+}
 
-	return (PyTypeObject*)py_obj;
 
 bool pyldb_check_type(PyObject *obj, const char *typename)
 {
-- 
2.14.1


From f30e46b28ac8ba5f3e2ea2a8cc8a5f23045632d0 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Fri, 27 Apr 2018 13:15:01 +1200
Subject: [PATCH 06/22] pyldb: rename pyldb_Dn_AsDn() to pyldb_Dn_AS_DN()

Following the python/C convention for checking vs non-checking
convertors.

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 lib/ldb/pyldb.c            | 34 +++++++++++++++++-----------------
 lib/ldb/pyldb.h            |  2 +-
 lib/ldb/pyldb_util.c       |  2 +-
 source4/dns_server/pydns.c |  2 +-
 source4/dsdb/pydsdb.c      |  2 +-
 5 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index 084363abe6c..be741da42d4 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -567,13 +567,13 @@ static PyObject *py_ldb_dn_richcmp(PyObject *dn1, PyObject *dn2, int op)
 		Py_INCREF(Py_NotImplemented);
 		return Py_NotImplemented;
 	}
-	ret = ldb_dn_compare(pyldb_Dn_AsDn(dn1), pyldb_Dn_AsDn(dn2));
+	ret = ldb_dn_compare(pyldb_Dn_AS_DN(dn1), pyldb_Dn_AS_DN(dn2));
 	return richcmp(ret, op);
 }
 
 static PyObject *py_ldb_dn_get_parent(PyLdbDnObject *self)
 {
-	struct ldb_dn *dn = pyldb_Dn_AsDn((PyObject *)self);
+	struct ldb_dn *dn = pyldb_Dn_AS_DN((PyObject *)self);
 	struct ldb_dn *parent;
 	PyLdbDnObject *py_ret;
 	TALLOC_CTX *mem_ctx = talloc_new(NULL);
@@ -602,7 +602,7 @@ static PyObject *py_ldb_dn_add_child(PyLdbDnObject *self, PyObject *args)
 	if (!PyArg_ParseTuple(args, "O", &py_other))
 		return NULL;
 
-	dn = pyldb_Dn_AsDn((PyObject *)self);
+	dn = pyldb_Dn_AS_DN((PyObject *)self);
 
 	if (!pyldb_Object_AsDn(NULL, py_other, ldb_dn_get_ldb_context(dn), &other))
 		return NULL;
@@ -617,7 +617,7 @@ static PyObject *py_ldb_dn_add_base(PyLdbDnObject *self, PyObject *args)
 	if (!PyArg_ParseTuple(args, "O", &py_other))
 		return NULL;
 
-	dn = pyldb_Dn_AsDn((PyObject *)self);
+	dn = pyldb_Dn_AS_DN((PyObject *)self);
 
 	if (!pyldb_Object_AsDn(NULL, py_other, ldb_dn_get_ldb_context(dn), &other))
 		return NULL;
@@ -632,7 +632,7 @@ static PyObject *py_ldb_dn_remove_base_components(PyLdbDnObject *self, PyObject
 	if (!PyArg_ParseTuple(args, "i", &i))
 		return NULL;
 
-	dn = pyldb_Dn_AsDn((PyObject *)self);
+	dn = pyldb_Dn_AS_DN((PyObject *)self);
 
 	return PyBool_FromLong(ldb_dn_remove_base_components(dn, i));
 }
@@ -644,7 +644,7 @@ static PyObject *py_ldb_dn_is_child_of(PyLdbDnObject *self, PyObject *args)
 	if (!PyArg_ParseTuple(args, "O", &py_base))
 		return NULL;
 
-	dn = pyldb_Dn_AsDn((PyObject *)self);
+	dn = pyldb_Dn_AS_DN((PyObject *)self);
 
 	if (!pyldb_Object_AsDn(NULL, py_base, ldb_dn_get_ldb_context(dn), &base))
 		return NULL;
@@ -661,7 +661,7 @@ static PyObject *py_ldb_dn_get_component_name(PyLdbDnObject *self, PyObject *arg
 	if (!PyArg_ParseTuple(args, "I", &num))
 		return NULL;
 
-	dn = pyldb_Dn_AsDn((PyObject *)self);
+	dn = pyldb_Dn_AS_DN((PyObject *)self);
 
 	name = ldb_dn_get_component_name(dn, num);
 	if (name == NULL) {
@@ -680,7 +680,7 @@ static PyObject *py_ldb_dn_get_component_value(PyLdbDnObject *self, PyObject *ar
 	if (!PyArg_ParseTuple(args, "I", &num))
 		return NULL;
 
-	dn = pyldb_Dn_AsDn((PyObject *)self);
+	dn = pyldb_Dn_AS_DN((PyObject *)self);
 
 	val = ldb_dn_get_component_val(dn, num);
 	if (val == NULL) {
@@ -718,7 +718,7 @@ static PyObject *py_ldb_dn_get_rdn_name(PyLdbDnObject *self)
 	struct ldb_dn *dn;
 	const char *name;
 
-	dn = pyldb_Dn_AsDn((PyObject *)self);
+	dn = pyldb_Dn_AS_DN((PyObject *)self);
 
 	name = ldb_dn_get_rdn_name(dn);
 	if (name == NULL) {
@@ -733,7 +733,7 @@ static PyObject *py_ldb_dn_get_rdn_value(PyLdbDnObject *self)
 	struct ldb_dn *dn;
 	const struct ldb_val *val;
 
-	dn = pyldb_Dn_AsDn((PyObject *)self);
+	dn = pyldb_Dn_AS_DN((PyObject *)self);
 
 	val = ldb_dn_get_rdn_val(dn);
 	if (val == NULL) {
@@ -810,7 +810,7 @@ static PyMethodDef py_ldb_dn_methods[] = {
 
 static Py_ssize_t py_ldb_dn_len(PyLdbDnObject *self)
 {
-	return ldb_dn_get_comp_num(pyldb_Dn_AsDn((PyObject *)self));
+	return ldb_dn_get_comp_num(pyldb_Dn_AS_DN((PyObject *)self));
 }
 
 /*
@@ -832,7 +832,7 @@ static PyObject *py_ldb_dn_copy(struct ldb_dn *dn)
 
 static PyObject *py_ldb_dn_concat(PyLdbDnObject *self, PyObject *py_other)
 {
-	struct ldb_dn *dn = pyldb_Dn_AsDn((PyObject *)self), 
+	struct ldb_dn *dn = pyldb_Dn_AS_DN((PyObject *)self),
 				  *other;
 	PyLdbDnObject *py_ret;
 
@@ -2679,7 +2679,7 @@ static PyObject *py_ldb_module_search(PyLdbModuleObject *self, PyObject *args, P
 			return NULL;
 	}
 
-	ret = ldb_build_search_req(&req, mod->ldb, NULL, pyldb_Dn_AsDn(py_base), 
+	ret = ldb_build_search_req(&req, mod->ldb, NULL, pyldb_Dn_AS_DN(py_base),
 			     scope, NULL /* expr */, attrs,
 			     NULL /* controls */, NULL, NULL, NULL);
 
@@ -2756,7 +2756,7 @@ static PyObject *py_ldb_module_delete(PyLdbModuleObject *self, PyObject *args)
 
 	req = talloc_zero(NULL, struct ldb_request);
 	req->operation = LDB_DELETE;
-	req->op.del.dn = pyldb_Dn_AsDn(py_dn);
+	req->op.del.dn = pyldb_Dn_AS_DN(py_dn);
 
 	ret = pyldb_Module_AsModule(self)->ops->del(pyldb_Module_AsModule(self), req);
 
@@ -2777,8 +2777,8 @@ static PyObject *py_ldb_module_rename(PyLdbModuleObject *self, PyObject *args)
 	req = talloc_zero(NULL, struct ldb_request);
 
 	req->operation = LDB_RENAME;
-	req->op.rename.olddn = pyldb_Dn_AsDn(py_dn1);
-	req->op.rename.newdn = pyldb_Dn_AsDn(py_dn2);
+	req->op.rename.olddn = pyldb_Dn_AS_DN(py_dn1);
+	req->op.rename.newdn = pyldb_Dn_AS_DN(py_dn2);
 
 	ret = pyldb_Module_AsModule(self)->ops->rename(pyldb_Module_AsModule(self), req);
 
@@ -3570,7 +3570,7 @@ static int py_ldb_msg_set_dn(PyLdbMessageObject *self, PyObject *value, void *cl
 		return -1;
 	}
 
-	msg->dn = talloc_reference(msg, pyldb_Dn_AsDn(value));
+	msg->dn = talloc_reference(msg, pyldb_Dn_AS_DN(value));
 	return 0;
 }
 
diff --git a/lib/ldb/pyldb.h b/lib/ldb/pyldb.h
index 56e0f5e19c0..2d354422cdb 100644
--- a/lib/ldb/pyldb.h
+++ b/lib/ldb/pyldb.h
@@ -50,7 +50,7 @@ typedef struct {
 
 PyObject *pyldb_Dn_FromDn(struct ldb_dn *);
 bool pyldb_Object_AsDn(TALLOC_CTX *mem_ctx, PyObject *object, struct ldb_context *ldb_ctx, struct ldb_dn **dn);
-#define pyldb_Dn_AsDn(pyobj) ((PyLdbDnObject *)pyobj)->dn
+#define pyldb_Dn_AS_DN(pyobj) ((PyLdbDnObject *)pyobj)->dn
 
 bool pyldb_check_type(PyObject *obj, const char *type_name);
 
diff --git a/lib/ldb/pyldb_util.c b/lib/ldb/pyldb_util.c
index 4e44d0a3744..eda26eccbe4 100644
--- a/lib/ldb/pyldb_util.c
+++ b/lib/ldb/pyldb_util.c
@@ -118,7 +118,7 @@ bool pyldb_Object_AsDn(TALLOC_CTX *mem_ctx, PyObject *object,
 	}
 
 	if (PyObject_TypeCheck(object, PyLdb_Dn_Type)) {
-		*dn = pyldb_Dn_AsDn(object);
+		*dn = pyldb_Dn_AS_DN(object);
 		return true;
 	}
 
diff --git a/source4/dns_server/pydns.c b/source4/dns_server/pydns.c
index a4441ddef56..98811edf8a3 100644
--- a/source4/dns_server/pydns.c
+++ b/source4/dns_server/pydns.c
@@ -43,7 +43,7 @@
 		PyErr_SetString(PyExc_TypeError, "ldb Dn object required"); \
 		return NULL; \
 	} \
-	dn = pyldb_Dn_AsDn(py_ldb_dn);
+	dn = pyldb_Dn_AS_DN(py_ldb_dn);
 
 static PyObject *py_dnsp_DnssrvRpcRecord_get_list(struct dnsp_DnssrvRpcRecord *records,
 						  uint16_t num_records)
diff --git a/source4/dsdb/pydsdb.c b/source4/dsdb/pydsdb.c
index 031b8a82e32..4f05952bb25 100644
--- a/source4/dsdb/pydsdb.c
+++ b/source4/dsdb/pydsdb.c
@@ -47,7 +47,7 @@
 		PyErr_SetString(PyExc_TypeError, "ldb Dn object required"); \
 		return NULL; \
 	} \
-	dn = pyldb_Dn_AsDn(py_ldb_dn);
+	dn = pyldb_Dn_AS_DN(py_ldb_dn);
 
 static PyObject *py_ldb_get_exception(void)
 {
-- 
2.14.1


From 65103cd48b83152b2eb39ab1b5361c41fb5954f5 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Tue, 24 Apr 2018 12:34:50 +1200
Subject: [PATCH 07/22] pynbt: catch type errors in PyObject_AsNBTName()

This fixes some known segfaults.

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 libcli/nbt/pynbt.c                    | 20 +++++++++++++++++++-
 selftest/knownfail.d/python-segfaults |  3 ---
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/libcli/nbt/pynbt.c b/libcli/nbt/pynbt.c
index 032561a4bd8..ccd7a039248 100644
--- a/libcli/nbt/pynbt.c
+++ b/libcli/nbt/pynbt.c
@@ -97,13 +97,28 @@ static bool PyObject_AsNBTName(PyObject *obj, struct nbt_name_socket *name_socke
 	if (PyTuple_Check(obj)) {
 		if (PyTuple_Size(obj) == 2) {
 			name->name = PyStr_AsString(PyTuple_GetItem(obj, 0));
+			if (name->name == NULL) {
+				goto err;
+			}
 			name->type = PyInt_AsLong(PyTuple_GetItem(obj, 1));
+			if (name->type == -1 && PyErr_Occurred()) {
+				goto err;
+			}
 			name->scope = NULL;
 			return true;
 		} else if (PyTuple_Size(obj) == 3) {
 			name->name = PyStr_AsString(PyTuple_GetItem(obj, 0));
+			if (name->name == NULL) {
+				goto err;
+			}
 			name->scope = PyStr_AsString(PyTuple_GetItem(obj, 1));
+			if (name->scope == NULL) {
+				goto err;
+			}
 			name->type = PyInt_AsLong(PyTuple_GetItem(obj, 2));
+			if (name->type == -1 && PyErr_Occurred()) {
+				goto err;
+			}
 			return true;
 		} else {
 			PyErr_SetString(PyExc_TypeError, "Invalid tuple size");
@@ -114,11 +129,14 @@ static bool PyObject_AsNBTName(PyObject *obj, struct nbt_name_socket *name_socke
 	if (PyStr_Check(obj) || PyUnicode_Check(obj)) {
 		/* FIXME: Parse string to be able to interpret things like RHONWYN<02> ? */
 		name->name = PyStr_AsString(obj);
+		if (name->name == NULL) {
+			goto err;
+		}
 		name->scope = NULL;
 		name->type = 0;
 		return true;
 	}
-
+err:
 	PyErr_SetString(PyExc_TypeError, "Invalid type for object");
 	return false;
 }
diff --git a/selftest/knownfail.d/python-segfaults b/selftest/knownfail.d/python-segfaults
index b1938cd1702..03c45ec7123 100644
--- a/selftest/knownfail.d/python-segfaults
+++ b/selftest/knownfail.d/python-segfaults
@@ -3,6 +3,3 @@ samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_encrypt_netr_crypt_
 samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_gensec_start_server
 samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_hive_open_ldb
 samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_chunk_1
-samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_init__1
-samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_init__3
-samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_netbios_query_name
-- 
2.14.1


From b1e414fc7dd3c66aeb995f4adabd8846d107ab23 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu, 3 May 2018 10:26:26 +1200
Subject: [PATCH 08/22] pygensec: insist on proper AuthContext in start_server

Fixes another segfault.

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 selftest/knownfail.d/python-segfaults |  1 -
 source4/auth/gensec/pygensec.c        | 13 ++++++++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/selftest/knownfail.d/python-segfaults b/selftest/knownfail.d/python-segfaults
index 03c45ec7123..8db1cf270af 100644
--- a/selftest/knownfail.d/python-segfaults
+++ b/selftest/knownfail.d/python-segfaults
@@ -1,5 +1,4 @@
 samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_auth_user_session
 samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_encrypt_netr_crypt_password
-samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_gensec_start_server
 samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_hive_open_ldb
 samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_chunk_1
diff --git a/source4/auth/gensec/pygensec.c b/source4/auth/gensec/pygensec.c
index d27fe28648a..79685f8d2b7 100644
--- a/source4/auth/gensec/pygensec.c
+++ b/source4/auth/gensec/pygensec.c
@@ -176,7 +176,18 @@ static PyObject *py_gensec_start_server(PyTypeObject *type, PyObject *args, PyOb
 	}
 
 	if (py_auth_context != Py_None) {
-		auth_context = pytalloc_get_type(py_auth_context, struct auth4_context);
+		bool ok = py_check_dcerpc_type(py_auth_context,
+					       "auth",
+					       "AuthContext");
+		if (!ok) {
+			PyErr_Format(PyExc_TypeError,
+				     "Expected auth.AuthContext for "
+				     "auth_context argument.");
+			return NULL;
+		}
+
+		auth_context = pytalloc_get_type(py_auth_context,
+						 struct auth4_context);
 		if (!auth_context) {
 			PyErr_Format(PyExc_TypeError,
 				     "Expected auth.AuthContext for auth_context argument, got %s",
-- 
2.14.1


From f3ffe63602bf07f360e920ec084598c3392033b5 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Tue, 24 Apr 2018 12:37:02 +1200
Subject: [PATCH 09/22] s4/pyauth: check ldb argument in py_user_session()

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 selftest/knownfail.d/python-segfaults | 1 -
 source4/auth/pyauth.c                 | 4 ++++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/selftest/knownfail.d/python-segfaults b/selftest/knownfail.d/python-segfaults
index 8db1cf270af..743ee03d1e2 100644
--- a/selftest/knownfail.d/python-segfaults
+++ b/selftest/knownfail.d/python-segfaults
@@ -1,4 +1,3 @@
-samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_auth_user_session
 samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_encrypt_netr_crypt_password
 samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_hive_open_ldb
 samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_chunk_1
diff --git a/source4/auth/pyauth.c b/source4/auth/pyauth.c
index fc22637564d..c79ed29f697 100644
--- a/source4/auth/pyauth.c
+++ b/source4/auth/pyauth.c
@@ -135,6 +135,10 @@ static PyObject *py_user_session(PyObject *module, PyObject *args, PyObject *kwa
 	}
 
 	ldb_ctx = pyldb_Ldb_AsLdbContext(py_ldb);
+	if (ldb_ctx == NULL) {
+		talloc_free(mem_ctx);
+		return NULL;
+	}
 
 	if (py_dn == Py_None) {
 		user_dn = NULL;
-- 
2.14.1


From 12bd2e40e3aa1432fa7489a6baf201ce6d5cfbbc Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu, 3 May 2018 10:26:34 +1200
Subject: [PATCH 10/22] s4/pyauth: insist on proper ldb in context_new()

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 source4/auth/pyauth.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/source4/auth/pyauth.c b/source4/auth/pyauth.c
index c79ed29f697..016a34b49ab 100644
--- a/source4/auth/pyauth.c
+++ b/source4/auth/pyauth.c
@@ -239,6 +239,10 @@ static PyObject *py_auth_context_new(PyTypeObject *type, PyObject *args, PyObjec
 
 	if (py_ldb != Py_None) {
 		ldb = pyldb_Ldb_AsLdbContext(py_ldb);
+		if (ldb == NULL) {
+			talloc_free(mem_ctx);
+			return NULL;
+		}
 	}
 
 	lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
-- 
2.14.1


From bf22af75f20bbcc1d3c88fbf4fdaee12a993dfe6 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Tue, 24 Apr 2018 12:38:22 +1200
Subject: [PATCH 11/22] s4/pyauth: fix memory leak when context_new() has bad
 arguments

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 source4/auth/pyauth.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/source4/auth/pyauth.c b/source4/auth/pyauth.c
index 016a34b49ab..b7092a0eb95 100644
--- a/source4/auth/pyauth.c
+++ b/source4/auth/pyauth.c
@@ -247,12 +247,14 @@ static PyObject *py_auth_context_new(PyTypeObject *type, PyObject *args, PyObjec
 
 	lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
 	if (lp_ctx == NULL) {
+		talloc_free(mem_ctx);		
 		PyErr_NoMemory();
 		return NULL;
 	}
 
 	ev = s4_event_context_init(mem_ctx);
 	if (ev == NULL) {
+		talloc_free(mem_ctx);		
 		PyErr_NoMemory();
 		return NULL;
 	}
-- 
2.14.1


From c9d751f78d0e4c59a92283ebcb3813f3ddb9cf33 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Tue, 24 Apr 2018 12:39:38 +1200
Subject: [PATCH 12/22] s4/libnet/pynet: check type of state in replicate_chunk

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 selftest/knownfail.d/python-segfaults | 1 -
 source4/libnet/py_net.c               | 5 +++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/selftest/knownfail.d/python-segfaults b/selftest/knownfail.d/python-segfaults
index 743ee03d1e2..2872cee1fb1 100644
--- a/selftest/knownfail.d/python-segfaults
+++ b/selftest/knownfail.d/python-segfaults
@@ -1,3 +1,2 @@
 samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_encrypt_netr_crypt_password
 samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_hive_open_ldb
-samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_chunk_1
diff --git a/source4/libnet/py_net.c b/source4/libnet/py_net.c
index 0567dbd6353..3e982d257fa 100644
--- a/source4/libnet/py_net.c
+++ b/source4/libnet/py_net.c
@@ -496,6 +496,11 @@ static PyObject *py_net_replicate_chunk(py_net_Object *self, PyObject *args, PyO
 					 &py_schema, &req_level, &py_req)) {
 		return NULL;
 	}
+	if (!py_check_dcerpc_type(py_state,
+				  "samba.dcerpc.drsuapi",
+				  "DsGetNCChangesCtr1")) {
+		return NULL;
+	}
 
 	s = pytalloc_get_type(py_state, struct replicate_state);
 	if (!s) {
-- 
2.14.1


From fb485d727051cb3811ef1848ac035adc58d0fe6f Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Tue, 24 Apr 2018 12:40:32 +1200
Subject: [PATCH 13/22] s4/param/provision: check samdb argument in
 provision_bare()

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 source4/param/provision.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/source4/param/provision.c b/source4/param/provision.c
index 4dab31f5c20..69656220d90 100644
--- a/source4/param/provision.c
+++ b/source4/param/provision.c
@@ -81,6 +81,7 @@ NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
 {
 	const char *configfile;
 	PyObject *provision_mod, *provision_dict, *provision_fn, *py_result, *parameters, *py_lp_ctx;
+	struct ldb_context *samdb;
 	
 	DEBUG(0,("Provision for Become-DC test using python\n"));
 
@@ -187,10 +188,14 @@ NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
 	if (py_lp_ctx == NULL) {
 		DEBUG(0, ("Missing 'lp' attribute"));
 		return NT_STATUS_UNSUCCESSFUL;
-	}
+	}	
 	result->lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
-	result->samdb = pyldb_Ldb_AsLdbContext(PyObject_GetAttrString(py_result, "samdb"));
-
+	samdb = pyldb_Ldb_AsLdbContext(PyObject_GetAttrString(py_result, "samdb"));
+	if (samdb == NULL) {
+		DEBUG(0, ("Missing 'samdb' attribute"));
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+	result->samdb = samdb;
 	return NT_STATUS_OK;
 }
 
-- 
2.14.1


From 235aa223f01e139816eb534274c4b06beec24609 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu, 3 May 2018 10:45:39 +1200
Subject: [PATCH 14/22] python/modules: maintain correct refcount for path
 items

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 python/modules.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/python/modules.c b/python/modules.c
index 5db3dd348e2..e99f56cf83a 100644
--- a/python/modules.c
+++ b/python/modules.c
@@ -25,11 +25,14 @@
 
 static bool PySys_PathPrepend(PyObject *list, const char *path)
 {
+	bool ok;
 	PyObject *py_path = PyStr_FromString(path);
-	if (py_path == NULL)
+	if (py_path == NULL) {
 		return false;
-
-	return (PyList_Insert(list, 0, py_path) == 0);
+	}
+	ok = PyList_Insert(list, 0, py_path) == 0;
+	Py_DECREF(py_path);
+	return ok;
 }
 
 bool py_update_path(void)
@@ -44,21 +47,24 @@ bool py_update_path(void)
 	py_path = PyObject_GetAttrString(mod_sys, "path");
 	if (py_path == NULL) {
 		return false;
-	}	
+	}
 
 	if (!PyList_Check(py_path)) {
+		Py_DECREF(py_path);
 		return false;
 	}
 
 	if (!PySys_PathPrepend(py_path, dyn_PYTHONDIR)) {
+		Py_DECREF(py_path);
 		return false;
 	}
 
 	if (strcmp(dyn_PYTHONARCHDIR, dyn_PYTHONDIR) != 0) {
 		if (!PySys_PathPrepend(py_path, dyn_PYTHONARCHDIR)) {
+			Py_DECREF(py_path);
 			return false;
 		}
 	}
-
+	Py_DECREF(py_path);
 	return true;
 }
-- 
2.14.1


From 1c4e230125cb909e791d542471bac6e7a31e1b8e Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu, 3 May 2018 09:39:18 +1200
Subject: [PATCH 15/22] s3/py_passdb: maintain correct refcount on allocation
 failure

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 source3/passdb/py_passdb.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/source3/passdb/py_passdb.c b/source3/passdb/py_passdb.c
index 31e3907c8bc..5ad57d70978 100644
--- a/source3/passdb/py_passdb.c
+++ b/source3/passdb/py_passdb.c
@@ -3761,6 +3761,7 @@ MODULE_INIT_FUNC(passdb)
 
 	dom_sid_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "dom_sid");
 	if (dom_sid_Type == NULL) {
+		Py_DECREF(mod);
 		talloc_free(frame);
 		return NULL;
 	}
@@ -3769,6 +3770,7 @@ MODULE_INIT_FUNC(passdb)
 	security_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "descriptor");
 	Py_DECREF(mod);
 	if (security_Type == NULL) {
+		Py_DECREF(dom_sid_Type);
 		talloc_free(frame);
 		return NULL;
 	}
@@ -3776,6 +3778,8 @@ MODULE_INIT_FUNC(passdb)
 	/* Import GUID type from dcerpc.misc */
 	mod = PyImport_ImportModule("samba.dcerpc.misc");
 	if (mod == NULL) {
+		Py_DECREF(security_Type);
+		Py_DECREF(dom_sid_Type);
 		talloc_free(frame);
 		return NULL;
 	}
@@ -3783,6 +3787,8 @@ MODULE_INIT_FUNC(passdb)
 	guid_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "GUID");
 	Py_DECREF(mod);
 	if (guid_Type == NULL) {
+		Py_DECREF(security_Type);
+		Py_DECREF(dom_sid_Type);
 		talloc_free(frame);
 		return NULL;
 	}
-- 
2.14.1


From 247a2c3994c7da1858e8b18db328777a5ea44b40 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu, 3 May 2018 09:47:18 +1200
Subject: [PATCH 16/22] s4/py_dsdb: catch/handle alloc failures in
 py_dsdb_normalise_attributes()

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 source4/dsdb/pydsdb.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/source4/dsdb/pydsdb.c b/source4/dsdb/pydsdb.c
index 4f05952bb25..97aef0990b6 100644
--- a/source4/dsdb/pydsdb.c
+++ b/source4/dsdb/pydsdb.c
@@ -746,10 +746,17 @@ static PyObject *py_dsdb_normalise_attributes(PyObject *self, PyObject *args)
 		return NULL;
 	}
 	py_ret = py_type->tp_alloc(py_type, 0);
+	if (py_ret == NULL) {
+		Py_DECREF(py_type);
+		PyErr_NoMemory();
+		return NULL;
+	}
 	ret = (PyLdbMessageElementObject *)py_ret;
 
 	ret->mem_ctx = talloc_new(NULL);
 	if (talloc_reference(ret->mem_ctx, new_el) == NULL) {
+		Py_DECREF(py_type);
+		Py_DECREF(py_ret);
 		PyErr_NoMemory();
 		return NULL;
 	}
-- 
2.14.1


From b0b4211d893ae2b3597074d1241fb046fcb03add Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu, 3 May 2018 09:53:56 +1200
Subject: [PATCH 17/22] s4/pyrpc_util: appropriately decrement refcounts on
 failure

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 source4/librpc/rpc/pyrpc_util.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/source4/librpc/rpc/pyrpc_util.c b/source4/librpc/rpc/pyrpc_util.c
index 21d94308cb9..cf68ef8890c 100644
--- a/source4/librpc/rpc/pyrpc_util.c
+++ b/source4/librpc/rpc/pyrpc_util.c
@@ -132,6 +132,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 		if (event_ctx == NULL) {
 			PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
 			TALLOC_FREE(ret->mem_ctx);
+			Py_DECREF(ret);
 			return NULL;
 		}
 
@@ -139,6 +140,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 		if (lp_ctx == NULL) {
 			PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
 			TALLOC_FREE(ret->mem_ctx);
+			Py_DECREF(ret);
 			return NULL;
 		}
 
@@ -147,6 +149,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 		if (!NT_STATUS_IS_OK(status)) {
 			PyErr_SetNTSTATUS(status);
 			TALLOC_FREE(ret->mem_ctx);
+			Py_DECREF(ret);
 			return NULL;
 		}
 	} else if (py_basis != Py_None) {
@@ -157,6 +160,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 		py_base = PyImport_ImportModule("samba.dcerpc.base");
 		if (py_base == NULL) {
 			TALLOC_FREE(ret->mem_ctx);
+			Py_DECREF(ret);
 			return NULL;
 		}
 
@@ -164,12 +168,14 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 		if (ClientConnection_Type == NULL) {
 			PyErr_SetNone(PyExc_TypeError);
 			TALLOC_FREE(ret->mem_ctx);
+			Py_DECREF(ret);
 			return NULL;
 		}
 
 		if (!PyObject_TypeCheck(py_basis, ClientConnection_Type)) {
 			PyErr_SetString(PyExc_TypeError, "basis_connection must be a DCE/RPC connection");
 			TALLOC_FREE(ret->mem_ctx);
+			Py_DECREF(ret);
 			return NULL;
 		}
 
@@ -178,6 +184,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 		if (base_pipe == NULL) {
 			PyErr_NoMemory();
 			TALLOC_FREE(ret->mem_ctx);
+			Py_DECREF(ret);
 			return NULL;
 		}
 
@@ -185,6 +192,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 		if (!NT_STATUS_IS_OK(status)) {
 			PyErr_SetNTSTATUS(status);
 			TALLOC_FREE(ret->mem_ctx);
+			Py_DECREF(ret);
 			return NULL;
 		}
 
@@ -198,6 +206,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 		if (event_ctx == NULL) {
 			PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
 			TALLOC_FREE(ret->mem_ctx);
+			Py_DECREF(ret);
 			return NULL;
 		}
 
@@ -205,6 +214,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 		if (lp_ctx == NULL) {
 			PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
 			TALLOC_FREE(ret->mem_ctx);
+			Py_DECREF(ret);
 			return NULL;
 		}
 
@@ -212,6 +222,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 		if (credentials == NULL) {
 			PyErr_SetString(PyExc_TypeError, "Expected credentials");
 			TALLOC_FREE(ret->mem_ctx);
+			Py_DECREF(ret);
 			return NULL;
 		}
 		status = dcerpc_pipe_connect(ret->mem_ctx, &ret->pipe, binding_string,
@@ -219,6 +230,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 		if (!NT_STATUS_IS_OK(status)) {
 			PyErr_SetNTSTATUS(status);
 			TALLOC_FREE(ret->mem_ctx);
+			Py_DECREF(ret);
 			return NULL;
 		}
 
@@ -378,6 +390,7 @@ PyObject *py_return_ndr_struct(const char *module_name, const char *type_name,
 
 	py_type = (PyTypeObject *)PyObject_GetAttrString(module, type_name);
 	if (py_type == NULL) {
+		Py_DECREF(module);
 		return NULL;
 	}
 
-- 
2.14.1


From 3cec6d1022af5b54029f16e5c2257f796b5522db Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu, 3 May 2018 09:56:10 +1200
Subject: [PATCH 18/22] s4/pyrpc_util: fix copy-pasted wrong exception type and
 message

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 source4/librpc/rpc/pyrpc_util.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/source4/librpc/rpc/pyrpc_util.c b/source4/librpc/rpc/pyrpc_util.c
index cf68ef8890c..e24b152a648 100644
--- a/source4/librpc/rpc/pyrpc_util.c
+++ b/source4/librpc/rpc/pyrpc_util.c
@@ -130,7 +130,8 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 
 		event_ctx = s4_event_context_init(ret->mem_ctx);
 		if (event_ctx == NULL) {
-			PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
+			PyErr_SetString(PyExc_RuntimeError,
+					"Could not initialize event context");
 			TALLOC_FREE(ret->mem_ctx);
 			Py_DECREF(ret);
 			return NULL;
-- 
2.14.1


From 804396870f24a875756f5d38ef671ce556401302 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu, 3 May 2018 09:57:29 +1200
Subject: [PATCH 19/22] s4/pyrpc_util: catch alloc failure in
 py_dcerpc_interface_init_helper()

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 source4/librpc/rpc/pyrpc_util.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/source4/librpc/rpc/pyrpc_util.c b/source4/librpc/rpc/pyrpc_util.c
index e24b152a648..5e8bcffe82a 100644
--- a/source4/librpc/rpc/pyrpc_util.c
+++ b/source4/librpc/rpc/pyrpc_util.c
@@ -116,6 +116,11 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
 	}
 
 	ret = PyObject_New(dcerpc_InterfaceObject, type);
+	if (ret == NULL) {
+		PyErr_NoMemory();
+		return NULL;
+	}
+
 	ret->pipe = NULL;
 	ret->binding_handle = NULL;
 	ret->mem_ctx = talloc_new(NULL);
-- 
2.14.1


From 4310508f54229c10c0d9cd5f054b6ff61e31d702 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Thu, 3 May 2018 09:59:13 +1200
Subject: [PATCH 20/22] s4/param/provision py_dom_sid_FromSid: avoid python
 memleak on failure

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 source4/param/provision.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/source4/param/provision.c b/source4/param/provision.c
index 69656220d90..135c6577853 100644
--- a/source4/param/provision.c
+++ b/source4/param/provision.c
@@ -204,13 +204,14 @@ static PyObject *py_dom_sid_FromSid(struct dom_sid *sid)
 	PyObject *mod_security, *dom_sid_Type;
 
 	mod_security = PyImport_ImportModule("samba.dcerpc.security");
-	if (mod_security == NULL)
+	if (mod_security == NULL) {
 		return NULL;
-
+	}
 	dom_sid_Type = PyObject_GetAttrString(mod_security, "dom_sid");
-	if (dom_sid_Type == NULL)
+	if (dom_sid_Type == NULL) {
+		Py_DECREF(mod_security);
 		return NULL;
-
+	}
 	return pytalloc_reference((PyTypeObject *)dom_sid_Type, sid);
 }
 
-- 
2.14.1


From d5fe11b82c05107eba7301749716d6d6c86bda3a Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Sat, 21 Apr 2018 00:37:15 +1200
Subject: [PATCH 21/22] py_net: fix != None check

Py_None is not false in C, so this branch was always taken.

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 source4/libnet/py_net.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/libnet/py_net.c b/source4/libnet/py_net.c
index 3e982d257fa..0deab6d4a5f 100644
--- a/source4/libnet/py_net.c
+++ b/source4/libnet/py_net.c
@@ -544,7 +544,7 @@ static PyObject *py_net_replicate_chunk(py_net_Object *self, PyObject *args, PyO
 	s->chunk.req5 = NULL;
 	s->chunk.req8 = NULL;
 	s->chunk.req10 = NULL;
-	if (py_req) {
+	if (py_req != Py_None) {
 		switch (req_level) {
 		case 0:
 			break;
-- 
2.14.1


From 1d6433b11d42df3c2816d00241acaf692040c770 Mon Sep 17 00:00:00 2001
From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date: Wed, 18 Apr 2018 14:37:12 +1200
Subject: [PATCH 22/22] pyldb: make ldb.connect() url mandatory

The call fails without it, so we might as well fail sooner

Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
---
 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 be741da42d4..571a9cc8388 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -1161,7 +1161,7 @@ static PyObject *py_ldb_connect(PyLdbObject *self, PyObject *args, PyObject *kwa
 	const char * const kwnames[] = { "url", "flags", "options", NULL };
 	struct ldb_context *ldb_ctx;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|zIO",
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|IO",
 					 discard_const_p(char *, kwnames),
 					 &url, &flags, &py_options))
 		return NULL;
-- 
2.14.1



More information about the samba-technical mailing list