1/* 2 Unix SMB/CIFS implementation. 3 RPC pipe client 4 5 Copyright (C) Guenther Deschner 2008 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. 19*/ 20 21#include "includes.h" 22#include "rpcclient.h" 23#include "../librpc/gen_ndr/cli_drsuapi.h" 24 25static WERROR cracknames(struct rpc_pipe_client *cli, 26 TALLOC_CTX *mem_ctx, 27 struct policy_handle *bind_handle, 28 enum drsuapi_DsNameFormat format_offered, 29 enum drsuapi_DsNameFormat format_desired, 30 int argc, 31 const char **argv, 32 union drsuapi_DsNameCtr *ctr) 33{ 34 NTSTATUS status; 35 WERROR werr; 36 int i; 37 int32_t level = 1; 38 union drsuapi_DsNameRequest req; 39 int32_t level_out; 40 struct drsuapi_DsNameString *names; 41 42 names = TALLOC_ZERO_ARRAY(mem_ctx, struct drsuapi_DsNameString, argc); 43 W_ERROR_HAVE_NO_MEMORY(names); 44 45 for (i=0; i<argc; i++) { 46 names[i].str = argv[i]; 47 } 48 49 req.req1.codepage = 1252; /* german */ 50 req.req1.language = 0x00000407; /* german */ 51 req.req1.count = argc; 52 req.req1.names = names; 53 req.req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS; 54 req.req1.format_offered = format_offered; 55 req.req1.format_desired = format_desired; 56 57 status = rpccli_drsuapi_DsCrackNames(cli, mem_ctx, 58 bind_handle, 59 level, 60 &req, 61 &level_out, 62 ctr, 63 &werr); 64 if (!NT_STATUS_IS_OK(status)) { 65 return ntstatus_to_werror(status); 66 } 67 68 if (!W_ERROR_IS_OK(werr)) { 69 return werr; 70 } 71 72 return WERR_OK; 73} 74 75static WERROR cmd_drsuapi_cracknames(struct rpc_pipe_client *cli, 76 TALLOC_CTX *mem_ctx, int argc, 77 const char **argv) 78{ 79 NTSTATUS status; 80 WERROR werr; 81 int i; 82 83 struct GUID bind_guid; 84 struct policy_handle bind_handle; 85 86 union drsuapi_DsNameCtr ctr; 87 88 if (argc < 2) { 89 printf("usage: %s name\n", argv[0]); 90 return WERR_OK; 91 } 92 93 GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid); 94 95 status = rpccli_drsuapi_DsBind(cli, mem_ctx, 96 &bind_guid, 97 NULL, 98 &bind_handle, 99 &werr); 100 101 if (!NT_STATUS_IS_OK(status)) { 102 return ntstatus_to_werror(status); 103 } 104 105 werr = cracknames(cli, mem_ctx, 106 &bind_handle, 107 DRSUAPI_DS_NAME_FORMAT_UNKNOWN, 108 DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 109 1, 110 argv+1, 111 &ctr); 112 113 if (!W_ERROR_IS_OK(werr)) { 114 goto out; 115 } 116 117 for (i=0; i < ctr.ctr1->count; i++) { 118 printf("status: %d\n", 119 ctr.ctr1->array[i].status); 120 printf("dns_domain_name: %s\n", 121 ctr.ctr1->array[i].dns_domain_name); 122 printf("result_name: %s\n", 123 ctr.ctr1->array[i].result_name); 124 } 125 126 out: 127 if (is_valid_policy_hnd(&bind_handle)) { 128 rpccli_drsuapi_DsUnbind(cli, mem_ctx, &bind_handle, &werr); 129 } 130 131 return werr; 132} 133 134static void display_domain_controller_info_01(struct drsuapi_DsGetDCConnection01 *r) 135{ 136 printf("client_ip_address:\t%s\n", r->client_ip_address); 137 printf("unknown2:\t%d\n", r->unknown2); 138 printf("connection_time:\t%d\n", r->connection_time); 139 printf("unknown4:\t%d\n", r->unknown4); 140 printf("unknown5:\t%d\n", r->unknown5); 141 printf("unknown6:\t%d\n", r->unknown6); 142 printf("client_account:\t%s\n", r->client_account); 143} 144 145static void display_domain_controller_info_1(struct drsuapi_DsGetDCInfo1 *r) 146{ 147 printf("netbios_name:\t%s\n", r->netbios_name); 148 printf("dns_name:\t%s\n", r->dns_name); 149 printf("site_name:\t%s\n", r->site_name); 150 printf("computer_dn:\t%s\n", r->computer_dn); 151 printf("server_dn:\t%s\n", r->server_dn); 152 printf("is_pdc:\t\t%s\n", r->is_pdc ? "true" : "false"); 153 printf("is_enabled:\t%s\n", r->is_enabled ? "true" : "false"); 154} 155 156static void display_domain_controller_info_2(struct drsuapi_DsGetDCInfo2 *r) 157{ 158 printf("netbios_name:\t%s\n", r->netbios_name); 159 printf("dns_name:\t%s\n", r->dns_name); 160 printf("site_name:\t%s\n", r->site_name); 161 printf("site_dn:\t%s\n", r->site_dn); 162 printf("computer_dn:\t%s\n", r->computer_dn); 163 printf("server_dn:\t%s\n", r->server_dn); 164 printf("ntds_dn:\t%s\n", r->ntds_dn); 165 printf("is_pdc:\t\t%s\n", r->is_pdc ? "true" : "false"); 166 printf("is_enabled:\t%s\n", r->is_enabled ? "true" : "false"); 167 printf("is_gc:\t\t%s\n", r->is_gc ? "true" : "false"); 168 printf("site_guid:\t%s\n", GUID_string(talloc_tos(), &r->site_guid)); 169 printf("computer_guid:\t%s\n", GUID_string(talloc_tos(), &r->computer_guid)); 170 printf("server_guid:\t%s\n", GUID_string(talloc_tos(), &r->server_guid)); 171 printf("ntds_guid:\t%s\n", GUID_string(talloc_tos(), &r->ntds_guid)); 172} 173 174static void display_domain_controller_info_3(struct drsuapi_DsGetDCInfo3 *r) 175{ 176 printf("netbios_name:\t%s\n", r->netbios_name); 177 printf("dns_name:\t%s\n", r->dns_name); 178 printf("site_name:\t%s\n", r->site_name); 179 printf("site_dn:\t%s\n", r->site_dn); 180 printf("computer_dn:\t%s\n", r->computer_dn); 181 printf("server_dn:\t%s\n", r->server_dn); 182 printf("ntds_dn:\t%s\n", r->ntds_dn); 183 printf("is_pdc:\t\t%s\n", r->is_pdc ? "true" : "false"); 184 printf("is_enabled:\t%s\n", r->is_enabled ? "true" : "false"); 185 printf("is_gc:\t\t%s\n", r->is_gc ? "true" : "false"); 186 printf("is_rodc:\t%s\n", r->is_rodc ? "true" : "false"); 187 printf("site_guid:\t%s\n", GUID_string(talloc_tos(), &r->site_guid)); 188 printf("computer_guid:\t%s\n", GUID_string(talloc_tos(), &r->computer_guid)); 189 printf("server_guid:\t%s\n", GUID_string(talloc_tos(), &r->server_guid)); 190 printf("ntds_guid:\t%s\n", GUID_string(talloc_tos(), &r->ntds_guid)); 191} 192 193static void display_domain_controller_info(int32_t level, 194 union drsuapi_DsGetDCInfoCtr *ctr) 195{ 196 int i; 197 198 switch (level) { 199 case DRSUAPI_DC_CONNECTION_CTR_01: 200 for (i=0; i<ctr->ctr01.count; i++) { 201 printf("----------\n"); 202 display_domain_controller_info_01(&ctr->ctr01.array[i]); 203 } 204 break; 205 case DRSUAPI_DC_INFO_CTR_1: 206 for (i=0; i<ctr->ctr1.count; i++) { 207 printf("----------\n"); 208 display_domain_controller_info_1(&ctr->ctr1.array[i]); 209 } 210 break; 211 case DRSUAPI_DC_INFO_CTR_2: 212 for (i=0; i<ctr->ctr2.count; i++) { 213 printf("----------\n"); 214 display_domain_controller_info_2(&ctr->ctr2.array[i]); 215 } 216 break; 217 case DRSUAPI_DC_INFO_CTR_3: 218 for (i=0; i<ctr->ctr3.count; i++) { 219 printf("----------\n"); 220 display_domain_controller_info_3(&ctr->ctr3.array[i]); 221 } 222 break; 223 default: 224 break; 225 } 226} 227 228static WERROR cmd_drsuapi_getdcinfo(struct rpc_pipe_client *cli, 229 TALLOC_CTX *mem_ctx, int argc, 230 const char **argv) 231{ 232 NTSTATUS status; 233 WERROR werr; 234 235 struct GUID bind_guid; 236 struct policy_handle bind_handle; 237 238 const char *domain = NULL; 239 int32_t level = 1; 240 int32_t level_out; 241 union drsuapi_DsGetDCInfoRequest req; 242 union drsuapi_DsGetDCInfoCtr ctr; 243 244 if (argc < 2) { 245 printf("usage: %s domain [level]\n", argv[0]); 246 return WERR_OK; 247 } 248 249 domain = argv[1]; 250 if (argc >= 3) { 251 level = atoi(argv[2]); 252 } 253 254 GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid); 255 256 status = rpccli_drsuapi_DsBind(cli, mem_ctx, 257 &bind_guid, 258 NULL, 259 &bind_handle, 260 &werr); 261 262 if (!NT_STATUS_IS_OK(status)) { 263 return ntstatus_to_werror(status); 264 } 265 266 req.req1.domain_name = domain; 267 req.req1.level = level; 268 269 status = rpccli_drsuapi_DsGetDomainControllerInfo(cli, mem_ctx, 270 &bind_handle, 271 1, 272 &req, 273 &level_out, 274 &ctr, 275 &werr); 276 if (!NT_STATUS_IS_OK(status)) { 277 werr = ntstatus_to_werror(status); 278 goto out; 279 } 280 281 if (!W_ERROR_IS_OK(werr)) { 282 goto out; 283 } 284 285 display_domain_controller_info(level_out, &ctr); 286 out: 287 if (is_valid_policy_hnd(&bind_handle)) { 288 rpccli_drsuapi_DsUnbind(cli, mem_ctx, &bind_handle, &werr); 289 } 290 291 return werr; 292} 293 294static WERROR cmd_drsuapi_getncchanges(struct rpc_pipe_client *cli, 295 TALLOC_CTX *mem_ctx, int argc, 296 const char **argv) 297{ 298 NTSTATUS status; 299 WERROR werr; 300 301 struct policy_handle bind_handle; 302 303 struct GUID bind_guid; 304 struct drsuapi_DsBindInfoCtr bind_info; 305 struct drsuapi_DsBindInfo28 info28; 306 307 const char *nc_dn = NULL; 308 309 DATA_BLOB session_key; 310 311 int32_t level = 8; 312 bool single = false; 313 int32_t level_out = 0; 314 union drsuapi_DsGetNCChangesRequest req; 315 union drsuapi_DsGetNCChangesCtr ctr; 316 struct drsuapi_DsReplicaObjectIdentifier nc; 317 struct dom_sid null_sid; 318 319 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL; 320 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL; 321 int32_t out_level = 0; 322 int y; 323 324 uint32_t supported_extensions = 0; 325 uint32_t replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE | 326 DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP | 327 DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS | 328 DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS | 329 DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED; 330 331 if (argc > 3) { 332 printf("usage: %s [naming_context_or_object_dn [single]]\n", argv[0]); 333 return WERR_OK; 334 } 335 336 if (argc >= 2) { 337 nc_dn = argv[1]; 338 } 339 340 if (argc == 3) { 341 if (strequal(argv[2], "single")) { 342 single = true; 343 } else { 344 printf("warning: ignoring unknown argument '%s'\n", 345 argv[2]); 346 } 347 } 348 349 ZERO_STRUCT(info28); 350 351 ZERO_STRUCT(null_sid); 352 ZERO_STRUCT(req); 353 354 GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid); 355 356 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE; 357 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION; 358 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI; 359 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2; 360 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS; 361 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1; 362 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION; 363 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE; 364 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2; 365 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION; 366 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2; 367 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD; 368 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND; 369 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO; 370 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION; 371 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01; 372 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP; 373 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY; 374 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3; 375 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2; 376 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6; 377 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS; 378 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8; 379 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5; 380 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6; 381 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3; 382 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7; 383 info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT; 384 info28.site_guid = GUID_zero(); 385 info28.pid = 0; 386 info28.repl_epoch = 0; 387 388 bind_info.length = 28; 389 bind_info.info.info28 = info28; 390 391 status = rpccli_drsuapi_DsBind(cli, mem_ctx, 392 &bind_guid, 393 &bind_info, 394 &bind_handle, 395 &werr); 396 397 if (!NT_STATUS_IS_OK(status)) { 398 return ntstatus_to_werror(status); 399 } 400 401 if (!W_ERROR_IS_OK(werr)) { 402 return werr; 403 } 404 405 if (bind_info.length == 24) { 406 supported_extensions = bind_info.info.info24.supported_extensions; 407 } else if (bind_info.length == 28) { 408 supported_extensions = bind_info.info.info28.supported_extensions; 409 } else if (bind_info.length == 48) { 410 supported_extensions = bind_info.info.info48.supported_extensions; 411 } 412 413 if (!nc_dn) { 414 415 union drsuapi_DsNameCtr crack_ctr; 416 const char *name; 417 418 name = talloc_asprintf(mem_ctx, "%s\\", lp_workgroup()); 419 W_ERROR_HAVE_NO_MEMORY(name); 420 421 werr = cracknames(cli, mem_ctx, 422 &bind_handle, 423 DRSUAPI_DS_NAME_FORMAT_UNKNOWN, 424 DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 425 1, 426 &name, 427 &crack_ctr); 428 if (!W_ERROR_IS_OK(werr)) { 429 return werr; 430 } 431 432 if (crack_ctr.ctr1->count != 1) { 433 return WERR_NO_SUCH_DOMAIN; 434 } 435 436 if (crack_ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { 437 return WERR_NO_SUCH_DOMAIN; 438 } 439 440 nc_dn = talloc_strdup(mem_ctx, crack_ctr.ctr1->array[0].result_name); 441 W_ERROR_HAVE_NO_MEMORY(nc_dn); 442 443 printf("using: %s\n", nc_dn); 444 } 445 446 nc.dn = nc_dn; 447 nc.guid = GUID_zero(); 448 nc.sid = null_sid; 449 450 if (supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) { 451 level = 8; 452 req.req8.naming_context = &nc; 453 req.req8.replica_flags = replica_flags; 454 req.req8.max_object_count = 402; 455 req.req8.max_ndr_size = 402116; 456 if (single) { 457 req.req8.extended_op = DRSUAPI_EXOP_REPL_OBJ; 458 } 459 } else { 460 level = 5; 461 req.req5.naming_context = &nc; 462 req.req5.replica_flags = replica_flags; 463 req.req5.max_object_count = 402; 464 req.req5.max_ndr_size = 402116; 465 if (single) { 466 req.req5.extended_op = DRSUAPI_EXOP_REPL_OBJ; 467 } 468 } 469 470 for (y=0; ;y++) { 471 472 if (level == 8) { 473 DEBUG(1,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y, 474 (long long)req.req8.highwatermark.tmp_highest_usn, 475 (long long)req.req8.highwatermark.highest_usn)); 476 } 477 478 status = rpccli_drsuapi_DsGetNCChanges(cli, mem_ctx, 479 &bind_handle, 480 level, 481 &req, 482 &level_out, 483 &ctr, 484 &werr); 485 if (!NT_STATUS_IS_OK(status)) { 486 printf("Failed to get NC Changes: %s", 487 get_friendly_werror_msg(werr)); 488 goto out; 489 } 490 491 if (!W_ERROR_IS_OK(werr)) { 492 status = werror_to_ntstatus(werr); 493 goto out; 494 } 495 496 if (level_out == 1) { 497 out_level = 1; 498 ctr1 = &ctr.ctr1; 499 } else if (level_out == 2 && ctr.ctr2.mszip1.ts) { 500 out_level = 1; 501 ctr1 = &ctr.ctr2.mszip1.ts->ctr1; 502 } 503 504 status = cli_get_session_key(mem_ctx, cli, &session_key); 505 if (!NT_STATUS_IS_OK(status)) { 506 printf("Failed to get Session Key: %s", 507 nt_errstr(status)); 508 return ntstatus_to_werror(status); 509 } 510 511 if (out_level == 1) { 512 DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y, 513 (long long)ctr1->new_highwatermark.tmp_highest_usn, 514 (long long)ctr1->new_highwatermark.highest_usn)); 515#if 0 516 libnet_dssync_decrypt_attributes(mem_ctx, 517 &session_key, 518 ctr1->first_object); 519#endif 520 if (ctr1->more_data) { 521 req.req5.highwatermark = ctr1->new_highwatermark; 522 continue; 523 } 524 } 525 526 if (level_out == 6) { 527 out_level = 6; 528 ctr6 = &ctr.ctr6; 529 } else if (level_out == 7 530 && ctr.ctr7.level == 6 531 && ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP 532 && ctr.ctr7.ctr.mszip6.ts) { 533 out_level = 6; 534 ctr6 = &ctr.ctr7.ctr.mszip6.ts->ctr6; 535 } else if (level_out == 7 536 && ctr.ctr7.level == 6 537 && ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS 538 && ctr.ctr7.ctr.xpress6.ts) { 539 out_level = 6; 540 ctr6 = &ctr.ctr7.ctr.xpress6.ts->ctr6; 541 } 542 543 if (out_level == 6) { 544 DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y, 545 (long long)ctr6->new_highwatermark.tmp_highest_usn, 546 (long long)ctr6->new_highwatermark.highest_usn)); 547#if 0 548 libnet_dssync_decrypt_attributes(mem_ctx, 549 &session_key, 550 ctr6->first_object); 551#endif 552 if (ctr6->more_data) { 553 req.req8.highwatermark = ctr6->new_highwatermark; 554 continue; 555 } 556 } 557 558 break; 559 } 560 561 out: 562 return werr; 563} 564 565/* List of commands exported by this module */ 566 567struct cmd_set drsuapi_commands[] = { 568 569 { "DRSUAPI" }, 570 { "dscracknames", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_cracknames, &ndr_table_drsuapi.syntax_id, NULL, "Crack Name", "" }, 571 { "dsgetdcinfo", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_getdcinfo, &ndr_table_drsuapi.syntax_id, NULL, "Get Domain Controller Info", "" }, 572 { "dsgetncchanges", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_getncchanges, &ndr_table_drsuapi.syntax_id, NULL, "Get NC Changes", "" }, 573 { NULL } 574}; 575