r25430: Add the loadparm context to all parametric options.
[jelmer/samba4-debian.git] / source / torture / rpc / dssync.c
index 3731f19c617249c4cbbe8e84d1cfbb2baeb7e08b..347b1a5bc743070a17247826f8e40d3fc4294e9f 100644 (file)
@@ -8,7 +8,7 @@
    
    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
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "lib/cmdline/popt_common.h"
-#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_drsuapi_c.h"
 #include "libcli/cldap/cldap.h"
+#include "libcli/ldap/ldap_client.h"
+#include "torture/torture.h"
 #include "torture/ldap/proto.h"
+#include "libcli/auth/libcli_auth.h"
+#include "lib/crypto/crypto.h"
+#include "auth/credentials/credentials.h"
+#include "libcli/auth/libcli_auth.h"
+#include "auth/gensec/gensec.h"
+#include "param/param.h"
 
 struct DsSyncBindInfo {
        struct dcerpc_pipe *pipe;
@@ -77,7 +84,7 @@ static struct DsSyncTest *test_create_context(TALLOC_CTX *mem_ctx)
        struct DsSyncTest *ctx;
        struct drsuapi_DsBindInfo28 *our_bind_info28;
        struct drsuapi_DsBindInfoCtr *our_bind_info_ctr;
-       const char *binding = lp_parm_string(-1, "torture", "binding");
+       const char *binding = lp_parm_string(global_loadparm, NULL, "torture", "binding");
        ctx = talloc_zero(mem_ctx, struct DsSyncTest);
        if (!ctx) return NULL;
 
@@ -111,6 +118,7 @@ static struct DsSyncTest *test_create_context(TALLOC_CTX *mem_ctx)
        ctx->admin.drsuapi.req.out.bind_handle          = &ctx->admin.drsuapi.bind_handle;
 
        /* ctx->new_dc ...*/
+       ctx->new_dc.credentials                 = cmdline_credentials;
 
        our_bind_info28                         = &ctx->new_dc.drsuapi.our_bind_info28;
        our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
@@ -141,7 +149,7 @@ static struct DsSyncTest *test_create_context(TALLOC_CTX *mem_ctx)
        our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
        our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
        our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
-       if (lp_parm_bool(-1,"dssync","xpress",False)) {
+       if (lp_parm_bool(global_loadparm, NULL, "dssync", "xpress", false)) {
                our_bind_info28->supported_extensions   |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
        }
        our_bind_info28->site_guid              = GUID_zero();
@@ -158,6 +166,8 @@ static struct DsSyncTest *test_create_context(TALLOC_CTX *mem_ctx)
        ctx->new_dc.drsuapi.req.in.bind_info            = our_bind_info_ctr;
        ctx->new_dc.drsuapi.req.out.bind_handle         = &ctx->new_dc.drsuapi.bind_handle;
 
+       ctx->new_dc.invocation_id                       = ctx->new_dc.drsuapi.bind_guid;
+
        /* ctx->old_dc ...*/
 
        return ctx;
@@ -171,7 +181,7 @@ static BOOL _test_DsBind(struct DsSyncTest *ctx, struct cli_credentials *credent
 
        status = dcerpc_pipe_connect_b(ctx,
                                       &b->pipe, ctx->drsuapi_binding, 
-                                          &dcerpc_table_drsuapi,
+                                      &ndr_table_drsuapi,
                                       credentials, event);
        
        if (!NT_STATUS_IS_OK(status)) {
@@ -248,14 +258,14 @@ static BOOL test_GetInfo(struct DsSyncTest *ctx)
        
        r.in.bind_handle                = &ctx->admin.drsuapi.bind_handle;
        r.in.level                      = 1;
-       r.in.req.req1.unknown1          = 0x000004e4;
-       r.in.req.req1.unknown2          = 0x00000407;
+       r.in.req.req1.codepage          = 1252; /* western european */
+       r.in.req.req1.language          = 0x00000407; /* german */
        r.in.req.req1.count             = 1;
        r.in.req.req1.names             = names;
        r.in.req.req1.format_flags      = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;                
        r.in.req.req1.format_offered    = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
        r.in.req.req1.format_desired    = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
-       names[0].str = talloc_asprintf(ctx, "%s\\", lp_workgroup());
+       names[0].str = talloc_asprintf(ctx, "%s\\", lp_workgroup(global_loadparm));
 
        status = dcerpc_drsuapi_DsCrackNames(ctx->admin.drsuapi.pipe, ctx, &r);
        if (!NT_STATUS_IS_OK(status)) {
@@ -282,74 +292,241 @@ static BOOL test_GetInfo(struct DsSyncTest *ctx)
                ctx->site_name = talloc_asprintf(ctx, "%s", "Default-First-Site-Name");
                printf("cldap_netlogon() returned %s. Defaulting to Site-Name: %s\n", errstr, ctx->site_name);          
        } else {
-               ctx->site_name = talloc_steal(ctx, search.out.netlogon.logon5.site_name);
-               printf("cldap_netlogon() returned Site-Name: %s.\n",ctx->site_name);
+               ctx->site_name = talloc_steal(ctx, search.out.netlogon.logon5.client_site);
+               printf("cldap_netlogon() returned Client Site-Name: %s.\n",ctx->site_name);
+               printf("cldap_netlogon() returned Server Site-Name: %s.\n",search.out.netlogon.logon5.server_site);
        }
 
+       return ret;
+}
+
+static DATA_BLOB decrypt_blob(TALLOC_CTX *mem_ctx,
+                             const DATA_BLOB *gensec_skey,
+                             bool rcrypt,
+                             struct drsuapi_DsReplicaObjectIdentifier *id,
+                             uint32_t rid,
+                             const DATA_BLOB *buffer)
+{
+       DATA_BLOB confounder;
+       DATA_BLOB enc_buffer;
 
-       ctx->new_dc.invocation_id = GUID_random();
+       struct MD5Context md5;
+       uint8_t _enc_key[16];
+       DATA_BLOB enc_key;
 
-       return ret;
+       DATA_BLOB dec_buffer;
+
+       uint32_t crc32_given;
+       uint32_t crc32_calc;
+       DATA_BLOB checked_buffer;
+
+       DATA_BLOB plain_buffer;
+
+       /*
+        * the combination "c[3] s[1] e[1] d[0]..."
+        * was successful!!!!!!!!!!!!!!!!!!!!!!!!!!
+        */
+
+       /* 
+        * the first 16 bytes at the beginning are the confounder
+        * followed by the 4 byte crc32 checksum
+        */
+       if (buffer->length < 20) {
+               return data_blob_const(NULL, 0);
+       }
+       confounder = data_blob_const(buffer->data, 16);
+       enc_buffer = data_blob_const(buffer->data + 16, buffer->length - 16);
+
+       /* 
+        * build the encryption key md5 over the session key followed
+        * by the confounder
+        * 
+        * here the gensec session key is used and
+        * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
+        */
+       enc_key = data_blob_const(_enc_key, sizeof(_enc_key));
+       MD5Init(&md5);
+       MD5Update(&md5, gensec_skey->data, gensec_skey->length);
+       MD5Update(&md5, confounder.data, confounder.length);
+       MD5Final(enc_key.data, &md5);
+
+       /*
+        * copy the encrypted buffer part and 
+        * decrypt it using the created encryption key using arcfour
+        */
+       dec_buffer = data_blob_talloc(mem_ctx, enc_buffer.data, enc_buffer.length);
+       if (!dec_buffer.data) {
+               return data_blob_const(NULL, 0);
+       }
+       arcfour_crypt_blob(dec_buffer.data, dec_buffer.length, &enc_key);
+
+       /* 
+        * the first 4 byte are the crc32 checksum
+        * of the remaining bytes
+        */
+       crc32_given = IVAL(dec_buffer.data, 0);
+       crc32_calc = crc32_calc_buffer(dec_buffer.data + 4 , dec_buffer.length - 4);
+       if (crc32_given != crc32_calc) {
+               DEBUG(0,("CRC32: given[0x%08X] calc[0x%08X]\n",
+                     crc32_given, crc32_calc));
+               return data_blob_const(NULL, 0);
+       }
+       checked_buffer = data_blob_talloc(mem_ctx, dec_buffer.data + 4, dec_buffer.length - 4);
+       if (!checked_buffer.data) {
+               return data_blob_const(NULL, 0);
+       }
+
+       /*
+        * some attributes seem to be in a usable form after this decryption
+        * (supplementalCredentials, priorValue, currentValue, trustAuthOutgoing,
+        *  trustAuthIncoming, initialAuthOutgoing, initialAuthIncoming)
+        * At least supplementalCredentials contains plaintext
+        * like "Primary:Kerberos" (in unicode form)
+        *
+        * some attributes seem to have some additional encryption
+        * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
+        *
+        * it's the sam_rid_crypt() function, as the value is constant,
+        * so it doesn't depend on sessionkeys.
+        */
+       if (rcrypt) {
+               uint32_t i, num_hashes;
+
+               if ((checked_buffer.length % 16) != 0) {
+                       return data_blob_const(NULL, 0);
+               }
+
+               plain_buffer = data_blob_talloc(mem_ctx, checked_buffer.data, checked_buffer.length);
+               if (!plain_buffer.data) {
+                       return data_blob_const(NULL, 0);
+               }
+                       
+               num_hashes = plain_buffer.length / 16;
+               for (i = 0; i < num_hashes; i++) {
+                       uint32_t offset = i * 16;
+                       sam_rid_crypt(rid, checked_buffer.data + offset, plain_buffer.data + offset, 0);
+               }
+       } else {
+               plain_buffer = checked_buffer;
+       }
+
+       return plain_buffer;
 }
 
 static void test_analyse_objects(struct DsSyncTest *ctx,
+                                const DATA_BLOB *gensec_skey,
                                 struct drsuapi_DsReplicaObjectListItemEx *cur)
 {
-       if (!lp_parm_bool(-1,"dssync","print_pwd_blobs",False)) {
+       static uint32_t object_id;
+       const char *save_values_dir;
+
+       if (!lp_parm_bool(global_loadparm, NULL,"dssync","print_pwd_blobs", false)) {
                return; 
        }
 
+       save_values_dir = lp_parm_string(global_loadparm, NULL, "dssync", "save_pwd_blobs_dir");
+
        for (; cur; cur = cur->next_object) {
                const char *dn;
+               struct dom_sid *sid = NULL;
+               uint32_t rid = 0;
                BOOL dn_printed = False;
                uint32_t i;
 
                if (!cur->object.identifier) continue;
 
                dn = cur->object.identifier->dn;
+               if (cur->object.identifier->sid.num_auths > 0) {
+                       sid = &cur->object.identifier->sid;
+                       rid = sid->sub_auths[sid->num_auths - 1];
+               }
 
                for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
                        const char *name = NULL;
-                       DATA_BLOB *data = NULL;
+                       bool rcrypt = false;
+                       DATA_BLOB *enc_data = NULL;
+                       DATA_BLOB plain_data;
                        struct drsuapi_DsReplicaAttribute *attr;
                        attr = &cur->object.attribute_ctr.attributes[i];
 
                        switch (attr->attid) {
                        case DRSUAPI_ATTRIBUTE_dBCSPwd:
                                name    = "dBCSPwd";
+                               rcrypt  = true;
                                break;
                        case DRSUAPI_ATTRIBUTE_unicodePwd:
                                name    = "unicodePwd";
+                               rcrypt  = true;
                                break;
                        case DRSUAPI_ATTRIBUTE_ntPwdHistory:
                                name    = "ntPwdHistory";
+                               rcrypt  = true;
                                break;
                        case DRSUAPI_ATTRIBUTE_lmPwdHistory:
                                name    = "lmPwdHistory";
+                               rcrypt  = true;
                                break;
                        case DRSUAPI_ATTRIBUTE_supplementalCredentials:
                                name    = "supplementalCredentials";
                                break;
-                       case DRSUAPI_ATTRIBUTE_msDS_KeyVersionNumber:
-                               name    = "msDS-KeyVersionNumber";
+                       case DRSUAPI_ATTRIBUTE_priorValue:
+                               name    = "priorValue";
+                               break;
+                       case DRSUAPI_ATTRIBUTE_currentValue:
+                               name    = "currentValue";
+                               break;
+                       case DRSUAPI_ATTRIBUTE_trustAuthOutgoing:
+                               name    = "trustAuthOutgoing";
+                               break;
+                       case DRSUAPI_ATTRIBUTE_trustAuthIncoming:
+                               name    = "trustAuthIncoming";
+                               break;
+                       case DRSUAPI_ATTRIBUTE_initialAuthOutgoing:
+                               name    = "initialAuthOutgoing";
+                               break;
+                       case DRSUAPI_ATTRIBUTE_initialAuthIncoming:
+                               name    = "initialAuthIncoming";
                                break;
                        default:
                                continue;
                        }
 
-                       if (attr->value_ctr.data_blob.num_values != 1) continue;
+                       if (attr->value_ctr.num_values != 1) continue;
 
-                       if (!attr->value_ctr.data_blob.values[0].data) continue;
+                       if (!attr->value_ctr.values[0].blob) continue;
 
-                       data = attr->value_ctr.data_blob.values[0].data;
+                       enc_data = attr->value_ctr.values[0].blob;
+                       ZERO_STRUCT(plain_data);
 
+                       plain_data = decrypt_blob(ctx, gensec_skey, rcrypt,
+                                                 cur->object.identifier, rid,
+                                                 enc_data);
                        if (!dn_printed) {
-                               DEBUG(0,("DN: %s\n", dn));
+                               object_id++;
+                               DEBUG(0,("DN[%u] %s\n", object_id, dn));
                                dn_printed = True;
                        }
-                       DEBUGADD(0,("ATTR: %s data_blob.length=%lu\n",
-                                   name, (long)data->length));
-                       dump_data(0,data->data, data->length);
+                       DEBUGADD(0,("ATTR: %s enc.length=%lu plain.length=%lu\n",
+                                   name, (long)enc_data->length, (long)plain_data.length));
+                       if (plain_data.length) {
+                               dump_data(0, plain_data.data, plain_data.length);
+                               if (save_values_dir) {
+                                       char *fname;
+                                       fname = talloc_asprintf(ctx, "%s/%s%02d",
+                                                               save_values_dir,
+                                                               name, object_id);
+                                       if (fname) {
+                                               bool ok;
+                                               ok = file_save(fname, plain_data.data, plain_data.length);
+                                               if (!ok) {
+                                                       DEBUGADD(0,("Failed to save '%s'\n", fname));
+                                               }
+                                       }
+                                       talloc_free(fname);
+                               }
+                       } else {
+                               dump_data(0, enc_data->data, enc_data->length);
+                       }
                }
        }
 }
@@ -368,6 +545,7 @@ static BOOL test_FetchData(struct DsSyncTest *ctx)
        int32_t out_level = 0;
        struct GUID null_guid;
        struct dom_sid null_sid;
+       DATA_BLOB gensec_skey;
        struct {
                int32_t level;
        } array[] = {
@@ -382,39 +560,56 @@ static BOOL test_FetchData(struct DsSyncTest *ctx)
        ZERO_STRUCT(null_guid);
        ZERO_STRUCT(null_sid);
 
-       partition = lp_parm_string(-1, "dssync", "partition");
+       partition = lp_parm_string(global_loadparm, NULL, "dssync", "partition");
        if (partition == NULL) {
                partition = ctx->domain_dn;
                printf("dssync:partition not specified, defaulting to %s.\n", ctx->domain_dn);
        }
 
-       highest_usn = lp_parm_int(-1, "dssync", "highest_usn", 0);
+       highest_usn = lp_parm_int(global_loadparm, NULL, "dssync", "highest_usn", 0);
+
+       array[0].level = lp_parm_int(global_loadparm, NULL, "dssync", "get_nc_changes_level", array[0].level);
+
+       if (lp_parm_bool(global_loadparm, NULL, "dssync", "print_pwd_blobs", false)) {
+               const struct samr_Password *nthash;
+               nthash = cli_credentials_get_nt_hash(ctx->new_dc.credentials, ctx);
+               if (nthash) {
+                       DEBUG(0,("CREDENTIALS nthash:\n"));
+                       dump_data(0, nthash->hash, sizeof(nthash->hash));
+               }
+       }
+       status = gensec_session_key(ctx->new_dc.drsuapi.pipe->conn->security_state.generic_state,
+                                   &gensec_skey);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("failed to get gensec session key: %s\n", nt_errstr(status));
+               return False;
+       }
 
        for (i=0; i < ARRAY_SIZE(array); i++) {
                printf("testing DsGetNCChanges level %d\n",
                        array[i].level);
 
                r.in.bind_handle        = &ctx->new_dc.drsuapi.bind_handle;
-               r.in.level              = array[i].level;
+               r.in.level              = &array[i].level;
 
-               switch (r.in.level) {
+               switch (*r.in.level) {
                case 5:
                        nc.guid = null_guid;
                        nc.sid  = null_sid;
                        nc.dn   = partition; 
 
                        r.in.req.req5.destination_dsa_guid              = ctx->new_dc.invocation_id;
-                       r.in.req.req5.source_dsa_guid                   = null_guid;
+                       r.in.req.req5.source_dsa_invocation_id          = null_guid;
                        r.in.req.req5.naming_context                    = &nc;
                        r.in.req.req5.highwatermark.tmp_highest_usn     = highest_usn;
                        r.in.req.req5.highwatermark.reserved_usn        = 0;
                        r.in.req.req5.highwatermark.highest_usn         = highest_usn;
                        r.in.req.req5.uptodateness_vector               = NULL;
                        r.in.req.req5.replica_flags                     = 0;
-                       if (lp_parm_bool(-1,"dssync","compression",False)) {
+                       if (lp_parm_bool(global_loadparm, NULL, "dssync", "compression", false)) {
                                r.in.req.req5.replica_flags             |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
                        }
-                       if (lp_parm_bool(-1,"dssync","neighbour_writeable",True)) {
+                       if (lp_parm_bool(global_loadparm, NULL, "dssync", "neighbour_writeable", true)) {
                                r.in.req.req5.replica_flags             |= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE;
                        }
                        r.in.req.req5.replica_flags                     |= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
@@ -422,8 +617,8 @@ static BOOL test_FetchData(struct DsSyncTest *ctx)
                                                                        | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS
                                                                        | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
                                                                        ;
-                       r.in.req.req5.unknown2                          = 133;
-                       r.in.req.req5.unknown3                          = 1336770;
+                       r.in.req.req5.max_object_count                  = 133;
+                       r.in.req.req5.max_ndr_size                      = 1336770;
                        r.in.req.req5.unknown4                          = 0;
                        r.in.req.req5.h1                                = 0;
 
@@ -435,17 +630,17 @@ static BOOL test_FetchData(struct DsSyncTest *ctx)
                        /* nc.dn can be set to any other ad partition */
                        
                        r.in.req.req8.destination_dsa_guid              = ctx->new_dc.invocation_id;
-                       r.in.req.req8.source_dsa_guid                   = null_guid;
+                       r.in.req.req8.source_dsa_invocation_id          = null_guid;
                        r.in.req.req8.naming_context                    = &nc;
                        r.in.req.req8.highwatermark.tmp_highest_usn     = highest_usn;
                        r.in.req.req8.highwatermark.reserved_usn        = 0;
                        r.in.req.req8.highwatermark.highest_usn         = highest_usn;
                        r.in.req.req8.uptodateness_vector               = NULL;
                        r.in.req.req8.replica_flags                     = 0;
-                       if (lp_parm_bool(-1,"dssync","compression",False)) {
+                       if (lp_parm_bool(global_loadparm, NULL, "dssync", "compression", false)) {
                                r.in.req.req8.replica_flags             |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
                        }
-                       if (lp_parm_bool(-1,"dssync","neighbour_writeable",True)) {
+                       if (lp_parm_bool(global_loadparm, NULL, "dssync", "neighbour_writeable", true)) {
                                r.in.req.req8.replica_flags             |= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE;
                        }
                        r.in.req.req8.replica_flags                     |= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
@@ -453,30 +648,32 @@ static BOOL test_FetchData(struct DsSyncTest *ctx)
                                                                        | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS
                                                                        | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
                                                                        ;
-                       r.in.req.req8.unknown2                          = 402;
-                       r.in.req.req8.unknown3                          = 402116;
+                       r.in.req.req8.max_object_count                  = 402;
+                       r.in.req.req8.max_ndr_size                      = 402116;
 
                        r.in.req.req8.unknown4                          = 0;
                        r.in.req.req8.h1                                = 0;
                        r.in.req.req8.unique_ptr1                       = 0;
                        r.in.req.req8.unique_ptr2                       = 0;
-                       r.in.req.req8.ctr12.count                       = 0;
-                       r.in.req.req8.ctr12.array                       = NULL;
+                       r.in.req.req8.mapping_ctr.num_mappings          = 0;
+                       r.in.req.req8.mapping_ctr.mappings              = NULL;
 
                        break;
                }
                
                printf("Dumping AD partition: %s\n", nc.dn);
                for (y=0; ;y++) {
+                       int32_t _level = 0;
                        ZERO_STRUCT(r.out);
+                       r.out.level = &_level;
 
-                       if (r.in.level == 5) {
+                       if (*r.in.level == 5) {
                                DEBUG(0,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y,
                                        (long long)r.in.req.req5.highwatermark.tmp_highest_usn,
                                        (long long)r.in.req.req5.highwatermark.highest_usn));
                        }
 
-                       if (r.in.level == 8) {
+                       if (*r.in.level == 8) {
                                DEBUG(0,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y,
                                        (long long)r.in.req.req8.highwatermark.tmp_highest_usn,
                                        (long long)r.in.req.req8.highwatermark.highest_usn));
@@ -495,10 +692,10 @@ static BOOL test_FetchData(struct DsSyncTest *ctx)
                                ret = False;
                        }
 
-                       if (ret == True && r.out.level == 1) {
+                       if (ret == True && *r.out.level == 1) {
                                out_level = 1;
                                ctr1 = &r.out.ctr.ctr1;
-                       } else if (ret == True && r.out.level == 2) {
+                       } else if (ret == True && *r.out.level == 2) {
                                out_level = 1;
                                ctr1 = r.out.ctr.ctr2.ctr.mszip1.ctr1;
                        }
@@ -508,7 +705,7 @@ static BOOL test_FetchData(struct DsSyncTest *ctx)
                                        (long long)ctr1->new_highwatermark.tmp_highest_usn,
                                        (long long)ctr1->new_highwatermark.highest_usn));
 
-                               test_analyse_objects(ctx, ctr1->first_object);
+                               test_analyse_objects(ctx, &gensec_skey, ctr1->first_object);
 
                                if (ctr1->new_highwatermark.tmp_highest_usn > ctr1->new_highwatermark.highest_usn) {
                                        r.in.req.req5.highwatermark = ctr1->new_highwatermark;
@@ -516,10 +713,10 @@ static BOOL test_FetchData(struct DsSyncTest *ctx)
                                }
                        }
 
-                       if (ret == True && r.out.level == 6) {
+                       if (ret == True && *r.out.level == 6) {
                                out_level = 6;
                                ctr6 = &r.out.ctr.ctr6;
-                       } else if (ret == True && r.out.level == 7
+                       } else if (ret == True && *r.out.level == 7
                                   && r.out.ctr.ctr7.level == 6
                                   && r.out.ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP) {
                                out_level = 6;
@@ -531,7 +728,7 @@ static BOOL test_FetchData(struct DsSyncTest *ctx)
                                        (long long)ctr6->new_highwatermark.tmp_highest_usn,
                                        (long long)ctr6->new_highwatermark.highest_usn));
 
-                               test_analyse_objects(ctx, ctr6->first_object);
+                               test_analyse_objects(ctx, &gensec_skey, ctr6->first_object);
 
                                if (ctr6->new_highwatermark.tmp_highest_usn > ctr6->new_highwatermark.highest_usn) {
                                        r.in.req.req8.highwatermark = ctr6->new_highwatermark;
@@ -546,9 +743,66 @@ static BOOL test_FetchData(struct DsSyncTest *ctx)
        return ret;
 }
 
-BOOL torture_rpc_dssync(void)
+static BOOL test_FetchNT4Data(struct DsSyncTest *ctx)
 {
+       NTSTATUS status;
        BOOL ret = True;
+       struct drsuapi_DsGetNT4ChangeLog r;
+       struct GUID null_guid;
+       struct dom_sid null_sid;
+       DATA_BLOB cookie;
+
+       ZERO_STRUCT(null_guid);
+       ZERO_STRUCT(null_sid);
+       ZERO_STRUCT(cookie);
+
+       ZERO_STRUCT(r);
+       r.in.bind_handle        = &ctx->new_dc.drsuapi.bind_handle;
+       r.in.level              = 1;
+
+       r.in.req.req1.unknown1  = lp_parm_int(global_loadparm, NULL, "dssync", "nt4-1", 3);
+       r.in.req.req1.unknown2  = lp_parm_int(global_loadparm, NULL, "dssync", "nt4-2", 0x00004000);
+
+       while (1) {
+               r.in.req.req1.length    = cookie.length;
+               r.in.req.req1.data      = cookie.data;
+
+               status = dcerpc_drsuapi_DsGetNT4ChangeLog(ctx->new_dc.drsuapi.pipe, ctx, &r);
+               if (!NT_STATUS_IS_OK(status)) {
+                       const char *errstr = nt_errstr(status);
+                       if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
+                               errstr = dcerpc_errstr(ctx, ctx->new_dc.drsuapi.pipe->last_fault_code);
+                       }
+                       printf("dcerpc_drsuapi_DsGetNT4ChangeLog failed - %s\n", errstr);
+                       ret = False;
+               } else if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_DOMAIN_ROLE)) {
+                       printf("DsGetNT4ChangeLog not supported by target server\n");
+                       break;
+               } else if (!W_ERROR_IS_OK(r.out.result)) {
+                       printf("DsGetNT4ChangeLog failed - %s\n", win_errstr(r.out.result));
+                       ret = False;
+               } else if (r.out.level != 1) {
+                       printf("DsGetNT4ChangeLog unknown level - %u\n", r.out.level);
+                       ret = False;
+               } else if (NT_STATUS_IS_OK(r.out.info.info1.status)) {
+               } else if (NT_STATUS_EQUAL(r.out.info.info1.status, STATUS_MORE_ENTRIES)) {
+                       cookie.length   = r.out.info.info1.length1;
+                       cookie.data     = r.out.info.info1.data1;
+                       continue;
+               } else {
+                       printf("DsGetNT4ChangeLog failed - %s\n", nt_errstr(r.out.info.info1.status));
+                       ret = False;
+               }
+
+               break;
+       }
+
+       return ret;
+}
+
+bool torture_rpc_dssync(struct torture_context *torture)
+{
+       bool ret = true;
        TALLOC_CTX *mem_ctx;
        struct DsSyncTest *ctx;
        
@@ -556,10 +810,20 @@ BOOL torture_rpc_dssync(void)
        ctx = test_create_context(mem_ctx);
        
        ret &= _test_DsBind(ctx, ctx->admin.credentials, &ctx->admin.drsuapi);
+       if (!ret) {
+               return ret;
+       }
        ret &= test_LDAPBind(ctx, ctx->admin.credentials, &ctx->admin.ldap);
+       if (!ret) {
+               return ret;
+       }
        ret &= test_GetInfo(ctx);
-       ret &= _test_DsBind(ctx, ctx->admin.credentials, &ctx->new_dc.drsuapi);
+       ret &= _test_DsBind(ctx, ctx->new_dc.credentials, &ctx->new_dc.drsuapi);
+       if (!ret) {
+               return ret;
+       }
        ret &= test_FetchData(ctx);
+       ret &= test_FetchNT4Data(ctx);
 
        return ret;
 }