1/* 2 Unix SMB/CIFS implementation. 3 4 DsGetNCChanges replication test 5 6 Copyright (C) Stefan (metze) Metzmacher 2005 7 Copyright (C) Brad Henry 2005 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. 21*/ 22 23#include "includes.h" 24#include "lib/cmdline/popt_common.h" 25#include "librpc/gen_ndr/ndr_drsuapi_c.h" 26#include "librpc/gen_ndr/ndr_drsblobs.h" 27#include "libcli/cldap/cldap.h" 28#include "libcli/ldap/ldap_client.h" 29#include "torture/torture.h" 30#include "torture/ldap/proto.h" 31#include "libcli/auth/libcli_auth.h" 32#include "../lib/crypto/crypto.h" 33#include "../libcli/drsuapi/drsuapi.h" 34#include "auth/credentials/credentials.h" 35#include "libcli/auth/libcli_auth.h" 36#include "auth/gensec/gensec.h" 37#include "param/param.h" 38#include "dsdb/samdb/samdb.h" 39 40struct DsSyncBindInfo { 41 struct dcerpc_pipe *pipe; 42 struct drsuapi_DsBind req; 43 struct GUID bind_guid; 44 struct drsuapi_DsBindInfoCtr our_bind_info_ctr; 45 struct drsuapi_DsBindInfo28 our_bind_info28; 46 struct drsuapi_DsBindInfo28 peer_bind_info28; 47 struct policy_handle bind_handle; 48}; 49 50struct DsSyncLDAPInfo { 51 struct ldap_connection *conn; 52}; 53 54struct DsSyncTest { 55 struct dcerpc_binding *drsuapi_binding; 56 57 const char *ldap_url; 58 const char *site_name; 59 60 const char *domain_dn; 61 62 /* what we need to do as 'Administrator' */ 63 struct { 64 struct cli_credentials *credentials; 65 struct DsSyncBindInfo drsuapi; 66 struct DsSyncLDAPInfo ldap; 67 } admin; 68 69 /* what we need to do as the new dc machine account */ 70 struct { 71 struct cli_credentials *credentials; 72 struct DsSyncBindInfo drsuapi; 73 struct drsuapi_DsGetDCInfo2 dc_info2; 74 struct GUID invocation_id; 75 struct GUID object_guid; 76 } new_dc; 77 78 /* info about the old dc */ 79 struct { 80 struct drsuapi_DsGetDomainControllerInfo dc_info; 81 } old_dc; 82}; 83 84static struct DsSyncTest *test_create_context(struct torture_context *tctx) 85{ 86 NTSTATUS status; 87 struct DsSyncTest *ctx; 88 struct drsuapi_DsBindInfo28 *our_bind_info28; 89 struct drsuapi_DsBindInfoCtr *our_bind_info_ctr; 90 const char *binding = torture_setting_string(tctx, "binding", NULL); 91 ctx = talloc_zero(tctx, struct DsSyncTest); 92 if (!ctx) return NULL; 93 94 status = dcerpc_parse_binding(ctx, binding, &ctx->drsuapi_binding); 95 if (!NT_STATUS_IS_OK(status)) { 96 printf("Bad binding string %s\n", binding); 97 return NULL; 98 } 99 ctx->drsuapi_binding->flags |= DCERPC_SIGN | DCERPC_SEAL; 100 101 ctx->ldap_url = talloc_asprintf(ctx, "ldap://%s/", ctx->drsuapi_binding->host); 102 103 /* ctx->admin ...*/ 104 ctx->admin.credentials = cmdline_credentials; 105 106 our_bind_info28 = &ctx->admin.drsuapi.our_bind_info28; 107 our_bind_info28->supported_extensions = 0xFFFFFFFF; 108 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3; 109 our_bind_info28->site_guid = GUID_zero(); 110 our_bind_info28->pid = 0; 111 our_bind_info28->repl_epoch = 1; 112 113 our_bind_info_ctr = &ctx->admin.drsuapi.our_bind_info_ctr; 114 our_bind_info_ctr->length = 28; 115 our_bind_info_ctr->info.info28 = *our_bind_info28; 116 117 GUID_from_string(DRSUAPI_DS_BIND_GUID, &ctx->admin.drsuapi.bind_guid); 118 119 ctx->admin.drsuapi.req.in.bind_guid = &ctx->admin.drsuapi.bind_guid; 120 ctx->admin.drsuapi.req.in.bind_info = our_bind_info_ctr; 121 ctx->admin.drsuapi.req.out.bind_handle = &ctx->admin.drsuapi.bind_handle; 122 123 /* ctx->new_dc ...*/ 124 ctx->new_dc.credentials = cmdline_credentials; 125 126 our_bind_info28 = &ctx->new_dc.drsuapi.our_bind_info28; 127 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE; 128 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION; 129 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI; 130 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2; 131 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS; 132 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1; 133 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION; 134 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE; 135 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2; 136 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION; 137 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2; 138 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD; 139 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND; 140 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO; 141 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION; 142 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01; 143 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP; 144 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY; 145 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3; 146 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2; 147 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6; 148 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS; 149 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8; 150 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5; 151 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6; 152 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3; 153 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7; 154 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT; 155 if (lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "xpress", false)) { 156 our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS; 157 } 158 our_bind_info28->site_guid = GUID_zero(); 159 our_bind_info28->pid = 0; 160 our_bind_info28->repl_epoch = 0; 161 162 our_bind_info_ctr = &ctx->new_dc.drsuapi.our_bind_info_ctr; 163 our_bind_info_ctr->length = 28; 164 our_bind_info_ctr->info.info28 = *our_bind_info28; 165 166 GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &ctx->new_dc.drsuapi.bind_guid); 167 168 ctx->new_dc.drsuapi.req.in.bind_guid = &ctx->new_dc.drsuapi.bind_guid; 169 ctx->new_dc.drsuapi.req.in.bind_info = our_bind_info_ctr; 170 ctx->new_dc.drsuapi.req.out.bind_handle = &ctx->new_dc.drsuapi.bind_handle; 171 172 ctx->new_dc.invocation_id = ctx->new_dc.drsuapi.bind_guid; 173 174 /* ctx->old_dc ...*/ 175 176 return ctx; 177} 178 179static bool _test_DsBind(struct torture_context *tctx, 180 struct DsSyncTest *ctx, struct cli_credentials *credentials, struct DsSyncBindInfo *b) 181{ 182 NTSTATUS status; 183 bool ret = true; 184 185 status = dcerpc_pipe_connect_b(ctx, 186 &b->pipe, ctx->drsuapi_binding, 187 &ndr_table_drsuapi, 188 credentials, tctx->ev, tctx->lp_ctx); 189 190 if (!NT_STATUS_IS_OK(status)) { 191 printf("Failed to connect to server as a BDC: %s\n", nt_errstr(status)); 192 return false; 193 } 194 195 status = dcerpc_drsuapi_DsBind(b->pipe, ctx, &b->req); 196 if (!NT_STATUS_IS_OK(status)) { 197 const char *errstr = nt_errstr(status); 198 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { 199 errstr = dcerpc_errstr(ctx, b->pipe->last_fault_code); 200 } 201 printf("dcerpc_drsuapi_DsBind failed - %s\n", errstr); 202 ret = false; 203 } else if (!W_ERROR_IS_OK(b->req.out.result)) { 204 printf("DsBind failed - %s\n", win_errstr(b->req.out.result)); 205 ret = false; 206 } 207 208 ZERO_STRUCT(b->peer_bind_info28); 209 if (b->req.out.bind_info) { 210 switch (b->req.out.bind_info->length) { 211 case 24: { 212 struct drsuapi_DsBindInfo24 *info24; 213 info24 = &b->req.out.bind_info->info.info24; 214 b->peer_bind_info28.supported_extensions= info24->supported_extensions; 215 b->peer_bind_info28.site_guid = info24->site_guid; 216 b->peer_bind_info28.pid = info24->pid; 217 b->peer_bind_info28.repl_epoch = 0; 218 break; 219 } 220 case 48: { 221 struct drsuapi_DsBindInfo48 *info48; 222 info48 = &b->req.out.bind_info->info.info48; 223 b->peer_bind_info28.supported_extensions= info48->supported_extensions; 224 b->peer_bind_info28.site_guid = info48->site_guid; 225 b->peer_bind_info28.pid = info48->pid; 226 b->peer_bind_info28.repl_epoch = info48->repl_epoch; 227 break; 228 } 229 case 28: 230 b->peer_bind_info28 = b->req.out.bind_info->info.info28; 231 break; 232 default: 233 printf("DsBind - warning: unknown BindInfo length: %u\n", 234 b->req.out.bind_info->length); 235 } 236 } 237 238 return ret; 239} 240 241static bool test_LDAPBind(struct torture_context *tctx, struct DsSyncTest *ctx, 242 struct cli_credentials *credentials, struct DsSyncLDAPInfo *l) 243{ 244 NTSTATUS status; 245 bool ret = true; 246 247 status = torture_ldap_connection(tctx, &l->conn, ctx->ldap_url); 248 if (!NT_STATUS_IS_OK(status)) { 249 printf("failed to connect to LDAP: %s\n", ctx->ldap_url); 250 return false; 251 } 252 253 printf("connected to LDAP: %s\n", ctx->ldap_url); 254 255 status = torture_ldap_bind_sasl(l->conn, credentials, tctx->lp_ctx); 256 if (!NT_STATUS_IS_OK(status)) { 257 printf("failed to bind to LDAP:\n"); 258 return false; 259 } 260 printf("bound to LDAP.\n"); 261 262 return ret; 263} 264 265static bool test_GetInfo(struct torture_context *tctx, struct DsSyncTest *ctx) 266{ 267 NTSTATUS status; 268 struct drsuapi_DsCrackNames r; 269 union drsuapi_DsNameRequest req; 270 union drsuapi_DsNameCtr ctr; 271 int32_t level_out = 0; 272 struct drsuapi_DsNameString names[1]; 273 bool ret = true; 274 struct cldap_socket *cldap; 275 struct cldap_netlogon search; 276 277 status = cldap_socket_init(ctx, NULL, NULL, NULL, &cldap); 278 if (!NT_STATUS_IS_OK(status)) { 279 printf("failed to setup cldap socket - %s\n", 280 nt_errstr(status)); 281 return false; 282 } 283 284 r.in.bind_handle = &ctx->admin.drsuapi.bind_handle; 285 r.in.level = 1; 286 r.in.req = &req; 287 r.in.req->req1.codepage = 1252; /* western european */ 288 r.in.req->req1.language = 0x00000407; /* german */ 289 r.in.req->req1.count = 1; 290 r.in.req->req1.names = names; 291 r.in.req->req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS; 292 r.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT; 293 r.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; 294 names[0].str = talloc_asprintf(ctx, "%s\\", lp_workgroup(tctx->lp_ctx)); 295 296 r.out.level_out = &level_out; 297 r.out.ctr = &ctr; 298 299 status = dcerpc_drsuapi_DsCrackNames(ctx->admin.drsuapi.pipe, ctx, &r); 300 if (!NT_STATUS_IS_OK(status)) { 301 const char *errstr = nt_errstr(status); 302 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { 303 errstr = dcerpc_errstr(ctx, ctx->admin.drsuapi.pipe->last_fault_code); 304 } 305 printf("dcerpc_drsuapi_DsCrackNames failed - %s\n", errstr); 306 return false; 307 } else if (!W_ERROR_IS_OK(r.out.result)) { 308 printf("DsCrackNames failed - %s\n", win_errstr(r.out.result)); 309 return false; 310 } 311 312 ctx->domain_dn = r.out.ctr->ctr1->array[0].result_name; 313 314 ZERO_STRUCT(search); 315 search.in.dest_address = ctx->drsuapi_binding->host; 316 search.in.dest_port = lp_cldap_port(tctx->lp_ctx); 317 search.in.acct_control = -1; 318 search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; 319 search.in.map_response = true; 320 status = cldap_netlogon(cldap, lp_iconv_convenience(tctx->lp_ctx), ctx, &search); 321 if (!NT_STATUS_IS_OK(status)) { 322 const char *errstr = nt_errstr(status); 323 ctx->site_name = talloc_asprintf(ctx, "%s", "Default-First-Site-Name"); 324 printf("cldap_netlogon() returned %s. Defaulting to Site-Name: %s\n", errstr, ctx->site_name); 325 } else { 326 ctx->site_name = talloc_steal(ctx, search.out.netlogon.data.nt5_ex.client_site); 327 printf("cldap_netlogon() returned Client Site-Name: %s.\n",ctx->site_name); 328 printf("cldap_netlogon() returned Server Site-Name: %s.\n",search.out.netlogon.data.nt5_ex.server_site); 329 } 330 331 if (!ctx->domain_dn) { 332 struct ldb_context *ldb = ldb_init(ctx, tctx->ev); 333 struct ldb_dn *dn = samdb_dns_domain_to_dn(ldb, ctx, search.out.netlogon.data.nt5_ex.dns_domain); 334 ctx->domain_dn = ldb_dn_alloc_linearized(ctx, dn); 335 talloc_free(dn); 336 talloc_free(ldb); 337 } 338 339 return ret; 340} 341 342static void test_analyse_objects(struct torture_context *tctx, 343 struct DsSyncTest *ctx, 344 const DATA_BLOB *gensec_skey, 345 struct drsuapi_DsReplicaObjectListItemEx *cur) 346{ 347 static uint32_t object_id; 348 const char *save_values_dir; 349 350 if (!lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "print_pwd_blobs", false)) { 351 return; 352 } 353 354 save_values_dir = lp_parm_string(tctx->lp_ctx, NULL, "dssync", "save_pwd_blobs_dir"); 355 356 for (; cur; cur = cur->next_object) { 357 const char *dn; 358 struct dom_sid *sid = NULL; 359 uint32_t rid = 0; 360 bool dn_printed = false; 361 uint32_t i; 362 363 if (!cur->object.identifier) continue; 364 365 dn = cur->object.identifier->dn; 366 if (cur->object.identifier->sid.num_auths > 0) { 367 sid = &cur->object.identifier->sid; 368 rid = sid->sub_auths[sid->num_auths - 1]; 369 } 370 371 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) { 372 WERROR werr; 373 const char *name = NULL; 374 bool rcrypt = false; 375 DATA_BLOB *enc_data = NULL; 376 DATA_BLOB plain_data; 377 struct drsuapi_DsReplicaAttribute *attr; 378 ndr_pull_flags_fn_t pull_fn = NULL; 379 ndr_print_fn_t print_fn = NULL; 380 void *ptr = NULL; 381 attr = &cur->object.attribute_ctr.attributes[i]; 382 383 switch (attr->attid) { 384 case DRSUAPI_ATTRIBUTE_dBCSPwd: 385 name = "dBCSPwd"; 386 rcrypt = true; 387 break; 388 case DRSUAPI_ATTRIBUTE_unicodePwd: 389 name = "unicodePwd"; 390 rcrypt = true; 391 break; 392 case DRSUAPI_ATTRIBUTE_ntPwdHistory: 393 name = "ntPwdHistory"; 394 rcrypt = true; 395 break; 396 case DRSUAPI_ATTRIBUTE_lmPwdHistory: 397 name = "lmPwdHistory"; 398 rcrypt = true; 399 break; 400 case DRSUAPI_ATTRIBUTE_supplementalCredentials: 401 name = "supplementalCredentials"; 402 pull_fn = (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob; 403 print_fn = (ndr_print_fn_t)ndr_print_supplementalCredentialsBlob; 404 ptr = talloc(ctx, struct supplementalCredentialsBlob); 405 break; 406 case DRSUAPI_ATTRIBUTE_priorValue: 407 name = "priorValue"; 408 break; 409 case DRSUAPI_ATTRIBUTE_currentValue: 410 name = "currentValue"; 411 break; 412 case DRSUAPI_ATTRIBUTE_trustAuthOutgoing: 413 name = "trustAuthOutgoing"; 414 pull_fn = (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob; 415 print_fn = (ndr_print_fn_t)ndr_print_trustAuthInOutBlob; 416 ptr = talloc(ctx, struct trustAuthInOutBlob); 417 break; 418 case DRSUAPI_ATTRIBUTE_trustAuthIncoming: 419 name = "trustAuthIncoming"; 420 pull_fn = (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob; 421 print_fn = (ndr_print_fn_t)ndr_print_trustAuthInOutBlob; 422 ptr = talloc(ctx, struct trustAuthInOutBlob); 423 break; 424 case DRSUAPI_ATTRIBUTE_initialAuthOutgoing: 425 name = "initialAuthOutgoing"; 426 break; 427 case DRSUAPI_ATTRIBUTE_initialAuthIncoming: 428 name = "initialAuthIncoming"; 429 break; 430 default: 431 continue; 432 } 433 434 if (attr->value_ctr.num_values != 1) continue; 435 436 if (!attr->value_ctr.values[0].blob) continue; 437 438 enc_data = attr->value_ctr.values[0].blob; 439 ZERO_STRUCT(plain_data); 440 441 werr = drsuapi_decrypt_attribute_value(ctx, gensec_skey, rcrypt, 442 rid, 443 enc_data, &plain_data); 444 if (!W_ERROR_IS_OK(werr)) { 445 DEBUG(0, ("Failed to decrypt %s\n", name)); 446 continue; 447 } 448 if (!dn_printed) { 449 object_id++; 450 DEBUG(0,("DN[%u] %s\n", object_id, dn)); 451 dn_printed = true; 452 } 453 DEBUGADD(0,("ATTR: %s enc.length=%lu plain.length=%lu\n", 454 name, (long)enc_data->length, (long)plain_data.length)); 455 if (plain_data.length) { 456 enum ndr_err_code ndr_err; 457 dump_data(0, plain_data.data, plain_data.length); 458 if (save_values_dir) { 459 char *fname; 460 fname = talloc_asprintf(ctx, "%s/%s%02d", 461 save_values_dir, 462 name, object_id); 463 if (fname) { 464 bool ok; 465 ok = file_save(fname, plain_data.data, plain_data.length); 466 if (!ok) { 467 DEBUGADD(0,("Failed to save '%s'\n", fname)); 468 } 469 } 470 talloc_free(fname); 471 } 472 473 if (pull_fn) { 474 /* Can't use '_all' because of PIDL bugs with relative pointers */ 475 ndr_err = ndr_pull_struct_blob(&plain_data, ptr, 476 lp_iconv_convenience(tctx->lp_ctx), ptr, 477 pull_fn); 478 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 479 ndr_print_debug(print_fn, name, ptr); 480 } else { 481 DEBUG(0, ("Failed to decode %s\n", name)); 482 } 483 } 484 } else { 485 dump_data(0, enc_data->data, enc_data->length); 486 } 487 talloc_free(ptr); 488 } 489 } 490} 491 492static bool test_FetchData(struct torture_context *tctx, struct DsSyncTest *ctx) 493{ 494 NTSTATUS status; 495 bool ret = true; 496 int i, y = 0; 497 uint64_t highest_usn = 0; 498 const char *partition = NULL; 499 struct drsuapi_DsGetNCChanges r; 500 union drsuapi_DsGetNCChangesRequest req; 501 struct drsuapi_DsReplicaObjectIdentifier nc; 502 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL; 503 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL; 504 int32_t out_level = 0; 505 struct GUID null_guid; 506 struct dom_sid null_sid; 507 DATA_BLOB gensec_skey; 508 struct { 509 int32_t level; 510 } array[] = { 511/* { 512 5 513 }, 514*/ { 515 8 516 } 517 }; 518 519 ZERO_STRUCT(null_guid); 520 ZERO_STRUCT(null_sid); 521 522 partition = lp_parm_string(tctx->lp_ctx, NULL, "dssync", "partition"); 523 if (partition == NULL) { 524 partition = ctx->domain_dn; 525 printf("dssync:partition not specified, defaulting to %s.\n", ctx->domain_dn); 526 } 527 528 highest_usn = lp_parm_int(tctx->lp_ctx, NULL, "dssync", "highest_usn", 0); 529 530 array[0].level = lp_parm_int(tctx->lp_ctx, NULL, "dssync", "get_nc_changes_level", array[0].level); 531 532 if (lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "print_pwd_blobs", false)) { 533 const struct samr_Password *nthash; 534 nthash = cli_credentials_get_nt_hash(ctx->new_dc.credentials, ctx); 535 if (nthash) { 536 dump_data_pw("CREDENTIALS nthash:", nthash->hash, sizeof(nthash->hash)); 537 } 538 } 539 status = gensec_session_key(ctx->new_dc.drsuapi.pipe->conn->security_state.generic_state, 540 &gensec_skey); 541 if (!NT_STATUS_IS_OK(status)) { 542 printf("failed to get gensec session key: %s\n", nt_errstr(status)); 543 return false; 544 } 545 546 for (i=0; i < ARRAY_SIZE(array); i++) { 547 printf("testing DsGetNCChanges level %d\n", 548 array[i].level); 549 550 r.in.bind_handle = &ctx->new_dc.drsuapi.bind_handle; 551 r.in.level = array[i].level; 552 553 switch (r.in.level) { 554 case 5: 555 nc.guid = null_guid; 556 nc.sid = null_sid; 557 nc.dn = partition; 558 559 r.in.req = &req; 560 r.in.req->req5.destination_dsa_guid = ctx->new_dc.invocation_id; 561 r.in.req->req5.source_dsa_invocation_id = null_guid; 562 r.in.req->req5.naming_context = &nc; 563 r.in.req->req5.highwatermark.tmp_highest_usn = highest_usn; 564 r.in.req->req5.highwatermark.reserved_usn = 0; 565 r.in.req->req5.highwatermark.highest_usn = highest_usn; 566 r.in.req->req5.uptodateness_vector = NULL; 567 r.in.req->req5.replica_flags = 0; 568 if (lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "compression", false)) { 569 r.in.req->req5.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES; 570 } 571 if (lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "neighbour_writeable", true)) { 572 r.in.req->req5.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE; 573 } 574 r.in.req->req5.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP 575 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS 576 | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS 577 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED 578 ; 579 r.in.req->req5.max_object_count = 133; 580 r.in.req->req5.max_ndr_size = 1336770; 581 r.in.req->req5.extended_op = DRSUAPI_EXOP_NONE; 582 r.in.req->req5.fsmo_info = 0; 583 584 break; 585 case 8: 586 nc.guid = null_guid; 587 nc.sid = null_sid; 588 nc.dn = partition; 589 /* nc.dn can be set to any other ad partition */ 590 591 r.in.req = &req; 592 r.in.req->req8.destination_dsa_guid = ctx->new_dc.invocation_id; 593 r.in.req->req8.source_dsa_invocation_id = null_guid; 594 r.in.req->req8.naming_context = &nc; 595 r.in.req->req8.highwatermark.tmp_highest_usn = highest_usn; 596 r.in.req->req8.highwatermark.reserved_usn = 0; 597 r.in.req->req8.highwatermark.highest_usn = highest_usn; 598 r.in.req->req8.uptodateness_vector = NULL; 599 r.in.req->req8.replica_flags = 0; 600 if (lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "compression", false)) { 601 r.in.req->req8.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES; 602 } 603 if (lp_parm_bool(tctx->lp_ctx, NULL, "dssync", "neighbour_writeable", true)) { 604 r.in.req->req8.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE; 605 } 606 r.in.req->req8.replica_flags |= DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP 607 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS 608 | DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS 609 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED 610 ; 611 r.in.req->req8.max_object_count = 402; 612 r.in.req->req8.max_ndr_size = 402116; 613 614 r.in.req->req8.extended_op = DRSUAPI_EXOP_NONE; 615 r.in.req->req8.fsmo_info = 0; 616 r.in.req->req8.partial_attribute_set = NULL; 617 r.in.req->req8.partial_attribute_set_ex = NULL; 618 r.in.req->req8.mapping_ctr.num_mappings = 0; 619 r.in.req->req8.mapping_ctr.mappings = NULL; 620 621 break; 622 } 623 624 printf("Dumping AD partition: %s\n", nc.dn); 625 for (y=0; ;y++) { 626 int32_t _level = 0; 627 union drsuapi_DsGetNCChangesCtr ctr; 628 629 ZERO_STRUCT(r.out); 630 631 r.out.level_out = &_level; 632 r.out.ctr = &ctr; 633 634 if (r.in.level == 5) { 635 DEBUG(0,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y, 636 (long long)r.in.req->req5.highwatermark.tmp_highest_usn, 637 (long long)r.in.req->req5.highwatermark.highest_usn)); 638 } 639 640 if (r.in.level == 8) { 641 DEBUG(0,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y, 642 (long long)r.in.req->req8.highwatermark.tmp_highest_usn, 643 (long long)r.in.req->req8.highwatermark.highest_usn)); 644 } 645 646 status = dcerpc_drsuapi_DsGetNCChanges(ctx->new_dc.drsuapi.pipe, ctx, &r); 647 if (!NT_STATUS_IS_OK(status)) { 648 const char *errstr = nt_errstr(status); 649 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { 650 errstr = dcerpc_errstr(ctx, ctx->new_dc.drsuapi.pipe->last_fault_code); 651 } 652 printf("dcerpc_drsuapi_DsGetNCChanges failed - %s\n", errstr); 653 ret = false; 654 } else if (!W_ERROR_IS_OK(r.out.result)) { 655 printf("DsGetNCChanges failed - %s\n", win_errstr(r.out.result)); 656 ret = false; 657 } 658 659 if (ret == true && *r.out.level_out == 1) { 660 out_level = 1; 661 ctr1 = &r.out.ctr->ctr1; 662 } else if (ret == true && *r.out.level_out == 2 && 663 r.out.ctr->ctr2.mszip1.ts) { 664 out_level = 1; 665 ctr1 = &r.out.ctr->ctr2.mszip1.ts->ctr1; 666 } 667 668 if (out_level == 1) { 669 DEBUG(0,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y, 670 (long long)ctr1->new_highwatermark.tmp_highest_usn, 671 (long long)ctr1->new_highwatermark.highest_usn)); 672 673 test_analyse_objects(tctx, ctx, &gensec_skey, ctr1->first_object); 674 675 if (ctr1->more_data) { 676 r.in.req->req5.highwatermark = ctr1->new_highwatermark; 677 continue; 678 } 679 } 680 681 if (ret == true && *r.out.level_out == 6) { 682 out_level = 6; 683 ctr6 = &r.out.ctr->ctr6; 684 } else if (ret == true && *r.out.level_out == 7 685 && r.out.ctr->ctr7.level == 6 686 && r.out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP 687 && r.out.ctr->ctr7.ctr.mszip6.ts) { 688 out_level = 6; 689 ctr6 = &r.out.ctr->ctr7.ctr.mszip6.ts->ctr6; 690 } else if (ret == true && *r.out.level_out == 7 691 && r.out.ctr->ctr7.level == 6 692 && r.out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS 693 && r.out.ctr->ctr7.ctr.xpress6.ts) { 694 out_level = 6; 695 ctr6 = &r.out.ctr->ctr7.ctr.xpress6.ts->ctr6; 696 } 697 698 if (out_level == 6) { 699 DEBUG(0,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y, 700 (long long)ctr6->new_highwatermark.tmp_highest_usn, 701 (long long)ctr6->new_highwatermark.highest_usn)); 702 703 test_analyse_objects(tctx, ctx, &gensec_skey, ctr6->first_object); 704 705 if (ctr6->more_data) { 706 r.in.req->req8.highwatermark = ctr6->new_highwatermark; 707 continue; 708 } 709 } 710 711 break; 712 } 713 } 714 715 return ret; 716} 717 718static bool test_FetchNT4Data(struct torture_context *tctx, 719 struct DsSyncTest *ctx) 720{ 721 NTSTATUS status; 722 bool ret = true; 723 struct drsuapi_DsGetNT4ChangeLog r; 724 union drsuapi_DsGetNT4ChangeLogRequest req; 725 union drsuapi_DsGetNT4ChangeLogInfo info; 726 uint32_t level_out = 0; 727 struct GUID null_guid; 728 struct dom_sid null_sid; 729 DATA_BLOB cookie; 730 731 ZERO_STRUCT(null_guid); 732 ZERO_STRUCT(null_sid); 733 ZERO_STRUCT(cookie); 734 735 ZERO_STRUCT(r); 736 r.in.bind_handle = &ctx->new_dc.drsuapi.bind_handle; 737 r.in.level = 1; 738 r.out.info = &info; 739 r.out.level_out = &level_out; 740 741 req.req1.unknown1 = lp_parm_int(tctx->lp_ctx, NULL, "dssync", "nt4-1", 3); 742 req.req1.unknown2 = lp_parm_int(tctx->lp_ctx, NULL, "dssync", "nt4-2", 0x00004000); 743 744 while (1) { 745 req.req1.length = cookie.length; 746 req.req1.data = cookie.data; 747 748 r.in.req = &req; 749 750 status = dcerpc_drsuapi_DsGetNT4ChangeLog(ctx->new_dc.drsuapi.pipe, ctx, &r); 751 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) { 752 printf("DsGetNT4ChangeLog not supported by target server\n"); 753 break; 754 } else if (!NT_STATUS_IS_OK(status)) { 755 const char *errstr = nt_errstr(status); 756 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { 757 errstr = dcerpc_errstr(ctx, ctx->new_dc.drsuapi.pipe->last_fault_code); 758 } 759 printf("dcerpc_drsuapi_DsGetNT4ChangeLog failed - %s\n", errstr); 760 ret = false; 761 } else if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_DOMAIN_ROLE)) { 762 printf("DsGetNT4ChangeLog not supported by target server\n"); 763 break; 764 } else if (!W_ERROR_IS_OK(r.out.result)) { 765 printf("DsGetNT4ChangeLog failed - %s\n", win_errstr(r.out.result)); 766 ret = false; 767 } else if (*r.out.level_out != 1) { 768 printf("DsGetNT4ChangeLog unknown level - %u\n", *r.out.level_out); 769 ret = false; 770 } else if (NT_STATUS_IS_OK(r.out.info->info1.status)) { 771 } else if (NT_STATUS_EQUAL(r.out.info->info1.status, STATUS_MORE_ENTRIES)) { 772 cookie.length = r.out.info->info1.length1; 773 cookie.data = r.out.info->info1.data1; 774 continue; 775 } else { 776 printf("DsGetNT4ChangeLog failed - %s\n", nt_errstr(r.out.info->info1.status)); 777 ret = false; 778 } 779 780 break; 781 } 782 783 return ret; 784} 785 786bool torture_rpc_dssync(struct torture_context *torture) 787{ 788 bool ret = true; 789 TALLOC_CTX *mem_ctx; 790 struct DsSyncTest *ctx; 791 792 mem_ctx = talloc_init("torture_rpc_dssync"); 793 ctx = test_create_context(torture); 794 795 ret &= _test_DsBind(torture, ctx, ctx->admin.credentials, &ctx->admin.drsuapi); 796 if (!ret) { 797 return ret; 798 } 799 ret &= test_LDAPBind(torture, ctx, ctx->admin.credentials, &ctx->admin.ldap); 800 if (!ret) { 801 return ret; 802 } 803 ret &= test_GetInfo(torture, ctx); 804 ret &= _test_DsBind(torture, ctx, ctx->new_dc.credentials, &ctx->new_dc.drsuapi); 805 if (!ret) { 806 return ret; 807 } 808 ret &= test_FetchData(torture, ctx); 809 ret &= test_FetchNT4Data(torture, ctx); 810 811 return ret; 812} 813