diff options
-rw-r--r-- | source4/torture/config.mk | 1 | ||||
-rw-r--r-- | source4/torture/rpc/drsuapi.c | 12 | ||||
-rw-r--r-- | source4/torture/rpc/dssync.c | 410 | ||||
-rw-r--r-- | source4/torture/torture.c | 1 |
4 files changed, 420 insertions, 4 deletions
diff --git a/source4/torture/config.mk b/source4/torture/config.mk index 548ded1111..ec60dbbe55 100644 --- a/source4/torture/config.mk +++ b/source4/torture/config.mk @@ -79,6 +79,7 @@ ADD_OBJ_FILES = \ torture/rpc/dfs.o \ torture/rpc/drsuapi.o \ torture/rpc/drsuapi_cracknames.o \ + torture/rpc/dssync.o \ torture/rpc/spoolss.o \ torture/rpc/unixinfo.o \ torture/rpc/samr.o \ diff --git a/source4/torture/rpc/drsuapi.c b/source4/torture/rpc/drsuapi.c index 1d47a58747..a3310e144f 100644 --- a/source4/torture/rpc/drsuapi.c +++ b/source4/torture/rpc/drsuapi.c @@ -553,13 +553,17 @@ static BOOL test_DsGetNCChanges(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 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 - | DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE - | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP + 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 - | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES ; r.in.req.req8.unknown2 = 402; r.in.req.req8.unknown3 = 402116; diff --git a/source4/torture/rpc/dssync.c b/source4/torture/rpc/dssync.c new file mode 100644 index 0000000000..7688a0c2f1 --- /dev/null +++ b/source4/torture/rpc/dssync.c @@ -0,0 +1,410 @@ +/* + Unix SMB/CIFS implementation. + + DsGetNCChanges replication test + + Copyright (C) Stefan (metze) Metzmacher 2005 + Copyright (C) Brad Henry 2005 + + 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 + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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. +*/ + +#include "includes.h" +#include "lib/cmdline/popt_common.h" +#include "libnet/libnet.h" +#include "librpc/gen_ndr/ndr_drsuapi.h" +#include "librpc/gen_ndr/ndr_samr.h" +#include "libcli/ldap/ldap.h" +#include "libcli/cldap/cldap.h" +#include "ads.h" + +struct DsSyncBindInfo { + struct dcerpc_pipe *pipe; + struct drsuapi_DsBind req; + struct GUID bind_guid; + struct drsuapi_DsBindInfoCtr our_bind_info; + struct policy_handle bind_handle; +}; + +struct DsSyncLDAPInfo { + struct ldap_connection *conn; +}; + +struct DsSyncTest { + struct dcerpc_binding *drsuapi_binding; + + const char *ldap_url; + const char *site_name; + + const char *domain_dn; + + /* what we need to do as 'Administrator' */ + struct { + struct cli_credentials *credentials; + struct DsSyncBindInfo drsuapi; + struct DsSyncLDAPInfo ldap; + } admin; + + /* what we need to do as the new dc machine account */ + struct { + struct cli_credentials *credentials; + struct DsSyncBindInfo drsuapi; + struct drsuapi_DsGetDCInfo2 dc_info2; + struct GUID invocation_id; + struct GUID object_guid; + } new_dc; + + /* info about the old dc */ + struct { + struct drsuapi_DsGetDomainControllerInfo dc_info; + } old_dc; +}; + +static struct DsSyncTest *test_create_context(TALLOC_CTX *mem_ctx) +{ + NTSTATUS status; + struct DsSyncTest *ctx; + struct drsuapi_DsBindInfoCtr *our_bind_info; + const char *binding = lp_parm_string(-1, "torture", "binding"); + ctx = talloc_zero(mem_ctx, struct DsSyncTest); + if (!ctx) return NULL; + + status = dcerpc_parse_binding(ctx, binding, &ctx->drsuapi_binding); + if (!NT_STATUS_IS_OK(status)) { + printf("Bad binding string %s\n", binding); + return NULL; + } + ctx->drsuapi_binding->flags |= DCERPC_SIGN | DCERPC_SEAL; + + ctx->ldap_url = talloc_asprintf(ctx, "ldap://%s/", ctx->drsuapi_binding->host); + + /* ctx->admin ...*/ + ctx->admin.credentials = cmdline_credentials; + + our_bind_info = &ctx->admin.drsuapi.our_bind_info; + our_bind_info->length = 28; + our_bind_info->info.info28.supported_extensions = 0xFFFFFFFF; + our_bind_info->info.info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3; + our_bind_info->info.info28.site_guid = GUID_zero(); + our_bind_info->info.info28.u1 = 0; + our_bind_info->info.info28.repl_epoch = 1; + + GUID_from_string(DRSUAPI_DS_BIND_GUID, &ctx->admin.drsuapi.bind_guid); + + ctx->admin.drsuapi.req.in.bind_guid = &ctx->admin.drsuapi.bind_guid; + ctx->admin.drsuapi.req.in.bind_info = our_bind_info; + ctx->admin.drsuapi.req.out.bind_handle = &ctx->admin.drsuapi.bind_handle; + + /* ctx->new_dc ...*/ + + our_bind_info = &ctx->new_dc.drsuapi.our_bind_info; + our_bind_info->length = 28; + our_bind_info->info.info28.supported_extensions = 0x1ffffb7f; + our_bind_info->info.info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION; + our_bind_info->info.info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3; + our_bind_info->info.info28.site_guid = GUID_zero(); + our_bind_info->info.info28.u1 = 508; + our_bind_info->info.info28.repl_epoch = 0; + + GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &ctx->new_dc.drsuapi.bind_guid); + + ctx->new_dc.drsuapi.req.in.bind_guid = &ctx->new_dc.drsuapi.bind_guid; + ctx->new_dc.drsuapi.req.in.bind_info = our_bind_info; + ctx->new_dc.drsuapi.req.out.bind_handle = &ctx->new_dc.drsuapi.bind_handle; + + /* ctx->old_dc ...*/ + + return ctx; +} + +static BOOL _test_DsBind(struct DsSyncTest *ctx, struct cli_credentials *credentials, struct DsSyncBindInfo *b) +{ + NTSTATUS status; + BOOL ret = True; + struct event_context *event = NULL; + + status = dcerpc_pipe_connect_b(ctx, + &b->pipe, ctx->drsuapi_binding, + DCERPC_DRSUAPI_UUID, + DCERPC_DRSUAPI_VERSION, + credentials, event); + + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to connect to server as a BDC: %s\n", nt_errstr(status)); + return False; + } + + status = dcerpc_drsuapi_DsBind(b->pipe, ctx, &b->req); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { + errstr = dcerpc_errstr(ctx, b->pipe->last_fault_code); + } + printf("dcerpc_drsuapi_DsBind failed - %s\n", errstr); + ret = False; + } else if (!W_ERROR_IS_OK(b->req.out.result)) { + printf("DsBind failed - %s\n", win_errstr(b->req.out.result)); + ret = False; + } + + return ret; +} + +static BOOL test_LDAPBind(struct DsSyncTest *ctx, struct cli_credentials *credentials, struct DsSyncLDAPInfo *l) +{ + NTSTATUS status; + BOOL ret = True; + + status = torture_ldap_connection(ctx, &l->conn, ctx->ldap_url); + if (!NT_STATUS_IS_OK(status)) { + printf("failed to connect to LDAP: %s\n", ctx->ldap_url); + return False; + } + + printf("connected to LDAP: %s\n", ctx->ldap_url); + + status = torture_ldap_bind_sasl(l->conn, credentials); + if (!NT_STATUS_IS_OK(status)) { + printf("failed to bind to LDAP:\n"); + return False; + } + printf("bound to LDAP.\n"); + + return ret; +} + +static BOOL test_GetInfo(struct DsSyncTest *ctx) +{ + NTSTATUS status; + struct drsuapi_DsCrackNames r; + struct drsuapi_DsNameString names[1]; + BOOL ret = True; + + struct cldap_socket *cldap = cldap_socket_init(ctx, NULL); + struct cldap_netlogon search; + + r.in.bind_handle = &ctx->admin.drsuapi.bind_handle; + r.in.level = 1; + r.in.req.req1.unknown1 = 0x000004e4; + r.in.req.req1.unknown2 = 0x00000407; + r.in.req.req1.count = 1; + r.in.req.req1.names = names; + r.in.req.req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS; + r.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT; + r.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; + names[0].str = talloc_asprintf(ctx, "%s\\", lp_workgroup()); + + status = dcerpc_drsuapi_DsCrackNames(ctx->admin.drsuapi.pipe, ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { + errstr = dcerpc_errstr(ctx, ctx->admin.drsuapi.pipe->last_fault_code); + } + printf("dcerpc_drsuapi_DsCrackNames failed - %s\n", errstr); + return False; + } else if (!W_ERROR_IS_OK(r.out.result)) { + printf("DsCrackNames failed - %s\n", win_errstr(r.out.result)); + return False; + } + + ctx->domain_dn = r.out.ctr.ctr1->array[0].result_name; + + ZERO_STRUCT(search); + search.in.dest_address = ctx->drsuapi_binding->host; + search.in.acct_control = -1; + search.in.version = 6; + status = cldap_netlogon(cldap, ctx, &search); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + ctx->site_name = talloc_asprintf(ctx, "%s", "Default-First-Site-Name"); + printf("cldap_netlogon() returned %s. Defaulting to Site-Name: %s\n", errstr, ctx->site_name); + } else { + ctx->site_name = talloc_steal(ctx, search.out.netlogon.logon5.site_name); + printf("cldap_netlogon() returned Site-Name: %s.\n",ctx->site_name); + } + + + ctx->new_dc.invocation_id = GUID_random(); + + return ret; +} + + +static BOOL test_FetchData(struct DsSyncTest *ctx) +{ + NTSTATUS status; + BOOL ret = True; + int i, y = 0; + uint64_t highest_usn = 0; + const char *partition = NULL; + 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); + + partition = lp_parm_string(-1, "dssync", "partition"); + if (partition == NULL) { + partition = ctx->domain_dn; + printf("dssync:partition not specified, defaulting to %s.\n", ctx->domain_dn); + } + + highest_usn = lp_parm_int(-1, "dssync", "highest_usn", 0); + + for (i=0; i < ARRAY_SIZE(array); i++) { + printf("testing DsGetNCChanges level %d\n", + array[i].level); + + r.in.bind_handle = &ctx->new_dc.drsuapi.bind_handle; + r.in.level = array[i].level; + + switch (r.in.level) { + case 5: + nc.guid = null_guid; + nc.sid = null_sid; + nc.dn = partition; + + r.in.req.req5.destination_dsa_guid = ctx->new_dc.invocation_id; + r.in.req.req5.source_dsa_guid = null_guid; + r.in.req.req5.naming_context = &nc; + r.in.req.req5.highwatermark.tmp_highest_usn = highest_usn; + r.in.req.req5.highwatermark.reserved_usn = 0; + r.in.req.req5.highwatermark.highest_usn = highest_usn; + r.in.req.req5.uptodateness_vector = NULL; + r.in.req.req5.replica_flags = 0; + if (lp_parm_bool(-1,"dssync","compression",False)) { + r.in.req.req5.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES; + } + if (lp_parm_bool(-1,"dssync","neighbour_writeable",True)) { + r.in.req.req5.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE; + } + r.in.req.req5.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP + | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS + | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS + | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED + ; + r.in.req.req5.unknown2 = 133; + r.in.req.req5.unknown3 = 1336770; + r.in.req.req5.unknown4 = 0; + r.in.req.req5.h1 = 0; + + break; + case 8: + nc.guid = null_guid; + nc.sid = null_sid; + nc.dn = partition; + /* nc.dn can be set to any other ad partition */ + + r.in.req.req8.destination_dsa_guid = ctx->new_dc.invocation_id; + r.in.req.req8.source_dsa_guid = null_guid; + r.in.req.req8.naming_context = &nc; + r.in.req.req8.highwatermark.tmp_highest_usn = highest_usn; + r.in.req.req8.highwatermark.reserved_usn = 0; + r.in.req.req8.highwatermark.highest_usn = highest_usn; + r.in.req.req8.uptodateness_vector = NULL; + r.in.req.req8.replica_flags = 0; + if (lp_parm_bool(-1,"dssync","compression",False)) { + r.in.req.req8.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES; + } + if (lp_parm_bool(-1,"dssync","neighbour_writeable",True)) { + r.in.req.req8.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE; + } + r.in.req.req8.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP + | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS + | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS + | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED + ; + r.in.req.req8.unknown2 = 402; + r.in.req.req8.unknown3 = 402116; + + r.in.req.req8.unknown4 = 0; + r.in.req.req8.h1 = 0; + r.in.req.req8.unique_ptr1 = 0; + r.in.req.req8.unique_ptr2 = 0; + r.in.req.req8.ctr12.count = 0; + r.in.req.req8.ctr12.array = NULL; + + break; + } + + printf("Dumping AD partition: %s\n", nc.dn); + for (y=0; ;y++) { + ZERO_STRUCT(r.out); + + if (r.in.level == 8) { + DEBUG(0,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y, + r.in.req.req8.highwatermark.tmp_highest_usn, + r.in.req.req8.highwatermark.highest_usn)); + } + + status = dcerpc_drsuapi_DsGetNCChanges(ctx->new_dc.drsuapi.pipe, ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + const char *errstr = nt_errstr(status); + if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { + errstr = dcerpc_errstr(ctx, ctx->new_dc.drsuapi.pipe->last_fault_code); + } + printf("dcerpc_drsuapi_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; + } + + if (ret == True && r.out.level == 6) { + DEBUG(0,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y, + r.out.ctr.ctr6.new_highwatermark.tmp_highest_usn, + r.out.ctr.ctr6.new_highwatermark.highest_usn)); + + if (r.out.ctr.ctr6.new_highwatermark.tmp_highest_usn > r.out.ctr.ctr6.new_highwatermark.highest_usn) { + r.in.req.req8.highwatermark = r.out.ctr.ctr6.new_highwatermark; + continue; + } + } + break; + } + } + + return ret; +} + +BOOL torture_rpc_dssync(void) +{ + BOOL ret = True; + TALLOC_CTX *mem_ctx; + struct DsSyncTest *ctx; + + mem_ctx = talloc_init("torture_rpc_dssync"); + ctx = test_create_context(mem_ctx); + + ret &= _test_DsBind(ctx, ctx->admin.credentials, &ctx->admin.drsuapi); + ret &= test_LDAPBind(ctx, ctx->admin.credentials, &ctx->admin.ldap); + ret &= test_GetInfo(ctx); + ret &= _test_DsBind(ctx, ctx->admin.credentials, &ctx->new_dc.drsuapi); + ret &= test_FetchData(ctx); + + return ret; +} diff --git a/source4/torture/torture.c b/source4/torture/torture.c index ca348e841b..5941af978a 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -2313,6 +2313,7 @@ static struct { {"RPC-DSSETUP", torture_rpc_dssetup, 0}, {"RPC-ALTERCONTEXT", torture_rpc_alter_context, 0}, {"RPC-JOIN", torture_rpc_join, 0}, + {"RPC-DSSYNC", torture_rpc_dssync, 0}, /* local (no server) testers */ {"LOCAL-NTLMSSP", torture_ntlmssp_self_check, 0}, |