r25026: Move param/param.h out of includes.h
[kai/samba.git] / source4 / torture / rpc / drsuapi.c
index 5a12ef37f402754acd9934993996e1631dc685b7..c3ec54cbcdbe6ac5b6eaad921e2ad4ac767d365d 100644 (file)
@@ -5,10 +5,11 @@
 
    Copyright (C) Andrew Tridgell 2003
    Copyright (C) Stefan (metze) Metzmacher 2004
-   
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-
-static const char *machine_password;
+#include "torture/torture.h"
+#include "librpc/gen_ndr/ndr_drsuapi_c.h"
+#include "torture/rpc/rpc.h"
+#include "dlinklist.h"
+#include "param/param.h"
 
 #define TEST_MACHINE_NAME "torturetest"
 
-#if 0
-static void reopen(struct dcerpc_pipe **p, const struct dcerpc_interface_table *iface)
+bool test_DsBind(struct dcerpc_pipe *p, struct torture_context *tctx,
+                struct DsPrivate *priv)
 {
        NTSTATUS status;
+       struct drsuapi_DsBind r;
+       struct torture_rpc_tcase_data *rpc_tcase;
 
-       if (*p) {
-               dcerpc_pipe_close(*p);
-       }
+       GUID_from_string(DRSUAPI_DS_BIND_GUID, &priv->bind_guid);
 
-       status = torture_rpc_connection(p, iface->endpoints->names[0], iface->uuid, iface->if_version);
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("Failed to reopen '%s' - %s\n", iface->name, nt_errstr(status));
-               exit(1);
-       }
-}
+       r.in.bind_guid = &priv->bind_guid;
+       r.in.bind_info = NULL;
+       r.out.bind_handle = &priv->bind_handle;
 
-static void print_depth(int depth)
-{
-       int i;
-       for (i=0;i<depth;i++) {
-               printf("    ");
-       }
-}
+       status = dcerpc_drsuapi_DsBind(p, tctx, &r);
+       torture_assert_ntstatus_ok(tctx, status, "DsBind");
+       torture_assert_werr_ok(tctx, r.out.result, "DsBind");
 
-static void test_ptr_scan(TALLOC_CTX *mem_ctx, const struct dcerpc_interface_table *iface, 
-                         int opnum, DATA_BLOB *base_in, int min_ofs, int max_ofs, int depth);
+       rpc_tcase = (struct torture_rpc_tcase_data *)tctx->active_tcase->data;
 
-static void try_expand(TALLOC_CTX *mem_ctx, const struct dcerpc_interface_table *iface, 
-                      int opnum, DATA_BLOB *base_in, int insert_ofs, int depth)
-{
-       DATA_BLOB stub_in, stub_out;
-       int n;
-       NTSTATUS status;
-       struct dcerpc_pipe *p = NULL;
+       priv->join = rpc_tcase->join_ctx;
 
-       reopen(&p, iface);
+       return true;
+}
 
-       /* work out how much to expand to get a non fault */
-       for (n=0;n<2000;n++) {
-               stub_in = data_blob(NULL, base_in->length + n);
-               data_blob_clear(&stub_in);
-               memcpy(stub_in.data, base_in->data, insert_ofs);
-               memcpy(stub_in.data+insert_ofs+n, base_in->data+insert_ofs, base_in->length-insert_ofs);
+bool test_DsUnbind(struct dcerpc_pipe *p, struct torture_context *tctx,
+                  struct DsPrivate *priv)
+{
+       NTSTATUS status;
+       struct drsuapi_DsUnbind r;
 
-               status = dcerpc_request(p, opnum, mem_ctx, &stub_in, &stub_out);
+       r.in.bind_handle = &priv->bind_handle;
+       r.out.bind_handle = &priv->bind_handle;
 
-               if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
-                       print_depth(depth);
-                       printf("expand by %d gives %s\n", n, nt_errstr(status));
-                       if (n >= 4) {
-                               test_ptr_scan(mem_ctx, iface, opnum, &stub_in, 
-                                             insert_ofs, insert_ofs+n, depth+1);
-                       }
-                       return;
-               } else {
-#if 0
-                       print_depth(depth);
-                       printf("expand by %d gives fault 0x%x\n", n, p->last_fault_code);
-#endif
-               }
-               if (p->last_fault_code == 5) {
-                       reopen(&p, iface);
-               }
-       }
+       status = dcerpc_drsuapi_DsUnbind(p, tctx, &r);
+       torture_assert_ntstatus_ok(tctx, status,
+                       "dcerpc_drsuapi_DsUnbind failed");
+       torture_assert_werr_ok(tctx, r.out.result, "DsBind failed");
 
-       dcerpc_pipe_close(p);   
+       return true;
 }
 
-
-static void test_ptr_scan(TALLOC_CTX *mem_ctx, const struct dcerpc_interface_table *iface, 
-                         int opnum, DATA_BLOB *base_in, int min_ofs, int max_ofs, int depth)
+static bool wrap_test_drsuapi(struct torture_context *tctx, 
+                             struct torture_tcase *tcase,
+                             struct torture_test *test)
 {
-       DATA_BLOB stub_in, stub_out;
-       int ofs;
-       NTSTATUS status;
-       struct dcerpc_pipe *p = NULL;
+       bool (*fn) (struct torture_context *, struct dcerpc_pipe *, struct DsPrivate *);
+       struct torture_rpc_tcase_data *tcase_data = 
+               (struct torture_rpc_tcase_data *)tcase->data;
+       bool ret;
+       struct DsPrivate priv;
 
-       reopen(&p, iface);
+       ZERO_STRUCT(priv);
 
-       stub_in = data_blob(NULL, base_in->length);
-       memcpy(stub_in.data, base_in->data, base_in->length);
+       fn = test->fn;
 
-       /* work out which elements are pointers */
-       for (ofs=min_ofs;ofs<=max_ofs-4;ofs+=4) {
-               SIVAL(stub_in.data, ofs, 1);
-               status = dcerpc_request(p, opnum, mem_ctx, &stub_in, &stub_out);
+       if (!test_DsBind(tcase_data->pipe, tctx, &priv))
+               return false;
 
-               if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
-                       print_depth(depth);
-                       printf("possible ptr at ofs %d - fault 0x%08x\n", 
-                              ofs-min_ofs, p->last_fault_code);
-                       if (p->last_fault_code == 5) {
-                               reopen(&p, iface);
-                       }
-                       if (depth == 0) {
-                               try_expand(mem_ctx, iface, opnum, &stub_in, ofs+4, depth+1);
-                       } else {
-                               try_expand(mem_ctx, iface, opnum, &stub_in, max_ofs, depth+1);
-                       }
-                       SIVAL(stub_in.data, ofs, 0);
-                       continue;
-               }
-               SIVAL(stub_in.data, ofs, 0);
-       }
+       ret = fn(tctx, tcase_data->pipe, &priv);
+       
+       if (!test_DsUnbind(tcase_data->pipe, tctx, &priv))
+               return false;
 
-       dcerpc_pipe_close(p);   
+       return ret;
 }
-       
 
-static void test_scan_call(TALLOC_CTX *mem_ctx, const struct dcerpc_interface_table *iface, int opnum)
+static struct torture_test *torture_rpc_tcase_add_drsuapi_test(
+                                       struct torture_rpc_tcase *tcase, 
+                                       const char *name, 
+                                       bool (*fn) (struct torture_context *, struct dcerpc_pipe *, struct DsPrivate *priv))
 {
-       DATA_BLOB stub_in, stub_out;
-       int i;
-       NTSTATUS status;
-       struct dcerpc_pipe *p = NULL;
+       struct torture_test *test;
 
-       reopen(&p, iface);
+       test = talloc(tcase, struct torture_test);
 
-       /* work out the minimum amount of input data */
-       for (i=0;i<2000;i++) {
-               stub_in = data_blob(NULL, i);
-               data_blob_clear(&stub_in);
+       test->name = talloc_strdup(test, name);
+       test->description = NULL;
+       test->run = wrap_test_drsuapi;
+       test->dangerous = false;
+       test->data = NULL;
+       test->fn = fn;
 
+       DLIST_ADD(tcase->tcase.tests, test);
 
-               status = dcerpc_request(p, opnum, mem_ctx, &stub_in, &stub_out);
+       return test;
+}
 
-               if (NT_STATUS_IS_OK(status)) {
-                       printf("opnum %d   min_input %d - output %d\n", 
-                              opnum, stub_in.length, stub_out.length);
-                       dump_data(0, stub_out.data, stub_out.length);
-                       dcerpc_pipe_close(p);
-                       test_ptr_scan(mem_ctx, iface, opnum, &stub_in, 0, stub_in.length, 0);
-                       return;
-               }
+static bool test_DsGetDomainControllerInfo(struct torture_context *torture, 
+                                          struct dcerpc_pipe *p, 
+                                          struct DsPrivate *priv)
+{
+       NTSTATUS status;
+       struct drsuapi_DsGetDomainControllerInfo r;
+       bool found = false;
+       int i, j, k;
+       
+       struct {
+               const char *name;
+               WERROR expected;
+       } names[] = { 
+               {       
+                       .name = torture_join_dom_netbios_name(priv->join),
+                       .expected = WERR_OK
+               },
+               {
+                       .name = torture_join_dom_dns_name(priv->join),
+                       .expected = WERR_OK
+               },
+               {
+                       .name = "__UNKNOWN_DOMAIN__",
+                       .expected = WERR_DS_OBJ_NOT_FOUND
+               },
+               {
+                       .name = "unknown.domain.samba.example.com",
+                       .expected = WERR_DS_OBJ_NOT_FOUND
+               },
+       };
+       int levels[] = {1, 2};
+       int level;
+
+       for (i=0; i < ARRAY_SIZE(levels); i++) {
+               for (j=0; j < ARRAY_SIZE(names); j++) {
+                       level = levels[i];
+                       r.in.bind_handle = &priv->bind_handle;
+                       r.in.level = 1;
+                       
+                       r.in.req.req1.domain_name = names[j].name;
+                       r.in.req.req1.level = level;
+                       
+                       torture_comment(torture,
+                                  "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,
+                                  "dcerpc_drsuapi_DsGetDomainControllerInfo with dns domain failed");
+                       torture_assert_werr_equal(torture, 
+                                                                         r.out.result, names[j].expected, 
+                                          "DsGetDomainControllerInfo level with dns domain failed");
+               
+                       if (!W_ERROR_IS_OK(r.out.result)) {
+                               /* If this was an error, we can't read the result structure */
+                               continue;
+                       }
 
-               if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
-                       printf("opnum %d  size %d fault 0x%08x\n", opnum, i, p->last_fault_code);
-                       if (p->last_fault_code == 5) {
-                               reopen(&p, iface);
+                       torture_assert_int_equal(torture, 
+                                                r.in.req.req1.level, r.out.level_out, 
+                                                "dcerpc_drsuapi_DsGetDomainControllerInfo level"); 
+
+                       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, 
+                                                        torture_join_netbios_name(priv->join)) == 0) {
+                                               found = true;
+                                               break;
+                                       }
+                               }
+                               break;
+                       case 2:
+                               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];
+                                               break;
+                                       }
+                               }
+                               break;
                        }
-                       continue;
+                       torture_assert(torture, found,
+                                "dcerpc_drsuapi_DsGetDomainControllerInfo: Failed to find the domain controller we just created during the join");
                }
+       }
 
-               printf("opnum %d  size %d error %s\n", opnum, i, nt_errstr(status));
+       r.in.bind_handle = &priv->bind_handle;
+       r.in.level = 1;
+       
+       r.in.req.req1.domain_name = "__UNKNOWN_DOMAIN__"; /* This is clearly ignored for this level */
+       r.in.req.req1.level = -1;
+       
+       torture_comment(torture,
+               "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, 
+                       "dcerpc_drsuapi_DsGetDomainControllerInfo with dns domain failed");
+       torture_assert_werr_ok(torture, r.out.result, 
+                          "DsGetDomainControllerInfo with dns domain failed");
+       
+       {
+               const char *dc_account = talloc_asprintf(torture, "%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, 
+                                        dc_account)) {
+                               found = true;
+                               break;
+                       }
+               }
+               torture_assert(torture, found,
+                       "dcerpc_drsuapi_DsGetDomainControllerInfo level: Failed to find the domain controller in last logon records");
        }
 
-       printf("opnum %d minimum not found!?\n", opnum);
-       dcerpc_pipe_close(p);
+
+       return true;
 }
 
+static bool test_DsWriteAccountSpn(struct torture_context *tctx, 
+                                  struct dcerpc_pipe *p, 
+                                  struct DsPrivate *priv)
+{
+       NTSTATUS status;
+       struct drsuapi_DsWriteAccountSpn r;
+       struct drsuapi_DsNameString names[2];
+
+       r.in.bind_handle                = &priv->bind_handle;
+       r.in.level                      = 1;
+
+       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, tctx, &r);
+       torture_assert_ntstatus_ok(tctx, status, 
+               "dcerpc_drsuapi_DsWriteAccountSpn failed");
+       torture_assert_werr_ok(tctx, r.out.result, "DsWriteAccountSpn failed");
+
+       r.in.req.req1.operation = DRSUAPI_DS_SPN_OPERATION_DELETE;
+       r.in.req.req1.unknown1  = 0;
+
+       status = dcerpc_drsuapi_DsWriteAccountSpn(p, tctx, &r);
+       torture_assert_ntstatus_ok(tctx, status, 
+               "dcerpc_drsuapi_DsWriteAccountSpn failed");
+       torture_assert_werr_ok(tctx, r.out.result, "DsWriteAccountSpn failed");
+
+       return true;
+}
 
-static BOOL test_scan(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
+static bool test_DsReplicaGetInfo(struct torture_context *tctx, 
+                                 struct dcerpc_pipe *p, 
+                                 struct DsPrivate *priv)
 {
-       test_scan_call(mem_ctx, &dcerpc_table_drsuapi, 0x0);
-       return True;
+       NTSTATUS status;
+       struct drsuapi_DsReplicaGetInfo r;
+       int i;
+       struct {
+               int32_t level;
+               int32_t infotype;
+               const char *obj_dn;
+       } array[] = {
+               {       
+                       DRSUAPI_DS_REPLICA_GET_INFO,
+                       DRSUAPI_DS_REPLICA_INFO_NEIGHBORS,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO,
+                       DRSUAPI_DS_REPLICA_INFO_CURSORS,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO,
+                       DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO,
+                       DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO,
+                       DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO,
+                       DRSUAPI_DS_REPLICA_INFO_PENDING_OPS,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO2,
+                       DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO2,
+                       DRSUAPI_DS_REPLICA_INFO_CURSORS2,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO2,
+                       DRSUAPI_DS_REPLICA_INFO_CURSORS3,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO2,
+                       DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO2,
+                       DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO2,
+                       DRSUAPI_DS_REPLICA_INFO_NEIGHBORS02,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO2,
+                       DRSUAPI_DS_REPLICA_INFO_CONNECTIONS04,
+                       "__IGNORED__"
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO2,
+                       DRSUAPI_DS_REPLICA_INFO_CURSORS05,
+                       NULL
+               },{
+                       DRSUAPI_DS_REPLICA_GET_INFO2,
+                       DRSUAPI_DS_REPLICA_INFO_06,
+                       NULL
+               }
+       };
+
+       r.in.bind_handle        = &priv->bind_handle;
+
+       for (i=0; i < ARRAY_SIZE(array); i++) {
+               const char *object_dn;
+
+               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);
+                       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;
+                       break;
+               }
+
+               status = dcerpc_drsuapi_DsReplicaGetInfo(p, tctx, &r);
+               torture_assert_ntstatus_ok(tctx, status, 
+                       "dcerpc_drsuapi_DsReplicaGetInfo failed");
+               torture_assert_werr_ok(tctx, r.out.result, 
+                                      "DsReplicaGetInfo failed");
+       }
+
+       return true;
 }
-#endif
 
-static BOOL test_DRSBind(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
+static bool test_DsReplicaSync(struct torture_context *tctx,
+                              struct dcerpc_pipe *p, 
+                              struct DsPrivate *priv)
 {
        NTSTATUS status;
-       struct DRSUAPI_BIND r;
-       BOOL ret = True;
+       int i;
+       struct drsuapi_DsReplicaSync r;
+       struct drsuapi_DsReplicaObjectIdentifier nc;
+       struct GUID null_guid;
+       struct dom_sid null_sid;
+       struct {
+               int32_t level;
+       } array[] = {
+               {       
+                       1
+               }
+       };
+
+       ZERO_STRUCT(null_guid);
+       ZERO_STRUCT(null_sid);
+
+       r.in.bind_handle        = &priv->bind_handle;
 
-       ZERO_STRUCT(r.in.blob);
+       for (i=0; i < ARRAY_SIZE(array); i++) {
+               torture_comment(tctx, "testing DsReplicaSync level %d\n",
+                               array[i].level);
 
-       status = dcerpc_DRSUAPI_BIND(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(p->last_fault_code);
+               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.source_dsa_guid           = priv->dcinfo.ntds_guid;
+                       r.in.req.req1.other_info                = NULL;
+                       r.in.req.req1.options                   = 16;
+                       break;
                }
-               printf("DRSUAPI_BIND level failed - %s\n", errstr);
-               ret = False;
+
+               status = dcerpc_drsuapi_DsReplicaSync(p, tctx, &r);
+               torture_assert_ntstatus_ok(tctx, status, 
+                       "dcerpc_drsuapi_DsReplicaSync failed");
+               torture_assert_werr_ok(tctx, r.out.result, 
+                                      "DsReplicaSync failed");
        }
 
-       return ret;
+       return true;
 }
 
-BOOL torture_rpc_drsuapi(int dummy)
+static bool test_DsReplicaUpdateRefs(struct torture_context *tctx, 
+                                    struct dcerpc_pipe *p, 
+                                    struct DsPrivate *priv)
 {
-        NTSTATUS status;
-        struct dcerpc_pipe *p;
-       TALLOC_CTX *mem_ctx;
-       BOOL ret = True;
-       void *join_ctx;
-       const char *binding = lp_parm_string(-1, "torture", "binding");
-
-       if (!binding) {
-               printf("You must specify a ncacn binding string\n");
-               return False;
-       }
-
-       lp_set_cmdline("netbios name", TEST_MACHINE_NAME);
+       NTSTATUS status;
+       int i;
+       struct drsuapi_DsReplicaUpdateRefs r;
+       struct drsuapi_DsReplicaObjectIdentifier nc;
+       struct GUID null_guid;
+       struct dom_sid null_sid;
+       struct {
+               int32_t level;
+       } array[] = {
+               {       
+                       1
+               }
+       };
+
+       ZERO_STRUCT(null_guid);
+       ZERO_STRUCT(null_sid);
+
+       r.in.bind_handle        = &priv->bind_handle;
+
+       for (i=0; i < ARRAY_SIZE(array); i++) {
+               torture_comment(tctx, "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;
+               }
 
-       join_ctx = torture_join_domain(TEST_MACHINE_NAME, lp_workgroup(), ACB_SVRTRUST, 
-                                      &machine_password);
-       if (!join_ctx) {
-               printf("Failed to join as BDC\n");
-               return False;
+               status = dcerpc_drsuapi_DsReplicaUpdateRefs(p, tctx, &r);
+               torture_assert_ntstatus_ok(tctx, status, 
+                       "dcerpc_drsuapi_DsReplicaUpdateRefs failed");
+               torture_assert_werr_ok(tctx, r.out.result, 
+                       "DsReplicaUpdateRefs failed");
        }
 
-       status = dcerpc_pipe_connect(&p, binding,
-                                       DCERPC_DRSUAPI_UUID,
-                                       DCERPC_DRSUAPI_VERSION,
-                                       lp_workgroup(), 
-                                       TEST_MACHINE_NAME"$",
-                                       machine_password);
+       return true;
+}
+
+static bool test_DsGetNCChanges(struct torture_context *tctx, 
+                               struct dcerpc_pipe *p, 
+                               struct DsPrivate *priv)
+{
+       NTSTATUS status;
+       int i;
+       struct drsuapi_DsGetNCChanges r;
+       struct drsuapi_DsReplicaObjectIdentifier nc;
+       struct GUID null_guid;
+       struct dom_sid null_sid;
+       struct {
+               int32_t level;
+       } array[] = {
+               {       
+                       5
+               },
+               {       
+                       8
+               }
+       };
+
+       ZERO_STRUCT(null_guid);
+       ZERO_STRUCT(null_sid);
+
+       for (i=0; i < ARRAY_SIZE(array); i++) {
+               torture_comment(tctx, "testing DsGetNCChanges level %d\n",
+                       array[i].level);
+
+               r.in.bind_handle        = &priv->bind_handle;
+               r.in.level              = &array[i].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(-1, "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;
+
+                       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(-1, "drsuapi", "compression", false)) {
+                               r.in.req.req8.replica_flags             |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
+                       }
+                       if (lp_parm_bool(-1, "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
+                                                                       | 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;
+
+                       break;
+               }
 
-       if (!NT_STATUS_IS_OK(status)) {
-               return False;
+               status = dcerpc_drsuapi_DsGetNCChanges(p, tctx, &r);
+               torture_assert_ntstatus_ok(tctx, status, 
+                       "dcerpc_drsuapi_DsGetNCChanges failed");
+               torture_assert_werr_ok(tctx, r.out.result, 
+                                      "DsGetNCChanges failed");
        }
 
-       mem_ctx = talloc_init("torture_rpc_drsuapi");
+       return true;
+}
 
-       if (!test_DRSBind(p, mem_ctx)) {
-               ret = False;
-       }
+bool test_QuerySitesByCost(struct torture_context *tctx, struct dcerpc_pipe *p, 
+                          struct DsPrivate *priv)
+{
+       NTSTATUS status;
+       struct drsuapi_QuerySitesByCost r;
+
+       const char *my_site = "Default-First-Site-Name";
+       const char *remote_site1 = "smbtorture-nonexisting-site1";
+       const char *remote_site2 = "smbtorture-nonexisting-site2";
+
+       r.in.bind_handle = &priv->bind_handle;
+       r.in.level = 1;
+       r.in.req.req1.site_from = talloc_strdup(tctx, my_site);
+       r.in.req.req1.num_req = 2;
+       r.in.req.req1.site_to = talloc_zero_array(tctx, const char *, r.in.req.req1.num_req);
+       r.in.req.req1.site_to[0] = talloc_strdup(tctx, remote_site1);
+       r.in.req.req1.site_to[1] = talloc_strdup(tctx, remote_site2);
+       r.in.req.req1.flags = 0;
+
+       status = dcerpc_drsuapi_QuerySitesByCost(p, tctx, &r);
+       torture_assert_ntstatus_ok(tctx, status, "drsuapi_QuerySitesByCost");
+       torture_assert_werr_ok(tctx, r.out.result, "QuerySitesByCost failed");
+
+       torture_assert_werr_equal(tctx, r.out.ctr.ctr1.info[0].error_code, 
+                                 WERR_DS_OBJ_NOT_FOUND, "expected not found error");
+       torture_assert_werr_equal(tctx, r.out.ctr.ctr1.info[1].error_code, 
+                                 WERR_DS_OBJ_NOT_FOUND, "expected not found error");
+
+       torture_assert_int_equal(tctx, r.out.ctr.ctr1.info[0].site_cost,
+                                (uint32_t) -1, "unexpected site cost");
+         
+       torture_assert_int_equal(tctx, r.out.ctr.ctr1.info[1].site_cost, 
+                                (uint32_t) -1, "unexpected site cost");
+
+       return true;
+}
 
-#if 0
-       if (!test_scan(p, mem_ctx)) {
-               ret = False;
-       }
-#endif
-       talloc_destroy(mem_ctx);
+struct torture_suite *torture_rpc_drsuapi(TALLOC_CTX *mem_ctx)
+{
+       struct torture_suite *suite = torture_suite_create(mem_ctx, "DRSUAPI");
+       struct torture_test *test;
+       struct torture_rpc_tcase *tcase = torture_suite_add_machine_rpc_iface_tcase(suite, "drsuapi", 
+                                                                           &ndr_table_drsuapi, TEST_MACHINE_NAME);
+
+       torture_rpc_tcase_add_drsuapi_test(tcase, "QuerySitesByCost", test_QuerySitesByCost);
+       torture_rpc_tcase_add_drsuapi_test(tcase, "DsGetDomainControllerInfo", test_DsGetDomainControllerInfo);
+       torture_rpc_tcase_add_drsuapi_test(tcase, "DsCrackNames", test_DsCrackNames);
+       torture_rpc_tcase_add_drsuapi_test(tcase, "DsWriteAccountSpn", test_DsWriteAccountSpn);
+       torture_rpc_tcase_add_drsuapi_test(tcase, "DsReplicaGetInfo", test_DsReplicaGetInfo);
+       test = torture_rpc_tcase_add_drsuapi_test(tcase, "DsReplicaSync", test_DsReplicaSync);
+       test->dangerous = true;
+       torture_rpc_tcase_add_drsuapi_test(tcase, "DsReplicaUpdateRefs", test_DsReplicaUpdateRefs);
+       torture_rpc_tcase_add_drsuapi_test(tcase, "DsGetNCChange", test_DsGetNCChanges);
+
+       return suite;
+}
 
-        torture_rpc_close(p);
+struct torture_suite *torture_rpc_drsuapi_cracknames(TALLOC_CTX *mem_ctx)
+{
+       struct torture_suite *suite = torture_suite_create(mem_ctx, "CRACKNAMES");
+       struct torture_rpc_tcase *tcase = torture_suite_add_machine_rpc_iface_tcase(suite, "drsuapi", 
+                                                                           &ndr_table_drsuapi, TEST_MACHINE_NAME);
 
-       torture_leave_domain(join_ctx);
+       torture_rpc_tcase_add_drsuapi_test(tcase, "DsGetDomainControllerInfo", test_DsGetDomainControllerInfo);
+       torture_rpc_tcase_add_drsuapi_test(tcase, "DsCrackNames", test_DsCrackNames);
 
-       return ret;
+       return suite;
 }
+