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 <[email protected]>
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 <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    
    Autobuild-User(master): Andrew Bartlett <[email protected]>
    Autobuild-Date(master): Fri Jun 17 18:13:56 CEST 2016 on sn-devel-144

commit 0fc95c12b651efbe3eb1005e42459b60780be482
Author: Andrew Bartlett <[email protected]>
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 <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>

commit 0c0b8988f7ba1778e862a644173272ac9db3fa79
Author: Garming Sam <[email protected]>
Date:   Fri Jun 17 12:51:47 2016 +1200

    flapping: remove samba_dnsupdate from flapping
    
    nsupdate is now installed
    
    Signed-off-by: Garming Sam <[email protected]>
    Reviewed-by: Douglas Bagnall <[email protected]>

commit a896a92444f744a89e70bfcd7e4ed55061ce4235
Author: Andrew Bartlett <[email protected]>
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 <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>

commit 8dc3110a5f27cf2f45949cf48cb055a59dc9454e
Author: Garming Sam <[email protected]>
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 <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

commit 570237f0f331c3e05aac3054a98a41ab8f335738
Author: Garming Sam <[email protected]>
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 <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

commit 2ce9f249bb1a7c14260a9319323de0664e559fe6
Author: Garming Sam <[email protected]>
Date:   Tue Jun 7 11:57:02 2016 +1200

    getncchanges: remove some whitespace
    
    Signed-off-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

commit 2bb8e183fdf7d936c0f6a0d2faa7aeacdb331ebe
Author: Garming Sam <[email protected]>
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 <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

commit 4de5e7da9c2e9cac1b3fe33f4ba161e2b79a9bdc
Author: Garming Sam <[email protected]>
Date:   Thu Jun 9 14:55:57 2016 +1200

    tests/drs: assert sorted identifier GUIDs across getncchanges
    
    Signed-off-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

commit 3f0be46b91fe6e106b314e383fcfad2df94e3513
Author: Garming Sam <[email protected]>
Date:   Thu Jun 9 10:56:28 2016 +1200

    tests/drs: make cleanup more robust
    
    Signed-off-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11960

commit ed6a423232f5555a2111997689802e9d15d3cecd
Author: Garming Sam <[email protected]>
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 <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>
    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

Reply via email to