1/* 2 Unix SMB/CIFS implementation. 3 4 Copyright (C) Stefan Metzmacher <metze@samba.org> 2006 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21#include "libnet/libnet.h" 22#include "libcli/composite/composite.h" 23#include "libcli/cldap/cldap.h" 24#include "lib/ldb/include/ldb.h" 25#include "lib/ldb/include/ldb_errors.h" 26#include "lib/ldb_wrap.h" 27#include "dsdb/samdb/samdb.h" 28#include "../libds/common/flags.h" 29#include "librpc/gen_ndr/ndr_drsuapi_c.h" 30#include "libcli/security/security.h" 31#include "librpc/gen_ndr/ndr_misc.h" 32#include "librpc/gen_ndr/ndr_security.h" 33#include "librpc/gen_ndr/ndr_nbt.h" 34#include "librpc/gen_ndr/ndr_drsuapi.h" 35#include "auth/gensec/gensec.h" 36#include "param/param.h" 37 38/***************************************************************************** 39 * Windows 2003 (w2k3) does the following steps when changing the server role 40 * from domain member to domain controller 41 * 42 * We mostly do the same. 43 *****************************************************************************/ 44 45/* 46 * lookup DC: 47 * - using nbt name<1C> request and a samlogon mailslot request 48 * or 49 * - using a DNS SRV _ldap._tcp.dc._msdcs. request and a CLDAP netlogon request 50 * 51 * see: becomeDC_recv_cldap() and becomeDC_send_cldap() 52 */ 53 54/* 55 * Open 1st LDAP connection to the DC using admin credentials 56 * 57 * see: becomeDC_connect_ldap1() and becomeDC_ldap_connect() 58 */ 59 60/* 61 * LDAP search 1st LDAP connection: 62 * 63 * see: becomeDC_ldap1_rootdse() 64 * 65 * Request: 66 * basedn: "" 67 * scope: base 68 * filter: (objectClass=*) 69 * attrs: * 70 * Result: 71 * "" 72 * currentTime: 20061202155100.0Z 73 * subschemaSubentry: CN=Aggregate,CN=Schema,CN=Configuration,<domain_partition> 74 * dsServiceName: CN=<netbios_name>,CN=Servers,CN=<site_name>,CN=Sites,CN=Configuration,<domain_partition> 75 * namingContexts: <domain_partition> 76 * CN=Configuration,<domain_partition> 77 * CN=Schema,CN=Configuration,<domain_partition> 78 * defaultNamingContext: <domain_partition> 79 * schemaNamingContext: CN=Schema,CN=Configuration,<domain_partition> 80 * configurationNamingContext:CN=Configuration,<domain_partition> 81 * rootDomainNamingContext:<domain_partition> 82 * supportedControl: ... 83 * supportedLDAPVersion: 3 84 * 2 85 * supportedLDAPPolicies: ... 86 * highestCommitedUSN: ... 87 * supportedSASLMechanisms:GSSAPI 88 * GSS-SPNEGO 89 * EXTERNAL 90 * DIGEST-MD5 91 * dnsHostName: <dns_host_name> 92 * ldapServiceName: <domain_dns_name>:<netbios_name>$@<REALM> 93 * serverName: CN=Servers,CN=<site_name>,CN=Sites,CN=Configuration,<domain_partition> 94 * supportedCapabilities: ... 95 * isSyncronized: TRUE 96 * isGlobalCatalogReady: TRUE 97 * domainFunctionality: 0 98 * forestFunctionality: 0 99 * domainControllerFunctionality: 2 100 */ 101 102/* 103 * LDAP search 1st LDAP connection: 104 * 105 * see: becomeDC_ldap1_crossref_behavior_version() 106 * 107 * Request: 108 * basedn: CN=Configuration,<domain_partition> 109 * scope: one 110 * filter: (cn=Partitions) 111 * attrs: msDS-Behavior-Version 112 * Result: 113 * CN=Partitions,CN=Configuration,<domain_partition> 114 * msDS-Behavior-Version: 0 115 */ 116 117/* 118 * LDAP search 1st LDAP connection: 119 * 120 * NOTE: this seems to be a bug! as the messageID of the LDAP message is corrupted! 121 * 122 * not implemented here 123 * 124 * Request: 125 * basedn: CN=Schema,CN=Configuration,<domain_partition> 126 * scope: one 127 * filter: (cn=Partitions) 128 * attrs: msDS-Behavior-Version 129 * Result: 130 * <none> 131 * 132 */ 133 134/* 135 * LDAP search 1st LDAP connection: 136 * 137 * see: becomeDC_ldap1_domain_behavior_version() 138 * 139 * Request: 140 * basedn: <domain_partition> 141 * scope: base 142 * filter: (objectClass=*) 143 * attrs: msDS-Behavior-Version 144 * Result: 145 * <domain_partition> 146 * msDS-Behavior-Version: 0 147 */ 148 149/* 150 * LDAP search 1st LDAP connection: 151 * 152 * see: becomeDC_ldap1_schema_object_version() 153 * 154 * Request: 155 * basedn: CN=Schema,CN=Configuration,<domain_partition> 156 * scope: base 157 * filter: (objectClass=*) 158 * attrs: objectVersion 159 * Result: 160 * CN=Schema,CN=Configuration,<domain_partition> 161 * objectVersion: 30 162 */ 163 164/* 165 * LDAP search 1st LDAP connection: 166 * 167 * not implemented, because the information is already there 168 * 169 * Request: 170 * basedn: "" 171 * scope: base 172 * filter: (objectClass=*) 173 * attrs: defaultNamingContext 174 * dnsHostName 175 * Result: 176 * "" 177 * defaultNamingContext: <domain_partition> 178 * dnsHostName: <dns_host_name> 179 */ 180 181/* 182 * LDAP search 1st LDAP connection: 183 * 184 * see: becomeDC_ldap1_infrastructure_fsmo() 185 * 186 * Request: 187 * basedn: <WKGUID=2fbac1870ade11d297c400c04fd8d5cd,domain_partition> 188 * scope: base 189 * filter: (objectClass=*) 190 * attrs: 1.1 191 * Result: 192 * CN=Infrastructure,<domain_partition> 193 */ 194 195/* 196 * LDAP search 1st LDAP connection: 197 * 198 * see: becomeDC_ldap1_w2k3_update_revision() 199 * 200 * Request: 201 * basedn: CN=Windows2003Update,CN=DomainUpdates,CN=System,<domain_partition> 202 * scope: base 203 * filter: (objectClass=*) 204 * attrs: revision 205 * Result: 206 * CN=Windows2003Update,CN=DomainUpdates,CN=System,<domain_partition> 207 * revision: 8 208 */ 209 210/* 211 * LDAP search 1st LDAP connection: 212 * 213 * see: becomeDC_ldap1_infrastructure_fsmo() 214 * 215 * Request: 216 * basedn: CN=Infrastructure,<domain_partition> 217 * scope: base 218 * filter: (objectClass=*) 219 * attrs: fSMORoleOwner 220 * Result: 221 * CN=Infrastructure,<domain_partition> 222 * fSMORoleOwner: CN=NTDS Settings,<infrastructure_fsmo_server_object> 223 */ 224 225/* 226 * LDAP search 1st LDAP connection: 227 * 228 * see: becomeDC_ldap1_infrastructure_fsmo() 229 * 230 * Request: 231 * basedn: <infrastructure_fsmo_server_object> 232 * scope: base 233 * filter: (objectClass=*) 234 * attrs: dnsHostName 235 * Result: 236 * <infrastructure_fsmo_server_object> 237 * dnsHostName: <dns_host_name> 238 */ 239 240/* 241 * LDAP search 1st LDAP connection: 242 * 243 * see: becomeDC_ldap1_infrastructure_fsmo() 244 * 245 * Request: 246 * basedn: CN=NTDS Settings,<infrastructure_fsmo_server_object> 247 * scope: base 248 * filter: (objectClass=*) 249 * attrs: objectGUID 250 * Result: 251 * CN=NTDS Settings,<infrastructure_fsmo_server_object> 252 * objectGUID: <object_guid> 253 */ 254 255/* 256 * LDAP search 1st LDAP connection: 257 * 258 * see: becomeDC_ldap1_rid_manager_fsmo() 259 * 260 * Request: 261 * basedn: <domain_partition> 262 * scope: base 263 * filter: (objectClass=*) 264 * attrs: rIDManagerReference 265 * Result: 266 * <domain_partition> 267 * rIDManagerReference: CN=RID Manager$,CN=System,<domain_partition> 268 */ 269 270/* 271 * LDAP search 1st LDAP connection: 272 * 273 * see: becomeDC_ldap1_rid_manager_fsmo() 274 * 275 * Request: 276 * basedn: CN=RID Manager$,CN=System,<domain_partition> 277 * scope: base 278 * filter: (objectClass=*) 279 * attrs: fSMORoleOwner 280 * Result: 281 * CN=Infrastructure,<domain_partition> 282 * fSMORoleOwner: CN=NTDS Settings,<rid_manager_fsmo_server_object> 283 */ 284 285/* 286 * LDAP search 1st LDAP connection: 287 * 288 * see: becomeDC_ldap1_rid_manager_fsmo() 289 * 290 * Request: 291 * basedn: <rid_manager_fsmo_server_object> 292 * scope: base 293 * filter: (objectClass=*) 294 * attrs: dnsHostName 295 * Result: 296 * <rid_manager_fsmo_server_object> 297 * dnsHostName: <dns_host_name> 298 */ 299 300/* 301 * LDAP search 1st LDAP connection: 302 * 303 * see: becomeDC_ldap1_rid_manager_fsmo() 304 * 305 * Request: 306 * basedn: CN=NTDS Settings,<rid_manager_fsmo_server_object> 307 * scope: base 308 * filter: (objectClass=*) 309 * attrs: msDs-ReplicationEpoch 310 * Result: 311 * CN=NTDS Settings,<rid_manager_fsmo_server_object> 312 */ 313 314/* 315 * LDAP search 1st LDAP connection: 316 * 317 * see: becomeDC_ldap1_site_object() 318 * 319 * Request: 320 * basedn: CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition> 321 * scope: base 322 * filter: (objectClass=*) 323 * attrs: 324 * Result: 325 * CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition> 326 * objectClass: top 327 * site 328 * cn: <new_dc_site_name> 329 * distinguishedName:CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition> 330 * instanceType: 4 331 * whenCreated: ... 332 * whenChanged: ... 333 * uSNCreated: ... 334 * uSNChanged: ... 335 * showInAdvancedViewOnly: TRUE 336 * name: <new_dc_site_name> 337 * objectGUID: <object_guid> 338 * systemFlags: 1107296256 <0x42000000> 339 * objectCategory: CN=Site,C=Schema,CN=Configuration,<domain_partition> 340 */ 341 342/*************************************************************** 343 * Add this stage we call the check_options() callback function 344 * of the caller, to see if he wants us to continue 345 * 346 * see: becomeDC_check_options() 347 ***************************************************************/ 348 349/* 350 * LDAP search 1st LDAP connection: 351 * 352 * see: becomeDC_ldap1_computer_object() 353 * 354 * Request: 355 * basedn: <domain_partition> 356 * scope: sub 357 * filter: (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<new_dc_account_name>)) 358 * attrs: distinguishedName 359 * userAccountControl 360 * Result: 361 * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 362 * distinguishedName: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 363 * userAccoountControl: 4096 <0x1000> 364 */ 365 366/* 367 * LDAP search 1st LDAP connection: 368 * 369 * see: becomeDC_ldap1_server_object_1() 370 * 371 * Request: 372 * basedn: CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition> 373 * scope: base 374 * filter: (objectClass=*) 375 * attrs: 376 * Result: 377 * <noSuchObject> 378 * <matchedDN:CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>> 379 */ 380 381/* 382 * LDAP search 1st LDAP connection: 383 * 384 * see: becomeDC_ldap1_server_object_2() 385 * 386 * Request: 387 * basedn: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 388 * scope: base 389 * filter: (objectClass=*) 390 * attrs: serverReferenceBL 391 * typesOnly: TRUE!!! 392 * Result: 393 * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 394 */ 395 396/* 397 * LDAP add 1st LDAP connection: 398 * 399 * see: becomeDC_ldap1_server_object_add() 400 * 401 * Request: 402 * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 403 * objectClass: server 404 * systemFlags: 50000000 <0x2FAF080> 405 * serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 406 * Result: 407 * <success> 408 */ 409 410/* 411 * LDAP search 1st LDAP connection: 412 * 413 * not implemented, maybe we can add that later 414 * 415 * Request: 416 * basedn: CN=NTDS Settings,CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition> 417 * scope: base 418 * filter: (objectClass=*) 419 * attrs: 420 * Result: 421 * <noSuchObject> 422 * <matchedDN:CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>> 423 */ 424 425/* 426 * LDAP search 1st LDAP connection: 427 * 428 * not implemented because it gives no new information 429 * 430 * Request: 431 * basedn: CN=Partitions,CN=Configuration,<domain_partition> 432 * scope: sub 433 * filter: (nCName=<domain_partition>) 434 * attrs: nCName 435 * dnsRoot 436 * controls: LDAP_SERVER_EXTENDED_DN_OID:critical=false 437 * Result: 438 * <GUID=<hex_guid>>;CN=<domain_netbios_name>,CN=Partitions,<domain_partition>> 439 * nCName: <GUID=<hex_guid>>;<SID=<hex_sid>>;<domain_partition>> 440 * dnsRoot: <domain_dns_name> 441 */ 442 443/* 444 * LDAP modify 1st LDAP connection: 445 * 446 * see: becomeDC_ldap1_server_object_modify() 447 * 448 * Request (add): 449 * CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>> 450 * serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 451 * Result: 452 * <attributeOrValueExist> 453 */ 454 455/* 456 * LDAP modify 1st LDAP connection: 457 * 458 * see: becomeDC_ldap1_server_object_modify() 459 * 460 * Request (replace): 461 * CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>> 462 * serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 463 * Result: 464 * <success> 465 */ 466 467/* 468 * Open 1st DRSUAPI connection to the DC using admin credentials 469 * DsBind with DRSUAPI_DS_BIND_GUID_W2K3 ("6afab99c-6e26-464a-975f-f58f105218bc") 470 * (w2k3 does 2 DsBind() calls here..., where is first is unused and contains garbage at the end) 471 * 472 * see: becomeDC_drsuapi_connect_send(), becomeDC_drsuapi1_connect_recv(), 473 * becomeDC_drsuapi_bind_send(), becomeDC_drsuapi_bind_recv() and becomeDC_drsuapi1_bind_recv() 474 */ 475 476/* 477 * DsAddEntry to create the CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ... 478 * on the 1st DRSUAPI connection 479 * 480 * see: becomeDC_drsuapi1_add_entry_send() and becomeDC_drsuapi1_add_entry_recv() 481 */ 482 483/*************************************************************** 484 * Add this stage we call the prepare_db() callback function 485 * of the caller, to see if he wants us to continue 486 * 487 * see: becomeDC_prepare_db() 488 ***************************************************************/ 489 490/* 491 * Open 2nd and 3rd DRSUAPI connection to the DC using admin credentials 492 * - a DsBind with DRSUAPI_DS_BIND_GUID_W2K3 ("6afab99c-6e26-464a-975f-f58f105218bc") 493 * on the 2nd connection 494 * 495 * see: becomeDC_drsuapi_connect_send(), becomeDC_drsuapi2_connect_recv(), 496 * becomeDC_drsuapi_bind_send(), becomeDC_drsuapi_bind_recv(), becomeDC_drsuapi2_bind_recv() 497 * and becomeDC_drsuapi3_connect_recv() 498 */ 499 500/* 501 * replicate CN=Schema,CN=Configuration,... 502 * on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection 503 * 504 * see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(), 505 * becomeDC_drsuapi3_pull_schema_send() and becomeDC_drsuapi3_pull_schema_recv() 506 * 507 *************************************************************** 508 * Add this stage we call the schema_chunk() callback function 509 * for each replication message 510 ***************************************************************/ 511 512/* 513 * replicate CN=Configuration,... 514 * on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection 515 * 516 * see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(), 517 * becomeDC_drsuapi3_pull_config_send() and becomeDC_drsuapi3_pull_config_recv() 518 * 519 *************************************************************** 520 * Add this stage we call the config_chunk() callback function 521 * for each replication message 522 ***************************************************************/ 523 524/* 525 * LDAP unbind on the 1st LDAP connection 526 * 527 * not implemented, because it's not needed... 528 */ 529 530/* 531 * Open 2nd LDAP connection to the DC using admin credentials 532 * 533 * see: becomeDC_connect_ldap2() and becomeDC_ldap_connect() 534 */ 535 536/* 537 * LDAP search 2nd LDAP connection: 538 * 539 * not implemented because it gives no new information 540 * same as becomeDC_ldap1_computer_object() 541 * 542 * Request: 543 * basedn: <domain_partition> 544 * scope: sub 545 * filter: (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<new_dc_account_name>)) 546 * attrs: distinguishedName 547 * userAccountControl 548 * Result: 549 * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 550 * distinguishedName: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 551 * userAccoountControl: 4096 <0x00001000> 552 */ 553 554/* 555 * LDAP search 2nd LDAP connection: 556 * 557 * not implemented because it gives no new information 558 * same as becomeDC_ldap1_computer_object() 559 * 560 * Request: 561 * basedn: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 562 * scope: base 563 * filter: (objectClass=*) 564 * attrs: userAccountControl 565 * Result: 566 * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 567 * userAccoountControl: 4096 <0x00001000> 568 */ 569 570/* 571 * LDAP modify 2nd LDAP connection: 572 * 573 * see: becomeDC_ldap2_modify_computer() 574 * 575 * Request (replace): 576 * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 577 * userAccoountControl: 532480 <0x82000> 578 * Result: 579 * <success> 580 */ 581 582/* 583 * LDAP search 2nd LDAP connection: 584 * 585 * see: becomeDC_ldap2_move_computer() 586 * 587 * Request: 588 * basedn: <WKGUID=2fbac1870ade11d297c400c04fd8d5cd,<domain_partition>> 589 * scope: base 590 * filter: (objectClass=*) 591 * attrs: 1.1 592 * Result: 593 * CN=Domain Controllers,<domain_partition> 594 */ 595 596/* 597 * LDAP search 2nd LDAP connection: 598 * 599 * not implemented because it gives no new information 600 * 601 * Request: 602 * basedn: CN=Domain Controllers,<domain_partition> 603 * scope: base 604 * filter: (objectClass=*) 605 * attrs: distinguishedName 606 * Result: 607 * CN=Domain Controller,<domain_partition> 608 * distinguishedName: CN=Domain Controllers,<domain_partition> 609 */ 610 611/* 612 * LDAP modifyRDN 2nd LDAP connection: 613 * 614 * see: becomeDC_ldap2_move_computer() 615 * 616 * Request: 617 * entry: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition> 618 * newrdn: CN=<new_dc_netbios_name> 619 * deleteoldrdn: TRUE 620 * newparent: CN=Domain Controllers,<domain_partition> 621 * Result: 622 * <success> 623 */ 624 625/* 626 * LDAP unbind on the 2nd LDAP connection 627 * 628 * not implemented, because it's not needed... 629 */ 630 631/* 632 * replicate Domain Partition 633 * on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection 634 * 635 * see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(), 636 * becomeDC_drsuapi3_pull_domain_send() and becomeDC_drsuapi3_pull_domain_recv() 637 * 638 *************************************************************** 639 * Add this stage we call the domain_chunk() callback function 640 * for each replication message 641 ***************************************************************/ 642 643/* call DsReplicaUpdateRefs() for all partitions like this: 644 * req1: struct drsuapi_DsReplicaUpdateRefsRequest1 645 * 646 * naming_context: struct drsuapi_DsReplicaObjectIdentifier 647 * __ndr_size : 0x000000ae (174) 648 * __ndr_size_sid : 0x00000000 (0) 649 * guid : 00000000-0000-0000-0000-000000000000 650 * sid : S-0-0 651 * dn : 'CN=Schema,CN=Configuration,DC=w2k3,DC=vmnet1,DC=vm,DC=base' 652 * 653 * dest_dsa_dns_name : '4a0df188-a0b8-47ea-bbe5-e614723f16dd._msdcs.w2k3.vmnet1.vm.base' 654 * dest_dsa_guid : 4a0df188-a0b8-47ea-bbe5-e614723f16dd 655 * options : 0x0000001c (28) 656 * 0: DRSUAPI_DS_REPLICA_UPDATE_ASYNCHRONOUS_OPERATION 657 * 0: DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE 658 * 1: DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE 659 * 1: DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE 660 * 1: DRSUAPI_DS_REPLICA_UPDATE_0x00000010 661 * 662 * 4a0df188-a0b8-47ea-bbe5-e614723f16dd is the objectGUID the DsAddEntry() returned for the 663 * CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ... 664 * on the 2nd!!! DRSUAPI connection 665 * 666 * see: becomeDC_drsuapi_update_refs_send(), becomeDC_drsuapi2_update_refs_schema_recv(), 667 * becomeDC_drsuapi2_update_refs_config_recv() and becomeDC_drsuapi2_update_refs_domain_recv() 668 */ 669 670/* 671 * Windows does opens the 4th and 5th DRSUAPI connection... 672 * and does a DsBind() with the objectGUID from DsAddEntry() as bind_guid 673 * on the 4th connection 674 * 675 * and then 2 full replications of the domain partition on the 5th connection 676 * with the bind_handle from the 4th connection 677 * 678 * not implemented because it gives no new information 679 */ 680 681struct libnet_BecomeDC_state { 682 struct composite_context *creq; 683 684 struct libnet_context *libnet; 685 686 struct dom_sid zero_sid; 687 688 struct { 689 struct cldap_socket *sock; 690 struct cldap_netlogon io; 691 struct NETLOGON_SAM_LOGON_RESPONSE_EX netlogon; 692 } cldap; 693 694 struct becomeDC_ldap { 695 struct ldb_context *ldb; 696 const struct ldb_message *rootdse; 697 } ldap1, ldap2; 698 699 struct becomeDC_drsuapi { 700 struct libnet_BecomeDC_state *s; 701 struct dcerpc_binding *binding; 702 struct dcerpc_pipe *pipe; 703 DATA_BLOB gensec_skey; 704 struct drsuapi_DsBind bind_r; 705 struct GUID bind_guid; 706 struct drsuapi_DsBindInfoCtr bind_info_ctr; 707 struct drsuapi_DsBindInfo28 local_info28; 708 struct drsuapi_DsBindInfo28 remote_info28; 709 struct policy_handle bind_handle; 710 } drsuapi1, drsuapi2, drsuapi3; 711 712 struct libnet_BecomeDC_Domain domain; 713 struct libnet_BecomeDC_Forest forest; 714 struct libnet_BecomeDC_SourceDSA source_dsa; 715 struct libnet_BecomeDC_DestDSA dest_dsa; 716 717 struct libnet_BecomeDC_Partition schema_part, config_part, domain_part; 718 719 struct becomeDC_fsmo { 720 const char *dns_name; 721 const char *server_dn_str; 722 const char *ntds_dn_str; 723 struct GUID ntds_guid; 724 } infrastructure_fsmo; 725 726 struct becomeDC_fsmo rid_manager_fsmo; 727 728 struct libnet_BecomeDC_CheckOptions _co; 729 struct libnet_BecomeDC_PrepareDB _pp; 730 struct libnet_BecomeDC_StoreChunk _sc; 731 struct libnet_BecomeDC_Callbacks callbacks; 732}; 733 734static void becomeDC_recv_cldap(struct tevent_req *req); 735 736static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s) 737{ 738 struct composite_context *c = s->creq; 739 struct tevent_req *req; 740 741 s->cldap.io.in.dest_address = s->source_dsa.address; 742 s->cldap.io.in.dest_port = lp_cldap_port(s->libnet->lp_ctx); 743 s->cldap.io.in.realm = s->domain.dns_name; 744 s->cldap.io.in.host = s->dest_dsa.netbios_name; 745 s->cldap.io.in.user = NULL; 746 s->cldap.io.in.domain_guid = NULL; 747 s->cldap.io.in.domain_sid = NULL; 748 s->cldap.io.in.acct_control = -1; 749 s->cldap.io.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; 750 s->cldap.io.in.map_response = true; 751 752 c->status = cldap_socket_init(s, s->libnet->event_ctx, 753 NULL, NULL, &s->cldap.sock);//TODO 754 if (!composite_is_ok(c)) return; 755 756 req = cldap_netlogon_send(s, s->cldap.sock, &s->cldap.io); 757 if (composite_nomem(req, c)) return; 758 tevent_req_set_callback(req, becomeDC_recv_cldap, s); 759} 760 761static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s); 762 763static void becomeDC_recv_cldap(struct tevent_req *req) 764{ 765 struct libnet_BecomeDC_state *s = tevent_req_callback_data(req, 766 struct libnet_BecomeDC_state); 767 struct composite_context *c = s->creq; 768 769 c->status = cldap_netlogon_recv(req, 770 lp_iconv_convenience(s->libnet->lp_ctx), 771 s, &s->cldap.io); 772 talloc_free(req); 773 if (!composite_is_ok(c)) return; 774 775 s->cldap.netlogon = s->cldap.io.out.netlogon.data.nt5_ex; 776 777 s->domain.dns_name = s->cldap.netlogon.dns_domain; 778 s->domain.netbios_name = s->cldap.netlogon.domain; 779 s->domain.guid = s->cldap.netlogon.domain_uuid; 780 781 s->forest.dns_name = s->cldap.netlogon.forest; 782 783 s->source_dsa.dns_name = s->cldap.netlogon.pdc_dns_name; 784 s->source_dsa.netbios_name = s->cldap.netlogon.pdc_name; 785 s->source_dsa.site_name = s->cldap.netlogon.server_site; 786 787 s->dest_dsa.site_name = s->cldap.netlogon.client_site; 788 789 becomeDC_connect_ldap1(s); 790} 791 792static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s, 793 struct becomeDC_ldap *ldap) 794{ 795 char *url; 796 797 url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name); 798 NT_STATUS_HAVE_NO_MEMORY(url); 799 800 ldap->ldb = ldb_wrap_connect(s, s->libnet->event_ctx, s->libnet->lp_ctx, url, 801 NULL, 802 s->libnet->cred, 803 0, NULL); 804 talloc_free(url); 805 if (ldap->ldb == NULL) { 806 return NT_STATUS_UNEXPECTED_NETWORK_ERROR; 807 } 808 809 return NT_STATUS_OK; 810} 811 812static NTSTATUS becomeDC_ldap1_rootdse(struct libnet_BecomeDC_state *s) 813{ 814 int ret; 815 struct ldb_result *r; 816 struct ldb_dn *basedn; 817 static const char *attrs[] = { 818 "*", 819 NULL 820 }; 821 822 basedn = ldb_dn_new(s, s->ldap1.ldb, NULL); 823 NT_STATUS_HAVE_NO_MEMORY(basedn); 824 825 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs, 826 "(objectClass=*)"); 827 talloc_free(basedn); 828 if (ret != LDB_SUCCESS) { 829 return NT_STATUS_LDAP(ret); 830 } else if (r->count != 1) { 831 talloc_free(r); 832 return NT_STATUS_INVALID_NETWORK_RESPONSE; 833 } 834 835 s->ldap1.rootdse = r->msgs[0]; 836 837 s->domain.dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "defaultNamingContext", NULL); 838 if (!s->domain.dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; 839 840 s->forest.root_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "rootDomainNamingContext", NULL); 841 if (!s->forest.root_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; 842 s->forest.config_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "configurationNamingContext", NULL); 843 if (!s->forest.config_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; 844 s->forest.schema_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "schemaNamingContext", NULL); 845 if (!s->forest.schema_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; 846 847 s->source_dsa.server_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "serverName", NULL); 848 if (!s->source_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; 849 s->source_dsa.ntds_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "dsServiceName", NULL); 850 if (!s->source_dsa.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; 851 852 return NT_STATUS_OK; 853} 854 855static NTSTATUS becomeDC_ldap1_crossref_behavior_version(struct libnet_BecomeDC_state *s) 856{ 857 int ret; 858 struct ldb_result *r; 859 struct ldb_dn *basedn; 860 static const char *attrs[] = { 861 "msDs-Behavior-Version", 862 NULL 863 }; 864 865 basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.config_dn_str); 866 NT_STATUS_HAVE_NO_MEMORY(basedn); 867 868 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_ONELEVEL, attrs, 869 "(cn=Partitions)"); 870 talloc_free(basedn); 871 if (ret != LDB_SUCCESS) { 872 return NT_STATUS_LDAP(ret); 873 } else if (r->count != 1) { 874 talloc_free(r); 875 return NT_STATUS_INVALID_NETWORK_RESPONSE; 876 } 877 878 s->forest.crossref_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0); 879 880 talloc_free(r); 881 return NT_STATUS_OK; 882} 883 884static NTSTATUS becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_state *s) 885{ 886 int ret; 887 struct ldb_result *r; 888 struct ldb_dn *basedn; 889 static const char *attrs[] = { 890 "msDs-Behavior-Version", 891 NULL 892 }; 893 894 basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str); 895 NT_STATUS_HAVE_NO_MEMORY(basedn); 896 897 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs, 898 "(objectClass=*)"); 899 talloc_free(basedn); 900 if (ret != LDB_SUCCESS) { 901 return NT_STATUS_LDAP(ret); 902 } else if (r->count != 1) { 903 talloc_free(r); 904 return NT_STATUS_INVALID_NETWORK_RESPONSE; 905 } 906 907 s->domain.behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0); 908 909 talloc_free(r); 910 return NT_STATUS_OK; 911} 912 913static NTSTATUS becomeDC_ldap1_schema_object_version(struct libnet_BecomeDC_state *s) 914{ 915 int ret; 916 struct ldb_result *r; 917 struct ldb_dn *basedn; 918 static const char *attrs[] = { 919 "objectVersion", 920 NULL 921 }; 922 923 basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.schema_dn_str); 924 NT_STATUS_HAVE_NO_MEMORY(basedn); 925 926 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs, 927 "(objectClass=*)"); 928 talloc_free(basedn); 929 if (ret != LDB_SUCCESS) { 930 return NT_STATUS_LDAP(ret); 931 } else if (r->count != 1) { 932 talloc_free(r); 933 return NT_STATUS_INVALID_NETWORK_RESPONSE; 934 } 935 936 s->forest.schema_object_version = ldb_msg_find_attr_as_uint(r->msgs[0], "objectVersion", 0); 937 938 talloc_free(r); 939 return NT_STATUS_OK; 940} 941 942static NTSTATUS becomeDC_ldap1_w2k3_update_revision(struct libnet_BecomeDC_state *s) 943{ 944 int ret; 945 struct ldb_result *r; 946 struct ldb_dn *basedn; 947 static const char *attrs[] = { 948 "revision", 949 NULL 950 }; 951 952 basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=Windows2003Update,CN=DomainUpdates,CN=System,%s", 953 s->domain.dn_str); 954 NT_STATUS_HAVE_NO_MEMORY(basedn); 955 956 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs, 957 "(objectClass=*)"); 958 talloc_free(basedn); 959 if (ret == LDB_ERR_NO_SUCH_OBJECT) { 960 /* w2k doesn't have this object */ 961 s->domain.w2k3_update_revision = 0; 962 return NT_STATUS_OK; 963 } else if (ret != LDB_SUCCESS) { 964 return NT_STATUS_LDAP(ret); 965 } else if (r->count != 1) { 966 talloc_free(r); 967 return NT_STATUS_INVALID_NETWORK_RESPONSE; 968 } 969 970 s->domain.w2k3_update_revision = ldb_msg_find_attr_as_uint(r->msgs[0], "revision", 0); 971 972 talloc_free(r); 973 return NT_STATUS_OK; 974} 975 976static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state *s) 977{ 978 int ret; 979 struct ldb_result *r; 980 struct ldb_dn *basedn; 981 struct ldb_dn *ntds_dn; 982 struct ldb_dn *server_dn; 983 static const char *_1_1_attrs[] = { 984 "1.1", 985 NULL 986 }; 987 static const char *fsmo_attrs[] = { 988 "fSMORoleOwner", 989 NULL 990 }; 991 static const char *dns_attrs[] = { 992 "dnsHostName", 993 NULL 994 }; 995 static const char *guid_attrs[] = { 996 "objectGUID", 997 NULL 998 }; 999 1000 basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "<WKGUID=2fbac1870ade11d297c400c04fd8d5cd,%s>", 1001 s->domain.dn_str); 1002 NT_STATUS_HAVE_NO_MEMORY(basedn); 1003 1004 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, 1005 _1_1_attrs, "(objectClass=*)"); 1006 talloc_free(basedn); 1007 if (ret != LDB_SUCCESS) { 1008 return NT_STATUS_LDAP(ret); 1009 } else if (r->count != 1) { 1010 talloc_free(r); 1011 return NT_STATUS_INVALID_NETWORK_RESPONSE; 1012 } 1013 1014 basedn = talloc_steal(s, r->msgs[0]->dn); 1015 talloc_free(r); 1016 1017 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, 1018 fsmo_attrs, "(objectClass=*)"); 1019 talloc_free(basedn); 1020 if (ret != LDB_SUCCESS) { 1021 return NT_STATUS_LDAP(ret); 1022 } else if (r->count != 1) { 1023 talloc_free(r); 1024 return NT_STATUS_INVALID_NETWORK_RESPONSE; 1025 } 1026 1027 s->infrastructure_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL); 1028 if (!s->infrastructure_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; 1029 talloc_steal(s, s->infrastructure_fsmo.ntds_dn_str); 1030 1031 talloc_free(r); 1032 1033 ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->infrastructure_fsmo.ntds_dn_str); 1034 NT_STATUS_HAVE_NO_MEMORY(ntds_dn); 1035 1036 server_dn = ldb_dn_get_parent(s, ntds_dn); 1037 NT_STATUS_HAVE_NO_MEMORY(server_dn); 1038 1039 s->infrastructure_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn); 1040 NT_STATUS_HAVE_NO_MEMORY(s->infrastructure_fsmo.server_dn_str); 1041 1042 ret = ldb_search(s->ldap1.ldb, s, &r, server_dn, LDB_SCOPE_BASE, 1043 dns_attrs, "(objectClass=*)"); 1044 if (ret != LDB_SUCCESS) { 1045 return NT_STATUS_LDAP(ret); 1046 } else if (r->count != 1) { 1047 talloc_free(r); 1048 return NT_STATUS_INVALID_NETWORK_RESPONSE; 1049 } 1050 1051 s->infrastructure_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL); 1052 if (!s->infrastructure_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE; 1053 talloc_steal(s, s->infrastructure_fsmo.dns_name); 1054 1055 talloc_free(r); 1056 1057 ret = ldb_search(s->ldap1.ldb, s, &r, ntds_dn, LDB_SCOPE_BASE, 1058 guid_attrs, "(objectClass=*)"); 1059 if (ret != LDB_SUCCESS) { 1060 return NT_STATUS_LDAP(ret); 1061 } else if (r->count != 1) { 1062 talloc_free(r); 1063 return NT_STATUS_INVALID_NETWORK_RESPONSE; 1064 } 1065 1066 s->infrastructure_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID"); 1067 1068 talloc_free(r); 1069 1070 return NT_STATUS_OK; 1071} 1072 1073static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s) 1074{ 1075 int ret; 1076 struct ldb_result *r; 1077 struct ldb_dn *basedn; 1078 const char *reference_dn_str; 1079 struct ldb_dn *ntds_dn; 1080 struct ldb_dn *server_dn; 1081 static const char *rid_attrs[] = { 1082 "rIDManagerReference", 1083 NULL 1084 }; 1085 static const char *fsmo_attrs[] = { 1086 "fSMORoleOwner", 1087 NULL 1088 }; 1089 static const char *dns_attrs[] = { 1090 "dnsHostName", 1091 NULL 1092 }; 1093 static const char *guid_attrs[] = { 1094 "objectGUID", 1095 NULL 1096 }; 1097 1098 basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str); 1099 NT_STATUS_HAVE_NO_MEMORY(basedn); 1100 1101 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, 1102 rid_attrs, "(objectClass=*)"); 1103 talloc_free(basedn); 1104 if (ret != LDB_SUCCESS) { 1105 return NT_STATUS_LDAP(ret); 1106 } else if (r->count != 1) { 1107 talloc_free(r); 1108 return NT_STATUS_INVALID_NETWORK_RESPONSE; 1109 } 1110 1111 reference_dn_str = samdb_result_string(r->msgs[0], "rIDManagerReference", NULL); 1112 if (!reference_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; 1113 1114 basedn = ldb_dn_new(s, s->ldap1.ldb, reference_dn_str); 1115 NT_STATUS_HAVE_NO_MEMORY(basedn); 1116 1117 talloc_free(r); 1118 1119 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, 1120 fsmo_attrs, "(objectClass=*)"); 1121 talloc_free(basedn); 1122 if (ret != LDB_SUCCESS) { 1123 return NT_STATUS_LDAP(ret); 1124 } else if (r->count != 1) { 1125 talloc_free(r); 1126 return NT_STATUS_INVALID_NETWORK_RESPONSE; 1127 } 1128 1129 s->rid_manager_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL); 1130 if (!s->rid_manager_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; 1131 talloc_steal(s, s->rid_manager_fsmo.ntds_dn_str); 1132 1133 talloc_free(r); 1134 1135 ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->rid_manager_fsmo.ntds_dn_str); 1136 NT_STATUS_HAVE_NO_MEMORY(ntds_dn); 1137 1138 server_dn = ldb_dn_get_parent(s, ntds_dn); 1139 NT_STATUS_HAVE_NO_MEMORY(server_dn); 1140 1141 s->rid_manager_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn); 1142 NT_STATUS_HAVE_NO_MEMORY(s->rid_manager_fsmo.server_dn_str); 1143 1144 ret = ldb_search(s->ldap1.ldb, s, &r, server_dn, LDB_SCOPE_BASE, 1145 dns_attrs, "(objectClass=*)"); 1146 if (ret != LDB_SUCCESS) { 1147 return NT_STATUS_LDAP(ret); 1148 } else if (r->count != 1) { 1149 talloc_free(r); 1150 return NT_STATUS_INVALID_NETWORK_RESPONSE; 1151 } 1152 1153 s->rid_manager_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL); 1154 if (!s->rid_manager_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE; 1155 talloc_steal(s, s->rid_manager_fsmo.dns_name); 1156 1157 talloc_free(r); 1158 1159 ret = ldb_search(s->ldap1.ldb, s, &r, ntds_dn, LDB_SCOPE_BASE, 1160 guid_attrs, "(objectClass=*)"); 1161 if (ret != LDB_SUCCESS) { 1162 return NT_STATUS_LDAP(ret); 1163 } else if (r->count != 1) { 1164 talloc_free(r); 1165 return NT_STATUS_INVALID_NETWORK_RESPONSE; 1166 } 1167 1168 s->rid_manager_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID"); 1169 1170 talloc_free(r); 1171 1172 return NT_STATUS_OK; 1173} 1174 1175static NTSTATUS becomeDC_ldap1_site_object(struct libnet_BecomeDC_state *s) 1176{ 1177 int ret; 1178 struct ldb_result *r; 1179 struct ldb_dn *basedn; 1180 1181 basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Sites,%s", 1182 s->dest_dsa.site_name, 1183 s->forest.config_dn_str); 1184 NT_STATUS_HAVE_NO_MEMORY(basedn); 1185 1186 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, 1187 NULL, "(objectClass=*)"); 1188 talloc_free(basedn); 1189 if (ret != LDB_SUCCESS) { 1190 return NT_STATUS_LDAP(ret); 1191 } else if (r->count != 1) { 1192 talloc_free(r); 1193 return NT_STATUS_INVALID_NETWORK_RESPONSE; 1194 } 1195 1196 s->dest_dsa.site_guid = samdb_result_guid(r->msgs[0], "objectGUID"); 1197 1198 talloc_free(r); 1199 return NT_STATUS_OK; 1200} 1201 1202static NTSTATUS becomeDC_check_options(struct libnet_BecomeDC_state *s) 1203{ 1204 if (!s->callbacks.check_options) return NT_STATUS_OK; 1205 1206 s->_co.domain = &s->domain; 1207 s->_co.forest = &s->forest; 1208 s->_co.source_dsa = &s->source_dsa; 1209 1210 return s->callbacks.check_options(s->callbacks.private_data, &s->_co); 1211} 1212 1213static NTSTATUS becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state *s) 1214{ 1215 int ret; 1216 struct ldb_result *r; 1217 struct ldb_dn *basedn; 1218 static const char *attrs[] = { 1219 "distinguishedName", 1220 "userAccountControl", 1221 NULL 1222 }; 1223 1224 basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str); 1225 NT_STATUS_HAVE_NO_MEMORY(basedn); 1226 1227 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_SUBTREE, attrs, 1228 "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))", 1229 s->dest_dsa.netbios_name); 1230 talloc_free(basedn); 1231 if (ret != LDB_SUCCESS) { 1232 return NT_STATUS_LDAP(ret); 1233 } else if (r->count != 1) { 1234 talloc_free(r); 1235 return NT_STATUS_INVALID_NETWORK_RESPONSE; 1236 } 1237 1238 s->dest_dsa.computer_dn_str = samdb_result_string(r->msgs[0], "distinguishedName", NULL); 1239 if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; 1240 talloc_steal(s, s->dest_dsa.computer_dn_str); 1241 1242 s->dest_dsa.user_account_control = samdb_result_uint(r->msgs[0], "userAccountControl", 0); 1243 1244 talloc_free(r); 1245 return NT_STATUS_OK; 1246} 1247 1248static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s) 1249{ 1250 int ret; 1251 struct ldb_result *r; 1252 struct ldb_dn *basedn; 1253 const char *server_reference_dn_str; 1254 struct ldb_dn *server_reference_dn; 1255 struct ldb_dn *computer_dn; 1256 1257 basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s", 1258 s->dest_dsa.netbios_name, 1259 s->dest_dsa.site_name, 1260 s->forest.config_dn_str); 1261 NT_STATUS_HAVE_NO_MEMORY(basedn); 1262 1263 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, 1264 NULL, "(objectClass=*)"); 1265 talloc_free(basedn); 1266 if (ret == LDB_ERR_NO_SUCH_OBJECT) { 1267 /* if the object doesn't exist, we'll create it later */ 1268 return NT_STATUS_OK; 1269 } else if (ret != LDB_SUCCESS) { 1270 return NT_STATUS_LDAP(ret); 1271 } else if (r->count != 1) { 1272 talloc_free(r); 1273 return NT_STATUS_INVALID_NETWORK_RESPONSE; 1274 } 1275 1276 server_reference_dn_str = samdb_result_string(r->msgs[0], "serverReference", NULL); 1277 if (server_reference_dn_str) { 1278 server_reference_dn = ldb_dn_new(r, s->ldap1.ldb, server_reference_dn_str); 1279 NT_STATUS_HAVE_NO_MEMORY(server_reference_dn); 1280 1281 computer_dn = ldb_dn_new(r, s->ldap1.ldb, s->dest_dsa.computer_dn_str); 1282 NT_STATUS_HAVE_NO_MEMORY(computer_dn); 1283 1284 /* 1285 * if the server object belongs to another DC in another domain in the forest, 1286 * we should not touch this object! 1287 */ 1288 if (ldb_dn_compare(computer_dn, server_reference_dn) != 0) { 1289 talloc_free(r); 1290 return NT_STATUS_OBJECT_NAME_COLLISION; 1291 } 1292 } 1293 1294 /* if the server object is already for the dest_dsa, then we don't need to create it */ 1295 s->dest_dsa.server_dn_str = samdb_result_string(r->msgs[0], "distinguishedName", NULL); 1296 if (!s->dest_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; 1297 talloc_steal(s, s->dest_dsa.server_dn_str); 1298 1299 talloc_free(r); 1300 return NT_STATUS_OK; 1301} 1302 1303static NTSTATUS becomeDC_ldap1_server_object_2(struct libnet_BecomeDC_state *s) 1304{ 1305 int ret; 1306 struct ldb_result *r; 1307 struct ldb_dn *basedn; 1308 const char *server_reference_bl_dn_str; 1309 static const char *attrs[] = { 1310 "serverReferenceBL", 1311 NULL 1312 }; 1313 1314 /* if the server_dn_str has a valid value, we skip this lookup */ 1315 if (s->dest_dsa.server_dn_str) return NT_STATUS_OK; 1316 1317 basedn = ldb_dn_new(s, s->ldap1.ldb, s->dest_dsa.computer_dn_str); 1318 NT_STATUS_HAVE_NO_MEMORY(basedn); 1319 1320 ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, 1321 attrs, "(objectClass=*)"); 1322 talloc_free(basedn); 1323 if (ret != LDB_SUCCESS) { 1324 return NT_STATUS_LDAP(ret); 1325 } else if (r->count != 1) { 1326 talloc_free(r); 1327 return NT_STATUS_INVALID_NETWORK_RESPONSE; 1328 } 1329 1330 server_reference_bl_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL); 1331 if (!server_reference_bl_dn_str) { 1332 /* if no back link is present, we're done for this function */ 1333 talloc_free(r); 1334 return NT_STATUS_OK; 1335 } 1336 1337 /* if the server object is already for the dest_dsa, then we don't need to create it */ 1338 s->dest_dsa.server_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL); 1339 if (s->dest_dsa.server_dn_str) { 1340 /* if a back link is present, we know that the server object is present */ 1341 talloc_steal(s, s->dest_dsa.server_dn_str); 1342 } 1343 1344 talloc_free(r); 1345 return NT_STATUS_OK; 1346} 1347 1348static NTSTATUS becomeDC_ldap1_server_object_add(struct libnet_BecomeDC_state *s) 1349{ 1350 int ret; 1351 struct ldb_message *msg; 1352 char *server_dn_str; 1353 1354 /* if the server_dn_str has a valid value, we skip this lookup */ 1355 if (s->dest_dsa.server_dn_str) return NT_STATUS_OK; 1356 1357 msg = ldb_msg_new(s); 1358 NT_STATUS_HAVE_NO_MEMORY(msg); 1359 1360 msg->dn = ldb_dn_new_fmt(msg, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s", 1361 s->dest_dsa.netbios_name, 1362 s->dest_dsa.site_name, 1363 s->forest.config_dn_str); 1364 NT_STATUS_HAVE_NO_MEMORY(msg->dn); 1365 1366 ret = ldb_msg_add_string(msg, "objectClass", "server"); 1367 if (ret != 0) { 1368 talloc_free(msg); 1369 return NT_STATUS_NO_MEMORY; 1370 } 1371 ret = ldb_msg_add_string(msg, "systemFlags", "50000000"); 1372 if (ret != 0) { 1373 talloc_free(msg); 1374 return NT_STATUS_NO_MEMORY; 1375 } 1376 ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str); 1377 if (ret != 0) { 1378 talloc_free(msg); 1379 return NT_STATUS_NO_MEMORY; 1380 } 1381 1382 server_dn_str = ldb_dn_alloc_linearized(s, msg->dn); 1383 NT_STATUS_HAVE_NO_MEMORY(server_dn_str); 1384 1385 ret = ldb_add(s->ldap1.ldb, msg); 1386 talloc_free(msg); 1387 if (ret != LDB_SUCCESS) { 1388 talloc_free(server_dn_str); 1389 return NT_STATUS_LDAP(ret); 1390 } 1391 1392 s->dest_dsa.server_dn_str = server_dn_str; 1393 1394 return NT_STATUS_OK; 1395} 1396 1397static NTSTATUS becomeDC_ldap1_server_object_modify(struct libnet_BecomeDC_state *s) 1398{ 1399 int ret; 1400 struct ldb_message *msg; 1401 uint32_t i; 1402 1403 /* make a 'modify' msg, and only for serverReference */ 1404 msg = ldb_msg_new(s); 1405 NT_STATUS_HAVE_NO_MEMORY(msg); 1406 msg->dn = ldb_dn_new(msg, s->ldap1.ldb, s->dest_dsa.server_dn_str); 1407 NT_STATUS_HAVE_NO_MEMORY(msg->dn); 1408 1409 ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str); 1410 if (ret != 0) { 1411 talloc_free(msg); 1412 return NT_STATUS_NO_MEMORY; 1413 } 1414 1415 /* mark all the message elements (should be just one) 1416 as LDB_FLAG_MOD_ADD */ 1417 for (i=0;i<msg->num_elements;i++) { 1418 msg->elements[i].flags = LDB_FLAG_MOD_ADD; 1419 } 1420 1421 ret = ldb_modify(s->ldap1.ldb, msg); 1422 if (ret == LDB_SUCCESS) { 1423 talloc_free(msg); 1424 return NT_STATUS_OK; 1425 } else if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) { 1426 /* retry with LDB_FLAG_MOD_REPLACE */ 1427 } else { 1428 talloc_free(msg); 1429 return NT_STATUS_LDAP(ret); 1430 } 1431 1432 /* mark all the message elements (should be just one) 1433 as LDB_FLAG_MOD_REPLACE */ 1434 for (i=0;i<msg->num_elements;i++) { 1435 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; 1436 } 1437 1438 ret = ldb_modify(s->ldap1.ldb, msg); 1439 talloc_free(msg); 1440 if (ret != LDB_SUCCESS) { 1441 return NT_STATUS_LDAP(ret); 1442 } 1443 1444 return NT_STATUS_OK; 1445} 1446 1447static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s, 1448 struct becomeDC_drsuapi *drsuapi, 1449 void (*recv_fn)(struct composite_context *req)); 1450static void becomeDC_drsuapi1_connect_recv(struct composite_context *req); 1451static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s); 1452 1453static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s) 1454{ 1455 struct composite_context *c = s->creq; 1456 1457 c->status = becomeDC_ldap_connect(s, &s->ldap1); 1458 if (!composite_is_ok(c)) return; 1459 1460 c->status = becomeDC_ldap1_rootdse(s); 1461 if (!composite_is_ok(c)) return; 1462 1463 c->status = becomeDC_ldap1_crossref_behavior_version(s); 1464 if (!composite_is_ok(c)) return; 1465 1466 c->status = becomeDC_ldap1_domain_behavior_version(s); 1467 if (!composite_is_ok(c)) return; 1468 1469 c->status = becomeDC_ldap1_schema_object_version(s); 1470 if (!composite_is_ok(c)) return; 1471 1472 c->status = becomeDC_ldap1_w2k3_update_revision(s); 1473 if (!composite_is_ok(c)) return; 1474 1475 c->status = becomeDC_ldap1_infrastructure_fsmo(s); 1476 if (!composite_is_ok(c)) return; 1477 1478 c->status = becomeDC_ldap1_rid_manager_fsmo(s); 1479 if (!composite_is_ok(c)) return; 1480 1481 c->status = becomeDC_ldap1_site_object(s); 1482 if (!composite_is_ok(c)) return; 1483 1484 c->status = becomeDC_check_options(s); 1485 if (!composite_is_ok(c)) return; 1486 1487 c->status = becomeDC_ldap1_computer_object(s); 1488 if (!composite_is_ok(c)) return; 1489 1490 c->status = becomeDC_ldap1_server_object_1(s); 1491 if (!composite_is_ok(c)) return; 1492 1493 c->status = becomeDC_ldap1_server_object_2(s); 1494 if (!composite_is_ok(c)) return; 1495 1496 c->status = becomeDC_ldap1_server_object_add(s); 1497 if (!composite_is_ok(c)) return; 1498 1499 c->status = becomeDC_ldap1_server_object_modify(s); 1500 if (!composite_is_ok(c)) return; 1501 1502 becomeDC_drsuapi_connect_send(s, &s->drsuapi1, becomeDC_drsuapi1_connect_recv); 1503} 1504 1505static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s, 1506 struct becomeDC_drsuapi *drsuapi, 1507 void (*recv_fn)(struct composite_context *req)) 1508{ 1509 struct composite_context *c = s->creq; 1510 struct composite_context *creq; 1511 char *binding_str; 1512 1513 drsuapi->s = s; 1514 1515 if (!drsuapi->binding) { 1516 const char *krb5_str = ""; 1517 const char *print_str = ""; 1518 /* 1519 * Note: Replication only works with Windows 2000 when 'krb5' is 1520 * passed as auth_type here. If NTLMSSP is used, Windows 1521 * 2000 returns garbage in the DsGetNCChanges() response 1522 * if encrypted password attributes would be in the response. 1523 * That means the replication of the schema and configuration 1524 * partition works fine, but it fails for the domain partition. 1525 */ 1526 if (lp_parm_bool(s->libnet->lp_ctx, NULL, "become_dc", 1527 "force krb5", true)) 1528 { 1529 krb5_str = "krb5,"; 1530 } 1531 if (lp_parm_bool(s->libnet->lp_ctx, NULL, "become_dc", 1532 "print", false)) 1533 { 1534 print_str = "print,"; 1535 } 1536 binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[%s%sseal]", 1537 s->source_dsa.dns_name, 1538 krb5_str, print_str); 1539 if (composite_nomem(binding_str, c)) return; 1540 c->status = dcerpc_parse_binding(s, binding_str, &drsuapi->binding); 1541 talloc_free(binding_str); 1542 if (!composite_is_ok(c)) return; 1543 } 1544 1545 creq = dcerpc_pipe_connect_b_send(s, drsuapi->binding, &ndr_table_drsuapi, 1546 s->libnet->cred, s->libnet->event_ctx, 1547 s->libnet->lp_ctx); 1548 composite_continue(c, creq, recv_fn, s); 1549} 1550 1551static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s, 1552 struct becomeDC_drsuapi *drsuapi, 1553 void (*recv_fn)(struct rpc_request *req)); 1554static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req); 1555 1556static void becomeDC_drsuapi1_connect_recv(struct composite_context *req) 1557{ 1558 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, 1559 struct libnet_BecomeDC_state); 1560 struct composite_context *c = s->creq; 1561 1562 c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi1.pipe); 1563 if (!composite_is_ok(c)) return; 1564 1565 c->status = gensec_session_key(s->drsuapi1.pipe->conn->security_state.generic_state, 1566 &s->drsuapi1.gensec_skey); 1567 if (!composite_is_ok(c)) return; 1568 1569 becomeDC_drsuapi_bind_send(s, &s->drsuapi1, becomeDC_drsuapi1_bind_recv); 1570} 1571 1572static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s, 1573 struct becomeDC_drsuapi *drsuapi, 1574 void (*recv_fn)(struct rpc_request *req)) 1575{ 1576 struct composite_context *c = s->creq; 1577 struct rpc_request *req; 1578 struct drsuapi_DsBindInfo28 *bind_info28; 1579 1580 GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &drsuapi->bind_guid); 1581 1582 bind_info28 = &drsuapi->local_info28; 1583 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE; 1584 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION; 1585 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI; 1586 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2; 1587 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS; 1588 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1; 1589 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION; 1590 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE; 1591 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2; 1592 if (s->domain.behavior_version == 2) { 1593 /* TODO: find out how this is really triggered! */ 1594 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION; 1595 } 1596 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2; 1597 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD; 1598 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND; 1599 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO; 1600 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION; 1601 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01; 1602 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP; 1603 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY; 1604 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3; 1605 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_00100000; 1606 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2; 1607 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6; 1608 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS; 1609 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8; 1610 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5; 1611 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6; 1612 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3; 1613 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7; 1614 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT; 1615#if 0 /* we don't support XPRESS compression yet */ 1616 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS; 1617#endif 1618 bind_info28->site_guid = s->dest_dsa.site_guid; 1619 bind_info28->pid = 0; 1620 bind_info28->repl_epoch = 0; 1621 1622 drsuapi->bind_info_ctr.length = 28; 1623 drsuapi->bind_info_ctr.info.info28 = *bind_info28; 1624 1625 drsuapi->bind_r.in.bind_guid = &drsuapi->bind_guid; 1626 drsuapi->bind_r.in.bind_info = &drsuapi->bind_info_ctr; 1627 drsuapi->bind_r.out.bind_handle = &drsuapi->bind_handle; 1628 1629 req = dcerpc_drsuapi_DsBind_send(drsuapi->pipe, s, &drsuapi->bind_r); 1630 composite_continue_rpc(c, req, recv_fn, s); 1631} 1632 1633static WERROR becomeDC_drsuapi_bind_recv(struct libnet_BecomeDC_state *s, 1634 struct becomeDC_drsuapi *drsuapi) 1635{ 1636 if (!W_ERROR_IS_OK(drsuapi->bind_r.out.result)) { 1637 return drsuapi->bind_r.out.result; 1638 } 1639 1640 ZERO_STRUCT(drsuapi->remote_info28); 1641 if (drsuapi->bind_r.out.bind_info) { 1642 switch (drsuapi->bind_r.out.bind_info->length) { 1643 case 24: { 1644 struct drsuapi_DsBindInfo24 *info24; 1645 info24 = &drsuapi->bind_r.out.bind_info->info.info24; 1646 drsuapi->remote_info28.supported_extensions = info24->supported_extensions; 1647 drsuapi->remote_info28.site_guid = info24->site_guid; 1648 drsuapi->remote_info28.pid = info24->pid; 1649 drsuapi->remote_info28.repl_epoch = 0; 1650 break; 1651 } 1652 case 48: { 1653 struct drsuapi_DsBindInfo48 *info48; 1654 info48 = &drsuapi->bind_r.out.bind_info->info.info48; 1655 drsuapi->remote_info28.supported_extensions = info48->supported_extensions; 1656 drsuapi->remote_info28.site_guid = info48->site_guid; 1657 drsuapi->remote_info28.pid = info48->pid; 1658 drsuapi->remote_info28.repl_epoch = info48->repl_epoch; 1659 break; 1660 } 1661 case 28: 1662 drsuapi->remote_info28 = drsuapi->bind_r.out.bind_info->info.info28; 1663 break; 1664 } 1665 } 1666 1667 return WERR_OK; 1668} 1669 1670static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s); 1671 1672static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req) 1673{ 1674 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, 1675 struct libnet_BecomeDC_state); 1676 struct composite_context *c = s->creq; 1677 WERROR status; 1678 1679 bool print = false; 1680 1681 if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { 1682 print = true; 1683 } 1684 1685 c->status = dcerpc_ndr_request_recv(req); 1686 if (!composite_is_ok(c)) return; 1687 1688 if (print) { 1689 NDR_PRINT_OUT_DEBUG(drsuapi_DsBind, &s->drsuapi1.bind_r); 1690 } 1691 1692 status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi1); 1693 if (!W_ERROR_IS_OK(status)) { 1694 composite_error(c, werror_to_ntstatus(status)); 1695 return; 1696 } 1697 1698 becomeDC_drsuapi1_add_entry_send(s); 1699} 1700 1701static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req); 1702 1703static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) 1704{ 1705 struct composite_context *c = s->creq; 1706 struct rpc_request *req; 1707 struct drsuapi_DsAddEntry *r; 1708 struct drsuapi_DsReplicaObjectIdentifier *identifier; 1709 uint32_t num_attrs, i = 0; 1710 struct drsuapi_DsReplicaAttribute *attrs; 1711 struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(s->libnet->lp_ctx); 1712 enum ndr_err_code ndr_err; 1713 bool w2k3; 1714 1715 /* choose a random invocationId */ 1716 s->dest_dsa.invocation_id = GUID_random(); 1717 1718 /* 1719 * if the schema version indicates w2k3, then 1720 * also send some w2k3 specific attributes 1721 */ 1722 if (s->forest.schema_object_version >= 30) { 1723 w2k3 = true; 1724 } else { 1725 w2k3 = false; 1726 } 1727 1728 r = talloc_zero(s, struct drsuapi_DsAddEntry); 1729 if (composite_nomem(r, c)) return; 1730 1731 /* setup identifier */ 1732 identifier = talloc(r, struct drsuapi_DsReplicaObjectIdentifier); 1733 if (composite_nomem(identifier, c)) return; 1734 identifier->guid = GUID_zero(); 1735 identifier->sid = s->zero_sid; 1736 identifier->dn = talloc_asprintf(identifier, "CN=NTDS Settings,%s", 1737 s->dest_dsa.server_dn_str); 1738 if (composite_nomem(identifier->dn, c)) return; 1739 1740 /* allocate attribute array */ 1741 num_attrs = 11; 1742 attrs = talloc_array(r, struct drsuapi_DsReplicaAttribute, num_attrs); 1743 if (composite_nomem(attrs, c)) return; 1744 1745 /* ntSecurityDescriptor */ 1746 { 1747 struct drsuapi_DsAttributeValue *vs; 1748 DATA_BLOB *vd; 1749 struct security_descriptor *v; 1750 struct dom_sid *domain_admins_sid; 1751 const char *domain_admins_sid_str; 1752 1753 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1); 1754 if (composite_nomem(vs, c)) return; 1755 1756 vd = talloc_array(vs, DATA_BLOB, 1); 1757 if (composite_nomem(vd, c)) return; 1758 1759 domain_admins_sid = dom_sid_add_rid(vs, s->domain.sid, DOMAIN_RID_ADMINS); 1760 if (composite_nomem(domain_admins_sid, c)) return; 1761 1762 domain_admins_sid_str = dom_sid_string(domain_admins_sid, domain_admins_sid); 1763 if (composite_nomem(domain_admins_sid_str, c)) return; 1764 1765 v = security_descriptor_dacl_create(vd, 1766 0, 1767 /* owner: domain admins */ 1768 domain_admins_sid_str, 1769 /* owner group: domain admins */ 1770 domain_admins_sid_str, 1771 /* authenticated users */ 1772 SID_NT_AUTHENTICATED_USERS, 1773 SEC_ACE_TYPE_ACCESS_ALLOWED, 1774 SEC_STD_READ_CONTROL | 1775 SEC_ADS_LIST | 1776 SEC_ADS_READ_PROP | 1777 SEC_ADS_LIST_OBJECT, 1778 0, 1779 /* domain admins */ 1780 domain_admins_sid_str, 1781 SEC_ACE_TYPE_ACCESS_ALLOWED, 1782 SEC_STD_REQUIRED | 1783 SEC_ADS_CREATE_CHILD | 1784 SEC_ADS_LIST | 1785 SEC_ADS_SELF_WRITE | 1786 SEC_ADS_READ_PROP | 1787 SEC_ADS_WRITE_PROP | 1788 SEC_ADS_DELETE_TREE | 1789 SEC_ADS_LIST_OBJECT | 1790 SEC_ADS_CONTROL_ACCESS, 1791 0, 1792 /* system */ 1793 SID_NT_SYSTEM, 1794 SEC_ACE_TYPE_ACCESS_ALLOWED, 1795 SEC_STD_REQUIRED | 1796 SEC_ADS_CREATE_CHILD | 1797 SEC_ADS_DELETE_CHILD | 1798 SEC_ADS_LIST | 1799 SEC_ADS_SELF_WRITE | 1800 SEC_ADS_READ_PROP | 1801 SEC_ADS_WRITE_PROP | 1802 SEC_ADS_DELETE_TREE | 1803 SEC_ADS_LIST_OBJECT | 1804 SEC_ADS_CONTROL_ACCESS, 1805 0, 1806 /* end */ 1807 NULL); 1808 if (composite_nomem(v, c)) return; 1809 1810 ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, v,(ndr_push_flags_fn_t)ndr_push_security_descriptor); 1811 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 1812 c->status = ndr_map_error2ntstatus(ndr_err); 1813 if (!composite_is_ok(c)) return; 1814 } 1815 1816 vs[0].blob = &vd[0]; 1817 1818 attrs[i].attid = DRSUAPI_ATTRIBUTE_ntSecurityDescriptor; 1819 attrs[i].value_ctr.num_values = 1; 1820 attrs[i].value_ctr.values = vs; 1821 1822 i++; 1823 } 1824 1825 /* objectClass: nTDSDSA */ 1826 { 1827 struct drsuapi_DsAttributeValue *vs; 1828 DATA_BLOB *vd; 1829 1830 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1); 1831 if (composite_nomem(vs, c)) return; 1832 1833 vd = talloc_array(vs, DATA_BLOB, 1); 1834 if (composite_nomem(vd, c)) return; 1835 1836 vd[0] = data_blob_talloc(vd, NULL, 4); 1837 if (composite_nomem(vd[0].data, c)) return; 1838 1839 /* value for nTDSDSA */ 1840 SIVAL(vd[0].data, 0, 0x0017002F); 1841 1842 vs[0].blob = &vd[0]; 1843 1844 attrs[i].attid = DRSUAPI_ATTRIBUTE_objectClass; 1845 attrs[i].value_ctr.num_values = 1; 1846 attrs[i].value_ctr.values = vs; 1847 1848 i++; 1849 } 1850 1851 /* objectCategory: CN=NTDS-DSA,CN=Schema,... */ 1852 { 1853 struct drsuapi_DsAttributeValue *vs; 1854 DATA_BLOB *vd; 1855 struct drsuapi_DsReplicaObjectIdentifier3 v[1]; 1856 1857 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1); 1858 if (composite_nomem(vs, c)) return; 1859 1860 vd = talloc_array(vs, DATA_BLOB, 1); 1861 if (composite_nomem(vd, c)) return; 1862 1863 v[0].guid = GUID_zero(); 1864 v[0].sid = s->zero_sid; 1865 v[0].dn = talloc_asprintf(vd, "CN=NTDS-DSA,%s", 1866 s->forest.schema_dn_str); 1867 if (composite_nomem(v[0].dn, c)) return; 1868 1869 ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], 1870 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); 1871 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 1872 c->status = ndr_map_error2ntstatus(ndr_err); 1873 if (!composite_is_ok(c)) return; 1874 } 1875 1876 vs[0].blob = &vd[0]; 1877 1878 attrs[i].attid = DRSUAPI_ATTRIBUTE_objectCategory; 1879 attrs[i].value_ctr.num_values = 1; 1880 attrs[i].value_ctr.values = vs; 1881 1882 i++; 1883 } 1884 1885 /* invocationId: random guid */ 1886 { 1887 struct drsuapi_DsAttributeValue *vs; 1888 DATA_BLOB *vd; 1889 const struct GUID *v; 1890 1891 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1); 1892 if (composite_nomem(vs, c)) return; 1893 1894 vd = talloc_array(vs, DATA_BLOB, 1); 1895 if (composite_nomem(vd, c)) return; 1896 1897 v = &s->dest_dsa.invocation_id; 1898 1899 ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, v, (ndr_push_flags_fn_t)ndr_push_GUID); 1900 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 1901 c->status = ndr_map_error2ntstatus(ndr_err); 1902 if (!composite_is_ok(c)) return; 1903 } 1904 1905 vs[0].blob = &vd[0]; 1906 1907 attrs[i].attid = DRSUAPI_ATTRIBUTE_invocationId; 1908 attrs[i].value_ctr.num_values = 1; 1909 attrs[i].value_ctr.values = vs; 1910 1911 i++; 1912 } 1913 1914 /* hasMasterNCs: ... */ 1915 { 1916 struct drsuapi_DsAttributeValue *vs; 1917 DATA_BLOB *vd; 1918 struct drsuapi_DsReplicaObjectIdentifier3 v[3]; 1919 1920 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 3); 1921 if (composite_nomem(vs, c)) return; 1922 1923 vd = talloc_array(vs, DATA_BLOB, 3); 1924 if (composite_nomem(vd, c)) return; 1925 1926 v[0].guid = GUID_zero(); 1927 v[0].sid = s->zero_sid; 1928 v[0].dn = s->forest.config_dn_str; 1929 1930 v[1].guid = GUID_zero(); 1931 v[1].sid = s->zero_sid; 1932 v[1].dn = s->domain.dn_str; 1933 1934 v[2].guid = GUID_zero(); 1935 v[2].sid = s->zero_sid; 1936 v[2].dn = s->forest.schema_dn_str; 1937 1938 ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], 1939 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); 1940 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 1941 c->status = ndr_map_error2ntstatus(ndr_err); 1942 if (!composite_is_ok(c)) return; 1943 } 1944 1945 ndr_err = ndr_push_struct_blob(&vd[1], vd, iconv_convenience, &v[1], 1946 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); 1947 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 1948 c->status = ndr_map_error2ntstatus(ndr_err); 1949 if (!composite_is_ok(c)) return; 1950 } 1951 1952 ndr_err = ndr_push_struct_blob(&vd[2], vd, iconv_convenience, &v[2], 1953 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); 1954 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 1955 c->status = ndr_map_error2ntstatus(ndr_err); 1956 if (!composite_is_ok(c)) return; 1957 } 1958 1959 vs[0].blob = &vd[0]; 1960 vs[1].blob = &vd[1]; 1961 vs[2].blob = &vd[2]; 1962 1963 attrs[i].attid = DRSUAPI_ATTRIBUTE_hasMasterNCs; 1964 attrs[i].value_ctr.num_values = 3; 1965 attrs[i].value_ctr.values = vs; 1966 1967 i++; 1968 } 1969 1970 /* msDS-hasMasterNCs: ... */ 1971 if (w2k3) { 1972 struct drsuapi_DsAttributeValue *vs; 1973 DATA_BLOB *vd; 1974 struct drsuapi_DsReplicaObjectIdentifier3 v[3]; 1975 1976 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 3); 1977 if (composite_nomem(vs, c)) return; 1978 1979 vd = talloc_array(vs, DATA_BLOB, 3); 1980 if (composite_nomem(vd, c)) return; 1981 1982 v[0].guid = GUID_zero(); 1983 v[0].sid = s->zero_sid; 1984 v[0].dn = s->forest.config_dn_str; 1985 1986 v[1].guid = GUID_zero(); 1987 v[1].sid = s->zero_sid; 1988 v[1].dn = s->domain.dn_str; 1989 1990 v[2].guid = GUID_zero(); 1991 v[2].sid = s->zero_sid; 1992 v[2].dn = s->forest.schema_dn_str; 1993 1994 ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], 1995 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); 1996 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 1997 c->status = ndr_map_error2ntstatus(ndr_err); 1998 if (!composite_is_ok(c)) return; 1999 } 2000 2001 ndr_err = ndr_push_struct_blob(&vd[1], vd, iconv_convenience, &v[1], 2002 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); 2003 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 2004 c->status = ndr_map_error2ntstatus(ndr_err); 2005 if (!composite_is_ok(c)) return; 2006 } 2007 2008 ndr_err = ndr_push_struct_blob(&vd[2], vd, iconv_convenience, &v[2], 2009 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); 2010 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 2011 c->status = ndr_map_error2ntstatus(ndr_err); 2012 if (!composite_is_ok(c)) return; 2013 } 2014 2015 vs[0].blob = &vd[0]; 2016 vs[1].blob = &vd[1]; 2017 vs[2].blob = &vd[2]; 2018 2019 attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs; 2020 attrs[i].value_ctr.num_values = 3; 2021 attrs[i].value_ctr.values = vs; 2022 2023 i++; 2024 } 2025 2026 /* dMDLocation: CN=Schema,... */ 2027 { 2028 struct drsuapi_DsAttributeValue *vs; 2029 DATA_BLOB *vd; 2030 struct drsuapi_DsReplicaObjectIdentifier3 v[1]; 2031 2032 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1); 2033 if (composite_nomem(vs, c)) return; 2034 2035 vd = talloc_array(vs, DATA_BLOB, 1); 2036 if (composite_nomem(vd, c)) return; 2037 2038 v[0].guid = GUID_zero(); 2039 v[0].sid = s->zero_sid; 2040 v[0].dn = s->forest.schema_dn_str; 2041 2042 ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], 2043 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); 2044 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 2045 c->status = ndr_map_error2ntstatus(ndr_err); 2046 if (!composite_is_ok(c)) return; 2047 } 2048 2049 vs[0].blob = &vd[0]; 2050 2051 attrs[i].attid = DRSUAPI_ATTRIBUTE_dMDLocation; 2052 attrs[i].value_ctr.num_values = 1; 2053 attrs[i].value_ctr.values = vs; 2054 2055 i++; 2056 } 2057 2058 /* msDS-HasDomainNCs: <domain_partition> */ 2059 if (w2k3) { 2060 struct drsuapi_DsAttributeValue *vs; 2061 DATA_BLOB *vd; 2062 struct drsuapi_DsReplicaObjectIdentifier3 v[1]; 2063 2064 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1); 2065 if (composite_nomem(vs, c)) return; 2066 2067 vd = talloc_array(vs, DATA_BLOB, 1); 2068 if (composite_nomem(vd, c)) return; 2069 2070 v[0].guid = GUID_zero(); 2071 v[0].sid = s->zero_sid; 2072 v[0].dn = s->domain.dn_str; 2073 2074 ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], 2075 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); 2076 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 2077 c->status = ndr_map_error2ntstatus(ndr_err); 2078 if (!composite_is_ok(c)) return; 2079 } 2080 2081 vs[0].blob = &vd[0]; 2082 2083 attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs; 2084 attrs[i].value_ctr.num_values = 1; 2085 attrs[i].value_ctr.values = vs; 2086 2087 i++; 2088 } 2089 2090 /* msDS-Behavior-Version */ 2091 if (w2k3) { 2092 struct drsuapi_DsAttributeValue *vs; 2093 DATA_BLOB *vd; 2094 2095 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1); 2096 if (composite_nomem(vs, c)) return; 2097 2098 vd = talloc_array(vs, DATA_BLOB, 1); 2099 if (composite_nomem(vd, c)) return; 2100 2101 vd[0] = data_blob_talloc(vd, NULL, 4); 2102 if (composite_nomem(vd[0].data, c)) return; 2103 2104 SIVAL(vd[0].data, 0, 2105 lp_parm_int(s->libnet->lp_ctx, NULL, "ads", "functional level", DS_DC_FUNCTION_2008)); 2106 2107 vs[0].blob = &vd[0]; 2108 2109 attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_Behavior_Version; 2110 attrs[i].value_ctr.num_values = 1; 2111 attrs[i].value_ctr.values = vs; 2112 2113 i++; 2114 } 2115 2116 /* systemFlags */ 2117 { 2118 struct drsuapi_DsAttributeValue *vs; 2119 DATA_BLOB *vd; 2120 2121 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1); 2122 if (composite_nomem(vs, c)) return; 2123 2124 vd = talloc_array(vs, DATA_BLOB, 1); 2125 if (composite_nomem(vd, c)) return; 2126 2127 vd[0] = data_blob_talloc(vd, NULL, 4); 2128 if (composite_nomem(vd[0].data, c)) return; 2129 2130 SIVAL(vd[0].data, 0, SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE); 2131 2132 vs[0].blob = &vd[0]; 2133 2134 attrs[i].attid = DRSUAPI_ATTRIBUTE_systemFlags; 2135 attrs[i].value_ctr.num_values = 1; 2136 attrs[i].value_ctr.values = vs; 2137 2138 i++; 2139 } 2140 2141 /* serverReference: ... */ 2142 { 2143 struct drsuapi_DsAttributeValue *vs; 2144 DATA_BLOB *vd; 2145 struct drsuapi_DsReplicaObjectIdentifier3 v[1]; 2146 2147 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1); 2148 if (composite_nomem(vs, c)) return; 2149 2150 vd = talloc_array(vs, DATA_BLOB, 1); 2151 if (composite_nomem(vd, c)) return; 2152 2153 v[0].guid = GUID_zero(); 2154 v[0].sid = s->zero_sid; 2155 v[0].dn = s->dest_dsa.computer_dn_str; 2156 2157 ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], 2158 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); 2159 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 2160 c->status = ndr_map_error2ntstatus(ndr_err); 2161 if (!composite_is_ok(c)) return; 2162 } 2163 2164 vs[0].blob = &vd[0]; 2165 2166 attrs[i].attid = DRSUAPI_ATTRIBUTE_serverReference; 2167 attrs[i].value_ctr.num_values = 1; 2168 attrs[i].value_ctr.values = vs; 2169 2170 i++; 2171 } 2172 2173 /* truncate the attribute list to the attribute count we have filled in */ 2174 num_attrs = i; 2175 2176 /* setup request structure */ 2177 r->in.bind_handle = &s->drsuapi1.bind_handle; 2178 r->in.level = 2; 2179 r->in.req = talloc(s, union drsuapi_DsAddEntryRequest); 2180 r->in.req->req2.first_object.next_object = NULL; 2181 r->in.req->req2.first_object.object.identifier = identifier; 2182 r->in.req->req2.first_object.object.flags = 0x00000000; 2183 r->in.req->req2.first_object.object.attribute_ctr.num_attributes= num_attrs; 2184 r->in.req->req2.first_object.object.attribute_ctr.attributes = attrs; 2185 2186 r->out.level_out = talloc(s, int32_t); 2187 r->out.ctr = talloc(s, union drsuapi_DsAddEntryCtr); 2188 2189 req = dcerpc_drsuapi_DsAddEntry_send(s->drsuapi1.pipe, r, r); 2190 composite_continue_rpc(c, req, becomeDC_drsuapi1_add_entry_recv, s); 2191} 2192 2193static void becomeDC_drsuapi2_connect_recv(struct composite_context *req); 2194static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s); 2195 2196static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req) 2197{ 2198 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, 2199 struct libnet_BecomeDC_state); 2200 struct composite_context *c = s->creq; 2201 struct drsuapi_DsAddEntry *r = talloc_get_type(req->ndr.struct_ptr, 2202 struct drsuapi_DsAddEntry); 2203 char *binding_str; 2204 bool print = false; 2205 2206 if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { 2207 print = true; 2208 } 2209 2210 c->status = dcerpc_ndr_request_recv(req); 2211 if (!composite_is_ok(c)) return; 2212 2213 if (print) { 2214 NDR_PRINT_OUT_DEBUG(drsuapi_DsAddEntry, r); 2215 } 2216 2217 if (!W_ERROR_IS_OK(r->out.result)) { 2218 composite_error(c, werror_to_ntstatus(r->out.result)); 2219 return; 2220 } 2221 2222 if (*r->out.level_out == 3) { 2223 if (r->out.ctr->ctr3.count != 1) { 2224 WERROR status; 2225 2226 if (r->out.ctr->ctr3.level != 1) { 2227 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); 2228 return; 2229 } 2230 2231 if (!r->out.ctr->ctr3.error) { 2232 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); 2233 return; 2234 } 2235 2236 status = r->out.ctr->ctr3.error->info1.status; 2237 2238 if (!r->out.ctr->ctr3.error->info1.info) { 2239 composite_error(c, werror_to_ntstatus(status)); 2240 return; 2241 } 2242 2243 /* see if we can get a more detailed error */ 2244 switch (r->out.ctr->ctr3.error->info1.level) { 2245 case 1: 2246 status = r->out.ctr->ctr3.error->info1.info->error1.status; 2247 break; 2248 case 4: 2249 case 5: 2250 case 6: 2251 case 7: 2252 status = r->out.ctr->ctr3.error->info1.info->errorX.status; 2253 break; 2254 } 2255 2256 composite_error(c, werror_to_ntstatus(status)); 2257 return; 2258 } 2259 2260 s->dest_dsa.ntds_guid = r->out.ctr->ctr3.objects[0].guid; 2261 } else if (*r->out.level_out == 2) { 2262 if (r->out.ctr->ctr2.count != 1) { 2263 composite_error(c, werror_to_ntstatus(r->out.ctr->ctr2.error.status)); 2264 return; 2265 } 2266 2267 s->dest_dsa.ntds_guid = r->out.ctr->ctr2.objects[0].guid; 2268 } else { 2269 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); 2270 return; 2271 } 2272 2273 talloc_free(r); 2274 2275 s->dest_dsa.ntds_dn_str = talloc_asprintf(s, "CN=NTDS Settings,%s", 2276 s->dest_dsa.server_dn_str); 2277 if (composite_nomem(s->dest_dsa.ntds_dn_str, c)) return; 2278 2279 c->status = becomeDC_prepare_db(s); 2280 if (!composite_is_ok(c)) return; 2281 2282 /* this avoids the epmapper lookup on the 2nd connection */ 2283 binding_str = dcerpc_binding_string(s, s->drsuapi1.binding); 2284 if (composite_nomem(binding_str, c)) return; 2285 2286 c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi2.binding); 2287 talloc_free(binding_str); 2288 if (!composite_is_ok(c)) return; 2289 2290 /* w2k3 uses the same assoc_group_id as on the first connection, so we do */ 2291 s->drsuapi2.binding->assoc_group_id = s->drsuapi1.pipe->assoc_group_id; 2292 2293 becomeDC_drsuapi_connect_send(s, &s->drsuapi2, becomeDC_drsuapi2_connect_recv); 2294} 2295 2296static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s) 2297{ 2298 if (!s->callbacks.prepare_db) return NT_STATUS_OK; 2299 2300 s->_pp.domain = &s->domain; 2301 s->_pp.forest = &s->forest; 2302 s->_pp.source_dsa = &s->source_dsa; 2303 s->_pp.dest_dsa = &s->dest_dsa; 2304 2305 return s->callbacks.prepare_db(s->callbacks.private_data, &s->_pp); 2306} 2307 2308static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req); 2309 2310static void becomeDC_drsuapi2_connect_recv(struct composite_context *req) 2311{ 2312 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, 2313 struct libnet_BecomeDC_state); 2314 struct composite_context *c = s->creq; 2315 2316 c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi2.pipe); 2317 if (!composite_is_ok(c)) return; 2318 2319 c->status = gensec_session_key(s->drsuapi2.pipe->conn->security_state.generic_state, 2320 &s->drsuapi2.gensec_skey); 2321 if (!composite_is_ok(c)) return; 2322 2323 becomeDC_drsuapi_bind_send(s, &s->drsuapi2, becomeDC_drsuapi2_bind_recv); 2324} 2325 2326static void becomeDC_drsuapi3_connect_recv(struct composite_context *req); 2327 2328static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req) 2329{ 2330 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, 2331 struct libnet_BecomeDC_state); 2332 struct composite_context *c = s->creq; 2333 char *binding_str; 2334 WERROR status; 2335 2336 bool print = false; 2337 2338 if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { 2339 print = true; 2340 } 2341 2342 c->status = dcerpc_ndr_request_recv(req); 2343 if (!composite_is_ok(c)) return; 2344 2345 if (print) { 2346 NDR_PRINT_OUT_DEBUG(drsuapi_DsBind, &s->drsuapi2.bind_r); 2347 } 2348 2349 status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi2); 2350 if (!W_ERROR_IS_OK(status)) { 2351 composite_error(c, werror_to_ntstatus(status)); 2352 return; 2353 } 2354 2355 /* this avoids the epmapper lookup on the 3rd connection */ 2356 binding_str = dcerpc_binding_string(s, s->drsuapi1.binding); 2357 if (composite_nomem(binding_str, c)) return; 2358 2359 c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi3.binding); 2360 talloc_free(binding_str); 2361 if (!composite_is_ok(c)) return; 2362 2363 /* w2k3 uses the same assoc_group_id as on the first connection, so we do */ 2364 s->drsuapi3.binding->assoc_group_id = s->drsuapi1.pipe->assoc_group_id; 2365 /* w2k3 uses the concurrent multiplex feature on the 3rd connection, so we do */ 2366 s->drsuapi3.binding->flags |= DCERPC_CONCURRENT_MULTIPLEX; 2367 2368 becomeDC_drsuapi_connect_send(s, &s->drsuapi3, becomeDC_drsuapi3_connect_recv); 2369} 2370 2371static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s); 2372 2373static void becomeDC_drsuapi3_connect_recv(struct composite_context *req) 2374{ 2375 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, 2376 struct libnet_BecomeDC_state); 2377 struct composite_context *c = s->creq; 2378 2379 c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi3.pipe); 2380 if (!composite_is_ok(c)) return; 2381 2382 c->status = gensec_session_key(s->drsuapi3.pipe->conn->security_state.generic_state, 2383 &s->drsuapi3.gensec_skey); 2384 if (!composite_is_ok(c)) return; 2385 2386 becomeDC_drsuapi3_pull_schema_send(s); 2387} 2388 2389static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s, 2390 struct becomeDC_drsuapi *drsuapi_h, 2391 struct becomeDC_drsuapi *drsuapi_p, 2392 struct libnet_BecomeDC_Partition *partition, 2393 void (*recv_fn)(struct rpc_request *req)) 2394{ 2395 struct composite_context *c = s->creq; 2396 struct rpc_request *req; 2397 struct drsuapi_DsGetNCChanges *r; 2398 2399 r = talloc(s, struct drsuapi_DsGetNCChanges); 2400 if (composite_nomem(r, c)) return; 2401 2402 r->out.level_out = talloc(r, int32_t); 2403 if (composite_nomem(r->out.level_out, c)) return; 2404 r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest); 2405 if (composite_nomem(r->in.req, c)) return; 2406 r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr); 2407 if (composite_nomem(r->out.ctr, c)) return; 2408 2409 r->in.bind_handle = &drsuapi_h->bind_handle; 2410 if (drsuapi_h->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) { 2411 r->in.level = 8; 2412 r->in.req->req8.destination_dsa_guid = partition->destination_dsa_guid; 2413 r->in.req->req8.source_dsa_invocation_id= partition->source_dsa_invocation_id; 2414 r->in.req->req8.naming_context = &partition->nc; 2415 r->in.req->req8.highwatermark = partition->highwatermark; 2416 r->in.req->req8.uptodateness_vector = NULL; 2417 r->in.req->req8.replica_flags = partition->replica_flags; 2418 r->in.req->req8.max_object_count = 133; 2419 r->in.req->req8.max_ndr_size = 1336811; 2420 r->in.req->req8.extended_op = DRSUAPI_EXOP_NONE; 2421 r->in.req->req8.fsmo_info = 0; 2422 r->in.req->req8.partial_attribute_set = NULL; 2423 r->in.req->req8.partial_attribute_set_ex= NULL; 2424 r->in.req->req8.mapping_ctr.num_mappings= 0; 2425 r->in.req->req8.mapping_ctr.mappings = NULL; 2426 } else { 2427 r->in.level = 5; 2428 r->in.req->req5.destination_dsa_guid = partition->destination_dsa_guid; 2429 r->in.req->req5.source_dsa_invocation_id= partition->source_dsa_invocation_id; 2430 r->in.req->req5.naming_context = &partition->nc; 2431 r->in.req->req5.highwatermark = partition->highwatermark; 2432 r->in.req->req5.uptodateness_vector = NULL; 2433 r->in.req->req5.replica_flags = partition->replica_flags; 2434 r->in.req->req5.max_object_count = 133; 2435 r->in.req->req5.max_ndr_size = 1336770; 2436 r->in.req->req5.extended_op = DRSUAPI_EXOP_NONE; 2437 r->in.req->req5.fsmo_info = 0; 2438 } 2439 2440 /* 2441 * we should try to use the drsuapi_p->pipe here, as w2k3 does 2442 * but it seems that some extra flags in the DCERPC Bind call 2443 * are needed for it. Or the same KRB5 TGS is needed on both 2444 * connections. 2445 */ 2446 req = dcerpc_drsuapi_DsGetNCChanges_send(drsuapi_p->pipe, r, r); 2447 composite_continue_rpc(c, req, recv_fn, s); 2448} 2449 2450static WERROR becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state *s, 2451 struct becomeDC_drsuapi *drsuapi_h, 2452 struct becomeDC_drsuapi *drsuapi_p, 2453 struct libnet_BecomeDC_Partition *partition, 2454 struct drsuapi_DsGetNCChanges *r) 2455{ 2456 uint32_t ctr_level = 0; 2457 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL; 2458 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL; 2459 struct GUID *source_dsa_guid = NULL; 2460 struct GUID *source_dsa_invocation_id = NULL; 2461 struct drsuapi_DsReplicaHighWaterMark *new_highwatermark = NULL; 2462 bool more_data = false; 2463 NTSTATUS nt_status; 2464 2465 if (!W_ERROR_IS_OK(r->out.result)) { 2466 return r->out.result; 2467 } 2468 2469 if (*r->out.level_out == 1) { 2470 ctr_level = 1; 2471 ctr1 = &r->out.ctr->ctr1; 2472 } else if (*r->out.level_out == 2 && 2473 r->out.ctr->ctr2.mszip1.ts) { 2474 ctr_level = 1; 2475 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1; 2476 } else if (*r->out.level_out == 6) { 2477 ctr_level = 6; 2478 ctr6 = &r->out.ctr->ctr6; 2479 } else if (*r->out.level_out == 7 && 2480 r->out.ctr->ctr7.level == 6 && 2481 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP && 2482 r->out.ctr->ctr7.ctr.mszip6.ts) { 2483 ctr_level = 6; 2484 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6; 2485 } else if (*r->out.level_out == 7 && 2486 r->out.ctr->ctr7.level == 6 && 2487 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS && 2488 r->out.ctr->ctr7.ctr.xpress6.ts) { 2489 ctr_level = 6; 2490 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6; 2491 } else { 2492 return WERR_BAD_NET_RESP; 2493 } 2494 2495 if (!ctr1 && ! ctr6) { 2496 return WERR_BAD_NET_RESP; 2497 } 2498 2499 if (ctr_level == 6) { 2500 if (!W_ERROR_IS_OK(ctr6->drs_error)) { 2501 return ctr6->drs_error; 2502 } 2503 } 2504 2505 switch (ctr_level) { 2506 case 1: 2507 source_dsa_guid = &ctr1->source_dsa_guid; 2508 source_dsa_invocation_id = &ctr1->source_dsa_invocation_id; 2509 new_highwatermark = &ctr1->new_highwatermark; 2510 more_data = ctr1->more_data; 2511 break; 2512 case 6: 2513 source_dsa_guid = &ctr6->source_dsa_guid; 2514 source_dsa_invocation_id = &ctr6->source_dsa_invocation_id; 2515 new_highwatermark = &ctr6->new_highwatermark; 2516 more_data = ctr6->more_data; 2517 break; 2518 } 2519 2520 partition->highwatermark = *new_highwatermark; 2521 partition->source_dsa_guid = *source_dsa_guid; 2522 partition->source_dsa_invocation_id = *source_dsa_invocation_id; 2523 partition->more_data = more_data; 2524 2525 if (!partition->store_chunk) return WERR_OK; 2526 2527 s->_sc.domain = &s->domain; 2528 s->_sc.forest = &s->forest; 2529 s->_sc.source_dsa = &s->source_dsa; 2530 s->_sc.dest_dsa = &s->dest_dsa; 2531 s->_sc.partition = partition; 2532 s->_sc.ctr_level = ctr_level; 2533 s->_sc.ctr1 = ctr1; 2534 s->_sc.ctr6 = ctr6; 2535 /* 2536 * we need to use the drsuapi_p->gensec_skey here, 2537 * when we use drsuapi_p->pipe in the for this request 2538 */ 2539 s->_sc.gensec_skey = &drsuapi_p->gensec_skey; 2540 2541 nt_status = partition->store_chunk(s->callbacks.private_data, &s->_sc); 2542 if (!NT_STATUS_IS_OK(nt_status)) { 2543 return ntstatus_to_werror(nt_status); 2544 } 2545 2546 return WERR_OK; 2547} 2548 2549static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req); 2550 2551static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s) 2552{ 2553 s->schema_part.nc.guid = GUID_zero(); 2554 s->schema_part.nc.sid = s->zero_sid; 2555 s->schema_part.nc.dn = s->forest.schema_dn_str; 2556 2557 s->schema_part.destination_dsa_guid = s->drsuapi2.bind_guid; 2558 2559 s->schema_part.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE 2560 | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP 2561 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS 2562 | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS 2563 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED 2564 | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES; 2565 2566 s->schema_part.store_chunk = s->callbacks.schema_chunk; 2567 2568 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part, 2569 becomeDC_drsuapi3_pull_schema_recv); 2570} 2571 2572static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s); 2573 2574static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req) 2575{ 2576 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, 2577 struct libnet_BecomeDC_state); 2578 struct composite_context *c = s->creq; 2579 struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr, 2580 struct drsuapi_DsGetNCChanges); 2581 WERROR status; 2582 2583 bool print = false; 2584 2585 if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { 2586 print = true; 2587 } 2588 2589 c->status = dcerpc_ndr_request_recv(req); 2590 if (!composite_is_ok(c)) return; 2591 2592 if (print) { 2593 NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r); 2594 } 2595 2596 status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part, r); 2597 if (!W_ERROR_IS_OK(status)) { 2598 composite_error(c, werror_to_ntstatus(status)); 2599 return; 2600 } 2601 2602 talloc_free(r); 2603 2604 if (s->schema_part.more_data) { 2605 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part, 2606 becomeDC_drsuapi3_pull_schema_recv); 2607 return; 2608 } 2609 2610 becomeDC_drsuapi3_pull_config_send(s); 2611} 2612 2613static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req); 2614 2615static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s) 2616{ 2617 s->config_part.nc.guid = GUID_zero(); 2618 s->config_part.nc.sid = s->zero_sid; 2619 s->config_part.nc.dn = s->forest.config_dn_str; 2620 2621 s->config_part.destination_dsa_guid = s->drsuapi2.bind_guid; 2622 2623 s->config_part.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE 2624 | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP 2625 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS 2626 | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS 2627 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED 2628 | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES; 2629 2630 s->config_part.store_chunk = s->callbacks.config_chunk; 2631 2632 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part, 2633 becomeDC_drsuapi3_pull_config_recv); 2634} 2635 2636static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req) 2637{ 2638 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, 2639 struct libnet_BecomeDC_state); 2640 struct composite_context *c = s->creq; 2641 struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr, 2642 struct drsuapi_DsGetNCChanges); 2643 WERROR status; 2644 2645 bool print = false; 2646 2647 if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { 2648 print = true; 2649 } 2650 2651 c->status = dcerpc_ndr_request_recv(req); 2652 if (!composite_is_ok(c)) return; 2653 2654 if (print) { 2655 NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r); 2656 } 2657 2658 status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->config_part, r); 2659 if (!W_ERROR_IS_OK(status)) { 2660 composite_error(c, werror_to_ntstatus(status)); 2661 return; 2662 } 2663 2664 talloc_free(r); 2665 2666 if (s->config_part.more_data) { 2667 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part, 2668 becomeDC_drsuapi3_pull_config_recv); 2669 return; 2670 } 2671 2672 becomeDC_connect_ldap2(s); 2673} 2674 2675static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req); 2676 2677static void becomeDC_drsuapi3_pull_domain_send(struct libnet_BecomeDC_state *s) 2678{ 2679 s->domain_part.nc.guid = GUID_zero(); 2680 s->domain_part.nc.sid = s->zero_sid; 2681 s->domain_part.nc.dn = s->domain.dn_str; 2682 2683 s->domain_part.destination_dsa_guid = s->drsuapi2.bind_guid; 2684 2685 s->domain_part.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE 2686 | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP 2687 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS 2688 | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS 2689 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED 2690 | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES; 2691 2692 s->domain_part.store_chunk = s->callbacks.domain_chunk; 2693 2694 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part, 2695 becomeDC_drsuapi3_pull_domain_recv); 2696} 2697 2698static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s, 2699 struct becomeDC_drsuapi *drsuapi, 2700 struct libnet_BecomeDC_Partition *partition, 2701 void (*recv_fn)(struct rpc_request *req)); 2702static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req); 2703 2704static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req) 2705{ 2706 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, 2707 struct libnet_BecomeDC_state); 2708 struct composite_context *c = s->creq; 2709 struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr, 2710 struct drsuapi_DsGetNCChanges); 2711 WERROR status; 2712 bool print = false; 2713 2714 if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { 2715 print = true; 2716 } 2717 2718 c->status = dcerpc_ndr_request_recv(req); 2719 if (!composite_is_ok(c)) return; 2720 2721 if (print) { 2722 NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r); 2723 } 2724 2725 status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part, r); 2726 if (!W_ERROR_IS_OK(status)) { 2727 composite_error(c, werror_to_ntstatus(status)); 2728 return; 2729 } 2730 2731 talloc_free(r); 2732 2733 if (s->domain_part.more_data) { 2734 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part, 2735 becomeDC_drsuapi3_pull_domain_recv); 2736 return; 2737 } 2738 2739 becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->schema_part, 2740 becomeDC_drsuapi2_update_refs_schema_recv); 2741} 2742 2743static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s, 2744 struct becomeDC_drsuapi *drsuapi, 2745 struct libnet_BecomeDC_Partition *partition, 2746 void (*recv_fn)(struct rpc_request *req)) 2747{ 2748 struct composite_context *c = s->creq; 2749 struct rpc_request *req; 2750 struct drsuapi_DsReplicaUpdateRefs *r; 2751 const char *ntds_guid_str; 2752 const char *ntds_dns_name; 2753 2754 r = talloc(s, struct drsuapi_DsReplicaUpdateRefs); 2755 if (composite_nomem(r, c)) return; 2756 2757 ntds_guid_str = GUID_string(r, &s->dest_dsa.ntds_guid); 2758 if (composite_nomem(ntds_guid_str, c)) return; 2759 2760 ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s", 2761 ntds_guid_str, 2762 s->domain.dns_name); 2763 if (composite_nomem(ntds_dns_name, c)) return; 2764 2765 r->in.bind_handle = &drsuapi->bind_handle; 2766 r->in.level = 1; 2767 r->in.req.req1.naming_context = &partition->nc; 2768 r->in.req.req1.dest_dsa_dns_name= ntds_dns_name; 2769 r->in.req.req1.dest_dsa_guid = s->dest_dsa.ntds_guid; 2770 r->in.req.req1.options = DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE 2771 | DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE; 2772 2773 /* I think this is how we mark ourselves as a RODC */ 2774 if (!lp_parm_bool(s->libnet->lp_ctx, NULL, "repl", "RODC", false)) { 2775 r->in.req.req1.options |= DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE; 2776 } 2777 2778 req = dcerpc_drsuapi_DsReplicaUpdateRefs_send(drsuapi->pipe, r, r); 2779 composite_continue_rpc(c, req, recv_fn, s); 2780} 2781 2782static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req); 2783 2784static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req) 2785{ 2786 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, 2787 struct libnet_BecomeDC_state); 2788 struct composite_context *c = s->creq; 2789 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr, 2790 struct drsuapi_DsReplicaUpdateRefs); 2791 bool print = false; 2792 2793 if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { 2794 print = true; 2795 } 2796 2797 c->status = dcerpc_ndr_request_recv(req); 2798 if (!composite_is_ok(c)) return; 2799 2800 if (print) { 2801 NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaUpdateRefs, r); 2802 } 2803 2804 if (!W_ERROR_IS_OK(r->out.result)) { 2805 composite_error(c, werror_to_ntstatus(r->out.result)); 2806 return; 2807 } 2808 2809 talloc_free(r); 2810 2811 becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->config_part, 2812 becomeDC_drsuapi2_update_refs_config_recv); 2813} 2814 2815static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req); 2816 2817static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req) 2818{ 2819 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, 2820 struct libnet_BecomeDC_state); 2821 struct composite_context *c = s->creq; 2822 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr, 2823 struct drsuapi_DsReplicaUpdateRefs); 2824 2825 c->status = dcerpc_ndr_request_recv(req); 2826 if (!composite_is_ok(c)) return; 2827 2828 if (!W_ERROR_IS_OK(r->out.result)) { 2829 composite_error(c, werror_to_ntstatus(r->out.result)); 2830 return; 2831 } 2832 2833 talloc_free(r); 2834 2835 becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->domain_part, 2836 becomeDC_drsuapi2_update_refs_domain_recv); 2837} 2838 2839static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req) 2840{ 2841 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, 2842 struct libnet_BecomeDC_state); 2843 struct composite_context *c = s->creq; 2844 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr, 2845 struct drsuapi_DsReplicaUpdateRefs); 2846 2847 c->status = dcerpc_ndr_request_recv(req); 2848 if (!composite_is_ok(c)) return; 2849 2850 if (!W_ERROR_IS_OK(r->out.result)) { 2851 composite_error(c, werror_to_ntstatus(r->out.result)); 2852 return; 2853 } 2854 2855 talloc_free(r); 2856 2857 /* TODO: use DDNS updates and register dns names */ 2858 composite_done(c); 2859} 2860 2861static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s) 2862{ 2863 int ret; 2864 struct ldb_message *msg; 2865 uint32_t i; 2866 uint32_t user_account_control = UF_SERVER_TRUST_ACCOUNT | 2867 UF_TRUSTED_FOR_DELEGATION; 2868 2869 /* as the value is already as we want it to be, we're done */ 2870 if (s->dest_dsa.user_account_control == user_account_control) { 2871 return NT_STATUS_OK; 2872 } 2873 2874 /* make a 'modify' msg, and only for serverReference */ 2875 msg = ldb_msg_new(s); 2876 NT_STATUS_HAVE_NO_MEMORY(msg); 2877 msg->dn = ldb_dn_new(msg, s->ldap2.ldb, s->dest_dsa.computer_dn_str); 2878 NT_STATUS_HAVE_NO_MEMORY(msg->dn); 2879 2880 ret = ldb_msg_add_fmt(msg, "userAccountControl", "%u", user_account_control); 2881 if (ret != 0) { 2882 talloc_free(msg); 2883 return NT_STATUS_NO_MEMORY; 2884 } 2885 2886 /* mark all the message elements (should be just one) 2887 as LDB_FLAG_MOD_REPLACE */ 2888 for (i=0;i<msg->num_elements;i++) { 2889 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; 2890 } 2891 2892 ret = ldb_modify(s->ldap2.ldb, msg); 2893 talloc_free(msg); 2894 if (ret != LDB_SUCCESS) { 2895 return NT_STATUS_LDAP(ret); 2896 } 2897 2898 s->dest_dsa.user_account_control = user_account_control; 2899 2900 return NT_STATUS_OK; 2901} 2902 2903static NTSTATUS becomeDC_ldap2_move_computer(struct libnet_BecomeDC_state *s) 2904{ 2905 int ret; 2906 struct ldb_result *r; 2907 struct ldb_dn *basedn; 2908 struct ldb_dn *old_dn; 2909 struct ldb_dn *new_dn; 2910 static const char *_1_1_attrs[] = { 2911 "1.1", 2912 NULL 2913 }; 2914 2915 basedn = ldb_dn_new_fmt(s, s->ldap2.ldb, "<WKGUID=a361b2ffffd211d1aa4b00c04fd7d83a,%s>", 2916 s->domain.dn_str); 2917 NT_STATUS_HAVE_NO_MEMORY(basedn); 2918 2919 ret = ldb_search(s->ldap2.ldb, s, &r, basedn, LDB_SCOPE_BASE, 2920 _1_1_attrs, "(objectClass=*)"); 2921 talloc_free(basedn); 2922 if (ret != LDB_SUCCESS) { 2923 return NT_STATUS_LDAP(ret); 2924 } else if (r->count != 1) { 2925 talloc_free(r); 2926 return NT_STATUS_INVALID_NETWORK_RESPONSE; 2927 } 2928 2929 old_dn = ldb_dn_new(r, s->ldap2.ldb, s->dest_dsa.computer_dn_str); 2930 NT_STATUS_HAVE_NO_MEMORY(old_dn); 2931 2932 new_dn = r->msgs[0]->dn; 2933 2934 if (!ldb_dn_add_child_fmt(new_dn, "CN=%s", s->dest_dsa.netbios_name)) { 2935 talloc_free(r); 2936 return NT_STATUS_NO_MEMORY; 2937 } 2938 2939 if (ldb_dn_compare(old_dn, new_dn) == 0) { 2940 /* we don't need to rename if the old and new dn match */ 2941 talloc_free(r); 2942 return NT_STATUS_OK; 2943 } 2944 2945 ret = ldb_rename(s->ldap2.ldb, old_dn, new_dn); 2946 if (ret != LDB_SUCCESS) { 2947 talloc_free(r); 2948 return NT_STATUS_LDAP(ret); 2949 } 2950 2951 s->dest_dsa.computer_dn_str = ldb_dn_alloc_linearized(s, new_dn); 2952 NT_STATUS_HAVE_NO_MEMORY(s->dest_dsa.computer_dn_str); 2953 2954 talloc_free(r); 2955 2956 return NT_STATUS_OK; 2957} 2958 2959static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s) 2960{ 2961 struct composite_context *c = s->creq; 2962 2963 c->status = becomeDC_ldap_connect(s, &s->ldap2); 2964 if (!composite_is_ok(c)) return; 2965 2966 c->status = becomeDC_ldap2_modify_computer(s); 2967 if (!composite_is_ok(c)) return; 2968 2969 c->status = becomeDC_ldap2_move_computer(s); 2970 if (!composite_is_ok(c)) return; 2971 2972 becomeDC_drsuapi3_pull_domain_send(s); 2973} 2974 2975struct composite_context *libnet_BecomeDC_send(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r) 2976{ 2977 struct composite_context *c; 2978 struct libnet_BecomeDC_state *s; 2979 char *tmp_name; 2980 2981 c = composite_create(mem_ctx, ctx->event_ctx); 2982 if (c == NULL) return NULL; 2983 2984 s = talloc_zero(c, struct libnet_BecomeDC_state); 2985 if (composite_nomem(s, c)) return c; 2986 c->private_data = s; 2987 s->creq = c; 2988 s->libnet = ctx; 2989 2990 /* Domain input */ 2991 s->domain.dns_name = talloc_strdup(s, r->in.domain_dns_name); 2992 if (composite_nomem(s->domain.dns_name, c)) return c; 2993 s->domain.netbios_name = talloc_strdup(s, r->in.domain_netbios_name); 2994 if (composite_nomem(s->domain.netbios_name, c)) return c; 2995 s->domain.sid = dom_sid_dup(s, r->in.domain_sid); 2996 if (composite_nomem(s->domain.sid, c)) return c; 2997 2998 /* Source DSA input */ 2999 s->source_dsa.address = talloc_strdup(s, r->in.source_dsa_address); 3000 if (composite_nomem(s->source_dsa.address, c)) return c; 3001 3002 /* Destination DSA input */ 3003 s->dest_dsa.netbios_name= talloc_strdup(s, r->in.dest_dsa_netbios_name); 3004 if (composite_nomem(s->dest_dsa.netbios_name, c)) return c; 3005 3006 /* Destination DSA dns_name construction */ 3007 tmp_name = strlower_talloc(s, s->dest_dsa.netbios_name); 3008 if (composite_nomem(tmp_name, c)) return c; 3009 tmp_name = talloc_asprintf_append_buffer(tmp_name, ".%s",s->domain.dns_name); 3010 if (composite_nomem(tmp_name, c)) return c; 3011 s->dest_dsa.dns_name = tmp_name; 3012 3013 /* Callback function pointers */ 3014 s->callbacks = r->in.callbacks; 3015 3016 becomeDC_send_cldap(s); 3017 return c; 3018} 3019 3020NTSTATUS libnet_BecomeDC_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r) 3021{ 3022 NTSTATUS status; 3023 3024 status = composite_wait(c); 3025 3026 ZERO_STRUCT(r->out); 3027 3028 talloc_free(c); 3029 return status; 3030} 3031 3032NTSTATUS libnet_BecomeDC(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r) 3033{ 3034 NTSTATUS status; 3035 struct composite_context *c; 3036 c = libnet_BecomeDC_send(ctx, mem_ctx, r); 3037 status = libnet_BecomeDC_recv(c, mem_ctx, r); 3038 return status; 3039} 3040