[SCM] Samba Shared Repository - branch master updated
Garming Sam
garming at samba.org
Wed Dec 21 03:38:02 UTC 2016
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 <garming at catalyst.net.nz>
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 <garming at catalyst.net.nz>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
Autobuild-User(master): Garming Sam <garming at samba.org>
Autobuild-Date(master): Wed Dec 21 04:37:54 CET 2016 on sn-devel-144
commit 56314211439b281647a2f11e7a94bd874a5df337
Author: Bob Campbell <bobcampbell at catalyst.net.nz>
Date: Mon Dec 19 12:27:31 2016 +1300
torture/drs: test link replication with hwm and utdv
Signed-off-by: Bob Campbell <bobcampbell at catalyst.net.nz>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
commit e130c46e87a9dbda51a6ca7611f8bc4887ea6c7f
Author: Bob Campbell <bobcampbell at catalyst.net.nz>
Date: Thu Dec 15 14:23:58 2016 +1300
torture/drs: move ExopBaseTest into DrsBaseTest and extend
Signed-off-by: Bob Campbell <bobcampbell at catalyst.net.nz>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
-----------------------------------------------------------------------
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 <kamenim at samba.org> 2011
+# Copyright (C) Andrew Bartlett <abartlet at samba.org> 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
More information about the samba-cvs
mailing list