[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Fri Jun 17 16:14:03 UTC 2016


The branch, master has been updated
       via  61cb3a6 lib/ldb-samba: We can confirm a GUID is a GUID by length
       via  0fc95c1 selftest: Do not run local.ndr 3 times
       via  0c0b898 flapping: remove samba_dnsupdate from flapping
       via  a896a92 repl: Avoid excessive stack use and instead sort the links in the heap
       via  8dc3110 getncchanges: Match Windows on linked attribute sort
       via  570237f getncchanges: sort with precalculated target guid array
       via  2ce9f24 getncchanges: remove some whitespace
       via  2bb8e18 tests/drs: change sort order in tests to match Windows
       via  4de5e7d tests/drs: assert sorted identifier GUIDs across getncchanges
       via  3f0be46 tests/drs: make cleanup more robust
       via  ed6a423 tests/drs: extend getnc_exop test to check linked attributes
      from  d2ebe2d libnet: only create local private krb5.conf if joining an AD domain

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


- Log -----------------------------------------------------------------
commit 61cb3a6a3b948b2c1768d29236a59c3620fc4331
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Jun 15 15:42:18 2016 +1200

    lib/ldb-samba: We can confirm a GUID is a GUID by length
    
    The GUID_from_ndr_blob() is pointless and costly
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Fri Jun 17 18:13:56 CEST 2016 on sn-devel-144

commit 0fc95c12b651efbe3eb1005e42459b60780be482
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Jun 14 20:08:40 2016 +1200

    selftest: Do not run local.ndr 3 times
    
    This is already run from under source4/selftest/tests.py
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 0c0b8988f7ba1778e862a644173272ac9db3fa79
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Fri Jun 17 12:51:47 2016 +1200

    flapping: remove samba_dnsupdate from flapping
    
    nsupdate is now installed
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit a896a92444f744a89e70bfcd7e4ed55061ce4235
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Jun 13 16:41:08 2016 +1200

    repl: Avoid excessive stack use and instead sort the links in the heap
    
    The two large stack-based arrays would overflow the stack, this avoids
    a duplicate of the struct drsuapi_DsReplicaLinkedAttribute array
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 8dc3110a5f27cf2f45949cf48cb055a59dc9454e
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Thu Jun 9 17:03:18 2016 +1200

    getncchanges: Match Windows on linked attribute sort
    
    The order of linked attributes depends on comparison of the NDR packed
    GUIDs (not its struct GUID form).
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

commit 570237f0f331c3e05aac3054a98a41ab8f335738
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Tue Jun 7 11:56:49 2016 +1200

    getncchanges: sort with precalculated target guid array
    
    This avoids reparsing the linked attribute and schema refetching.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

commit 2ce9f249bb1a7c14260a9319323de0664e559fe6
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Tue Jun 7 11:57:02 2016 +1200

    getncchanges: remove some whitespace
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

commit 2bb8e183fdf7d936c0f6a0d2faa7aeacdb331ebe
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Thu Jun 9 15:54:25 2016 +1200

    tests/drs: change sort order in tests to match Windows
    
    Although we attempted to sort by GUID based on DRSR, it is actually
    sorted by the ndr packed GUID.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

commit 4de5e7da9c2e9cac1b3fe33f4ba161e2b79a9bdc
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Thu Jun 9 14:55:57 2016 +1200

    tests/drs: assert sorted identifier GUIDs across getncchanges
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

commit 3f0be46b91fe6e106b314e383fcfad2df94e3513
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Thu Jun 9 10:56:28 2016 +1200

    tests/drs: make cleanup more robust
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

commit ed6a423232f5555a2111997689802e9d15d3cecd
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Wed Jun 8 11:10:58 2016 +1200

    tests/drs: extend getnc_exop test to check linked attributes
    
    Assert that linked attributes propagate across DRS and come in a
    particular sorted order.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

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

Summary of changes:
 lib/ldb-samba/ldif_handlers.c             |   8 +-
 selftest/flapping                         |   1 -
 source3/selftest/tests.py                 |   2 +-
 source4/rpc_server/drsuapi/getncchanges.c | 179 ++++++++++++---------
 source4/torture/drs/python/getnc_exop.py  | 258 ++++++++++++++++++++++++++++--
 5 files changed, 351 insertions(+), 97 deletions(-)


Changeset truncated at 500 lines:

diff --git a/lib/ldb-samba/ldif_handlers.c b/lib/ldb-samba/ldif_handlers.c
index 87c171e..c0972a4 100644
--- a/lib/ldb-samba/ldif_handlers.c
+++ b/lib/ldb-samba/ldif_handlers.c
@@ -265,8 +265,6 @@ static bool ldif_comparision_objectGUID_isString(const struct ldb_val *v)
 static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx,
 			      const struct ldb_val *in, struct ldb_val *out)
 {
-	struct GUID guid;
-	NTSTATUS status;
 
 	if (in->length == 36 && ldif_read_objectGUID(ldb, mem_ctx, in, out) == 0) {
 		return 0;
@@ -285,13 +283,13 @@ static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx,
 	
 	(*out).length = strhex_to_str((char *)out->data, out->length,
 				      (const char *)in->data, in->length);
-	
+
 	/* Check it looks like a GUID */
-	status = GUID_from_ndr_blob(out, &guid);
-	if (!NT_STATUS_IS_OK(status)) {
+	if ((*out).length != 16) {
 		data_blob_free(out);
 		return -1;
 	}
+
 	return 0;
 }
 
diff --git a/selftest/flapping b/selftest/flapping
index 425cf8c..e5995ef 100644
--- a/selftest/flapping
+++ b/selftest/flapping
@@ -31,4 +31,3 @@
 # This test just is not reliable in finding the max search limit
 #
 ^samba4.ldap.notification.python\(.*\).__main__.LDAPNotificationTest.test_max_search
-^samba.tests.blackbox.samba_dnsupdate.* # missing nsupdate on sn-devel
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index b96df8a..f20e4ec 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -304,7 +304,7 @@ rpc = ["rpc.authcontext", "rpc.samba3.bind", "rpc.samba3.srvsvc", "rpc.samba3.sh
        "rpc.netlogon.admin",
        "rpc.schannel", "rpc.schannel2", "rpc.bench-schannel1", "rpc.schannel_anon_setpw", "rpc.join", "rpc.bind"]
 
-local = ["local.nss", "local.ndr"]
+local = ["local.nss"]
 
 idmap = [ "idmap.rfc2307" ]
 
diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c
index 6b961bc..a992c09 100644
--- a/source4/rpc_server/drsuapi/getncchanges.c
+++ b/source4/rpc_server/drsuapi/getncchanges.c
@@ -53,10 +53,17 @@ struct drsuapi_getncchanges_state {
 	struct drsuapi_DsReplicaCursor2CtrEx *final_udv;
 	struct drsuapi_DsReplicaLinkedAttribute *la_list;
 	uint32_t la_count;
-	bool la_sorted;
+	struct la_for_sorting *la_sorted;
 	uint32_t la_idx;
 };
 
+/* We must keep the GUIDs in NDR form for sorting */
+struct la_for_sorting {
+	struct drsuapi_DsReplicaLinkedAttribute *link;
+	uint8_t target_guid[16];
+        uint8_t source_guid[16];
+};
+
 static int drsuapi_DsReplicaHighWaterMark_cmp(const struct drsuapi_DsReplicaHighWaterMark *h1,
 					      const struct drsuapi_DsReplicaHighWaterMark *h2)
 {
@@ -117,13 +124,13 @@ static bool udv_filter(const struct drsuapi_DsReplicaCursorCtrEx *udv,
 {
 	const struct drsuapi_DsReplicaCursor *c;
 	if (udv == NULL) return false;
-	BINARY_ARRAY_SEARCH(udv->cursors, udv->count, source_dsa_invocation_id, 
+	BINARY_ARRAY_SEARCH(udv->cursors, udv->count, source_dsa_invocation_id,
 			    originating_invocation_id, udv_compare, c);
 	if (c && originating_usn <= c->highest_usn) {
 		return true;
 	}
 	return false;
-	
+
 }
 
 static int attid_cmp(enum drsuapi_DsAttributeId a1, enum drsuapi_DsAttributeId a2)
@@ -195,7 +202,7 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
 		}
 	}
 	obj->next_object = NULL;
-	
+
 	md_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
 	if (!md_value) {
 		/* nothing to send */
@@ -212,7 +219,7 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 		return WERR_DS_DRA_INTERNAL_ERROR;
 	}
-	
+
 	if (md.version != 1) {
 		return WERR_DS_DRA_INTERNAL_ERROR;
 	}
@@ -225,7 +232,7 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
 
 	rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn);
 	if (rdn_sa == NULL) {
-		DEBUG(0,(__location__ ": Can't find dsds_attribute for rDN %s in %s\n", 
+		DEBUG(0,(__location__ ": Can't find dsds_attribute for rDN %s in %s\n",
 			 rdn, ldb_dn_get_linearized(msg->dn)));
 		return WERR_DS_DRA_INTERNAL_ERROR;
 	}
@@ -238,7 +245,7 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
 		return WERR_NOMEM;
 	}
 	dom_sid_split_rid(NULL, &obj->object.identifier->sid, NULL, &rid);
-	
+
 	obj->meta_data_ctr->meta_data = talloc_array(obj, struct drsuapi_DsReplicaMetaData, md.ctr.ctr1.count);
 	for (n=i=0; i<md.ctr.ctr1.count; i++) {
 		const struct dsdb_attribute *sa;
@@ -255,10 +262,10 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
 
 		sa = dsdb_attribute_by_attributeID_id(schema, md.ctr.ctr1.array[i].attid);
 		if (!sa) {
-			DEBUG(0,(__location__ ": Failed to find attribute in schema for attrid %u mentioned in replPropertyMetaData of %s\n", 
-				 (unsigned int)md.ctr.ctr1.array[i].attid, 
+			DEBUG(0,(__location__ ": Failed to find attribute in schema for attrid %u mentioned in replPropertyMetaData of %s\n",
+				 (unsigned int)md.ctr.ctr1.array[i].attid,
 				 ldb_dn_get_linearized(msg->dn)));
-			return WERR_DS_DRA_INTERNAL_ERROR;		
+			return WERR_DS_DRA_INTERNAL_ERROR;
 		}
 
 		if (sa->linkID) {
@@ -281,7 +288,7 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
 		if (md.ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType &&
 		    !force_attribute &&
 		    udv_filter(uptodateness_vector,
-			       &md.ctr.ctr1.array[i].originating_invocation_id, 
+			       &md.ctr.ctr1.array[i].originating_invocation_id,
 			       md.ctr.ctr1.array[i].originating_usn)) {
 			continue;
 		}
@@ -335,7 +342,7 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
 		struct ldb_message_element *el;
 		WERROR werr;
 		const struct dsdb_attribute *sa;
-	
+
 		sa = dsdb_attribute_by_attributeID_id(schema, attids[i]);
 		if (!sa) {
 			DEBUG(0,("Unable to find attributeID %u in schema\n", attids[i]));
@@ -619,75 +626,36 @@ static WERROR get_nc_changes_udv(struct ldb_context *sam_ctx,
 			 ldb_dn_get_linearized(ncRoot_dn), ldb_errstring(sam_ctx)));
 		return WERR_DS_DRA_INTERNAL_ERROR;
 	}
-	
+
 	return WERR_OK;
 }
 
 
 /* comparison function for linked attributes - see CompareLinks() in
  * MS-DRSR section 4.1.10.5.17 */
-static int linked_attribute_compare(const struct drsuapi_DsReplicaLinkedAttribute *la1,
-				    const struct drsuapi_DsReplicaLinkedAttribute *la2,
-				    struct ldb_context *sam_ctx)
+static int linked_attribute_compare(const struct la_for_sorting *la1,
+				    const struct la_for_sorting *la2,
+				    void *opaque)
 {
 	int c;
-	WERROR werr;
-	TALLOC_CTX *tmp_ctx;
-	const struct dsdb_schema *schema;
-	const struct dsdb_attribute *schema_attrib;
-	struct dsdb_dn *dn1, *dn2;
-	struct GUID guid1, guid2;
-	NTSTATUS status;
-
-	c = GUID_compare(&la1->identifier->guid,
-			 &la2->identifier->guid);
-	if (c != 0) return c;
-
-	if (la1->attid != la2->attid) {
-		return la1->attid < la2->attid? -1:1;
+	c = memcmp(la1->source_guid,
+		   la2->source_guid, sizeof(la2->source_guid));
+	if (c != 0) {
+		return c;
 	}
 
-	if ((la1->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) !=
-	    (la2->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)) {
-		return (la1->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)? 1:-1;
+	if (la1->link->attid != la2->link->attid) {
+		return la1->link->attid < la2->link->attid? -1:1;
 	}
 
-	/* we need to get the target GUIDs to compare */
-	tmp_ctx = talloc_new(sam_ctx);
-
-	schema = dsdb_get_schema(sam_ctx, tmp_ctx);
-	schema_attrib = dsdb_attribute_by_attributeID_id(schema, la1->attid);
-
-	werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema, tmp_ctx, la1->value.blob, &dn1);
-	if (!W_ERROR_IS_OK(werr)) {
-		DEBUG(0,(__location__ ": Bad la1 blob in sort\n"));
-		talloc_free(tmp_ctx);
-		return 0;
-	}
-
-	werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema, tmp_ctx, la2->value.blob, &dn2);
-	if (!W_ERROR_IS_OK(werr)) {
-		DEBUG(0,(__location__ ": Bad la2 blob in sort\n"));
-		talloc_free(tmp_ctx);
-		return 0;
+	if ((la1->link->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) !=
+	    (la2->link->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)) {
+		return (la1->link->flags &
+			DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)? 1:-1;
 	}
 
-	status = dsdb_get_extended_dn_guid(dn1->dn, &guid1, "GUID");
-	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0,(__location__ ": Bad la1 guid in sort\n"));
-		talloc_free(tmp_ctx);
-		return 0;
-	}
-	status = dsdb_get_extended_dn_guid(dn2->dn, &guid2, "GUID");
-	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0,(__location__ ": Bad la2 guid in sort\n"));
-		talloc_free(tmp_ctx);
-		return 0;
-	}
-
-	talloc_free(tmp_ctx);
-
-	return GUID_compare(&guid1, &guid2);
+	return memcmp(la1->target_guid,
+		      la2->target_guid, sizeof(la2->target_guid));
 }
 
 struct drsuapi_changed_objects {
@@ -1627,7 +1595,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
 {
 	struct drsuapi_DsReplicaObjectIdentifier *ncRoot;
 	int ret;
-	uint32_t i;
+	uint32_t i, k;
 	struct dsdb_schema *schema;
 	struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
 	struct drsuapi_DsReplicaObjectListItemEx **currentObject;
@@ -1784,7 +1752,7 @@ allowed:
 	if (req10->replica_flags & DRSUAPI_DRS_FULL_SYNC_PACKET) {
 		/* Ignore the _in_ uptpdateness vector*/
 		req10->uptodateness_vector = NULL;
-	} 
+	}
 
 	if (GUID_all_zero(&req10->source_dsa_invocation_id)) {
 		req10->source_dsa_invocation_id = invocation_id;
@@ -1914,7 +1882,7 @@ allowed:
 	status = dcesrv_inherited_session_key(dce_call->conn, &session_key);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,(__location__ ": Failed to get session key\n"));
-		return WERR_DS_DRA_INTERNAL_ERROR;		
+		return WERR_DS_DRA_INTERNAL_ERROR;
 	}
 
 	/* 
@@ -2165,7 +2133,7 @@ allowed:
 		}
 
 		r->out.ctr->ctr6.object_count++;
-		
+
 		*currentObject = obj;
 		currentObject = &obj->next_object;
 
@@ -2231,17 +2199,76 @@ allowed:
 		r->out.ctr->ctr6.more_data = true;
 	} else {
 		/* sort the whole array the first time */
-		if (!getnc_state->la_sorted) {
-			LDB_TYPESAFE_QSORT(getnc_state->la_list, getnc_state->la_count,
-					   sam_ctx, linked_attribute_compare);
-			getnc_state->la_sorted = true;
+		if (getnc_state->la_sorted == NULL) {
+			int j;
+			struct la_for_sorting *guid_array = talloc_array(getnc_state, struct la_for_sorting, getnc_state->la_count);
+			if (guid_array == NULL) {
+				DEBUG(0, ("Out of memory allocating %u linked attributes for sorting", getnc_state->la_count));
+				return WERR_NOMEM;
+			}
+			for (j = 0; j < getnc_state->la_count; j++) {
+				/* we need to get the target GUIDs to compare */
+				struct dsdb_dn *dn;
+				const struct drsuapi_DsReplicaLinkedAttribute *la = &getnc_state->la_list[j];
+				const struct dsdb_attribute *schema_attrib;
+				const struct ldb_val *target_guid;
+				DATA_BLOB source_guid;
+				TALLOC_CTX *frame = talloc_stackframe();
+
+				schema_attrib = dsdb_attribute_by_attributeID_id(schema, la->attid);
+
+				werr = dsdb_dn_la_from_blob(sam_ctx, schema_attrib, schema, frame, la->value.blob, &dn);
+				if (!W_ERROR_IS_OK(werr)) {
+					DEBUG(0,(__location__ ": Bad la blob in sort\n"));
+					TALLOC_FREE(frame);
+					return werr;
+				}
+
+				/* Extract the target GUID in NDR form */
+				target_guid = ldb_dn_get_extended_component(dn->dn, "GUID");
+				if (target_guid == NULL
+				    || target_guid->length != sizeof(guid_array[0].target_guid)) {
+					status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+				} else {
+					/* Repack the source GUID as NDR for sorting */
+					status = GUID_to_ndr_blob(&la->identifier->guid,
+								  frame,
+								  &source_guid);
+				}
+
+				if (!NT_STATUS_IS_OK(status)
+				    || source_guid.length != sizeof(guid_array[0].source_guid)) {
+					DEBUG(0,(__location__ ": Bad la guid in sort\n"));
+					TALLOC_FREE(frame);
+					return ntstatus_to_werror(status);
+				}
+
+				guid_array[j].link = &getnc_state->la_list[j];
+				memcpy(guid_array[j].target_guid, target_guid->data,
+				       sizeof(guid_array[j].target_guid));
+				memcpy(guid_array[j].source_guid, source_guid.data,
+				       sizeof(guid_array[j].source_guid));
+				TALLOC_FREE(frame);
+			}
+
+			LDB_TYPESAFE_QSORT(guid_array, getnc_state->la_count, NULL, linked_attribute_compare);
+			getnc_state->la_sorted = guid_array;
 		}
 
 		link_count = getnc_state->la_count - getnc_state->la_idx;
 		link_count = MIN(max_links, link_count);
 
 		r->out.ctr->ctr6.linked_attributes_count = link_count;
-		r->out.ctr->ctr6.linked_attributes = getnc_state->la_list + getnc_state->la_idx;
+		r->out.ctr->ctr6.linked_attributes = talloc_array(r->out.ctr, struct drsuapi_DsReplicaLinkedAttribute, link_count);
+		if (r->out.ctr->ctr6.linked_attributes == NULL) {
+			DEBUG(0, ("Out of memory allocating %u linked attributes for output", link_count));
+			return WERR_NOMEM;
+		}
+
+		for (k = 0; k < link_count; k++) {
+			r->out.ctr->ctr6.linked_attributes[k]
+				= *getnc_state->la_sorted[getnc_state->la_idx + k].link;
+		}
 
 		getnc_state->la_idx += link_count;
 		link_given = getnc_state->la_idx;
diff --git a/source4/torture/drs/python/getnc_exop.py b/source4/torture/drs/python/getnc_exop.py
index 39875f4..ca6c443 100644
--- a/source4/torture/drs/python/getnc_exop.py
+++ b/source4/torture/drs/python/getnc_exop.py
@@ -36,26 +36,53 @@ 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
 
+def _linked_attribute_compare(la1, la2):
+    """See CompareLinks() in MS-DRSR section 4.1.10.5.17"""
+    la1, la1_target = la1
+    la2, la2_target = la2
 
-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).
-       Final goal is to make DsGetNCChanges as binary compatible to
-       Windows implementation as possible"""
+    # Ascending host object GUID
+    c = cmp(ndr_pack(la1.identifier.guid), ndr_pack(la2.identifier.guid))
+    if c != 0:
+        return c
 
-    def setUp(self):
-        super(DrsReplicaSyncTestCase, self).setUp()
+    # Ascending attribute ID
+    if la1.attid != la2.attid:
+        return -1 if la1.attid < la2.attid else 1
 
-    def tearDown(self):
-        super(DrsReplicaSyncTestCase, self).tearDown()
+    la1_active = la1.flags & drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
+    la2_active = la2.flags & drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
+
+    # Ascending 'is present'
+    if la1_active != la2_active:
+        return 1 if la1_active else -1
+
+    # 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):
+                   replica_flags=0, max_objects=0):
         req8 = drsuapi.DsGetNCChangesRequest8()
-    
-        req8.destination_dsa_guid = misc.GUID(dest_dsa)
+
+        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)
@@ -65,7 +92,7 @@ class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
         req8.highwatermark.highest_usn = 0
         req8.uptodateness_vector = None
         req8.replica_flags = replica_flags
-        req8.max_object_count = 0
+        req8.max_object_count = max_objects
         req8.max_ndr_size = 402116
         req8.extended_op = exop
         req8.fsmo_info = 0
@@ -83,6 +110,20 @@ class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
         (drs_handle, supported_extensions) = drs_DsBind(drs)
         return (drs, drs_handle)
 
+
+class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase, ExopBaseTest):
+    """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).
+       Final goal is to make DsGetNCChanges as binary compatible to
+       Windows implementation as possible"""
+
+    def setUp(self):
+        super(DrsReplicaSyncTestCase, self).setUp()
+
+    def tearDown(self):
+        super(DrsReplicaSyncTestCase, self).tearDown()
+
     def _determine_fSMORoleOwner(self, fsmo_obj_dn):
         """Returns (owner, not_owner) pair where:
              owner: dns name for FSMO owner
@@ -243,3 +284,192 @@ class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
         self.assertEqual(ctr6.drs_error[0], 0)
         # We don't check the linked_attributes_count as if the domain
         # has an RODC, it can gain links on the server account object
+
+class DrsReplicaSyncSortTestCase(drs_base.DrsBaseTestCase, ExopBaseTest):
+    def setUp(self):
+        super(DrsReplicaSyncSortTestCase, self).setUp()
+        self.base_dn = self.ldb_dc1.get_default_basedn()
+        self.ou = "ou=sort_exop,%s" % self.base_dn
+        self.ldb_dc1.add({
+            "dn": self.ou,
+            "objectclass": "organizationalUnit"})
+
+    def tearDown(self):
+        super(DrsReplicaSyncSortTestCase, self).tearDown()
+        # tidyup groups and users
+        try:
+            self.ldb_dc1.delete(self.ou, ["tree_delete:1"])
+        except ldb.LdbError as (enum, string):
+            if enum == ldb.ERR_NO_SUCH_OBJECT:
+                pass
+
+    def add_linked_attribute(self, src, dest, attr='member'):
+        m = ldb.Message()
+        m.dn = ldb.Dn(self.ldb_dc1, src)
+        m[attr] = ldb.MessageElement(dest, ldb.FLAG_MOD_ADD, attr)
+        self.ldb_dc1.modify(m)
+
+    def remove_linked_attribute(self, src, dest, attr='member'):


-- 
Samba Shared Repository



More information about the samba-cvs mailing list