Merge branch 'master' of ssh://jra@git.samba.org/data/git/samba
[amitay/samba.git] / source4 / torture / rpc / drsuapi.c
index 88d6b78124356067d6d622eacc5510755008000c..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;
@@ -105,14 +137,14 @@ static bool test_DsGetDomainControllerInfo(struct dcerpc_pipe *p, struct torture
                        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);
                
-                       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");
                
@@ -121,9 +153,9 @@ 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:
@@ -146,7 +178,7 @@ static bool test_DsGetDomainControllerInfo(struct dcerpc_pipe *p, struct torture
                                }
                                break;
                        }
-                       torture_assert(torture, found,
+                       torture_assert(tctx, found,
                                 "dcerpc_drsuapi_DsGetDomainControllerInfo: Failed to find the domain controller we just created during the join");
                }
        }
@@ -160,20 +192,21 @@ static bool test_DsGetDomainControllerInfo(struct dcerpc_pipe *p, struct torture
        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);
+               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)) {
@@ -181,7 +214,7 @@ static bool test_DsGetDomainControllerInfo(struct dcerpc_pipe *p, struct torture
                                break;
                        }
                }
-               torture_assert(torture, found,
+               torture_assert(tctx, found,
                        "dcerpc_drsuapi_DsGetDomainControllerInfo level: Failed to find the domain controller in last logon records");
        }
 
@@ -189,75 +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];
        union drsuapi_DsWriteAccountSpnResult res;
        int32_t level_out;
-       bool ret = true;
 
        r.in.bind_handle                = &priv->bind_handle;
        r.in.level                      = 1;
        r.in.req                        = &req;
 
-       printf("testing DsWriteAccountSpn\n");
+       torture_comment(tctx, "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);
+       names[0].str = talloc_asprintf(tctx, "smbtortureSPN/%s",priv->dcinfo.netbios_name);
+       names[1].str = talloc_asprintf(tctx, "smbtortureSPN/%s",priv->dcinfo.dns_name);
 
        r.out.res                       = &res;
        r.out.level_out                 = &level_out;
 
-       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;
-       }
+       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, 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;
-       }
+       status = dcerpc_drsuapi_DsWriteAccountSpn(p, tctx, &r);
+       torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsWriteAccountSpn");
 
-       return ret;
+       return true;
 }
 
-static bool test_DsReplicaGetInfo(struct dcerpc_pipe *p, struct torture_context *tctx,
-                       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;
        union drsuapi_DsReplicaGetInfoRequest req;
        union drsuapi_DsReplicaInfo info;
        enum drsuapi_DsReplicaInfoType info_type;
-       bool ret = true;
        int i;
        struct {
                int32_t level;
@@ -328,7 +341,7 @@ static bool test_DsReplicaGetInfo(struct dcerpc_pipe *p, struct torture_context
        };
 
        if (torture_setting_bool(tctx, "samba4", false)) {
-               printf("skipping DsReplicaGetInfo test against Samba4\n");
+               torture_comment(tctx, "skipping DsReplicaGetInfo test against Samba4\n");
                return true;
        }
 
@@ -338,8 +351,8 @@ static bool test_DsReplicaGetInfo(struct dcerpc_pipe *p, struct torture_context
        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);
 
@@ -365,32 +378,24 @@ static bool test_DsReplicaGetInfo(struct dcerpc_pipe *p, struct torture_context
                r.out.info_type         = &info_type;
 
                status = dcerpc_drsuapi_DsReplicaGetInfo(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);
-                       }
-                       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",
+               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, struct torture_context *tctx,
-                       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;
@@ -405,12 +410,12 @@ static bool test_DsReplicaSync(struct dcerpc_pipe *p, struct torture_context *tc
        };
 
        if (!torture_setting_bool(tctx, "dangerous", false)) {
-               printf("DsReplicaSync disabled - enable dangerous tests to use\n");
+               torture_comment(tctx, "DsReplicaSync disabled - enable dangerous tests to use\n");
                return true;
        }
 
        if (torture_setting_bool(tctx, "samba4", false)) {
-               printf("skipping DsReplicaSync test against Samba4\n");
+               torture_comment(tctx, "skipping DsReplicaSync test against Samba4\n");
                return true;
        }
 
@@ -420,8 +425,8 @@ static bool test_DsReplicaSync(struct dcerpc_pipe *p, struct torture_context *tc
        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) {
@@ -438,91 +443,84 @@ static bool test_DsReplicaSync(struct dcerpc_pipe *p, struct torture_context *tc
                }
 
                status = dcerpc_drsuapi_DsReplicaSync(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);
-                       }
-                       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;
-               }
+               torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaSync");
        }
 
-       return ret;
+       return true;
 }
 
-static bool test_DsReplicaUpdateRefs(struct dcerpc_pipe *p, struct torture_context *tctx,
-                       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 (torture_setting_bool(tctx, "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(tctx, "__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, 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);
-                       }
-                       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, struct torture_context *tctx, 
-                       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;
@@ -543,7 +541,7 @@ static bool test_DsGetNCChanges(struct dcerpc_pipe *p, struct torture_context *t
        };
 
        if (torture_setting_bool(tctx, "samba4", false)) {
-               printf("skipping DsGetNCChanges test against Samba4\n");
+               torture_comment(tctx, "skipping DsGetNCChanges test against Samba4\n");
                return true;
        }
 
@@ -551,8 +549,9 @@ static bool test_DsGetNCChanges(struct dcerpc_pipe *p, struct torture_context *t
        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;
@@ -563,7 +562,7 @@ static bool test_DsGetNCChanges(struct dcerpc_pipe *p, struct torture_context *t
                case 5:
                        nc.guid = null_guid;
                        nc.sid  = null_sid;
-                       nc.dn   = priv->domain_obj_dn?priv->domain_obj_dn:"";
+                       nc.dn   = priv->domain_obj_dn ? priv->domain_obj_dn : "";
 
                        r.in.req                                        = &req;
                        r.in.req->req5.destination_dsa_guid             = GUID_random();
@@ -574,7 +573,7 @@ static bool test_DsGetNCChanges(struct dcerpc_pipe *p, struct torture_context *t
                        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)) {
+                       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;
@@ -586,7 +585,7 @@ static bool test_DsGetNCChanges(struct dcerpc_pipe *p, struct torture_context *t
                case 8:
                        nc.guid = null_guid;
                        nc.sid  = null_sid;
-                       nc.dn   = priv->domain_obj_dn?priv->domain_obj_dn:"";
+                       nc.dn   = priv->domain_obj_dn ? priv->domain_obj_dn : "";
 
                        r.in.req                                        = &req;
                        r.in.req->req8.destination_dsa_guid             = GUID_random();
@@ -621,156 +620,77 @@ static bool test_DsGetNCChanges(struct dcerpc_pipe *p, struct torture_context *t
                }
 
                status = dcerpc_drsuapi_DsGetNCChanges(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);
-                       }
-                       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;
-               }
+               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;
        union drsuapi_QuerySitesByCostRequest req;
-       bool ret = true;
 
        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(mem_ctx, my_site);
+       req.req1.site_from = talloc_strdup(tctx, my_site);
        req.req1.num_req = 2;
-       req.req1.site_to = talloc_zero_array(mem_ctx, const char *, 2);
-       req.req1.site_to[0] = talloc_strdup(mem_ctx, remote_site1);
-       req.req1.site_to[1] = talloc_strdup(mem_ctx, remote_site2);
+       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 = &req;
 
-       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;
-       }
+       status = dcerpc_drsuapi_QuerySitesByCost(p, tctx, &r);
+       torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_QuerySitesByCost");
 
        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;
-               }
-
-               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;
-               }
+               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, 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_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;
-       }
+       status = dcerpc_drsuapi_DsUnbind(p, tctx, &r);
+       torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsUnbind");
 
-       return ret;
+       return true;
 }
 
-bool torture_rpc_drsuapi(struct torture_context *torture)
-{
-        NTSTATUS status;
-        struct dcerpc_pipe *p;
-       bool ret = true;
-       struct DsPrivate priv;
-       struct cli_credentials *machine_credentials;
-
-       ZERO_STRUCT(priv);
-
-       priv.join = torture_join_domain(torture, TEST_MACHINE_NAME, ACB_SVRTRUST, 
-                                      &machine_credentials);
-       if (!priv.join) {
-               torture_fail(torture, "Failed to join as BDC");
-       }
-
-       status = torture_rpc_connection(torture, 
-                                       &p, 
-                                       &ndr_table_drsuapi);
-       if (!NT_STATUS_IS_OK(status)) {
-               torture_leave_domain(torture, priv.join);
-               torture_fail(torture, "Unable to connect to DRSUAPI pipe");
-       }
-
-       ret &= test_DsBind(p, torture, &priv);
-#if 0
-       ret &= test_QuerySitesByCost(p, torture, &priv);
-#endif
-       ret &= test_DsGetDomainControllerInfo(p, torture, &priv);
-
-       ret &= test_DsCrackNames(torture, p, torture, &priv);
-
-       ret &= test_DsWriteAccountSpn(p, torture, &priv);
-
-       ret &= test_DsReplicaGetInfo(p, torture, &priv);
-
-       ret &= test_DsReplicaSync(p, torture, &priv);
-
-       ret &= test_DsReplicaUpdateRefs(p, torture, &priv);
-
-       ret &= test_DsGetNCChanges(p, torture, &priv);
-
-       ret &= test_DsUnbind(p, torture, &priv);
-
-       torture_leave_domain(torture, priv.join);
-
-       return ret;
-}
 
 /**
  * Helper func to collect DC information for testing purposes.
@@ -825,89 +745,104 @@ bool torture_rpc_drsuapi_get_dcinfo(struct torture_context *torture,
  * Common test case setup function to be used
  * in DRS suit of test when appropriate
  */
-bool torture_rpc_drsuapi_tcase_setup(struct torture_context *tctx, void **data)
+bool torture_drsuapi_tcase_setup_common(struct torture_context *tctx, struct DsPrivate *priv)
 {
         NTSTATUS status;
-       struct DsPrivate *priv;
        struct cli_credentials *machine_credentials;
 
-       *data = priv = talloc_zero(tctx, struct DsPrivate);
-       torture_assert(tctx, priv, "Not enough memory");
+       torture_assert(tctx, priv, "Invalid argument");
 
-       torture_comment(tctx, "Create DRSUAPI pipe");
+       torture_comment(tctx, "Create DRSUAPI pipe\n");
        status = torture_rpc_connection(tctx,
                                        &priv->pipe,
                                        &ndr_table_drsuapi);
        torture_assert(tctx, NT_STATUS_IS_OK(status), "Unable to connect to DRSUAPI pipe");
 
-       torture_comment(tctx, "Connected to DRSUAPI pipe\n");
+       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_rpc_drsuapi_tcase_teardown(tctx, priv);
+               torture_drsuapi_tcase_teardown_common(tctx, priv);
                torture_fail(tctx, "Failed execute test_DsBind()");
        }
 
+       /* try collect some information for testing */
+       torture_rpc_drsuapi_get_dcinfo(tctx, priv);
+
        return true;
 }
 
-bool torture_rpc_drsuapi_tcase_teardown(struct torture_context *tctx, void *data)
+/**
+ * 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)
 {
-       struct DsPrivate *priv = (struct DsPrivate *)data;
-
        if (priv->join) {
                torture_leave_domain(tctx, priv->join);
        }
 
-       talloc_free(priv);
-
        return true;
 }
 
+/**
+ * Test case setup for DRSUAPI test case
+ */
+static bool torture_drsuapi_tcase_setup(struct torture_context *tctx, void **data)
+{
+       struct DsPrivate *priv;
 
-/*
-bool torture_rpc_drsuapi_cracknames(struct torture_context *torture)
+       *data = priv = talloc_zero(tctx, struct DsPrivate);
+
+       return torture_drsuapi_tcase_setup_common(tctx, priv);
+}
+
+/**
+ * Test case tear-down for DRSUAPI test case
+ */
+static bool torture_drsuapi_tcase_teardown(struct torture_context *tctx, void *data)
 {
-        NTSTATUS status;
-        struct dcerpc_pipe *p;
-       bool ret = true;
-       struct DsPrivate priv;
-       struct cli_credentials *machine_credentials;
+       bool ret;
+       struct DsPrivate *priv = talloc_get_type(data, struct DsPrivate);
 
-       torture_comment(torture, "Connected to DRSUAPI pipe\n");
+       ret = torture_drsuapi_tcase_teardown_common(tctx, priv);
 
-       ZERO_STRUCT(priv);
+       talloc_free(priv);
+       return ret;
+}
 
-       priv.join = torture_join_domain(torture, TEST_MACHINE_NAME, ACB_SVRTRUST, 
-                                      &machine_credentials);
-       if (!priv.join) {
-               torture_fail(torture, "Failed to join as BDC\n");
-       }
+/**
+ * DRSUAPI test case implementation
+ */
+void torture_rpc_drsuapi_tcase(struct torture_suite *suite)
+{
+       typedef bool (*run_func) (struct torture_context *test, void *tcase_data);
 
-       status = torture_rpc_connection(torture, 
-                                       &p, 
-                                       &ndr_table_drsuapi);
-       if (!NT_STATUS_IS_OK(status)) {
-               torture_leave_domain(torture, priv.join);
-               torture_fail(torture, "Unable to connect to DRSUAPI pipe");
-       }
+       struct torture_test *test;
+       struct torture_tcase *tcase = torture_suite_add_tcase(suite, "DRSUAPI");
 
-       ret &= test_DsBind(p, torture, &priv);
+       torture_tcase_set_fixture(tcase,
+                                 torture_drsuapi_tcase_setup,
+                                 torture_drsuapi_tcase_teardown);
 
-       if (ret) {
-               /* We don't care if this fails, we just need some info from it */
-               test_DsGetDomainControllerInfo(p, torture, &priv);
-               
-               ret &= test_DsCrackNames(torture, p, torture, &priv);
-               
-               ret &= test_DsUnbind(p, torture, &priv);
-       }
+#if 0
+       test = torture_tcase_add_simple_test(tcase, "QuerySitesByCost", (run_func)test_QuerySitesByCost);
+#endif
 
-       torture_leave_domain(torture, priv.join);
+       test = torture_tcase_add_simple_test(tcase, "DsGetDomainControllerInfo", (run_func)test_DsGetDomainControllerInfo);
 
-       return ret;
-}
+       test = torture_tcase_add_simple_test(tcase, "DsCrackNames", (run_func)test_DsCrackNames);
+
+       test = torture_tcase_add_simple_test(tcase, "DsWriteAccountSpn", (run_func)test_DsWriteAccountSpn);
 
+       test = torture_tcase_add_simple_test(tcase, "DsReplicaGetInfo", (run_func)test_DsReplicaGetInfo);
+
+       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);
+}