Merge branch 'master' of ssh://jra@git.samba.org/data/git/samba
[amitay/samba.git] / source4 / torture / rpc / drsuapi.c
index 3407e49565cdd08f1a179665143c7b3acabf1453..8f6bbb163b6198f7de22794a97c8815076dc7e77 100644 (file)
 
 #define TEST_MACHINE_NAME "torturetest"
 
-bool test_DsBind(struct dcerpc_pipe *p, struct torture_context *tctx,
+bool test_DsBind(struct dcerpc_pipe *p,
+                struct torture_context *tctx,
                 struct DsPrivate *priv)
 {
        NTSTATUS status;
        struct drsuapi_DsBind r;
+       struct drsuapi_DsBindInfo28 *bind_info28;
+       struct drsuapi_DsBindInfoCtr bind_info_ctr;
+
+       ZERO_STRUCT(bind_info_ctr);
+       bind_info_ctr.length = 28;
+
+       bind_info28 = &bind_info_ctr.info.info28;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
+       bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
 
        GUID_from_string(DRSUAPI_DS_BIND_GUID, &priv->bind_guid);
 
        r.in.bind_guid = &priv->bind_guid;
-       r.in.bind_info = NULL;
+       r.in.bind_info = &bind_info_ctr;
        r.out.bind_handle = &priv->bind_handle;
 
        torture_comment(tctx, "testing DsBind\n");
 
        status = dcerpc_drsuapi_DsBind(p, tctx, &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(tctx, p->last_fault_code);
-               }
-               torture_fail(tctx, "dcerpc_drsuapi_DsBind failed");
-       } else if (!W_ERROR_IS_OK(r.out.result)) {
-               torture_fail(tctx, "DsBind failed");
-       }
+       torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsBind");
+
+       /* cache server supported extensions, i.e. bind_info */
+       priv->srv_bind_info = r.out.bind_info->info.info28;
 
        return true;
 }
 
-static bool test_DsGetDomainControllerInfo(struct dcerpc_pipe *p, struct torture_context *torture, 
-                     struct DsPrivate *priv)
+static bool test_DsGetDomainControllerInfo(struct torture_context *tctx,
+                                          struct DsPrivate *priv)
 {
        NTSTATUS status;
+       struct dcerpc_pipe *p = priv->pipe;
        struct drsuapi_DsGetDomainControllerInfo r;
+       union drsuapi_DsGetDCInfoCtr ctr;
+       int32_t level_out = 0;
        bool found = false;
        int i, j, k;
        
@@ -91,21 +125,26 @@ static bool test_DsGetDomainControllerInfo(struct dcerpc_pipe *p, struct torture
 
        for (i=0; i < ARRAY_SIZE(levels); i++) {
                for (j=0; j < ARRAY_SIZE(names); j++) {
+                       union drsuapi_DsGetDCInfoRequest req;
                        level = levels[i];
                        r.in.bind_handle = &priv->bind_handle;
                        r.in.level = 1;
+                       r.in.req = &req;
                        
-                       r.in.req.req1.domain_name = names[j].name;
-                       r.in.req.req1.level = level;
+                       r.in.req->req1.domain_name = names[j].name;
+                       r.in.req->req1.level = level;
+
+                       r.out.ctr = &ctr;
+                       r.out.level_out = &level_out;
                        
-                       torture_comment(torture,
+                       torture_comment(tctx,
                                   "testing DsGetDomainControllerInfo level %d on domainname '%s'\n",
-                              r.in.req.req1.level, r.in.req.req1.domain_name);
+                              r.in.req->req1.level, r.in.req->req1.domain_name);
                
-                       status = dcerpc_drsuapi_DsGetDomainControllerInfo(p, torture, &r);
-                       torture_assert_ntstatus_ok(torture, status,
+                       status = dcerpc_drsuapi_DsGetDomainControllerInfo(p, tctx, &r);
+                       torture_assert_ntstatus_ok(tctx, status,
                                   "dcerpc_drsuapi_DsGetDomainControllerInfo with dns domain failed");
-                       torture_assert_werr_equal(torture, 
+                       torture_assert_werr_equal(tctx,
                                                                          r.out.result, names[j].expected, 
                                           "DsGetDomainControllerInfo level with dns domain failed");
                
@@ -114,14 +153,14 @@ static bool test_DsGetDomainControllerInfo(struct dcerpc_pipe *p, struct torture
                                continue;
                        }
 
-                       torture_assert_int_equal(torture, 
-                                                                        r.in.req.req1.level, r.out.level_out, 
-                                                                        "dcerpc_drsuapi_DsGetDomainControllerInfo level"); 
+                       torture_assert_int_equal(tctx,
+                                                r.in.req->req1.level, *r.out.level_out,
+                                                "dcerpc_drsuapi_DsGetDomainControllerInfo in/out level differs");
 
                        switch (level) {
                        case 1:
-                               for (k=0; k < r.out.ctr.ctr1.count; k++) {
-                                       if (strcasecmp_m(r.out.ctr.ctr1.array[k].netbios_name, 
+                               for (k=0; k < r.out.ctr->ctr1.count; k++) {
+                                       if (strcasecmp_m(r.out.ctr->ctr1.array[k].netbios_name,
                                                         torture_join_netbios_name(priv->join)) == 0) {
                                                found = true;
                                                break;
@@ -129,49 +168,53 @@ static bool test_DsGetDomainControllerInfo(struct dcerpc_pipe *p, struct torture
                                }
                                break;
                        case 2:
-                               for (k=0; k < r.out.ctr.ctr2.count; k++) {
-                                       if (strcasecmp_m(r.out.ctr.ctr2.array[k].netbios_name, 
+                               for (k=0; k < r.out.ctr->ctr2.count; k++) {
+                                       if (strcasecmp_m(r.out.ctr->ctr2.array[k].netbios_name,
                                                         torture_join_netbios_name(priv->join)) == 0) {
                                                found = true;
-                                               priv->dcinfo    = r.out.ctr.ctr2.array[k];
+                                               priv->dcinfo    = r.out.ctr->ctr2.array[k];
                                                break;
                                        }
                                }
                                break;
                        }
-                       torture_assert(torture, found,
+                       torture_assert(tctx, found,
                                 "dcerpc_drsuapi_DsGetDomainControllerInfo: Failed to find the domain controller we just created during the join");
                }
        }
 
        r.in.bind_handle = &priv->bind_handle;
        r.in.level = 1;
+
+       r.out.ctr = &ctr;
+       r.out.level_out = &level_out;
+
+       r.in.req->req1.domain_name = "__UNKNOWN_DOMAIN__"; /* This is clearly ignored for this level */
+       r.in.req->req1.level = -1;
        
-       r.in.req.req1.domain_name = "__UNKNOWN_DOMAIN__"; /* This is clearly ignored for this level */
-       r.in.req.req1.level = -1;
-       
-       printf("testing DsGetDomainControllerInfo level %d on domainname '%s'\n",
-              r.in.req.req1.level, r.in.req.req1.domain_name);
+       torture_comment(tctx, "testing DsGetDomainControllerInfo level %d on domainname '%s'\n",
+                       r.in.req->req1.level, r.in.req->req1.domain_name);
        
-       status = dcerpc_drsuapi_DsGetDomainControllerInfo(p, torture, &r);
+       status = dcerpc_drsuapi_DsGetDomainControllerInfo(p, tctx, &r);
 
-       torture_assert_ntstatus_ok(torture, status, 
-                       "dcerpc_drsuapi_DsGetDomainControllerInfo with dns domain failed");
-       torture_assert_werr_ok(torture, r.out.result, 
-                          "DsGetDomainControllerInfo with dns domain failed");
+       torture_assert_ntstatus_ok(tctx, status,
+                                  "dcerpc_drsuapi_DsGetDomainControllerInfo with dns domain failed");
+       torture_assert_werr_ok(tctx, r.out.result,
+                               "DsGetDomainControllerInfo with dns domain failed");
        
        {
-               const char *dc_account = talloc_asprintf(torture, "%s\\%s$",
+               const char *dc_account = talloc_asprintf(tctx, "%s\\%s$",
                                                         torture_join_dom_netbios_name(priv->join), 
                                                         priv->dcinfo.netbios_name);
-               for (k=0; k < r.out.ctr.ctr01.count; k++) {
-                       if (strcasecmp_m(r.out.ctr.ctr01.array[k].client_account, 
+               torture_comment(tctx, "%s: Enum active LDAP sessions searching for %s\n", __func__, dc_account);
+               for (k=0; k < r.out.ctr->ctr01.count; k++) {
+                       if (strcasecmp_m(r.out.ctr->ctr01.array[k].client_account,
                                         dc_account)) {
                                found = true;
                                break;
                        }
                }
-               torture_assert(torture, found,
+               torture_assert(tctx, found,
                        "dcerpc_drsuapi_DsGetDomainControllerInfo level: Failed to find the domain controller in last logon records");
        }
 
@@ -179,65 +222,55 @@ static bool test_DsGetDomainControllerInfo(struct dcerpc_pipe *p, struct torture
        return true;
 }
 
-static bool test_DsWriteAccountSpn(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_DsWriteAccountSpn(struct torture_context *tctx,
                                   struct DsPrivate *priv)
 {
        NTSTATUS status;
+       struct dcerpc_pipe *p = priv->pipe;
        struct drsuapi_DsWriteAccountSpn r;
+       union drsuapi_DsWriteAccountSpnRequest req;
        struct drsuapi_DsNameString names[2];
-       bool ret = true;
+       union drsuapi_DsWriteAccountSpnResult res;
+       int32_t level_out;
 
        r.in.bind_handle                = &priv->bind_handle;
        r.in.level                      = 1;
+       r.in.req                        = &req;
 
-       printf("testing DsWriteAccountSpn\n");
-
-       r.in.req.req1.operation = DRSUAPI_DS_SPN_OPERATION_ADD;
-       r.in.req.req1.unknown1  = 0;
-       r.in.req.req1.object_dn = priv->dcinfo.computer_dn;
-       r.in.req.req1.count     = 2;
-       r.in.req.req1.spn_names = names;
-       names[0].str = talloc_asprintf(mem_ctx, "smbtortureSPN/%s",priv->dcinfo.netbios_name);
-       names[1].str = talloc_asprintf(mem_ctx, "smbtortureSPN/%s",priv->dcinfo.dns_name);
-
-       status = dcerpc_drsuapi_DsWriteAccountSpn(p, mem_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(mem_ctx, p->last_fault_code);
-               }
-               printf("dcerpc_drsuapi_DsWriteAccountSpn failed - %s\n", errstr);
-               ret = false;
-       } else if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("DsWriteAccountSpn failed - %s\n", win_errstr(r.out.result));
-               ret = false;
-       }
+       torture_comment(tctx, "testing DsWriteAccountSpn\n");
 
-       r.in.req.req1.operation = DRSUAPI_DS_SPN_OPERATION_DELETE;
-       r.in.req.req1.unknown1  = 0;
+       r.in.req->req1.operation        = DRSUAPI_DS_SPN_OPERATION_ADD;
+       r.in.req->req1.unknown1 = 0;
+       r.in.req->req1.object_dn        = priv->dcinfo.computer_dn;
+       r.in.req->req1.count            = 2;
+       r.in.req->req1.spn_names        = names;
+       names[0].str = talloc_asprintf(tctx, "smbtortureSPN/%s",priv->dcinfo.netbios_name);
+       names[1].str = talloc_asprintf(tctx, "smbtortureSPN/%s",priv->dcinfo.dns_name);
 
-       status = dcerpc_drsuapi_DsWriteAccountSpn(p, mem_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(mem_ctx, p->last_fault_code);
-               }
-               printf("dcerpc_drsuapi_DsWriteAccountSpn failed - %s\n", errstr);
-               ret = false;
-       } else if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("DsWriteAccountSpn failed - %s\n", win_errstr(r.out.result));
-               ret = false;
-       }
+       r.out.res                       = &res;
+       r.out.level_out                 = &level_out;
 
-       return ret;
+       status = dcerpc_drsuapi_DsWriteAccountSpn(p, tctx, &r);
+       torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsWriteAccountSpn");
+
+       r.in.req->req1.operation        = DRSUAPI_DS_SPN_OPERATION_DELETE;
+       r.in.req->req1.unknown1         = 0;
+
+       status = dcerpc_drsuapi_DsWriteAccountSpn(p, tctx, &r);
+       torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsWriteAccountSpn");
+
+       return true;
 }
 
-static bool test_DsReplicaGetInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
-                       struct DsPrivate *priv)
+static bool test_DsReplicaGetInfo(struct torture_context *tctx,
+                                 struct DsPrivate *priv)
 {
        NTSTATUS status;
+       struct dcerpc_pipe *p = priv->pipe;
        struct drsuapi_DsReplicaGetInfo r;
-       bool ret = true;
+       union drsuapi_DsReplicaGetInfoRequest req;
+       union drsuapi_DsReplicaInfo info;
+       enum drsuapi_DsReplicaInfoType info_type;
        int i;
        struct {
                int32_t level;
@@ -307,66 +340,62 @@ static bool test_DsReplicaGetInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                }
        };
 
-       if (lp_parm_bool(global_loadparm, NULL, "torture", "samba4", false)) {
-               printf("skipping DsReplicaGetInfo test against Samba4\n");
+       if (torture_setting_bool(tctx, "samba4", false)) {
+               torture_comment(tctx, "skipping DsReplicaGetInfo test against Samba4\n");
                return true;
        }
 
        r.in.bind_handle        = &priv->bind_handle;
+       r.in.req                = &req;
 
        for (i=0; i < ARRAY_SIZE(array); i++) {
                const char *object_dn;
 
-               printf("testing DsReplicaGetInfo level %d infotype %d\n",
-                       array[i].level, array[i].infotype);
+               torture_comment(tctx, "testing DsReplicaGetInfo level %d infotype %d\n",
+                               array[i].level, array[i].infotype);
 
                object_dn = (array[i].obj_dn ? array[i].obj_dn : priv->domain_obj_dn);
 
                r.in.level = array[i].level;
                switch(r.in.level) {
                case DRSUAPI_DS_REPLICA_GET_INFO:
-                       r.in.req.req1.info_type = array[i].infotype;
-                       r.in.req.req1.object_dn = object_dn;
-                       ZERO_STRUCT(r.in.req.req1.guid1);
+                       r.in.req->req1.info_type        = array[i].infotype;
+                       r.in.req->req1.object_dn        = object_dn;
+                       ZERO_STRUCT(r.in.req->req1.guid1);
                        break;
                case DRSUAPI_DS_REPLICA_GET_INFO2:
-                       r.in.req.req2.info_type = array[i].infotype;
-                       r.in.req.req2.object_dn = object_dn;
-                       ZERO_STRUCT(r.in.req.req1.guid1);
-                       r.in.req.req2.unknown1  = 0;
-                       r.in.req.req2.string1   = NULL;
-                       r.in.req.req2.string2   = NULL;
-                       r.in.req.req2.unknown2  = 0;
+                       r.in.req->req2.info_type        = array[i].infotype;
+                       r.in.req->req2.object_dn        = object_dn;
+                       ZERO_STRUCT(r.in.req->req2.guid1);
+                       r.in.req->req2.unknown1 = 0;
+                       r.in.req->req2.string1  = NULL;
+                       r.in.req->req2.string2  = NULL;
+                       r.in.req->req2.unknown2 = 0;
                        break;
                }
 
-               status = dcerpc_drsuapi_DsReplicaGetInfo(p, mem_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(mem_ctx, p->last_fault_code);
-                       }
-                       if (p->last_fault_code != DCERPC_FAULT_INVALID_TAG) {
-                               printf("dcerpc_drsuapi_DsReplicaGetInfo failed - %s\n", errstr);
-                               ret = false;
-                       } else {
-                               printf("DsReplicaGetInfo level %d and/or infotype %d not supported by server\n",
+               r.out.info              = &info;
+               r.out.info_type         = &info_type;
+
+               status = dcerpc_drsuapi_DsReplicaGetInfo(p, tctx, &r);
+               torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaGetInfo");
+               if (!NT_STATUS_IS_OK(status) && p->last_fault_code == DCERPC_FAULT_INVALID_TAG) {
+                       torture_comment(tctx,
+                                       "DsReplicaGetInfo level %d and/or infotype %d not supported by server\n",
                                        array[i].level, array[i].infotype);
-                       }
-               } else if (!W_ERROR_IS_OK(r.out.result)) {
-                       printf("DsReplicaGetInfo failed - %s\n", win_errstr(r.out.result));
-                       ret = false;
+               } else {
+                       torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaGetInfo");
                }
        }
 
-       return ret;
+       return true;
 }
 
-static bool test_DsReplicaSync(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
-                       struct DsPrivate *priv)
+static bool test_DsReplicaSync(struct torture_context *tctx,
+                               struct DsPrivate *priv)
 {
        NTSTATUS status;
-       bool ret = true;
+       struct dcerpc_pipe *p = priv->pipe;
        int i;
        struct drsuapi_DsReplicaSync r;
        struct drsuapi_DsReplicaObjectIdentifier nc;
@@ -380,13 +409,13 @@ static bool test_DsReplicaSync(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                }
        };
 
-       if (!lp_parm_bool(global_loadparm, NULL, "torture", "dangerous", false)) {
-               printf("DsReplicaSync disabled - enable dangerous tests to use\n");
+       if (!torture_setting_bool(tctx, "dangerous", false)) {
+               torture_comment(tctx, "DsReplicaSync disabled - enable dangerous tests to use\n");
                return true;
        }
 
-       if (lp_parm_bool(global_loadparm, NULL, "torture", "samba4", false)) {
-               printf("skipping DsReplicaSync test against Samba4\n");
+       if (torture_setting_bool(tctx, "samba4", false)) {
+               torture_comment(tctx, "skipping DsReplicaSync test against Samba4\n");
                return true;
        }
 
@@ -396,8 +425,8 @@ static bool test_DsReplicaSync(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        r.in.bind_handle        = &priv->bind_handle;
 
        for (i=0; i < ARRAY_SIZE(array); i++) {
-               printf("testing DsReplicaSync level %d\n",
-                       array[i].level);
+               torture_comment(tctx, "testing DsReplicaSync level %d\n",
+                               array[i].level);
 
                r.in.level = array[i].level;
                switch(r.in.level) {
@@ -413,97 +442,93 @@ static bool test_DsReplicaSync(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                        break;
                }
 
-               status = dcerpc_drsuapi_DsReplicaSync(p, mem_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(mem_ctx, p->last_fault_code);
-                       }
-                       printf("dcerpc_drsuapi_DsReplicaSync failed - %s\n", errstr);
-                       ret = false;
-               } else if (!W_ERROR_IS_OK(r.out.result)) {
-                       printf("DsReplicaSync failed - %s\n", win_errstr(r.out.result));
-                       ret = false;
-               }
+               status = dcerpc_drsuapi_DsReplicaSync(p, tctx, &r);
+               torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaSync");
        }
 
-       return ret;
+       return true;
 }
 
-static bool test_DsReplicaUpdateRefs(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
-                       struct DsPrivate *priv)
+static bool test_DsReplicaUpdateRefs(struct torture_context *tctx,
+                                    struct DsPrivate *priv)
 {
        NTSTATUS status;
-       bool ret = true;
-       int i;
+       struct dcerpc_pipe *p = priv->pipe;
        struct drsuapi_DsReplicaUpdateRefs r;
        struct drsuapi_DsReplicaObjectIdentifier nc;
        struct GUID null_guid;
+       struct GUID dest_dsa_guid;
+       const char *dest_dsa_guid_str;
        struct dom_sid null_sid;
-       struct {
-               int32_t level;
-       } array[] = {
-               {       
-                       1
-               }
-       };
-
-       if (lp_parm_bool(global_loadparm, NULL, "torture", "samba4", false)) {
-               printf("skipping DsReplicaUpdateRefs test against Samba4\n");
-               return true;
-       }
 
        ZERO_STRUCT(null_guid);
        ZERO_STRUCT(null_sid);
+       dest_dsa_guid = GUID_random();
+       dest_dsa_guid_str = GUID_string(tctx, &dest_dsa_guid);
 
-       r.in.bind_handle        = &priv->bind_handle;
-
-       for (i=0; i < ARRAY_SIZE(array); i++) {
-               printf("testing DsReplicaUpdateRefs level %d\n",
-                       array[i].level);
-
-               r.in.level = array[i].level;
-               switch(r.in.level) {
-               case 1:
-                       nc.guid                         = null_guid;
-                       nc.sid                          = null_sid;
-                       nc.dn                           = priv->domain_obj_dn?priv->domain_obj_dn:"";
-
-                       r.in.req.req1.naming_context    = &nc;
-                       r.in.req.req1.dest_dsa_dns_name = talloc_asprintf(mem_ctx, "__some_dest_dsa_guid_string._msdn.%s",
-                                                                               priv->domain_dns_name);
-                       r.in.req.req1.dest_dsa_guid     = null_guid;
-                       r.in.req.req1.options           = 0;
-                       break;
-               }
-
-               status = dcerpc_drsuapi_DsReplicaUpdateRefs(p, mem_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(mem_ctx, p->last_fault_code);
-                       }
-                       printf("dcerpc_drsuapi_DsReplicaUpdateRefs failed - %s\n", errstr);
-                       ret = false;
-               } else if (!W_ERROR_IS_OK(r.out.result)) {
-                       printf("DsReplicaUpdateRefs failed - %s\n", win_errstr(r.out.result));
-                       ret = false;
-               }
-       }
+       r.in.bind_handle = &priv->bind_handle;
+       r.in.level       = 1; /* Only version 1 is defined presently */
+
+       /* setup NC */
+       nc.guid         = priv->domain_obj_dn ? null_guid : priv->domain_guid;
+       nc.sid          = null_sid;
+       nc.dn           = priv->domain_obj_dn ? priv->domain_obj_dn : "";
+
+       /* default setup for request */
+       r.in.req.req1.naming_context    = &nc;
+       r.in.req.req1.dest_dsa_dns_name = talloc_asprintf(tctx, "%s._msdn.%s",
+                                                               dest_dsa_guid_str,
+                                                               priv->domain_dns_name);
+       r.in.req.req1.dest_dsa_guid     = dest_dsa_guid;
+
+       /* 1. deleting replica dest should fail */
+       torture_comment(tctx, "delete: %s\n", r.in.req.req1.dest_dsa_dns_name);
+       r.in.req.req1.options           = DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE;
+       status = dcerpc_drsuapi_DsReplicaUpdateRefs(p, tctx, &r);
+       torture_drsuapi_assert_call_werr(tctx, p,
+                                        status, WERR_DS_DRA_REF_NOT_FOUND, &r,
+                                        "dcerpc_drsuapi_DsReplicaUpdateRefs");
+
+       /* 2. hopefully adding random replica dest should succeed */
+       torture_comment(tctx, "add   : %s\n", r.in.req.req1.dest_dsa_dns_name);
+       r.in.req.req1.options           = DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE;
+       status = dcerpc_drsuapi_DsReplicaUpdateRefs(p, tctx, &r);
+       torture_drsuapi_assert_call_werr(tctx, p,
+                                        status, WERR_OK, &r,
+                                        "dcerpc_drsuapi_DsReplicaUpdateRefs");
+
+       /* 3. try adding same replica dest - should fail */
+       torture_comment(tctx, "add   : %s\n", r.in.req.req1.dest_dsa_dns_name);
+       r.in.req.req1.options           = DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE;
+       status = dcerpc_drsuapi_DsReplicaUpdateRefs(p, tctx, &r);
+       torture_drsuapi_assert_call_werr(tctx, p,
+                                        status, WERR_DS_DRA_REF_ALREADY_EXISTS, &r,
+                                        "dcerpc_drsuapi_DsReplicaUpdateRefs");
+
+       /* 4. delete random replicate added at step 2. */
+       torture_comment(tctx, "delete: %s\n", r.in.req.req1.dest_dsa_dns_name);
+       r.in.req.req1.options           = DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE;
+       status = dcerpc_drsuapi_DsReplicaUpdateRefs(p, tctx, &r);
+       torture_drsuapi_assert_call_werr(tctx, p,
+                                        status, WERR_OK, &r,
+                                        "dcerpc_drsuapi_DsReplicaUpdateRefs");
 
-       return ret;
+       return true;
 }
 
-static bool test_DsGetNCChanges(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
-                       struct DsPrivate *priv)
+static bool test_DsGetNCChanges(struct torture_context *tctx,
+                               struct DsPrivate *priv)
 {
        NTSTATUS status;
-       bool ret = true;
+       struct dcerpc_pipe *p = priv->pipe;
        int i;
        struct drsuapi_DsGetNCChanges r;
+       union drsuapi_DsGetNCChangesRequest req;
+       union drsuapi_DsGetNCChangesCtr ctr;
        struct drsuapi_DsReplicaObjectIdentifier nc;
        struct GUID null_guid;
        struct dom_sid null_sid;
+       int32_t level_out;
        struct {
                int32_t level;
        } array[] = {
@@ -515,8 +540,8 @@ static bool test_DsGetNCChanges(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                }
        };
 
-       if (lp_parm_bool(global_loadparm, NULL, "torture", "samba4", false)) {
-               printf("skipping DsGetNCChanges test against Samba4\n");
+       if (torture_setting_bool(tctx, "samba4", false)) {
+               torture_comment(tctx, "skipping DsGetNCChanges test against Samba4\n");
                return true;
        }
 
@@ -524,260 +549,300 @@ static bool test_DsGetNCChanges(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        ZERO_STRUCT(null_sid);
 
        for (i=0; i < ARRAY_SIZE(array); i++) {
-               printf("testing DsGetNCChanges level %d\n",
-                       array[i].level);
+               torture_comment(tctx,
+                               "testing DsGetNCChanges level %d\n",
+                               array[i].level);
 
                r.in.bind_handle        = &priv->bind_handle;
-               r.in.level              = &array[i].level;
+               r.in.level              = array[i].level;
+               r.out.level_out         = &level_out;
+               r.out.ctr               = &ctr;
 
-               switch (*r.in.level) {
+               switch (r.in.level) {
                case 5:
                        nc.guid = null_guid;
                        nc.sid  = null_sid;
-                       nc.dn   = priv->domain_obj_dn?priv->domain_obj_dn:"";
-
-                       r.in.req.req5.destination_dsa_guid              = GUID_random();
-                       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     = 0;
-                       r.in.req.req5.highwatermark.reserved_usn        = 0;
-                       r.in.req.req5.highwatermark.highest_usn         = 0;
-                       r.in.req.req5.uptodateness_vector               = NULL;
-                       r.in.req.req5.replica_flags                     = 0;
-                       if (lp_parm_bool(global_loadparm, NULL, "drsuapi","compression", false)) {
-                               r.in.req.req5.replica_flags             |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
+                       nc.dn   = priv->domain_obj_dn ? priv->domain_obj_dn : "";
+
+                       r.in.req                                        = &req;
+                       r.in.req->req5.destination_dsa_guid             = GUID_random();
+                       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    = 0;
+                       r.in.req->req5.highwatermark.reserved_usn       = 0;
+                       r.in.req->req5.highwatermark.highest_usn        = 0;
+                       r.in.req->req5.uptodateness_vector              = NULL;
+                       r.in.req->req5.replica_flags                    = 0;
+                       if (lp_parm_bool(tctx->lp_ctx, NULL, "drsuapi", "compression", false)) {
+                               r.in.req->req5.replica_flags            |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
                        }
-                       r.in.req.req5.max_object_count                  = 0;
-                       r.in.req.req5.max_ndr_size                      = 0;
-                       r.in.req.req5.unknown4                          = 0;
-                       r.in.req.req5.h1                                = 0;
+                       r.in.req->req5.max_object_count                 = 0;
+                       r.in.req->req5.max_ndr_size                     = 0;
+                       r.in.req->req5.extended_op                      = DRSUAPI_EXOP_NONE;
+                       r.in.req->req5.fsmo_info                        = 0;
 
                        break;
                case 8:
                        nc.guid = null_guid;
                        nc.sid  = null_sid;
-                       nc.dn   = priv->domain_obj_dn?priv->domain_obj_dn:"";
-
-                       r.in.req.req8.destination_dsa_guid              = GUID_random();
-                       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     = 0;
-                       r.in.req.req8.highwatermark.reserved_usn        = 0;
-                       r.in.req.req8.highwatermark.highest_usn         = 0;
-                       r.in.req.req8.uptodateness_vector               = NULL;
-                       r.in.req.req8.replica_flags                     = 0;
-                       if (lp_parm_bool(global_loadparm, NULL, "drsuapi", "compression", false)) {
-                               r.in.req.req8.replica_flags             |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
+                       nc.dn   = priv->domain_obj_dn ? priv->domain_obj_dn : "";
+
+                       r.in.req                                        = &req;
+                       r.in.req->req8.destination_dsa_guid             = GUID_random();
+                       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    = 0;
+                       r.in.req->req8.highwatermark.reserved_usn       = 0;
+                       r.in.req->req8.highwatermark.highest_usn        = 0;
+                       r.in.req->req8.uptodateness_vector              = NULL;
+                       r.in.req->req8.replica_flags                    = 0;
+                       if (lp_parm_bool(tctx->lp_ctx, NULL, "drsuapi", "compression", false)) {
+                               r.in.req->req8.replica_flags            |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
                        }
-                       if (lp_parm_bool(global_loadparm, NULL, "drsuapi", "neighbour_writeable", true)) {
-                               r.in.req.req8.replica_flags             |= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE;
+                       if (lp_parm_bool(tctx->lp_ctx, NULL, "drsuapi", "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
+                       r.in.req->req8.replica_flags                    |= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
                                                                        | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
                                                                        | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS
                                                                        | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
                                                                        ;
-                       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.mapping_ctr.num_mappings          = 0;
-                       r.in.req.req8.mapping_ctr.mappings              = NULL;
+                       r.in.req->req8.max_object_count                 = 402;
+                       r.in.req->req8.max_ndr_size                     = 402116;
+                       r.in.req->req8.extended_op                      = DRSUAPI_EXOP_NONE;
+                       r.in.req->req8.fsmo_info                        = 0;
+                       r.in.req->req8.partial_attribute_set            = NULL;
+                       r.in.req->req8.partial_attribute_set_ex         = NULL;
+                       r.in.req->req8.mapping_ctr.num_mappings         = 0;
+                       r.in.req->req8.mapping_ctr.mappings             = NULL;
 
                        break;
                }
 
-               status = dcerpc_drsuapi_DsGetNCChanges(p, mem_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(mem_ctx, p->last_fault_code);
-                       }
-                       printf("dcerpc_drsuapi_DsGetNCChanges failed - %s\n", errstr);
-                       ret = false;
-               } else if (!W_ERROR_IS_OK(r.out.result)) {
-                       printf("DsGetNCChanges failed - %s\n", win_errstr(r.out.result));
-                       ret = false;
-               }
+               status = dcerpc_drsuapi_DsGetNCChanges(p, tctx, &r);
+               torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsGetNCChanges");
        }
 
-       return ret;
+       return true;
 }
 
-bool test_QuerySitesByCost(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+bool test_QuerySitesByCost(struct torture_context *tctx,
                           struct DsPrivate *priv)
 {
        NTSTATUS status;
+       struct dcerpc_pipe *p = priv->pipe;
        struct drsuapi_QuerySitesByCost r;
-       bool ret = true;
+       union drsuapi_QuerySitesByCostRequest req;
 
        const char *my_site = "Default-First-Site-Name";
        const char *remote_site1 = "smbtorture-nonexisting-site1";
        const char *remote_site2 = "smbtorture-nonexisting-site2";
 
+       req.req1.site_from = talloc_strdup(tctx, my_site);
+       req.req1.num_req = 2;
+       req.req1.site_to = talloc_zero_array(tctx, const char *, 2);
+       req.req1.site_to[0] = talloc_strdup(tctx, remote_site1);
+       req.req1.site_to[1] = talloc_strdup(tctx, remote_site2);
+       req.req1.flags = 0;
+
        r.in.bind_handle = &priv->bind_handle;
        r.in.level = 1;
-       r.in.req.req1.site_from = talloc_strdup(mem_ctx, my_site);
-       r.in.req.req1.num_req = 2;
-       r.in.req.req1.site_to = talloc_zero_array(mem_ctx, const char *, r.in.req.req1.num_req);
-       r.in.req.req1.site_to[0] = talloc_strdup(mem_ctx, remote_site1);
-       r.in.req.req1.site_to[1] = talloc_strdup(mem_ctx, remote_site2);
-       r.in.req.req1.flags = 0;
-
-       status = dcerpc_drsuapi_QuerySitesByCost(p, mem_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(mem_ctx, p->last_fault_code);
-               }
-               printf("drsuapi_QuerySitesByCost - %s\n", errstr);
-               ret = false;
-       } else if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("QuerySitesByCost failed - %s\n", win_errstr(r.out.result));
-               ret = false;
-       }
+       r.in.req = &req;
 
-       if (W_ERROR_IS_OK(r.out.result)) {
-
-               if (!W_ERROR_EQUAL(r.out.ctr.ctr1.info[0].error_code, WERR_DS_OBJ_NOT_FOUND) ||
-                   !W_ERROR_EQUAL(r.out.ctr.ctr1.info[1].error_code, WERR_DS_OBJ_NOT_FOUND)) { 
-                       printf("expected error_code WERR_DS_OBJ_NOT_FOUND, got %s\n", 
-                               win_errstr(r.out.ctr.ctr1.info[0].error_code));
-                       ret = false;
-               }
+       status = dcerpc_drsuapi_QuerySitesByCost(p, tctx, &r);
+       torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_QuerySitesByCost");
 
-               if ((r.out.ctr.ctr1.info[0].site_cost != (uint32_t) -1) ||
-                   (r.out.ctr.ctr1.info[1].site_cost != (uint32_t) -1)) {
-                       printf("expected site_cost %d, got %d\n", 
-                               (uint32_t) -1, r.out.ctr.ctr1.info[0].site_cost);
-                       ret = false;
-               }
+       if (W_ERROR_IS_OK(r.out.result)) {
+               torture_assert_werr_equal(tctx,
+                                         r.out.ctr->ctr1.info[0].error_code, WERR_DS_OBJ_NOT_FOUND,
+                                         "dcerpc_drsuapi_QuerySitesByCost");
+               torture_assert_werr_equal(tctx,
+                                         r.out.ctr->ctr1.info[1].error_code, WERR_DS_OBJ_NOT_FOUND,
+                                         "dcerpc_drsuapi_QuerySitesByCost expected error_code WERR_DS_OBJ_NOT_FOUND");
+
+               torture_assert_int_equal(tctx,
+                                        r.out.ctr->ctr1.info[0].site_cost, -1,
+                                        "dcerpc_drsuapi_QuerySitesByCost");
+               torture_assert_int_equal(tctx,
+                                        r.out.ctr->ctr1.info[1].site_cost, -1,
+                                        "dcerpc_drsuapi_QuerySitesByCost exptected site cost");
        }
 
-       return ret;
+       return true;
 
 
 }
 
-bool test_DsUnbind(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+bool test_DsUnbind(struct dcerpc_pipe *p,
+                  struct torture_context *tctx,
                   struct DsPrivate *priv)
 {
        NTSTATUS status;
        struct drsuapi_DsUnbind r;
-       bool ret = true;
 
        r.in.bind_handle = &priv->bind_handle;
        r.out.bind_handle = &priv->bind_handle;
 
-       printf("testing DsUnbind\n");
+       torture_comment(tctx, "testing DsUnbind\n");
+
+       status = dcerpc_drsuapi_DsUnbind(p, tctx, &r);
+       torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsUnbind");
+
+       return true;
+}
+
+
+/**
+ * Helper func to collect DC information for testing purposes.
+ * This function is almost identical to test_DsGetDomainControllerInfo
+ */
+bool torture_rpc_drsuapi_get_dcinfo(struct torture_context *torture,
+                                   struct DsPrivate *priv)
+{
+       NTSTATUS status;
+       int32_t level_out = 0;
+       struct drsuapi_DsGetDomainControllerInfo r;
+       union drsuapi_DsGetDCInfoCtr ctr;
+       int j, k;
+       const char *names[] = {
+                               torture_join_dom_netbios_name(priv->join),
+                               torture_join_dom_dns_name(priv->join)};
+
+       for (j=0; j < ARRAY_SIZE(names); j++) {
+               union drsuapi_DsGetDCInfoRequest req;
+               r.in.bind_handle = &priv->bind_handle;
+               r.in.level = 1;
+               r.in.req = &req;
+
+               r.in.req->req1.domain_name = names[j];
+               r.in.req->req1.level = 2;
+
+               r.out.ctr = &ctr;
+               r.out.level_out = &level_out;
 
-       status = dcerpc_drsuapi_DsUnbind(p, mem_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(mem_ctx, p->last_fault_code);
+               status = dcerpc_drsuapi_DsGetDomainControllerInfo(priv->pipe, torture, &r);
+               if (!NT_STATUS_IS_OK(status)) {
+                       continue;
+               }
+               if (!W_ERROR_IS_OK(r.out.result)) {
+                       /* If this was an error, we can't read the result structure */
+                       continue;
+               }
+
+               for (k=0; k < r.out.ctr->ctr2.count; k++) {
+                       if (strcasecmp_m(r.out.ctr->ctr2.array[k].netbios_name,
+                                        torture_join_netbios_name(priv->join)) == 0) {
+                               priv->dcinfo    = r.out.ctr->ctr2.array[k];
+                               return true;
+                       }
                }
-               printf("dcerpc_drsuapi_DsUnbind failed - %s\n", errstr);
-               ret = false;
-       } else if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("DsBind failed - %s\n", win_errstr(r.out.result));
-               ret = false;
        }
 
-       return ret;
+       return false;
 }
 
-bool torture_rpc_drsuapi(struct torture_context *torture)
+/**
+ * Common test case setup function to be used
+ * in DRS suit of test when appropriate
+ */
+bool torture_drsuapi_tcase_setup_common(struct torture_context *tctx, struct DsPrivate *priv)
 {
         NTSTATUS status;
-        struct dcerpc_pipe *p;
-       bool ret = true;
-       struct DsPrivate priv;
        struct cli_credentials *machine_credentials;
 
-       ZERO_STRUCT(priv);
+       torture_assert(tctx, priv, "Invalid argument");
 
-       priv.join = torture_join_domain(TEST_MACHINE_NAME, ACB_SVRTRUST, 
-                                      &machine_credentials);
-       if (!priv.join) {
-               torture_fail(torture, "Failed to join as BDC");
-       }
-
-       status = torture_rpc_connection(torture, 
-                                       &p, 
+       torture_comment(tctx, "Create DRSUAPI pipe\n");
+       status = torture_rpc_connection(tctx,
+                                       &priv->pipe,
                                        &ndr_table_drsuapi);
-       if (!NT_STATUS_IS_OK(status)) {
-               torture_leave_domain(priv.join);
-               torture_fail(torture, "Unable to connect to DRSUAPI pipe");
+       torture_assert(tctx, NT_STATUS_IS_OK(status), "Unable to connect to DRSUAPI pipe");
+
+       torture_comment(tctx, "About to join domain\n");
+       priv->join = torture_join_domain(tctx, TEST_MACHINE_NAME, ACB_SVRTRUST,
+                                        &machine_credentials);
+       torture_assert(tctx, priv->join, "Failed to join as BDC");
+
+       if (!test_DsBind(priv->pipe, tctx, priv)) {
+               /* clean up */
+               torture_drsuapi_tcase_teardown_common(tctx, priv);
+               torture_fail(tctx, "Failed execute test_DsBind()");
        }
 
-       ret &= test_DsBind(p, torture, &priv);
-#if 0
-       ret &= test_QuerySitesByCost(p, torture, &priv);
-#endif
-       ret &= test_DsGetDomainControllerInfo(p, torture, &priv);
+       /* try collect some information for testing */
+       torture_rpc_drsuapi_get_dcinfo(tctx, priv);
 
-       ret &= test_DsCrackNames(p, torture, &priv);
+       return true;
+}
 
-       ret &= test_DsWriteAccountSpn(p, torture, &priv);
+/**
+ * Common test case teardown function to be used
+ * in DRS suit of test when appropriate
+ */
+bool torture_drsuapi_tcase_teardown_common(struct torture_context *tctx, struct DsPrivate *priv)
+{
+       if (priv->join) {
+               torture_leave_domain(tctx, priv->join);
+       }
 
-       ret &= test_DsReplicaGetInfo(p, torture, &priv);
+       return true;
+}
 
-       ret &= test_DsReplicaSync(p, torture, &priv);
+/**
+ * Test case setup for DRSUAPI test case
+ */
+static bool torture_drsuapi_tcase_setup(struct torture_context *tctx, void **data)
+{
+       struct DsPrivate *priv;
 
-       ret &= test_DsReplicaUpdateRefs(p, torture, &priv);
+       *data = priv = talloc_zero(tctx, struct DsPrivate);
 
-       ret &= test_DsGetNCChanges(p, torture, &priv);
+       return torture_drsuapi_tcase_setup_common(tctx, priv);
+}
 
-       ret &= test_DsUnbind(p, torture, &priv);
+/**
+ * Test case tear-down for DRSUAPI test case
+ */
+static bool torture_drsuapi_tcase_teardown(struct torture_context *tctx, void *data)
+{
+       bool ret;
+       struct DsPrivate *priv = talloc_get_type(data, struct DsPrivate);
 
-       torture_leave_domain(priv.join);
+       ret = torture_drsuapi_tcase_teardown_common(tctx, priv);
 
+       talloc_free(priv);
        return ret;
 }
 
-
-bool torture_rpc_drsuapi_cracknames(struct torture_context *torture)
+/**
+ * DRSUAPI test case implementation
+ */
+void torture_rpc_drsuapi_tcase(struct torture_suite *suite)
 {
-        NTSTATUS status;
-        struct dcerpc_pipe *p;
-       bool ret = true;
-       struct DsPrivate priv;
-       struct cli_credentials *machine_credentials;
+       typedef bool (*run_func) (struct torture_context *test, void *tcase_data);
 
-       torture_comment(torture, "Connected to DRSUAPI pipe\n");
+       struct torture_test *test;
+       struct torture_tcase *tcase = torture_suite_add_tcase(suite, "DRSUAPI");
 
-       ZERO_STRUCT(priv);
+       torture_tcase_set_fixture(tcase,
+                                 torture_drsuapi_tcase_setup,
+                                 torture_drsuapi_tcase_teardown);
 
-       priv.join = torture_join_domain(TEST_MACHINE_NAME, ACB_SVRTRUST, 
-                                      &machine_credentials);
-       if (!priv.join) {
-               torture_fail(torture, "Failed to join as BDC\n");
-       }
+#if 0
+       test = torture_tcase_add_simple_test(tcase, "QuerySitesByCost", (run_func)test_QuerySitesByCost);
+#endif
 
-       status = torture_rpc_connection(torture, 
-                                       &p, 
-                                       &ndr_table_drsuapi);
-       if (!NT_STATUS_IS_OK(status)) {
-               torture_leave_domain(priv.join);
-               torture_fail(torture, "Unable to connect to DRSUAPI pipe");
-       }
+       test = torture_tcase_add_simple_test(tcase, "DsGetDomainControllerInfo", (run_func)test_DsGetDomainControllerInfo);
 
-       ret &= test_DsBind(p, torture, &priv);
+       test = torture_tcase_add_simple_test(tcase, "DsCrackNames", (run_func)test_DsCrackNames);
 
-       if (ret) {
-               /* We don't care if this fails, we just need some info from it */
-               test_DsGetDomainControllerInfo(p, torture, &priv);
-               
-               ret &= test_DsCrackNames(p, torture, &priv);
-               
-               ret &= test_DsUnbind(p, torture, &priv);
-       }
+       test = torture_tcase_add_simple_test(tcase, "DsWriteAccountSpn", (run_func)test_DsWriteAccountSpn);
 
-       torture_leave_domain(priv.join);
+       test = torture_tcase_add_simple_test(tcase, "DsReplicaGetInfo", (run_func)test_DsReplicaGetInfo);
 
-       return ret;
-}
+       test = torture_tcase_add_simple_test(tcase, "DsReplicaSync", (run_func)test_DsReplicaSync);
+
+       test = torture_tcase_add_simple_test(tcase, "DsReplicaUpdateRefs", (run_func)test_DsReplicaUpdateRefs);
 
+       test = torture_tcase_add_simple_test(tcase, "DsGetNCChanges", (run_func)test_DsGetNCChanges);
+}