[PATCH] more PY2/PY3 compat changes

Andreas Schneider asn at samba.org
Wed Jul 4 14:22:24 UTC 2018


On Wednesday, 27 June 2018 16:38:38 CEST Noel Power via samba-technical wrote:
> Hi,
> 
> More hopefully low hanging fruit patches, the exception I would see as
> '[PATCH 05/26] lib/ldb: Implement a bytes derived object for attributes
> py2/py3' which is the modification discussed on this list some time back
> (see https://lists.samba.org/archive/samba-technical/2018-May/127718.html)
> 
> This passed CI earlier, I squashed some patches and fixed some
> whitespace issues and resubmitted (should pass again)
> 
> please see attached for patch and
> https://gitlab.com/samba-team/devel/samba/pipelines/24688131 for CI
> 
> Branch is at
> https://gitlab.com/samba-team/devel/samba/commits/npower-python3-misc%232

I've reviewed them with some minor cosmetic changes. Attached is my patchset 
with my RB+.

Attaching it here if someone else wants to comment.


Please push.


-- 
Andreas Schneider                      asn at samba.org
Samba Team                             www.samba.org
GPG-ID:     8DFF53E18F2ABC8D8F3C92237EE0FC4DCC014E3D
-------------- next part --------------
>From 7f1e4da2164420daebbcdf7e02195b039d86c947 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Mon, 30 Apr 2018 18:43:54 +0100
Subject: [PATCH 01/25] python/samba/tests: Py2/Py3 allow import of
 ndr_(un)pack to work

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/tests/dcerpc/raw_testcase.py | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/python/samba/tests/dcerpc/raw_testcase.py b/python/samba/tests/dcerpc/raw_testcase.py
index 15bf92993b1..61786dd3636 100644
--- a/python/samba/tests/dcerpc/raw_testcase.py
+++ b/python/samba/tests/dcerpc/raw_testcase.py
@@ -26,7 +26,7 @@ import samba.tests
 from samba import gensec
 from samba.credentials import Credentials
 from samba.tests import TestCase
-
+from samba.ndr import ndr_pack, ndr_unpack, ndr_unpack_out
 
 class RawDCERPCTest(TestCase):
     """A raw DCE/RPC Test case."""
@@ -424,7 +424,7 @@ class RawDCERPCTest(TestCase):
 
             if hexdump:
                 sys.stderr.write("stub_out: %d\n%s" % (len(stub_out), self.hexdump(stub_out)))
-            samba.ndr.ndr_unpack_out(io, stub_out, bigendian=bigendian, ndr64=ndr64,
+            ndr_unpack_out(io, stub_out, bigendian=bigendian, ndr64=ndr64,
                                      allow_remaining=allow_remaining)
             if ndr_print:
                 sys.stderr.write("out: %s" % samba.ndr.ndr_print_out(io))
@@ -441,7 +441,7 @@ class RawDCERPCTest(TestCase):
         ctx = self.prepare_presentation(samba.dcerpc.epmapper.abstract_syntax(),
                                         transfer, context_id=0)
 
-        data1 = samba.ndr.ndr_pack(abstract)
+        data1 = ndr_pack(abstract)
         lhs1 = samba.dcerpc.epmapper.epm_lhs()
         lhs1.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_UUID
         lhs1.lhs_data = data1[:18]
@@ -450,7 +450,7 @@ class RawDCERPCTest(TestCase):
         floor1 = samba.dcerpc.epmapper.epm_floor()
         floor1.lhs = lhs1
         floor1.rhs = rhs1
-        data2 = samba.ndr.ndr_pack(transfer)
+        data2 = ndr_pack(transfer)
         lhs2 = samba.dcerpc.epmapper.epm_lhs()
         lhs2.protocol = samba.dcerpc.epmapper.EPM_PROTOCOL_UUID
         lhs2.lhs_data = data2[:18]
@@ -515,7 +515,7 @@ class RawDCERPCTest(TestCase):
         if hexdump is None:
             hexdump = self.do_hexdump
         try:
-            req_pdu = samba.ndr.ndr_pack(req)
+            req_pdu = ndr_pack(req)
             if ndr_print:
                 sys.stderr.write("send_pdu: %s" % samba.ndr.ndr_print(req))
             if hexdump:
@@ -573,7 +573,7 @@ class RawDCERPCTest(TestCase):
             rep_pdu = self.recv_raw(hexdump=hexdump, timeout=timeout)
             if rep_pdu is None:
                 return (None,None)
-            rep = samba.ndr.ndr_unpack(samba.dcerpc.dcerpc.ncacn_packet, rep_pdu, allow_remaining=True)
+            rep = ndr_unpack(samba.dcerpc.dcerpc.ncacn_packet, rep_pdu, allow_remaining=True)
             if ndr_print:
                 sys.stderr.write("recv_pdu: %s" % samba.ndr.ndr_print(rep))
             self.assertEqual(rep.frag_length, len(rep_pdu))
@@ -607,7 +607,7 @@ class RawDCERPCTest(TestCase):
             a.auth_context_id= auth_context_id
             a.credentials = auth_blob
 
-            ai = samba.ndr.ndr_pack(a)
+            ai = ndr_pack(a)
             if ndr_print:
                 sys.stderr.write("generate_auth: %s" % samba.ndr.ndr_print(a))
             if hexdump:
@@ -628,7 +628,7 @@ class RawDCERPCTest(TestCase):
 
         if hexdump:
             sys.stderr.write("parse_auth: %d\n%s" % (len(auth_info), self.hexdump(auth_info)))
-        a = samba.ndr.ndr_unpack(samba.dcerpc.dcerpc.auth, auth_info, allow_remaining=True)
+        a = ndr_unpack(samba.dcerpc.dcerpc.auth, auth_info, allow_remaining=True)
         if ndr_print:
             sys.stderr.write("parse_auth: %s" % samba.ndr.ndr_print(a))
 
@@ -661,7 +661,7 @@ class RawDCERPCTest(TestCase):
         p.call_id = call_id
         p.u = payload
 
-        pdu = samba.ndr.ndr_pack(p)
+        pdu = ndr_pack(p)
         p.frag_length = len(pdu)
 
         return p
-- 
2.18.0


>From f8c4da8e55f8ffced828e2129dd8b55a43f05980 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Tue, 1 May 2018 19:58:36 +0100
Subject: [PATCH 02/25] python/samba/tests: Py2/Py3 port for hexdump

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/tests/__init__.py | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py
index 7061f8b3d14..8eb41cee538 100644
--- a/python/samba/tests/__init__.py
+++ b/python/samba/tests/__init__.py
@@ -36,6 +36,7 @@ import re
 import samba.auth
 import samba.dcerpc.base
 from samba.compat import PY3, text_type
+from samba.compat import string_types
 from random import randint
 if not PY3:
     # Py2 only
@@ -50,7 +51,7 @@ except ImportError:
     class SkipTest(Exception):
         """Test skipped."""
 
-HEXDUMP_FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])
+HEXDUMP_FILTER=bytearray([x if ((len(repr(chr(x)))==3) and (x < 127)) else ord('.') for x in range(256)])
 
 class TestCase(unittest.TestCase):
     """A Samba test case."""
@@ -80,14 +81,21 @@ class TestCase(unittest.TestCase):
     def hexdump(self, src):
         N = 0
         result = ''
+        is_string = isinstance(src, string_types)
         while src:
             ll = src[:8]
             lr = src[8:16]
             src = src[16:]
-            hl = ' '.join(["%02X" % ord(x) for x in ll])
-            hr = ' '.join(["%02X" % ord(x) for x in lr])
-            ll = ll.translate(HEXDUMP_FILTER)
-            lr = lr.translate(HEXDUMP_FILTER)
+            if is_string:
+                hl = ' '.join(["%02X" % ord(x) for x in ll])
+                hr = ' '.join(["%02X" % ord(x) for x in lr])
+                ll = ll.translate(HEXDUMP_FILTER)
+                lr = lr.translate(HEXDUMP_FILTER)
+            else:
+                hl = ' '.join(["%02X" % x for x in ll])
+                hr = ' '.join(["%02X" % x for x in lr])
+                ll = ll.translate(HEXDUMP_FILTER).decode('utf8')
+                lr = lr.translate(HEXDUMP_FILTER).decode('utf8')
             result += "[%04X] %-*s  %-*s  %s %s\n" % (N, 8*3, hl, 8*3, hr, ll, lr)
             N += 16
         return result
-- 
2.18.0


>From cde11688ee41f0170a945149a2bd9f4e7d48cfd4 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Wed, 9 May 2018 20:17:30 +0100
Subject: [PATCH 03/25] python/samba/emulate: Fix some more missed exception
 tuple assignments

In python3 we need to change

    except LdbError as e:
-        (status, _) = e
to
    except LdbError as e:
+        (status, _) = e.args

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/emulate/traffic.py | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py
index dba2c3f32f9..c96530b0164 100644
--- a/python/samba/emulate/traffic.py
+++ b/python/samba/emulate/traffic.py
@@ -1568,7 +1568,7 @@ def create_ou(ldb, instance_id):
         ldb.add({"dn":          ou.split(',', 1)[1],
                  "objectclass": "organizationalunit"})
     except LdbError as e:
-        (status, _) = e
+        (status, _) = e.args
         # ignore already exists
         if status != 68:
             raise
@@ -1576,7 +1576,7 @@ def create_ou(ldb, instance_id):
         ldb.add({"dn":          ou,
                  "objectclass": "organizationalunit"})
     except LdbError as e:
-        (status, _) = e
+        (status, _) = e.args
         # ignore already exists
         if status != 68:
             raise
@@ -1626,7 +1626,7 @@ def generate_traffic_accounts(ldb, instance_id, number, password):
             create_machine_account(ldb, instance_id, netbios_name, password)
             added += 1
         except LdbError as e:
-            (status, _) = e
+            (status, _) = e.args
             if status == 68:
                 break
             else:
@@ -1642,7 +1642,7 @@ def generate_traffic_accounts(ldb, instance_id, number, password):
             create_user_account(ldb, instance_id, username, password)
             added += 1
         except LdbError as e:
-            (status, _) = e
+            (status, _) = e.args
             if status == 68:
                 break
             else:
@@ -1728,7 +1728,7 @@ def generate_users(ldb, instance_id, number, password):
             create_user_account(ldb, instance_id, username, password)
             users += 1
         except LdbError as e:
-            (status, _) = e
+            (status, _) = e.args
             # Stop if entry exists
             if status == 68:
                 break
@@ -1752,7 +1752,7 @@ def generate_groups(ldb, instance_id, number):
             create_group(ldb, instance_id, name)
             groups += 1
         except LdbError as e:
-            (status, _) = e
+            (status, _) = e.args
             # Stop if entry exists
             if status == 68:
                 break
@@ -1767,7 +1767,7 @@ def clean_up_accounts(ldb, instance_id):
     try:
         ldb.delete(ou, ["tree_delete:1"])
     except LdbError as e:
-        (status, _) = e
+        (status, _) = e.args
         # ignore does not exist
         if status != 32:
             raise
-- 
2.18.0


>From 6d956d9fda2008485944ac9a292232341be8dd4c Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Thu, 10 May 2018 13:14:22 +0100
Subject: [PATCH 04/25] python/samba/tests: remove Py2 specific imports.

Remove some python2 specific import, probably this was due to
previous unavailability for some c-modules in python3

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/tests/__init__.py | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py
index 8eb41cee538..1d507102095 100644
--- a/python/samba/tests/__init__.py
+++ b/python/samba/tests/__init__.py
@@ -38,12 +38,10 @@ import samba.dcerpc.base
 from samba.compat import PY3, text_type
 from samba.compat import string_types
 from random import randint
-if not PY3:
-    # Py2 only
-    from samba.samdb import SamDB
-    import samba.ndr
-    import samba.dcerpc.dcerpc
-    import samba.dcerpc.epmapper
+from samba.samdb import SamDB
+import samba.ndr
+import samba.dcerpc.dcerpc
+import samba.dcerpc.epmapper
 
 try:
     from unittest import SkipTest
-- 
2.18.0


>From 8ccc45447a3e1e050dbe4820368d992e368efbd8 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Fri, 11 May 2018 13:48:29 +0100
Subject: [PATCH 05/25] lib/ldb: Implement a bytes derived object for
 attributes py2/py3

ldb attributes are either bytes (py3) or str (py2)

Some places in the code do str(res[0]['attribute'][0])
which results in
   'result' (py2)
  b'result' (py3)

or more commonly the attribute is used to construct a string e.g.
   "blah=" + res[0]['attribute'][0] + ",foo,bar=...."

giving
   "blah=result,foo,bar=...." (py2)
and very unhelpfully
   "blah=b'result',foo,bar=...." (py3)

lots of code already constructs various strings for passing to other
api using the above. To avoid many excessive
    res[0]['attribute'][0].decode('utf8')

code like 'res[0]['attribute'][0]'

will now return LdbBytes (a new object subclassing 'bytes') in py3
instead of bytes. This object has a custom '__str__' method which
attempts to return a string decoded to uft8. In Py2 this will behave as
it did previously (this is the safer option at the moment)

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/pyldb.c | 45 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 43 insertions(+), 2 deletions(-)

diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index 110ec8e60ad..66bc2021fb4 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -79,6 +79,7 @@ static struct ldb_message_element *PyObject_AsMessageElement(
 						      PyObject *set_obj,
 						      unsigned int flags,
 						      const char *attr_name);
+static PyTypeObject PyLdbBytesType;
 
 #if PY_MAJOR_VERSION >= 3
 #define PyStr_Check PyUnicode_Check
@@ -89,6 +90,16 @@ static struct ldb_message_element *PyObject_AsMessageElement(
 #define PyStr_AsUTF8 PyUnicode_AsUTF8
 #define PyStr_AsUTF8AndSize PyUnicode_AsUTF8AndSize
 #define PyInt_FromLong PyLong_FromLong
+
+static PyObject *PyLdbBytes_FromStringAndSize(const char *msg, int size)
+{
+	PyObject* result = NULL;
+	PyObject* args = NULL;
+	args = Py_BuildValue("(y#)", msg, size);
+	result = PyLdbBytesType.tp_new(&PyLdbBytesType, args, NULL);
+	Py_DECREF(args);
+	return result;
+}
 #else
 #define PyStr_Check PyString_Check
 #define PyStr_FromString PyString_FromString
@@ -96,6 +107,7 @@ static struct ldb_message_element *PyObject_AsMessageElement(
 #define PyStr_FromFormat PyString_FromFormat
 #define PyStr_FromFormatV PyString_FromFormatV
 #define PyStr_AsUTF8 PyString_AsString
+#define PyLdbBytes_FromStringAndSize PyString_FromStringAndSize
 
 const char *PyStr_AsUTF8AndSize(PyObject *pystr, Py_ssize_t *sizeptr);
 const char *
@@ -270,10 +282,34 @@ static void PyErr_SetLdbError(PyObject *error, int ret, struct ldb_context *ldb_
 			Py_BuildValue(discard_const_p(char, "(i,s)"), ret,
 				      ldb_ctx == NULL?ldb_strerror(ret):ldb_errstring(ldb_ctx)));
 }
+static PyObject *py_ldb_bytes_str(PyBytesObject *self)
+{
+	char *msg = NULL;
+	Py_ssize_t size;
+	int result = 0;
+	if (!PyBytes_Check(self)) {
+		PyErr_Format(PyExc_TypeError,"Unexpected type");
+		return NULL;
+	}
+	result = PyBytes_AsStringAndSize((PyObject *)self, &msg, &size);
+	if (result != 0) {
+		PyErr_Format(PyExc_TypeError, "Failed to extract bytes");
+		return NULL;
+	}
+	return PyUnicode_FromStringAndSize(msg, size);
+}
+
+static PyTypeObject PyLdbBytesType = {
+	PyVarObject_HEAD_INIT(NULL, 0)
+	.tp_name = "ldb.bytes",
+	.tp_doc = "str/bytes (with custom str)",
+        .tp_str = (reprfunc)py_ldb_bytes_str,
+	.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+};
 
 static PyObject *PyObject_FromLdbValue(const struct ldb_val *val)
 {
-	return PyBytes_FromStringAndSize((const char *)val->data, val->length);
+	return PyLdbBytes_FromStringAndSize((const char *)val->data, val->length);
 }
 
 static PyObject *PyStr_FromLdbValue(const struct ldb_val *val)
@@ -2990,7 +3026,7 @@ static PyObject *py_ldb_msg_element_find(PyLdbMessageElementObject *self, Py_ssi
 		PyErr_SetString(PyExc_IndexError, "Out of range");
 		return NULL;
 	}
-	return PyBytes_FromStringAndSize((char *)el->values[idx].data, el->values[idx].length);
+	return PyLdbBytes_FromStringAndSize((char *)el->values[idx].data, el->values[idx].length);
 }
 
 static PySequenceMethods py_ldb_msg_element_seq = {
@@ -4123,6 +4159,11 @@ static PyObject* module_init(void)
 {
 	PyObject *m;
 
+	PyLdbBytesType.tp_base = &PyBytes_Type;
+	if (PyType_Ready(&PyLdbBytesType) < 0) {
+		return NULL;
+	}
+
 	if (PyType_Ready(&PyLdbDn) < 0)
 		return NULL;
 
-- 
2.18.0


>From 81584c43a84db94276e2c3510a19cb19efe566ae Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Tue, 15 May 2018 15:32:35 +0100
Subject: [PATCH 06/25] s4/torture/drs/python: Py2/Py2 fix tab/space also
 incorrect unicode usage

Signed-off-by: Noel Power <noel.power at suse.com>
---
 source4/torture/drs/python/drs_base.py | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index a6a2439c457..c9518ef7358 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -268,11 +268,11 @@ class DrsBaseTestCase(SambaToolCmdTest):
 
                 print("Link Tgt %s... <-- Src %s"
                       %(target.dn[:25], l.identifier.guid))
-		state = "Del"
-		if l.flags & drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE:
-		    state = "Act"
-		print("  v%u %s changed %u" %(l.meta_data.version, state,
-		      l.meta_data.originating_change_time))
+                state = "Del"
+                if l.flags & drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE:
+                    state = "Act"
+                print("  v%u %s changed %u" %(l.meta_data.version, state,
+                    l.meta_data.originating_change_time))
 
             print("HWM:     %d" %(ctr6.new_highwatermark.highest_usn))
             print("Tmp HWM: %d" %(ctr6.new_highwatermark.tmp_highest_usn))
@@ -424,7 +424,7 @@ class DrsBaseTestCase(SambaToolCmdTest):
         req8.destination_dsa_guid = misc.GUID(dest_dsa) if dest_dsa else misc.GUID()
         req8.source_dsa_invocation_id = misc.GUID(invocation_id)
         req8.naming_context = drsuapi.DsReplicaObjectIdentifier()
-        req8.naming_context.dn = unicode(nc_dn_str)
+        req8.naming_context.dn = str(nc_dn_str)
         req8.highwatermark = drsuapi.DsReplicaHighWaterMark()
         req8.highwatermark.tmp_highest_usn = 0
         req8.highwatermark.reserved_usn = 0
@@ -454,7 +454,7 @@ class DrsBaseTestCase(SambaToolCmdTest):
         req10.destination_dsa_guid = misc.GUID(dest_dsa) if dest_dsa else misc.GUID()
         req10.source_dsa_invocation_id = misc.GUID(invocation_id)
         req10.naming_context = drsuapi.DsReplicaObjectIdentifier()
-        req10.naming_context.dn = unicode(nc_dn_str)
+        req10.naming_context.dn = str(nc_dn_str)
         req10.highwatermark = drsuapi.DsReplicaHighWaterMark()
         req10.highwatermark.tmp_highest_usn = 0
         req10.highwatermark.reserved_usn = 0
-- 
2.18.0


>From 4a38c51ff818aae6a3cfe7e32e23c2911d6e77a5 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Thu, 17 May 2018 15:23:38 +0100
Subject: [PATCH 07/25] python/samba/netcmd: fix py2/py3 bytes usage for
 replace

base64.b64encode returns bytes in py3 make sure associated replace
uses 'b' for strings passed to replace

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/netcmd/user.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/python/samba/netcmd/user.py b/python/samba/netcmd/user.py
index f211b5158ce..2131c68a0c7 100644
--- a/python/samba/netcmd/user.py
+++ b/python/samba/netcmd/user.py
@@ -119,7 +119,7 @@ def get_crypt_value(alg, utf8pw, rounds=0):
     # we can ignore the possible == at the end
     # of the base64 string
     # we just need to replace '+' by '.'
-    b64salt = base64.b64encode(salt)[0:16].replace('+', '.').decode('utf8')
+    b64salt = base64.b64encode(salt)[0:16].replace(b'+', b'.').decode('utf8')
     crypt_salt = ""
     if rounds != 0:
         crypt_salt = "$%s$rounds=%s$%s$" % (alg, rounds, b64salt)
-- 
2.18.0


>From 6bc537889466f897622b506f38ca44b1c44b8699 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Thu, 17 May 2018 15:25:29 +0100
Subject: [PATCH 08/25] python/samba/netcmd: Protect variable that can be None

In py3 None variable cannot be compared with '>' '<' etc operators

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/netcmd/domain.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py
index 86249073652..2fb96d143c5 100644
--- a/python/samba/netcmd/domain.py
+++ b/python/samba/netcmd/domain.py
@@ -1524,7 +1524,7 @@ class cmd_domain_passwordsettings_set(Command):
               ldb.FLAG_MOD_REPLACE, "lockOutObservationWindow")
             msgs.append("Duration to reset account lockout after changed!")
 
-        if max_pwd_age > 0 and min_pwd_age >= max_pwd_age:
+        if max_pwd_age and max_pwd_age > 0 and min_pwd_age >= max_pwd_age:
             raise CommandError("Maximum password age (%d) must be greater than minimum password age (%d)!" % (max_pwd_age, min_pwd_age))
 
         if len(m) == 0:
-- 
2.18.0


>From b3785701dd816adb3522ebc84f4fe23f04ab03c1 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Thu, 17 May 2018 15:28:10 +0100
Subject: [PATCH 09/25] python/samba/tests/samba_tool: Ensure test works for
 py3

self.ldb.get_minPwdLength() returns ldb.MessageElement item
(e.g.) bytes (or maybe new LdbBytes subclass of bytes)

need to use the str() function on the attribute (which will result in custom
__str__ function getting called when running in PY3)

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/tests/samba_tool/passwordsettings.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/python/samba/tests/samba_tool/passwordsettings.py b/python/samba/tests/samba_tool/passwordsettings.py
index 7c1afc8f51b..99b42ca49f0 100644
--- a/python/samba/tests/samba_tool/passwordsettings.py
+++ b/python/samba/tests/samba_tool/passwordsettings.py
@@ -427,7 +427,7 @@ class PwdSettingsCmdTestCase(SambaToolCmdTest):
         self.assertCmdSuccess(result, out, err)
         self.assertEquals(err,"","Shouldn't be any error messages")
         self.assertIn("successful", out)
-        self.assertEquals(str(new_len), self.ldb.get_minPwdLength())
+        self.assertEquals(str(new_len), str(self.ldb.get_minPwdLength()))
 
         # check the updated value is now displayed
         (result, out, err) = self.runsublevelcmd("domain", ("passwordsettings",
-- 
2.18.0


>From 85083fa8ea020bc2b3f9f2dd9bd6171d12124ada Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Fri, 18 May 2018 12:12:44 +0100
Subject: [PATCH 10/25] python/samba/netcmd: Fix relative module import

Part of future changes needed to enable samba4.drs.replica_sync_rodc
for PY3.

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/netcmd/drs.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/python/samba/netcmd/drs.py b/python/samba/netcmd/drs.py
index b8793b76606..6fb8c570a1a 100644
--- a/python/samba/netcmd/drs.py
+++ b/python/samba/netcmd/drs.py
@@ -21,7 +21,7 @@
 import samba.getopt as options
 import ldb
 import logging
-import common
+from . import common
 import json
 
 from samba.auth import system_session
-- 
2.18.0


>From 968a0f1960d8a078bc60d0a0d78486bf3dc0c38d Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Fri, 18 May 2018 17:15:44 +0100
Subject: [PATCH 11/25] s4/librpc/ndr: allow GUID to accept unicode also

This needed since _GUID_string method change
(in source4/torture/drs/python/drs_base.py) which makes use use
a unicode guid at times now

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source4/librpc/ndr/py_misc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/librpc/ndr/py_misc.c b/source4/librpc/ndr/py_misc.c
index 849a11460a4..6c0b8b2af14 100644
--- a/source4/librpc/ndr/py_misc.c
+++ b/source4/librpc/ndr/py_misc.c
@@ -97,7 +97,7 @@ static int py_GUID_init(PyObject *self, PyObject *args, PyObject *kwargs)
 		DATA_BLOB guid_val;
 		Py_ssize_t _size;
 
-		if (!IsPy3BytesOrString(str)) {
+		if (!IsPy3BytesOrString(str) && !PyUnicode_Check(str)) {
 			PyErr_SetString(PyExc_TypeError, "Expected a string or bytes argument to GUID()");
 			return -1;
 		}
-- 
2.18.0


>From 04d119ddedd7155f399fd7168cdfcc13c8ea7371 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Thu, 31 May 2018 16:13:28 +0100
Subject: [PATCH 12/25] s4/dsdb/tests/python: base64.b64encode returns bytes

adjust to unicode for py2/py3 compat needed as part of changes
to ensure samba4.ldap.password_settings will work with PY3

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source4/dsdb/tests/python/password_settings.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/source4/dsdb/tests/python/password_settings.py b/source4/dsdb/tests/python/password_settings.py
index 12779a033c6..614c5850857 100644
--- a/source4/dsdb/tests/python/password_settings.py
+++ b/source4/dsdb/tests/python/password_settings.py
@@ -727,7 +727,7 @@ class PasswordSettingsTestCase(PasswordTestCase):
         # defaults, to prove that the DC will reject bad passwords during a
         # user add
         userdn = "CN=testuser,%s" % self.ou
-        password = base64.b64encode("\"abcdef\"".encode('utf-16-le'))
+        password = base64.b64encode("\"abcdef\"".encode('utf-16-le')).decode('utf8')
 
         # Note we use an LDIF operation to ensure that the password gets set
         # as part of the 'add' operation (whereas self.add_user() adds the user
@@ -751,7 +751,7 @@ unicodePwd:: %s
         # now use a password that meets the domain defaults, but doesn't meet
         # the PSO requirements. Note that Windows allows this, i.e. it doesn't
         # honour the PSO during the add operation
-        password = base64.b64encode("\"abcde12#\"".encode('utf-16-le'))
+        password = base64.b64encode("\"abcde12#\"".encode('utf-16-le')).decode('utf8')
         ldif = """
 dn: %s
 objectClass: user
@@ -787,7 +787,7 @@ unicodePwd:: %s
                 self.assertTrue('0000052D' in msg, msg)
 
         # check setting a password that meets the PSO settings works
-        password = base64.b64encode("\"abcdefghijkl\"".encode('utf-16-le'))
+        password = base64.b64encode("\"abcdefghijkl\"".encode('utf-16-le')).decode('utf8')
         ldif = """
 dn: %s
 changetype: modify
-- 
2.18.0


>From 44ca635487be4330eca614799490497544057b7f Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Fri, 15 Jun 2018 10:18:30 +0100
Subject: [PATCH 13/25] s4/torture/drs: ndr_upack needs bytes in py3
 (samba4.drs.repl_move)

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/drs/python/repl_move.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/torture/drs/python/repl_move.py b/source4/torture/drs/python/repl_move.py
index c5e1de0d9a2..b53b0c0b1c5 100644
--- a/source4/torture/drs/python/repl_move.py
+++ b/source4/torture/drs/python/repl_move.py
@@ -107,7 +107,7 @@ class DrsMoveObjectTestCase(drs_base.DrsBaseTestCase):
         return "DrsMoveU_" + time.strftime("%s", time.gmtime())
 
     def _check_metadata(self, user_dn, sam_ldb, drs, metadata, expected):
-        repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(metadata[0]))
+        repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, metadata[0])
 
         self.assertEqual(len(repl.ctr.array), len(expected))
 
-- 
2.18.0


>From 359d32009e26f601bb60750e2698a0a26a11c870 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Fri, 15 Jun 2018 10:58:13 +0100
Subject: [PATCH 14/25] s4/torture/drs/python: py2/py3 port map / ord usage

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/drs/python/getnc_exop.py | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/source4/torture/drs/python/getnc_exop.py b/source4/torture/drs/python/getnc_exop.py
index e29e346b3eb..9d1b6ee038d 100644
--- a/source4/torture/drs/python/getnc_exop.py
+++ b/source4/torture/drs/python/getnc_exop.py
@@ -924,17 +924,20 @@ class DrsReplicaPrefixMapTestCase(drs_base.DrsBaseTestCase):
 
         schi = drsuapi.DsReplicaOIDMapping()
         schi.id_prefix = 0
-
         if 'schemaInfo' in res[0]:
-            schi.oid.length = len(map(ord, str(res[0]['schemaInfo'])))
-            schi.oid.binary_oid = map(ord, str(res[0]['schemaInfo']))
+            binary_oid = [x if isinstance(x, int) else ord(x) for x in res[0]['schemaInfo'][0]]
+            schi.oid.length = len(binary_oid)
+            schi.oid.binary_oid = binary_oid
         else:
             schema_info = drsblobs.schemaInfoBlob()
             schema_info.revision = 0
             schema_info.marker = 0xFF
             schema_info.invocation_id = misc.GUID(samdb.get_invocation_id())
-            schi.oid.length = len(map(ord, ndr_pack(schema_info)))
-            schi.oid.binary_oid = map(ord, ndr_pack(schema_info))
+
+            binary_oid = [x if isinstance(x, int) else ord(x) for x in ndr_pack(schema_info)]
+            # you have to set the length before setting binary_oid
+            schi.oid.length = len(binary_oid)
+            schi.oid.binary_oid = binary_oid
 
         pfm.ctr.mappings = pfm.ctr.mappings + [schi]
         pfm.ctr.num_mappings += 1
-- 
2.18.0


>From 1bf0e63f455549360473189a2550e8878d2fdc11 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Fri, 15 Jun 2018 13:00:15 +0100
Subject: [PATCH 15/25] python/samba: Add cmp_fn and cmp_to_key_fn functions
 for py2/py3

the cmp function and the cmp paramater (e.g. to sort functions)
no longer exist in python3.

cmp_fn is provides the missing functionality of the py2 cmp builtin
function.

cmp_to_key_fn allows the key paramater (e.g. for sort) to use the
old py2 cmp function for sorting. Note: the cmp_to_key is present in
since 2.7 (hence the inclusion of the source code for this function pre
that version)

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/compat.py | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/python/samba/compat.py b/python/samba/compat.py
index 042fc86a440..114c1eafb80 100644
--- a/python/samba/compat.py
+++ b/python/samba/compat.py
@@ -22,9 +22,20 @@ import sys
 PY3 = sys.version_info[0] == 3
 
 if PY3:
+    def cmp_fn(x, y):
+        """
+        Replacement for built-in function cmp that was removed in Python 3
+
+        Compare the two objects x and y and return an integer according to
+        the outcome. The return value is negative if x < y, zero if x == y
+        and strictly positive if x > y.
+        """
+
+        return (x > y) - (x < y)
     # compat functions
     from  urllib.parse import quote as urllib_quote
     from urllib.request import urlopen as urllib_urlopen
+    from functools import cmp_to_key as cmp_to_key_fn
 
     # compat types
     integer_types = int,
@@ -36,6 +47,32 @@ if PY3:
     import io
     StringIO = io.StringIO
 else:
+
+    if sys.version_info[0] < int(2.7):
+        def cmp_to_key_fn(mycmp):
+
+            """Convert a cmp= function into a key= function"""
+            class K(object):
+                __slots__ = ['obj']
+                def __init__(self, obj, *args):
+                    self.obj = obj
+                def __lt__(self, other):
+                    return mycmp(self.obj, other.obj) < 0
+                def __gt__(self, other):
+                    return mycmp(self.obj, other.obj) > 0
+                def __eq__(self, other):
+                    return mycmp(self.obj, other.obj) == 0
+                def __le__(self, other):
+                    return mycmp(self.obj, other.obj) <= 0
+                def __ge__(self, other):
+                    return mycmp(self.obj, other.obj) >= 0
+                def __ne__(self, other):
+                    return mycmp(self.obj, other.obj) != 0
+                def __hash__(self):
+                    raise TypeError('hash not implemented')
+            return K
+    else:
+        from functools import cmp_to_key as cmp_to_key_fn
     # compat functions
     from urllib import quote as urllib_quote
     from urllib import urlopen as urllib_urlopen
@@ -49,3 +86,4 @@ else:
     # alias
     import StringIO
     StringIO = StringIO.StringIO
+    cmp_fn = cmp
-- 
2.18.0


>From 784c362eb8a67f5763b1a1b3b469867106f45560 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Fri, 15 Jun 2018 13:04:13 +0100
Subject: [PATCH 16/25] s4/torture/drs/python: use cmp_fn and key=cmp_to_key_fn
 for py2/py3

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/drs/python/getnc_exop.py | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/source4/torture/drs/python/getnc_exop.py b/source4/torture/drs/python/getnc_exop.py
index 9d1b6ee038d..0bb545d78ca 100644
--- a/source4/torture/drs/python/getnc_exop.py
+++ b/source4/torture/drs/python/getnc_exop.py
@@ -43,6 +43,8 @@ from ldb import SCOPE_BASE
 from samba.dcerpc import drsuapi, misc, drsblobs
 from samba.drs_utils import drs_DsBind
 from samba.ndr import ndr_unpack, ndr_pack
+from samba.compat import cmp_to_key_fn
+from samba.compat import cmp_fn
 
 def _linked_attribute_compare(la1, la2):
     """See CompareLinks() in MS-DRSR section 4.1.10.5.17"""
@@ -50,7 +52,7 @@ def _linked_attribute_compare(la1, la2):
     la2, la2_target = la2
 
     # Ascending host object GUID
-    c = cmp(ndr_pack(la1.identifier.guid), ndr_pack(la2.identifier.guid))
+    c = cmp_fn(ndr_pack(la1.identifier.guid), ndr_pack(la2.identifier.guid))
     if c != 0:
         return c
 
@@ -66,7 +68,7 @@ def _linked_attribute_compare(la1, la2):
         return 1 if la1_active else -1
 
     # Ascending target object GUID
-    return cmp(ndr_pack(la1_target), ndr_pack(la2_target))
+    return cmp_fn(ndr_pack(la1_target), ndr_pack(la2_target))
 
 
 class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
@@ -1056,7 +1058,7 @@ class DrsReplicaSyncSortTestCase(drs_base.DrsBaseTestCase):
                                          link.identifier.guid,
                                          target_guid) in expected_links)
 
-        no_inactive.sort(cmp=_linked_attribute_compare)
+        no_inactive.sort(key=cmp_to_key_fn(_linked_attribute_compare))
 
         # assert the two arrays are the same
         self.assertEqual(len(expected_links), ctr.linked_attributes_count)
@@ -1080,7 +1082,7 @@ class DrsReplicaSyncSortTestCase(drs_base.DrsBaseTestCase):
                                          link.identifier.guid,
                                          target_guid) in expected_links)
 
-        has_inactive.sort(cmp=_linked_attribute_compare)
+        has_inactive.sort(key=cmp_to_key_fn(_linked_attribute_compare))
 
         # assert the two arrays are the same
         self.assertEqual(len(expected_links), ctr.linked_attributes_count)
@@ -1128,7 +1130,7 @@ class DrsReplicaSyncSortTestCase(drs_base.DrsBaseTestCase):
                                          link.value.blob).guid
             no_inactive.append((link, target_guid))
 
-        no_inactive.sort(cmp=_linked_attribute_compare)
+        no_inactive.sort(key=cmp_to_key_fn(_linked_attribute_compare))
 
         # assert the two arrays are the same
         self.assertEqual([x[0] for x in no_inactive], ctr.linked_attributes)
-- 
2.18.0


>From 036480ceb428dad15a8becf43c16a568480f38f8 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Fri, 15 Jun 2018 13:06:13 +0100
Subject: [PATCH 17/25] s4/torture/drs/python: use cmp_fn for cmp (for py2/py3
 compat)

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/drs/python/drs_base.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index c9518ef7358..91b76b3c6aa 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -39,7 +39,7 @@ from ldb import (
     Message,
     FLAG_MOD_REPLACE,
     )
-
+from samba.compat import cmp_fn
 
 class DrsBaseTestCase(SambaToolCmdTest):
     """Base class implementation for all DRS python tests.
@@ -515,7 +515,7 @@ class AbstractLink:
                 print("AbstractLink.__internal_cmp__(%r, %r) => wrong type" % (self, other))
             return NotImplemented
 
-        c = cmp(self.selfGUID_blob, other.selfGUID_blob)
+        c = cmp_fn(self.selfGUID_blob, other.selfGUID_blob)
         if c != 0:
             if verbose:
                 print("AbstractLink.__internal_cmp__(%r, %r) => %d different identifier" % (self, other, c))
@@ -536,7 +536,7 @@ class AbstractLink:
                 print("AbstractLink.__internal_cmp__(%r, %r) => %d different FLAG_ACTIVE" % (self, other, c))
             return c
 
-        c = cmp(self.targetGUID_blob, other.targetGUID_blob)
+        c = cmp_fn(self.targetGUID_blob, other.targetGUID_blob)
         if c != 0:
             if verbose:
                 print("AbstractLink.__internal_cmp__(%r, %r) => %d different target" % (self, other, c))
-- 
2.18.0


>From 4c5a2a5d76482126396ec9f7835d43d9657a53e7 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Fri, 15 Jun 2018 14:29:42 +0100
Subject: [PATCH 18/25] s4/torture/drs/python: long is not used in py3

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/drs/python/drs_base.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index 91b76b3c6aa..6405c990822 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -184,7 +184,7 @@ class DrsBaseTestCase(SambaToolCmdTest):
     def _get_highest_hwm_utdv(self, ldb_conn):
         res = ldb_conn.search("", scope=ldb.SCOPE_BASE, attrs=["highestCommittedUSN"])
         hwm = drsuapi.DsReplicaHighWaterMark()
-        hwm.tmp_highest_usn = long(res[0]["highestCommittedUSN"][0])
+        hwm.tmp_highest_usn = int(res[0]["highestCommittedUSN"][0])
         hwm.reserved_usn = 0
         hwm.highest_usn = hwm.tmp_highest_usn
 
-- 
2.18.0


>From f6742047a2e792f66d8ca30db829e4129818ce25 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Fri, 15 Jun 2018 15:13:56 +0100
Subject: [PATCH 19/25] s4/torture/drs/python: xrange -> range for py2/py3
 compat

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/drs/python/drs_base.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index 6405c990822..06300f57b0e 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -317,7 +317,7 @@ class DrsBaseTestCase(SambaToolCmdTest):
         if uptodateness_vector is not None:
             uptodateness_vector_v1 = drsuapi.DsReplicaCursorCtrEx()
             cursors = []
-            for i in xrange(0, uptodateness_vector.count):
+            for i in range(0, uptodateness_vector.count):
                 c = uptodateness_vector.cursors[i]
                 c1 = drsuapi.DsReplicaCursor()
                 c1.source_dsa_invocation_id = c.source_dsa_invocation_id
-- 
2.18.0


>From f3a2f619112bcb98516a6582f131afb99ff76e8a Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Fri, 15 Jun 2018 16:26:28 +0100
Subject: [PATCH 20/25] s4/torure/drs/python: Fix incorrect use of unicode
 which doesn't exist in py3

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/drs/python/repl_schema.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/source4/torture/drs/python/repl_schema.py b/source4/torture/drs/python/repl_schema.py
index 89346af724d..cca19d41a05 100644
--- a/source4/torture/drs/python/repl_schema.py
+++ b/source4/torture/drs/python/repl_schema.py
@@ -43,6 +43,7 @@ from ldb import (
 from samba.dcerpc import drsuapi, misc
 from samba.drs_utils import drs_DsBind
 from samba import dsdb
+from samba.compat import text_type
 
 class DrsReplSchemaTestCase(drs_base.DrsBaseTestCase):
 
@@ -65,7 +66,7 @@ class DrsReplSchemaTestCase(drs_base.DrsBaseTestCase):
         req8.destination_dsa_guid = misc.GUID(dest_dsa) if dest_dsa else misc.GUID()
         req8.source_dsa_invocation_id = misc.GUID(invocation_id)
         req8.naming_context = drsuapi.DsReplicaObjectIdentifier()
-        req8.naming_context.dn = unicode(nc_dn_str)
+        req8.naming_context.dn = text_type(nc_dn_str)
         req8.highwatermark = drsuapi.DsReplicaHighWaterMark()
         req8.highwatermark.tmp_highest_usn = 0
         req8.highwatermark.reserved_usn = 0
-- 
2.18.0


>From 3d0749f10b31de172625d434b12e969b8a23981e Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Mon, 18 Jun 2018 18:02:01 +0100
Subject: [PATCH 21/25] python/samba/tests: various py3 porting for ord/chr

various messages are lists of ints that need converting to str or bytes
depending on py2/py3, others are str/bytes that need modification and
are converted to lists or string char or ints for modificate (and then
reconstructed as str/bytes again)

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/tests/dns_base.py | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/python/samba/tests/dns_base.py b/python/samba/tests/dns_base.py
index 10c7a0a6af5..b1b3f05e434 100644
--- a/python/samba/tests/dns_base.py
+++ b/python/samba/tests/dns_base.py
@@ -27,6 +27,7 @@ import random
 import socket
 import uuid
 import time
+from samba.compat import binary_type
 
 class DNSTest(TestCaseInTempDir):
 
@@ -163,7 +164,6 @@ class DNSTest(TestCaseInTempDir):
         # unpacking and packing again should produce same bytestream
         my_packet = ndr.ndr_pack(response)
         self.assertEquals(my_packet, recv_packet[2:])
-
         return (response, recv_packet[2:])
 
     def make_txt_update(self, prefix, txt_array):
@@ -262,7 +262,7 @@ class DNSTKeyTest(DNSTest):
         (finished, server_to_client) = self.g.update(client_to_server)
         self.assertFalse(finished)
 
-        data = [ord(x) for x in list(server_to_client)]
+        data = [x if isinstance(x, int) else ord(x) for x in list(server_to_client)]
         rdata.key_data = data
         rdata.key_size = len(data)
         r.rdata = rdata
@@ -275,28 +275,34 @@ class DNSTKeyTest(DNSTest):
         self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
 
         tkey_record = response.answers[0].rdata
-        data = [chr(x) for x in tkey_record.key_data]
-        server_to_client = ''.join(data)
+        server_to_client = binary_type(bytearray(tkey_record.key_data))
         (finished, client_to_server) = self.g.update(server_to_client)
         self.assertTrue(finished)
 
         self.verify_packet(response, response_packet)
 
-    def verify_packet(self, response, response_packet, request_mac=""):
+    def verify_packet(self, response, response_packet, request_mac=b""):
         self.assertEqual(response.additional[0].rr_type, dns.DNS_QTYPE_TSIG)
 
         tsig_record = response.additional[0].rdata
-        mac = ''.join([chr(x) for x in tsig_record.mac])
+        mac = binary_type(bytearray(tsig_record.mac))
 
         # Cut off tsig record from dns response packet for MAC verification
         # and reset additional record count.
         key_name_len = len(self.key_name) + 2
         tsig_record_len = len(ndr.ndr_pack(tsig_record)) + key_name_len + 10
 
-        response_packet_list = list(response_packet)
+        # convert str/bytes to a list (of string char or int)
+        # so it can be modified
+        response_packet_list = [x if isinstance(x, int) else ord(x) for x in response_packet]
         del response_packet_list[-tsig_record_len:]
-        response_packet_list[11] = chr(0)
-        response_packet_wo_tsig = ''.join(response_packet_list)
+        if isinstance(response_packet_list[11], int):
+            response_packet_list[11] = 0
+        else:
+            response_packet_list[11] = chr(0)
+
+        # convert modified list (of string char or int) to str/bytes
+        response_packet_wo_tsig = binary_type(bytearray(response_packet_list))
 
         fake_tsig = dns.fake_tsig_rec()
         fake_tsig.name = self.key_name
@@ -331,7 +337,7 @@ class DNSTKeyTest(DNSTest):
 
         data = packet_data + fake_tsig_packet
         mac = self.g.sign_packet(data, data)
-        mac_list = [ord(x) for x in list(mac)]
+        mac_list = [x if isinstance(x, int) else ord(x) for x in list(mac)]
 
         rdata = dns.tsig_record()
         rdata.algorithm_name = "gss-tsig"
@@ -362,7 +368,7 @@ class DNSTKeyTest(DNSTest):
         '''Add bad signature for a packet by bitflipping
         the final byte in the MAC'''
 
-        mac_list = [ord(x) for x in list("badmac")]
+        mac_list = [x if isinstance(x, int) else ord(x) for x in list("badmac")]
 
         rdata = dns.tsig_record()
         rdata.algorithm_name = "gss-tsig"
-- 
2.18.0


>From b2e00469b13d82e9bfa3e9c9e741d065415abc17 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Tue, 19 Jun 2018 11:22:50 +0100
Subject: [PATCH 22/25] python/samba/kcc: md5 needs to be passed bytes in py3

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/kcc/__init__.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/python/samba/kcc/__init__.py b/python/samba/kcc/__init__.py
index 1b22bf73a9f..dcb65979310 100644
--- a/python/samba/kcc/__init__.py
+++ b/python/samba/kcc/__init__.py
@@ -44,6 +44,7 @@ from samba.kcc.graph import Vertex
 
 from samba.kcc.debug import DEBUG, DEBUG_FN, logger
 from samba.kcc import debug
+from samba.compat import text_type
 
 
 def sort_dsa_by_gc_and_guid(dsa1, dsa2):
@@ -2586,7 +2587,10 @@ class KCC(object):
                 dot_colours = []
                 for link in self.sitelink_table.values():
                     from hashlib import md5
-                    colour = '#' + md5(link.dnstr).hexdigest()[:6]
+                    tmp_str = link.dnstr
+                    if isinstance(tmp_str, text_type):
+                        tmp_str = tmp_str.encode('utf8')
+                    colour = '#' + md5(tmp_str).hexdigest()[:6]
                     for a, b in itertools.combinations(link.site_list, 2):
                         dot_edges.append((a[1], b[1]))
                         dot_colours.append(colour)
-- 
2.18.0


>From 13a892c68fa4e420a2013a675c36558542467dfb Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Tue, 19 Jun 2018 12:27:24 +0100
Subject: [PATCH 23/25] python/samba/tests: Another exception tuple py2/py3
 compat change

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/tests/netlogonsvc.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/python/samba/tests/netlogonsvc.py b/python/samba/tests/netlogonsvc.py
index 87afa3e233e..3dac66c71cc 100644
--- a/python/samba/tests/netlogonsvc.py
+++ b/python/samba/tests/netlogonsvc.py
@@ -57,7 +57,7 @@ class NetlogonServiceTests(TestCase):
         except NTSTATUSError as e:
             # On non-DC test environments, netlogon should not be running on
             # the server, so we expect the test to fail here
-            enum = ctypes.c_uint32(e[0]).value
+            enum = ctypes.c_uint32(e.args[0]).value
             if enum == ntstatus.NT_STATUS_OBJECT_NAME_NOT_FOUND:
                 self.fail("netlogon service is not running")
             else:
-- 
2.18.0


>From 04a00d0f3ffa954e17a88a8565d1cfdcbb76cbbe Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Tue, 19 Jun 2018 13:14:17 +0100
Subject: [PATCH 24/25] python/samba/tests: some more exception tuple py2/py3
 issues

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/netcmd/domain.py      | 14 +++++++-------
 python/samba/tests/net_join.py     |  2 +-
 python/samba/tests/ntlmdisabled.py |  4 ++--
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py
index 2fb96d143c5..3b133645bea 100644
--- a/python/samba/netcmd/domain.py
+++ b/python/samba/netcmd/domain.py
@@ -1715,7 +1715,7 @@ class DomainTrustCommand(Command):
         if runtime is None:
             return False
 
-        err32 = self._uint32(runtime[0])
+        err32 = self._uint32(runtime.args[0])
         if err32 == val:
             return True
 
@@ -1723,24 +1723,24 @@ class DomainTrustCommand(Command):
 
     class LocalRuntimeError(CommandError):
         def __init__(exception_self, self, runtime, message):
-            err32 = self._uint32(runtime[0])
-            errstr = runtime[1]
+            err32 = self._uint32(runtime.args[0])
+            errstr = runtime.args[1]
             msg = "LOCAL_DC[%s]: %s - ERROR(0x%08X) - %s" % (
                   self.local_server, message, err32, errstr)
             CommandError.__init__(exception_self, msg)
 
     class RemoteRuntimeError(CommandError):
         def __init__(exception_self, self, runtime, message):
-            err32 = self._uint32(runtime[0])
-            errstr = runtime[1]
+            err32 = self._uint32(runtime.args[0])
+            errstr = runtime.args[1]
             msg = "REMOTE_DC[%s]: %s - ERROR(0x%08X) - %s" % (
                   self.remote_server, message, err32, errstr)
             CommandError.__init__(exception_self, msg)
 
     class LocalLdbError(CommandError):
         def __init__(exception_self, self, ldb_error, message):
-            errval = ldb_error[0]
-            errstr = ldb_error[1]
+            errval = ldb_error.args[0]
+            errstr = ldb_error.args[1]
             msg = "LOCAL_DC[%s]: %s - ERROR(%d) - %s" % (
                   self.local_server, message, errval, errstr)
             CommandError.__init__(exception_self, msg)
diff --git a/python/samba/tests/net_join.py b/python/samba/tests/net_join.py
index daba2d2e3bc..41220280e62 100644
--- a/python/samba/tests/net_join.py
+++ b/python/samba/tests/net_join.py
@@ -57,7 +57,7 @@ class NetJoinTests(samba.tests.TestCaseInTempDir):
                 self.domain, netbios_name, LIBNET_JOIN_AUTOMATIC,
                 machinepass=machinepass)
         except NTSTATUSError as e:
-            code = ctypes.c_uint32(e[0]).value
+            code = ctypes.c_uint32(e.args[0]).value
             if code == ntstatus.NT_STATUS_CONNECTION_DISCONNECTED:
                 self.fail("Connection failure")
             raise
diff --git a/python/samba/tests/ntlmdisabled.py b/python/samba/tests/ntlmdisabled.py
index 90341a5cee3..dadebb327f5 100644
--- a/python/samba/tests/ntlmdisabled.py
+++ b/python/samba/tests/ntlmdisabled.py
@@ -56,7 +56,7 @@ class NtlmDisabledTests(TestCase):
             self.assertIsNotNone(conn)
         except NTSTATUSError as e:
             # NTLM might be blocked on this server
-            enum = ctypes.c_uint32(e[0]).value
+            enum = ctypes.c_uint32(e.args[0]).value
             if enum == ntstatus.NT_STATUS_NTLM_BLOCKED:
                 self.fail("NTLM is disabled on this server")
             else:
@@ -77,7 +77,7 @@ class NtlmDisabledTests(TestCase):
             conn.ChangePasswordUser2(server, username, None, None, True, None, None)
         except NTSTATUSError as e:
             # changing passwords should be rejected when NTLM is disabled
-            enum = ctypes.c_uint32(e[0]).value
+            enum = ctypes.c_uint32(e.args[0]).value
             if enum == ntstatus.NT_STATUS_NTLM_BLOCKED:
                 self.fail("NTLM is disabled on this server")
             elif enum == ntstatus.NT_STATUS_WRONG_PASSWORD:
-- 
2.18.0


>From 7fa0b4128f766ac28c97eb296c12e9aa43ed9747 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Wed, 27 Jun 2018 12:01:18 +0100
Subject: [PATCH 25/25] python/samba/netcmd: Fix wrong exception referenced in
 code

post commit: 52729d35495db638c84caa8cc6f5ffdf0b670353 wrong
exception name was referenced.

Signed-off-by: Noel Power <noel.power at suse.com>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 python/samba/netcmd/domain.py | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py
index 3b133645bea..555462c9615 100644
--- a/python/samba/netcmd/domain.py
+++ b/python/samba/netcmd/domain.py
@@ -821,7 +821,10 @@ class cmd_domain_demote(Command):
                             controls=["search_options:1:2"])
 
         if len(res) != 0:
-            raise CommandError("Current DC is still the owner of %d role(s), use the role command to transfer roles to another DC" % len(res))
+            raise CommandError("Current DC is still the owner of %d role(s), "
+                               "use the role command to transfer roles to "
+                               "another DC" %
+                               len(res))
 
         self.errf.write("Using %s as partner server for the demotion\n" %
                         server)
@@ -1012,9 +1015,13 @@ class cmd_domain_demote(Command):
             remote_samdb.modify(msg)
             remote_samdb.rename(newdn, dc_dn)
             if werr == werror.WERR_DS_DRA_NO_REPLICA:
-                raise CommandError("The DC %s is not present on (already removed from) the remote server: " % server_dsa_dn, e)
+                raise CommandError("The DC %s is not present on (already "
+                                   "removed from) the remote server: %s" %
+                                   (server_dsa_dn, e3))
             else:
-                raise CommandError("Error while sending a removeDsServer of %s: " % server_dsa_dn, e)
+                raise CommandError("Error while sending a removeDsServer "
+                                   "of %s: %s" %
+                                   (server_dsa_dn, e3))
 
         remove_dc.remove_sysvol_references(remote_samdb, logger, dc_name)
 
-- 
2.18.0



More information about the samba-technical mailing list