[SCM] Samba Shared Repository - branch master updated

[email protected] (Garming Sam)
Newsgroups gmane.network.samba.cvs
Message-ID <[email protected]>
The branch, master has been updated
       via  c94f824 getncchanges: use the uptodateness_vector to filter links to replicate
       via  5631421 torture/drs: test link replication with hwm and utdv
       via  e130c46 torture/drs: move ExopBaseTest into DrsBaseTest and extend
      from  8989725 s3-rpc_client: Pass NULL as no password

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit c94f82417035c8fdae9bb2631162798ba167e6b6
Author: Garming Sam <[email protected]>
Date:   Wed Dec 14 16:05:05 2016 +1300

    getncchanges: use the uptodateness_vector to filter links to replicate
    
    This is to mirror the check in get_nc_changes_build_object.
    
    Signed-off-by: Garming Sam <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>
    
    Autobuild-User(master): Garming Sam <[email protected]>
    Autobuild-Date(master): Wed Dec 21 04:37:54 CET 2016 on sn-devel-144

commit 56314211439b281647a2f11e7a94bd874a5df337
Author: Bob Campbell <[email protected]>
Date:   Mon Dec 19 12:27:31 2016 +1300

    torture/drs: test link replication with hwm and utdv
    
    Signed-off-by: Bob Campbell <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>

commit e130c46e87a9dbda51a6ca7611f8bc4887ea6c7f
Author: Bob Campbell <[email protected]>
Date:   Thu Dec 15 14:23:58 2016 +1300

    torture/drs: move ExopBaseTest into DrsBaseTest and extend
    
    Signed-off-by: Bob Campbell <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>

-----------------------------------------------------------------------

Summary of changes:
 source4/rpc_server/drsuapi/getncchanges.c          |  19 +-
 source4/torture/drs/python/drs_base.py             | 324 ++++++++++++++++++++-
 source4/torture/drs/python/getnc_exop.py           | 198 ++++++++-----
 .../torture/drs/python/linked_attributes_drs.py    |  40 +--
 source4/torture/drs/python/ridalloc_exop.py        |  40 +--
 5 files changed, 476 insertions(+), 145 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c
index 70ec04c..705c8cf 100644
--- a/source4/rpc_server/drsuapi/getncchanges.c
+++ b/source4/rpc_server/drsuapi/getncchanges.c
@@ -605,8 +605,10 @@ static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx,
 		for (j=0; j<el->num_values; j++) {
 			struct dsdb_dn *dsdb_dn;
 			uint64_t local_usn;
-			NTSTATUS status;
+			uint64_t originating_usn;
+			NTSTATUS status, status2;
 			WERROR werr;
+			struct GUID originating_invocation_id;
 
 			dsdb_dn = dsdb_dn_parse(tmp_ctx, sam_ctx, &el->values[j], sa->syntax->ldap_oid);
 			if (dsdb_dn == NULL) {
@@ -635,6 +637,21 @@ static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx,
 				continue;
 			}
 
+			status = dsdb_get_extended_dn_guid(dsdb_dn->dn,
+							   &originating_invocation_id,
+							   "RMD_INVOCID");
+			status2 = dsdb_get_extended_dn_uint64(dsdb_dn->dn,
+							      &originating_usn,
+							      "RMD_ORIGINATING_USN");
+
+			if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2)) {
+				if (udv_filter(uptodateness_vector,
+					       &originating_invocation_id,
+					       originating_usn)) {
+					continue;
+				}
+			}
+
 			werr = get_nc_changes_add_la(mem_ctx, sam_ctx, schema,
 						     sa, msg, dsdb_dn, la_list,
 						     la_count, is_schema_nc);
diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index aa0a7f6..e6f6e48 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -3,6 +3,8 @@
 #
 # Unix SMB/CIFS implementation.
 # Copyright (C) Kamen Mazdrashki <[email protected]> 2011
+# Copyright (C) Andrew Bartlett <[email protected]> 2016
+# Copyright (C) Catalyst IT Ltd. 2016
 #
 # 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
@@ -18,15 +20,18 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-
 import sys
 import time
 import os
+import ldb
 
 sys.path.insert(0, "bin/python")
 import samba.tests
 from samba.tests.samba_tool.base import SambaToolCmdTest
 from samba import dsdb
+from samba.dcerpc import drsuapi, misc, drsblobs, security
+from samba.ndr import ndr_unpack, ndr_pack
+from samba.drs_utils import drs_DsBind
 
 from ldb import (
     SCOPE_BASE,
@@ -143,3 +148,320 @@ class DrsBaseTestCase(SambaToolCmdTest):
         # disable replication
         self.check_run("%s %s --dsa-option=+DISABLE_INBOUND_REPL" %(samba_tool_cmd, DC))
         self.check_run("%s %s --dsa-option=+DISABLE_OUTBOUND_REPL" %(samba_tool_cmd, DC))
+
+    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.reserved_usn = 0
+        hwm.highest_usn = hwm.tmp_highest_usn
+
+        utdv = drsuapi.DsReplicaCursorCtrEx()
+        cursors = []
+        c1 = drsuapi.DsReplicaCursor()
+        c1.source_dsa_invocation_id = misc.GUID(ldb_conn.get_invocation_id())
+        c1.highest_usn = hwm.highest_usn
+        cursors.append(c1)
+        utdv.count = len(cursors)
+        utdv.cursors = cursors
+        return (hwm, utdv)
+
+    def _get_indentifier(self, ldb_conn, dn):
+        res = ldb_conn.search(dn, scope=ldb.SCOPE_BASE,
+                attrs=["objectGUID", "objectSid"])
+        id = drsuapi.DsReplicaObjectIdentifier()
+        id.guid = ndr_unpack(misc.GUID, res[0]['objectGUID'][0])
+        if "objectSid" in res[0]:
+            id.sid = ndr_unpack(security.dom_sid, res[0]['objectSid'][0])
+        id.dn = str(res[0].dn)
+        return id
+
+    def _check_replication(self, expected_dns, replica_flags, expected_links=[],
+                           drs_error=drsuapi.DRSUAPI_EXOP_ERR_NONE, drs=None, drs_handle=None,
+                           highwatermark=None, uptodateness_vector=None,
+                           more_flags=0, more_data=False,
+                           dn_ordered=True, links_ordered=True,
+                           max_objects=133, exop=0,
+                           dest_dsa=drsuapi.DRSUAPI_DS_BIND_GUID_W2K3,
+                           source_dsa=None, invocation_id=None, nc_dn_str=None,
+                           nc_object_count=0, nc_linked_attributes_count=0):
+        """
+        Makes sure that replication returns the specific error given.
+        """
+        if source_dsa is None:
+            source_dsa = self.ldb_dc1.get_ntds_GUID()
+        if invocation_id is None:
+            invocation_id = self.ldb_dc1.get_invocation_id()
+        if nc_dn_str is None:
+            nc_dn_str = self.ldb_dc1.domain_dn()
+
+        if highwatermark is None:
+            if self.default_hwm is None:
+                (highwatermark, _) = self._get_highest_hwm_utdv(self.ldb_dc1)
+            else:
+                highwatermark = self.default_hwm
+
+        if drs is None:
+            drs = self.drs
+        if drs_handle is None:
+            drs_handle = self.drs_handle
+
+        req10 = self._getnc_req10(dest_dsa=dest_dsa,
+                                  invocation_id=invocation_id,
+                                  nc_dn_str=nc_dn_str,
+                                  exop=exop,
+                                  max_objects=max_objects,
+                                  replica_flags=replica_flags)
+        req10.highwatermark = highwatermark
+        if uptodateness_vector is not None:
+            uptodateness_vector_v1 = drsuapi.DsReplicaCursorCtrEx()
+            cursors = []
+            for i in xrange(0, uptodateness_vector.count):
+                c = uptodateness_vector.cursors[i]
+                c1 = drsuapi.DsReplicaCursor()
+                c1.source_dsa_invocation_id = c.source_dsa_invocation_id
+                c1.highest_usn = c.highest_usn
+                cursors.append(c1)
+            uptodateness_vector_v1.count = len(cursors)
+            uptodateness_vector_v1.cursors = cursors
+            req10.uptodateness_vector = uptodateness_vector_v1
+        (level, ctr) = drs.DsGetNCChanges(drs_handle, 10, req10)
+
+        self.assertEqual(level, 6, "expected level 6 response!")
+        self.assertEqual(ctr.source_dsa_guid, misc.GUID(source_dsa))
+        self.assertEqual(ctr.source_dsa_invocation_id, misc.GUID(invocation_id))
+        ctr6 = ctr
+        self.assertEqual(ctr6.extended_ret, drs_error)
+        self._check_ctr6(ctr6, expected_dns, expected_links,
+                         nc_object_count=nc_object_count)
+        return (ctr6.new_highwatermark, ctr6.uptodateness_vector)
+
+    def _check_ctr6(self, ctr6, expected_dns=[], expected_links=[],
+                    dn_ordered=True, links_ordered=True,
+                    more_data=False, nc_object_count=0,
+                    nc_linked_attributes_count=0, drs_error=0):
+        """
+        Check that a ctr6 matches the specified parameters.
+        """
+        self.assertEqual(ctr6.object_count, len(expected_dns))
+        self.assertEqual(ctr6.linked_attributes_count, len(expected_links))
+        self.assertEqual(ctr6.more_data, more_data)
+        self.assertEqual(ctr6.nc_object_count, nc_object_count)
+        self.assertEqual(ctr6.nc_linked_attributes_count, nc_linked_attributes_count)
+        self.assertEqual(ctr6.drs_error[0], drs_error)
+
+        ctr6_dns = []
+        next_object = ctr6.first_object
+        for i in range(0, ctr6.object_count):
+            ctr6_dns.append(next_object.object.identifier.dn)
+            next_object = next_object.next_object
+        self.assertEqual(next_object, None)
+
+        i = 0
+        for dn in expected_dns:
+            # Expect them back in the exact same order as specified.
+            if dn_ordered:
+                self.assertNotEqual(ctr6_dns[i], None)
+                self.assertEqual(ctr6_dns[i], dn)
+                i = i + 1
+            # Don't care what order
+            else:
+                self.assertTrue(dn in ctr6_dns, "Couldn't find DN '%s' anywhere in ctr6 response." % dn)
+
+        ctr6_links = []
+        expected_links.sort()
+        lidx = 0
+        for lidx in range(0, ctr6.linked_attributes_count):
+            l = ctr6.linked_attributes[lidx]
+            try:
+                target = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3,
+                                    l.value.blob)
+            except:
+                target = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3Binary,
+                                    l.value.blob)
+            al = AbstractLink(l.attid, l.flags,
+                              l.identifier.guid,
+                              target.guid)
+            ctr6_links.append(al)
+
+        lidx = 0
+        for el in expected_links:
+            if links_ordered:
+                self.assertEqual(el, ctr6_links[lidx])
+                lidx += 1
+            else:
+                self.assertTrue(el in ctr6_links, "Couldn't find link '%s' anywhere in ctr6 response." % el)
+
+    def _exop_req8(self, dest_dsa, invocation_id, nc_dn_str, exop,
+                   replica_flags=0, max_objects=0, partial_attribute_set=None,
+                   partial_attribute_set_ex=None, mapping_ctr=None):
+        req8 = drsuapi.DsGetNCChangesRequest8()
+
+        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.highwatermark = drsuapi.DsReplicaHighWaterMark()
+        req8.highwatermark.tmp_highest_usn = 0
+        req8.highwatermark.reserved_usn = 0
+        req8.highwatermark.highest_usn = 0
+        req8.uptodateness_vector = None
+        req8.replica_flags = replica_flags
+        req8.max_object_count = max_objects
+        req8.max_ndr_size = 402116
+        req8.extended_op = exop
+        req8.fsmo_info = 0
+        req8.partial_attribute_set = partial_attribute_set
+        req8.partial_attribute_set_ex = partial_attribute_set_ex
+        if mapping_ctr:
+            req8.mapping_ctr = mapping_ctr
+        else:
+            req8.mapping_ctr.num_mappings = 0
+            req8.mapping_ctr.mappings = None
+
+        return req8
+
+    def _getnc_req10(self, dest_dsa, invocation_id, nc_dn_str, exop,
+                     replica_flags=0, max_objects=0, partial_attribute_set=None,
+                     partial_attribute_set_ex=None, mapping_ctr=None,
+                     more_flags=0):
+        req10 = drsuapi.DsGetNCChangesRequest10()
+
+        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.highwatermark = drsuapi.DsReplicaHighWaterMark()
+        req10.highwatermark.tmp_highest_usn = 0
+        req10.highwatermark.reserved_usn = 0
+        req10.highwatermark.highest_usn = 0
+        req10.uptodateness_vector = None
+        req10.replica_flags = replica_flags
+        req10.max_object_count = max_objects
+        req10.max_ndr_size = 402116
+        req10.extended_op = exop
+        req10.fsmo_info = 0
+        req10.partial_attribute_set = partial_attribute_set
+        req10.partial_attribute_set_ex = partial_attribute_set_ex
+        if mapping_ctr:
+            req10.mapping_ctr = mapping_ctr
+        else:
+            req10.mapping_ctr.num_mappings = 0
+            req10.mapping_ctr.mappings = None
+        req10.more_flags = more_flags
+
+        return req10
+
+    def _ds_bind(self, server_name):
+        binding_str = "ncacn_ip_tcp:%s[seal]" % server_name
+
+        drs = drsuapi.drsuapi(binding_str, self.get_loadparm(), self.get_credentials())
+        (drs_handle, supported_extensions) = drs_DsBind(drs)
+        return (drs, drs_handle)
+
+
+class AbstractLink:
+    def __init__(self, attid, flags, identifier, targetGUID):
+        self.attid = attid
+        self.flags = flags
+        self.identifier = str(identifier)
+        self.selfGUID_blob = ndr_pack(identifier)
+        self.targetGUID = str(targetGUID)
+        self.targetGUID_blob = ndr_pack(targetGUID)
+
+    def __repr__(self):
+        return "AbstractLink(0x%08x, 0x%08x, %s, %s)" % (
+                self.attid, self.flags, self.identifier, self.targetGUID)
+
+    def __internal_cmp__(self, other, verbose=False):
+        """See CompareLinks() in MS-DRSR section 4.1.10.5.17"""
+        if not isinstance(other, AbstractLink):
+            if verbose:
+                print "AbstractLink.__internal_cmp__(%r, %r) => wrong type" % (self, other)
+            return NotImplemented
+
+        c = cmp(self.selfGUID_blob, other.selfGUID_blob)
+        if c != 0:
+            if verbose:
+                print "AbstractLink.__internal_cmp__(%r, %r) => %d different identifier" % (self, other, c)
+            return c
+
+        c = other.attid - self.attid
+        if c != 0:
+            if verbose:
+                print "AbstractLink.__internal_cmp__(%r, %r) => %d different attid" % (self, other, c)
+            return c
+
+        self_active = self.flags & drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
+        other_active = other.flags & drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
+
+        c = self_active - other_active
+        if c != 0:
+            if verbose:
+                print "AbstractLink.__internal_cmp__(%r, %r) => %d different FLAG_ACTIVE" % (self, other, c)
+            return c
+
+        c = cmp(self.targetGUID_blob, other.targetGUID_blob)
+        if c != 0:
+            if verbose:
+                print "AbstractLink.__internal_cmp__(%r, %r) => %d different target" % (self, other, c)
+            return c
+
+        c = self.flags - other.flags
+        if c != 0:
+            if verbose:
+                print "AbstractLink.__internal_cmp__(%r, %r) => %d different flags" % (self, other, c)
+            return c
+
+        return 0
+
+    def __lt__(self, other):
+        c = self.__internal_cmp__(other)
+        if c == NotImplemented:
+            return NotImplemented
+        if c < 0:
+            return True
+        return False
+
+    def __le__(self, other):
+        c = self.__internal_cmp__(other)
+        if c == NotImplemented:
+            return NotImplemented
+        if c <= 0:
+            return True
+        return False
+
+    def __eq__(self, other):
+        c = self.__internal_cmp__(other, verbose=True)
+        if c == NotImplemented:
+            return NotImplemented
+        if c == 0:
+            return True
+        return False
+
+    def __ne__(self, other):
+        c = self.__internal_cmp__(other)
+        if c == NotImplemented:
+            return NotImplemented
+        if c != 0:
+            return True
+        return False
+
+    def __gt__(self, other):
+        c = self.__internal_cmp__(other)
+        if c == NotImplemented:
+            return NotImplemented
+        if c > 0:
+            return True
+        return False
+
+    def __ge__(self, other):
+        c = self.__internal_cmp__(other)
+        if c == NotImplemented:
+            return NotImplemented
+        if c >= 0:
+            return True
+        return False
+
+    def __hash__(self):
+        return hash((self.attid, self.flags, self.identifier, self.targetGUID))
diff --git a/source4/torture/drs/python/getnc_exop.py b/source4/torture/drs/python/getnc_exop.py
index 246d859..d9e06f2 100644
--- a/source4/torture/drs/python/getnc_exop.py
+++ b/source4/torture/drs/python/getnc_exop.py
@@ -28,7 +28,11 @@
 #  PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN getnc_exop -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
 #
 
+import random
+
 import drs_base
+from drs_base import AbstractLink
+
 import samba.tests
 
 import ldb
@@ -62,60 +66,8 @@ def _linked_attribute_compare(la1, la2):
     # Ascending target object GUID
     return cmp(ndr_pack(la1_target), ndr_pack(la2_target))
 
-class AbstractLink:
-    def __init__(self, attid, flags, identifier, targetGUID):
-        self.attid = attid
-        self.flags = flags
-        self.identifier = identifier
-        self.targetGUID = targetGUID
-
-    def __eq__(self, other):
-        return isinstance(other, AbstractLink) and \
-            ((self.attid, self.flags, self.identifier, self.targetGUID) ==
-             (other.attid, other.flags, other.identifier, other.targetGUID))
-
-    def __hash__(self):
-        return hash((self.attid, self.flags, self.identifier, self.targetGUID))
-
-class ExopBaseTest:
-    def _exop_req8(self, dest_dsa, invocation_id, nc_dn_str, exop,
-                   replica_flags=0, max_objects=0, partial_attribute_set=None,
-                   partial_attribute_set_ex=None, mapping_ctr=None):
-        req8 = drsuapi.DsGetNCChangesRequest8()
-
-        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.highwatermark = drsuapi.DsReplicaHighWaterMark()
-        req8.highwatermark.tmp_highest_usn = 0
-        req8.highwatermark.reserved_usn = 0
-        req8.highwatermark.highest_usn = 0
-        req8.uptodateness_vector = None
-        req8.replica_flags = replica_flags
-        req8.max_object_count = max_objects
-        req8.max_ndr_size = 402116
-        req8.extended_op = exop
-        req8.fsmo_info = 0
-        req8.partial_attribute_set = partial_attribute_set
-        req8.partial_attribute_set_ex = partial_attribute_set_ex
-        if mapping_ctr:
-            req8.mapping_ctr = mapping_ctr
-        else:
-            req8.mapping_ctr.num_mappings = 0
-            req8.mapping_ctr.mappings = None
-
-        return req8
-
-    def _ds_bind(self, server_name):
-        binding_str = "ncacn_ip_tcp:%s[seal]" % server_name
-
-        drs = drsuapi.drsuapi(binding_str, self.get_loadparm(), self.get_credentials())
-        (drs_handle, supported_extensions) = drs_DsBind(drs)
-        return (drs, drs_handle)
-
 
-class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase, ExopBaseTest):
+class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
     """Intended as a semi-black box test case for DsGetNCChanges
        implementation for extended operations. It should be testing
        how DsGetNCChanges handles different input params (mostly invalid).
@@ -124,8 +76,20 @@ class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase, ExopBaseTest):
 
     def setUp(self):
         super(DrsReplicaSyncTestCase, self).setUp()
+        self.base_dn = self.ldb_dc1.get_default_basedn()
+        self.ou = "OU=test_getncchanges,%s" % self.base_dn
+        self.ldb_dc1.add({
+            "dn": self.ou,
+            "objectclass": "organizationalUnit"})
+        (self.drs, self.drs_handle) = self._ds_bind(self.dnsname_dc1)
+        (self.default_hwm, self.default_utdv) = self._get_highest_hwm_utdv(self.ldb_dc1)
 
     def tearDown(self):
+        try:
+            self.ldb_dc1.delete(self.ou, ["tree_delete:1"])
+        except ldb.LdbError as (enum, string):
+            if enum == ldb.ERR_NO_SUCH_OBJECT:
+                pass
         super(DrsReplicaSyncTestCase, self).tearDown()
 
     def _determine_fSMORoleOwner(self, fsmo_obj_dn):
@@ -170,6 +134,106 @@ class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase, ExopBaseTest):
         self.assertEqual(ctr6.linked_attributes, [])
         self.assertEqual(ctr6.drs_error[0], 0)
 
+    def test_link_utdv_hwm(self):
+        ou1 = "OU=get_anc1,%s" % self.ou
+        self.ldb_dc1.add({
+            "dn": ou1,
+            "objectclass": "organizationalUnit"


-- 
Samba Shared Repository
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.