r25446: Merge some changes I made on the way home from SFO:
[tprouty/samba.git] / source4 / libnet / libnet_become_dc.c
index a302ded4f5b082850603c1d5ba320afc0ce8170a..cd782066dbe3e420893acfaf3f867b2dce80b2da 100644 (file)
@@ -1,11 +1,11 @@
 /*
    Unix SMB/CIFS implementation.
 
 /*
    Unix SMB/CIFS implementation.
 
-   Copyright (C) Stefan Metzmacher     2006
+   Copyright (C) Stefan Metzmacher <metze@samba.org> 2006
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 */
 
 #include "includes.h"
 #include "librpc/gen_ndr/ndr_security.h"
 #include "librpc/gen_ndr/ndr_drsuapi.h"
 #include "auth/gensec/gensec.h"
 #include "librpc/gen_ndr/ndr_security.h"
 #include "librpc/gen_ndr/ndr_drsuapi.h"
 #include "auth/gensec/gensec.h"
+#include "param/param.h"
+
+/*****************************************************************************
+ * Windows 2003 (w2k3) does the following steps when changing the server role
+ * from domain member to domain controller
+ *
+ * We mostly do the same.
+ *****************************************************************************/
+
+/*
+ * lookup DC:
+ * - using nbt name<1C> request and a samlogon mailslot request
+ * or
+ * - using a DNS SRV _ldap._tcp.dc._msdcs. request and a CLDAP netlogon request
+ *
+ * see: becomeDC_recv_cldap() and becomeDC_send_cldap()
+ */
+
+/*
+ * Open 1st LDAP connection to the DC using admin credentials
+ *
+ * see: becomeDC_connect_ldap1() and becomeDC_ldap_connect()
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_rootdse()
+ *
+ * Request:
+ *     basedn: ""
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  *
+ * Result:
+ *      ""
+ *             currentTime:            20061202155100.0Z
+ *             subschemaSubentry:      CN=Aggregate,CN=Schema,CN=Configuration,<domain_partition>
+ *             dsServiceName:          CN=<netbios_name>,CN=Servers,CN=<site_name>,CN=Sites,CN=Configuration,<domain_partition>
+ *             namingContexts:         <domain_partition>
+ *                                     CN=Configuration,<domain_partition>
+ *                                     CN=Schema,CN=Configuration,<domain_partition>
+ *             defaultNamingContext:   <domain_partition>
+ *             schemaNamingContext:    CN=Schema,CN=Configuration,<domain_partition>
+ *             configurationNamingContext:CN=Configuration,<domain_partition>
+ *             rootDomainNamingContext:<domain_partition>
+ *             supportedControl:       ...
+ *             supportedLDAPVersion:   3
+ *                                     2
+ *             supportedLDAPPolicies:  ...
+ *             highestCommitedUSN:     ...
+ *             supportedSASLMechanisms:GSSAPI
+ *                                     GSS-SPNEGO
+ *                                     EXTERNAL
+ *                                     DIGEST-MD5
+ *             dnsHostName:            <dns_host_name>
+ *             ldapServiceName:        <domain_dns_name>:<netbios_name>$@<REALM>
+ *             serverName:             CN=Servers,CN=<site_name>,CN=Sites,CN=Configuration,<domain_partition>
+ *             supportedCapabilities:  ...
+ *             isSyncronized:          TRUE
+ *             isGlobalCatalogReady:   TRUE
+ *             domainFunctionality:    0
+ *             forestFunctionality:    0
+ *             domainControllerFunctionality: 2
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_crossref_behavior_version()
+ *
+ * Request:
+ *     basedn: CN=Configuration,<domain_partition>
+ *     scope:  one
+ *     filter: (cn=Partitions)
+ *     attrs:  msDS-Behavior-Version
+ * Result:
+ *      CN=Partitions,CN=Configuration,<domain_partition>
+ *             msDS-Behavior-Version:  0
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * NOTE: this seems to be a bug! as the messageID of the LDAP message is corrupted!
+ *
+ * not implemented here
+ * 
+ * Request:
+ *     basedn: CN=Schema,CN=Configuration,<domain_partition>
+ *     scope:  one
+ *     filter: (cn=Partitions)
+ *     attrs:  msDS-Behavior-Version
+ * Result:
+ *     <none>
+ *
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_domain_behavior_version()
+ * 
+ * Request:
+ *     basedn: <domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  msDS-Behavior-Version
+ * Result:
+ *     <domain_partition>
+ *             msDS-Behavior-Version:  0
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ * 
+ * see: becomeDC_ldap1_schema_object_version()
+ *
+ * Request:
+ *     basedn: CN=Schema,CN=Configuration,<domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  objectVersion
+ * Result:
+ *     CN=Schema,CN=Configuration,<domain_partition>
+ *             objectVersion:  30
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ * 
+ * not implemented, because the information is already there
+ *
+ * Request:
+ *     basedn: ""
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  defaultNamingContext
+ *             dnsHostName
+ * Result:
+ *     ""
+ *             defaultNamingContext:   <domain_partition>
+ *             dnsHostName:            <dns_host_name>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_infrastructure_fsmo()
+ * 
+ * Request:
+ *     basedn: <WKGUID=2fbac1870ade11d297c400c04fd8d5cd,domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  1.1
+ * Result:
+ *     CN=Infrastructure,<domain_partition>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_w2k3_update_revision()
+ *
+ * Request:
+ *     basedn: CN=Windows2003Update,CN=DomainUpdates,CN=System,<domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  revision
+ * Result:
+ *      CN=Windows2003Update,CN=DomainUpdates,CN=System,<domain_partition>
+ *             revision:       8
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_infrastructure_fsmo()
+ *
+ * Request:
+ *     basedn: CN=Infrastructure,<domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  fSMORoleOwner
+ * Result:
+ *      CN=Infrastructure,<domain_partition>
+ *             fSMORoleOwner:  CN=NTDS Settings,<infrastructure_fsmo_server_object>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_infrastructure_fsmo()
+ *
+ * Request:
+ *     basedn: <infrastructure_fsmo_server_object>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  dnsHostName
+ * Result:
+ *      <infrastructure_fsmo_server_object>
+ *             dnsHostName:    <dns_host_name>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_infrastructure_fsmo()
+ *
+ * Request:
+ *     basedn: CN=NTDS Settings,<infrastructure_fsmo_server_object>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  objectGUID
+ * Result:
+ *      CN=NTDS Settings,<infrastructure_fsmo_server_object>
+ *             objectGUID:     <object_guid>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ * 
+ * see: becomeDC_ldap1_rid_manager_fsmo()
+ *
+ * Request:
+ *     basedn: <domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  rIDManagerReference
+ * Result:
+ *     <domain_partition>
+ *             rIDManagerReference:    CN=RID Manager$,CN=System,<domain_partition>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ * 
+ * see: becomeDC_ldap1_rid_manager_fsmo()
+ *
+ * Request:
+ *     basedn: CN=RID Manager$,CN=System,<domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  fSMORoleOwner
+ * Result:
+ *      CN=Infrastructure,<domain_partition>
+ *             fSMORoleOwner:  CN=NTDS Settings,<rid_manager_fsmo_server_object>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_rid_manager_fsmo()
+ *
+ * Request:
+ *     basedn: <rid_manager_fsmo_server_object>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  dnsHostName
+ * Result:
+ *      <rid_manager_fsmo_server_object>
+ *             dnsHostName:    <dns_host_name>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_rid_manager_fsmo()
+ *
+ * Request:
+ *     basedn: CN=NTDS Settings,<rid_manager_fsmo_server_object>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  msDs-ReplicationEpoch
+ * Result:
+ *      CN=NTDS Settings,<rid_manager_fsmo_server_object>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_site_object()
+ *
+ * Request:
+ *     basedn: CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:
+ * Result:
+ *      CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
+ *             objectClass:    top
+ *                             site
+ *             cn:             <new_dc_site_name>
+ *             distinguishedName:CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
+ *             instanceType:   4
+ *             whenCreated:    ...
+ *             whenChanged:    ...
+ *             uSNCreated:     ...
+ *             uSNChanged:     ...
+ *             showInAdvancedViewOnly: TRUE
+ *             name:           <new_dc_site_name>
+ *             objectGUID:     <object_guid>
+ *             systemFlags:    1107296256 <0x42000000>
+ *             objectCategory: CN=Site,C=Schema,CN=Configuration,<domain_partition>
+ */
+
+/***************************************************************
+ * Add this stage we call the check_options() callback function
+ * of the caller, to see if he wants us to continue
+ *
+ * see: becomeDC_check_options()
+ ***************************************************************/
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_computer_object()
+ *
+ * Request:
+ *     basedn: <domain_partition>
+ *     scope:  sub
+ *     filter: (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<new_dc_account_name>))
+ *     attrs:  distinguishedName
+ *             userAccountControl
+ * Result:
+ *      CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *             distinguishedName:      CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *             userAccoountControl:    4096 <0x1000>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_server_object_1()
+ *
+ * Request:
+ *     basedn: CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:
+ * Result:
+ *      <noSuchObject>
+ *     <matchedDN:CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_server_object_2()
+ * 
+ * Request:
+ *     basedn: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  serverReferenceBL
+ *     typesOnly: TRUE!!!
+ * Result:
+ *      CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ */
+
+/*
+ * LDAP add 1st LDAP connection:
+ * 
+ * see: becomeDC_ldap1_server_object_add()
+ *
+ * Request:
+ *     CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *     objectClass:    server
+ *     systemFlags:    50000000 <0x2FAF080>
+ *     serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ * Result:
+ *      <success>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * not implemented, maybe we can add that later
+ *
+ * Request:
+ *     basedn: CN=NTDS Settings,CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:
+ * Result:
+ *      <noSuchObject>
+ *     <matchedDN:CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
+ */
+
+/*
+ * LDAP search 1st LDAP connection:
+ *
+ * not implemented because it gives no new information
+ * 
+ * Request:
+ *     basedn: CN=Partitions,CN=Configuration,<domain_partition>
+ *     scope:  sub
+ *     filter: (nCName=<domain_partition>)
+ *     attrs:  nCName
+ *             dnsRoot
+ *     controls: LDAP_SERVER_EXTENDED_DN_OID:critical=false
+ * Result:
+ *      <GUID=<hex_guid>>;CN=<domain_netbios_name>,CN=Partitions,<domain_partition>>
+ *             nCName:         <GUID=<hex_guid>>;<SID=<hex_sid>>;<domain_partition>>
+ *             dnsRoot:        <domain_dns_name>
+ */
+
+/*
+ * LDAP modify 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_server_object_modify()
+ * 
+ * Request (add):
+ *     CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
+ *     serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ * Result:
+ *     <attributeOrValueExist>
+ */
+
+/*
+ * LDAP modify 1st LDAP connection:
+ *
+ * see: becomeDC_ldap1_server_object_modify()
+ *
+ * Request (replace):
+ *     CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
+ *     serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ * Result:
+ *     <success>
+ */
+
+/*
+ * Open 1st DRSUAPI connection to the DC using admin credentials
+ * DsBind with DRSUAPI_DS_BIND_GUID_W2K3 ("6afab99c-6e26-464a-975f-f58f105218bc")
+ * (w2k3 does 2 DsBind() calls here..., where is first is unused and contains garbage at the end)
+ *
+ * see: becomeDC_drsuapi_connect_send(), becomeDC_drsuapi1_connect_recv(),
+ *      becomeDC_drsuapi_bind_send(), becomeDC_drsuapi_bind_recv() and becomeDC_drsuapi1_bind_recv()
+ */
+
+/*
+ * DsAddEntry to create the CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
+ * on the 1st DRSUAPI connection
+ *
+ * see: becomeDC_drsuapi1_add_entry_send() and becomeDC_drsuapi1_add_entry_recv()
+ */
+
+/***************************************************************
+ * Add this stage we call the prepare_db() callback function
+ * of the caller, to see if he wants us to continue
+ *
+ * see: becomeDC_prepare_db()
+ ***************************************************************/
+
+/*
+ * Open 2nd and 3rd DRSUAPI connection to the DC using admin credentials
+ * - a DsBind with DRSUAPI_DS_BIND_GUID_W2K3 ("6afab99c-6e26-464a-975f-f58f105218bc")
+ *   on the 2nd connection
+ *
+ * see: becomeDC_drsuapi_connect_send(), becomeDC_drsuapi2_connect_recv(),
+ *      becomeDC_drsuapi_bind_send(), becomeDC_drsuapi_bind_recv(), becomeDC_drsuapi2_bind_recv()
+ *     and becomeDC_drsuapi3_connect_recv()
+ */
+
+/*
+ * replicate CN=Schema,CN=Configuration,...
+ * on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection
+ *
+ * see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(),
+ *     becomeDC_drsuapi3_pull_schema_send() and becomeDC_drsuapi3_pull_schema_recv()
+ *
+ ***************************************************************
+ * Add this stage we call the schema_chunk() callback function
+ * for each replication message
+ ***************************************************************/
+
+/*
+ * replicate CN=Configuration,...
+ * on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection
+ *
+ * see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(),
+ *     becomeDC_drsuapi3_pull_config_send() and becomeDC_drsuapi3_pull_config_recv()
+ *
+ ***************************************************************
+ * Add this stage we call the config_chunk() callback function
+ * for each replication message
+ ***************************************************************/
+
+/*
+ * LDAP unbind on the 1st LDAP connection
+ *
+ * not implemented, because it's not needed...
+ */
+
+/*
+ * Open 2nd LDAP connection to the DC using admin credentials
+ *
+ * see: becomeDC_connect_ldap2() and becomeDC_ldap_connect()
+ */
+
+/*
+ * LDAP search 2nd LDAP connection:
+ * 
+ * not implemented because it gives no new information
+ * same as becomeDC_ldap1_computer_object()
+ *
+ * Request:
+ *     basedn: <domain_partition>
+ *     scope:  sub
+ *     filter: (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<new_dc_account_name>))
+ *     attrs:  distinguishedName
+ *             userAccountControl
+ * Result:
+ *      CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *             distinguishedName:      CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *             userAccoountControl:    4096 <0x00001000>
+ */
+
+/*
+ * LDAP search 2nd LDAP connection:
+ * 
+ * not implemented because it gives no new information
+ * same as becomeDC_ldap1_computer_object()
+ *
+ * Request:
+ *     basedn: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  userAccountControl
+ * Result:
+ *      CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *             userAccoountControl:    4096 <0x00001000>
+ */
+
+/*
+ * LDAP modify 2nd LDAP connection:
+ *
+ * see: becomeDC_ldap2_modify_computer()
+ *
+ * Request (replace):
+ *     CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *     userAccoountControl:    532480 <0x82000>
+ * Result:
+ *     <success>
+ */
+
+/*
+ * LDAP search 2nd LDAP connection:
+ *
+ * see: becomeDC_ldap2_move_computer()
+ * 
+ * Request:
+ *     basedn: <WKGUID=2fbac1870ade11d297c400c04fd8d5cd,<domain_partition>>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  1.1
+ * Result:
+ *     CN=Domain Controllers,<domain_partition>
+ */
+
+/*
+ * LDAP search 2nd LDAP connection:
+ *
+ * not implemented because it gives no new information
+ * 
+ * Request:
+ *     basedn: CN=Domain Controllers,<domain_partition>
+ *     scope:  base
+ *     filter: (objectClass=*)
+ *     attrs:  distinguishedName
+ * Result:
+ *     CN=Domain Controller,<domain_partition>
+ *             distinguishedName:      CN=Domain Controllers,<domain_partition>
+ */
+
+/*
+ * LDAP modifyRDN 2nd LDAP connection:
+ *
+ * see: becomeDC_ldap2_move_computer()
+ * 
+ * Request:
+ *      entry:         CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
+ *     newrdn:         CN=<new_dc_netbios_name>
+ *     deleteoldrdn:   TRUE
+ *     newparent:      CN=Domain Controllers,<domain_partition>
+ * Result:
+ *     <success>
+ */
+
+/*
+ * LDAP unbind on the 2nd LDAP connection
+ *
+ * not implemented, because it's not needed...
+ */
+
+/*
+ * replicate Domain Partition
+ * on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection
+ *
+ * see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(),
+ *     becomeDC_drsuapi3_pull_domain_send() and becomeDC_drsuapi3_pull_domain_recv()
+ *
+ ***************************************************************
+ * Add this stage we call the domain_chunk() callback function
+ * for each replication message
+ ***************************************************************/
+
+/* call DsReplicaUpdateRefs() for all partitions like this:
+ *     req1: struct drsuapi_DsReplicaUpdateRefsRequest1
+ *
+ *                 naming_context: struct drsuapi_DsReplicaObjectIdentifier
+ *                     __ndr_size               : 0x000000ae (174)
+ *                     __ndr_size_sid           : 0x00000000 (0)
+ *                     guid                     : 00000000-0000-0000-0000-000000000000
+ *                     sid                      : S-0-0
+ *                     dn                       : 'CN=Schema,CN=Configuration,DC=w2k3,DC=vmnet1,DC=vm,DC=base'
+ *
+ *                 dest_dsa_dns_name        : '4a0df188-a0b8-47ea-bbe5-e614723f16dd._msdcs.w2k3.vmnet1.vm.base'
+ *           dest_dsa_guid            : 4a0df188-a0b8-47ea-bbe5-e614723f16dd
+ *           options                  : 0x0000001c (28)
+ *                 0: DRSUAPI_DS_REPLICA_UPDATE_ASYNCHRONOUS_OPERATION
+ *                 0: DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE
+ *                 1: DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE
+ *                 1: DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE
+ *                 1: DRSUAPI_DS_REPLICA_UPDATE_0x00000010
+ *
+ * 4a0df188-a0b8-47ea-bbe5-e614723f16dd is the objectGUID the DsAddEntry() returned for the
+ * CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
+ * on the 2nd!!! DRSUAPI connection
+ *
+ * see:        becomeDC_drsuapi_update_refs_send(), becomeDC_drsuapi2_update_refs_schema_recv(),
+ *     becomeDC_drsuapi2_update_refs_config_recv() and becomeDC_drsuapi2_update_refs_domain_recv()
+ */
+
+/*
+ * Windows does opens the 4th and 5th DRSUAPI connection...
+ * and does a DsBind() with the objectGUID from DsAddEntry() as bind_guid
+ * on the 4th connection
+ *
+ * and then 2 full replications of the domain partition on the 5th connection
+ * with the bind_handle from the 4th connection
+ *
+ * not implemented because it gives no new information
+ */
 
 struct libnet_BecomeDC_state {
        struct composite_context *creq;
 
 struct libnet_BecomeDC_state {
        struct composite_context *creq;
@@ -87,6 +730,31 @@ struct libnet_BecomeDC_state {
        struct libnet_BecomeDC_Callbacks callbacks;
 };
 
        struct libnet_BecomeDC_Callbacks callbacks;
 };
 
+static void becomeDC_recv_cldap(struct cldap_request *req);
+
+static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
+{
+       struct composite_context *c = s->creq;
+       struct cldap_request *req;
+
+       s->cldap.io.in.dest_address     = s->source_dsa.address;
+       s->cldap.io.in.realm            = s->domain.dns_name;
+       s->cldap.io.in.host             = s->dest_dsa.netbios_name;
+       s->cldap.io.in.user             = NULL;
+       s->cldap.io.in.domain_guid      = NULL;
+       s->cldap.io.in.domain_sid       = NULL;
+       s->cldap.io.in.acct_control     = -1;
+       s->cldap.io.in.version          = 6;
+
+       s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx);
+       if (composite_nomem(s->cldap.sock, c)) return;
+
+       req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
+       if (composite_nomem(req, c)) return;
+       req->async.fn           = becomeDC_recv_cldap;
+       req->async.private      = s;
+}
+
 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s);
 
 static void becomeDC_recv_cldap(struct cldap_request *req)
 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s);
 
 static void becomeDC_recv_cldap(struct cldap_request *req)
@@ -115,29 +783,6 @@ static void becomeDC_recv_cldap(struct cldap_request *req)
        becomeDC_connect_ldap1(s);
 }
 
        becomeDC_connect_ldap1(s);
 }
 
-static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
-{
-       struct composite_context *c = s->creq;
-       struct cldap_request *req;
-
-       s->cldap.io.in.dest_address     = s->source_dsa.address;
-       s->cldap.io.in.realm            = s->domain.dns_name;
-       s->cldap.io.in.host             = s->dest_dsa.netbios_name;
-       s->cldap.io.in.user             = NULL;
-       s->cldap.io.in.domain_guid      = NULL;
-       s->cldap.io.in.domain_sid       = NULL;
-       s->cldap.io.in.acct_control     = -1;
-       s->cldap.io.in.version          = 6;
-
-       s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx);
-       if (composite_nomem(s->cldap.sock, c)) return;
-
-       req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
-       if (composite_nomem(req, c)) return;
-       req->async.fn           = becomeDC_recv_cldap;
-       req->async.private      = s;
-}
-
 static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s, struct becomeDC_ldap *ldap)
 {
        char *url;
 static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s, struct becomeDC_ldap *ldap)
 {
        char *url;
@@ -145,7 +790,7 @@ static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s, struct be
        url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
        NT_STATUS_HAVE_NO_MEMORY(url);
 
        url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
        NT_STATUS_HAVE_NO_MEMORY(url);
 
-       ldap->ldb = ldb_wrap_connect(s, url,
+       ldap->ldb = ldb_wrap_connect(s, global_loadparm, url,
                                     NULL,
                                     s->libnet->cred,
                                     0, NULL);
                                     NULL,
                                     s->libnet->cred,
                                     0, NULL);
@@ -866,7 +1511,7 @@ static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
        drsuapi->s = s;
 
        if (!drsuapi->binding) {
        drsuapi->s = s;
 
        if (!drsuapi->binding) {
-               if (lp_parm_bool(-1, "become_dc", "print", False)) {
+               if (lp_parm_bool(global_loadparm, NULL, "become_dc", "print", false)) {
                        binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[krb5,print,seal]", s->source_dsa.dns_name);
                        if (composite_nomem(binding_str, c)) return;
                } else {
                        binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[krb5,print,seal]", s->source_dsa.dns_name);
                        if (composite_nomem(binding_str, c)) return;
                } else {
@@ -878,7 +1523,7 @@ static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
                if (!composite_is_ok(c)) return;
        }
 
                if (!composite_is_ok(c)) return;
        }
 
-       creq = dcerpc_pipe_connect_b_send(s, drsuapi->binding, &dcerpc_table_drsuapi,
+       creq = dcerpc_pipe_connect_b_send(s, drsuapi->binding, &ndr_table_drsuapi,
                                          s->libnet->cred, s->libnet->event_ctx);
        composite_continue(c, creq, recv_fn, s);
 }
                                          s->libnet->cred, s->libnet->event_ctx);
        composite_continue(c, creq, recv_fn, s);
 }
@@ -1002,7 +1647,7 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s);
 
 static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req)
 {
 
 static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req)
 {
-       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
+       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        WERROR status;
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        WERROR status;
@@ -1189,7 +1834,7 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
                v[0].sid                = s->zero_sid;
                v[0].dn                 = talloc_asprintf(vd, "CN=NTDS-DSA,%s",
                                                          s->forest.schema_dn_str);
                v[0].sid                = s->zero_sid;
                v[0].dn                 = talloc_asprintf(vd, "CN=NTDS-DSA,%s",
                                                          s->forest.schema_dn_str);
-               if (composite_nomem(v->dn, c)) return;
+               if (composite_nomem(v[0].dn, c)) return;
 
                c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
                                                 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
 
                c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
                                                 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
@@ -1482,11 +2127,12 @@ static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s);
 
 static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req)
 {
 
 static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req)
 {
-       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
+       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsAddEntry *r = talloc_get_type(req->ndr.struct_ptr,
                                       struct drsuapi_DsAddEntry);
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsAddEntry *r = talloc_get_type(req->ndr.struct_ptr,
                                       struct drsuapi_DsAddEntry);
+       char *binding_str;
        bool print = false;
 
        if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
        bool print = false;
 
        if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
@@ -1565,6 +2211,17 @@ static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req)
        c->status = becomeDC_prepare_db(s);
        if (!composite_is_ok(c)) return;
 
        c->status = becomeDC_prepare_db(s);
        if (!composite_is_ok(c)) return;
 
+       /* this avoids the epmapper lookup on the 2nd connection */
+       binding_str = dcerpc_binding_string(s, s->drsuapi1.binding);
+       if (composite_nomem(binding_str, c)) return;
+
+       c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi2.binding);
+       talloc_free(binding_str);
+       if (!composite_is_ok(c)) return;
+
+       /* w2k3 uses the same assoc_group_id as on the first connection, so we do */
+       s->drsuapi2.binding->assoc_group_id     = s->drsuapi1.pipe->assoc_group_id;
+
        becomeDC_drsuapi_connect_send(s, &s->drsuapi2, becomeDC_drsuapi2_connect_recv);
 }
 
        becomeDC_drsuapi_connect_send(s, &s->drsuapi2, becomeDC_drsuapi2_connect_recv);
 }
 
@@ -1602,7 +2259,7 @@ static void becomeDC_drsuapi3_connect_recv(struct composite_context *req);
 
 static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req)
 {
 
 static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req)
 {
-       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
+       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        char *binding_str;
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        char *binding_str;
@@ -1627,14 +2284,19 @@ static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req)
                return;
        }
 
                return;
        }
 
-       /* this avoids the epmapper lookup on the 2nd connection */
-       binding_str = dcerpc_binding_string(s, s->drsuapi2.binding);
+       /* this avoids the epmapper lookup on the 3rd connection */
+       binding_str = dcerpc_binding_string(s, s->drsuapi1.binding);
        if (composite_nomem(binding_str, c)) return;
 
        c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi3.binding);
        talloc_free(binding_str);
        if (!composite_is_ok(c)) return;
 
        if (composite_nomem(binding_str, c)) return;
 
        c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi3.binding);
        talloc_free(binding_str);
        if (!composite_is_ok(c)) return;
 
+       /* w2k3 uses the same assoc_group_id as on the first connection, so we do */
+       s->drsuapi3.binding->assoc_group_id     = s->drsuapi1.pipe->assoc_group_id;
+       /* w2k3 uses the concurrent multiplex feature on the 3rd connection, so we do */
+       s->drsuapi3.binding->flags              |= DCERPC_CONCURRENT_MULTIPLEX;
+
        becomeDC_drsuapi_connect_send(s, &s->drsuapi3, becomeDC_drsuapi3_connect_recv);
 }
 
        becomeDC_drsuapi_connect_send(s, &s->drsuapi3, becomeDC_drsuapi3_connect_recv);
 }
 
@@ -1711,11 +2373,13 @@ static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s
         * are needed for it. Or the same KRB5 TGS is needed on both
         * connections.
         */
         * are needed for it. Or the same KRB5 TGS is needed on both
         * connections.
         */
-       req = dcerpc_drsuapi_DsGetNCChanges_send(drsuapi_h->pipe, r, r);
+       req = dcerpc_drsuapi_DsGetNCChanges_send(drsuapi_p->pipe, r, r);
        composite_continue_rpc(c, req, recv_fn, s);
 }
 
 static WERROR becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state *s,
        composite_continue_rpc(c, req, recv_fn, s);
 }
 
 static WERROR becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state *s,
+                                                  struct becomeDC_drsuapi *drsuapi_h,
+                                                  struct becomeDC_drsuapi *drsuapi_p,
                                                   struct libnet_BecomeDC_Partition *partition,
                                                   struct drsuapi_DsGetNCChanges *r)
 {
                                                   struct libnet_BecomeDC_Partition *partition,
                                                   struct drsuapi_DsGetNCChanges *r)
 {
@@ -1776,6 +2440,11 @@ static WERROR becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state
        s->_sc.ctr_level        = ctr_level;
        s->_sc.ctr1             = ctr1;
        s->_sc.ctr6             = ctr6;
        s->_sc.ctr_level        = ctr_level;
        s->_sc.ctr1             = ctr1;
        s->_sc.ctr6             = ctr6;
+       /* 
+        * we need to use the drsuapi_p->gensec_skey here,
+        * when we use drsuapi_p->pipe in the for this request
+        */
+       s->_sc.gensec_skey      = &drsuapi_p->gensec_skey;
 
        nt_status = partition->store_chunk(s->callbacks.private_data, &s->_sc);
        if (!NT_STATUS_IS_OK(nt_status)) {
 
        nt_status = partition->store_chunk(s->callbacks.private_data, &s->_sc);
        if (!NT_STATUS_IS_OK(nt_status)) {
@@ -1812,7 +2481,7 @@ static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s);
 
 static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req)
 {
 
 static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req)
 {
-       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
+       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
@@ -1832,7 +2501,7 @@ static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req)
                NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r);
        }
 
                NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r);
        }
 
-       status = becomeDC_drsuapi_pull_partition_recv(s, &s->schema_part, r);
+       status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part, r);
        if (!W_ERROR_IS_OK(status)) {
                composite_error(c, werror_to_ntstatus(status));
                return;
        if (!W_ERROR_IS_OK(status)) {
                composite_error(c, werror_to_ntstatus(status));
                return;
@@ -1874,7 +2543,7 @@ static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s)
 
 static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req)
 {
 
 static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req)
 {
-       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
+       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
@@ -1894,7 +2563,7 @@ static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req)
                NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r);
        }
 
                NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r);
        }
 
-       status = becomeDC_drsuapi_pull_partition_recv(s, &s->config_part, r);
+       status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->config_part, r);
        if (!W_ERROR_IS_OK(status)) {
                composite_error(c, werror_to_ntstatus(status));
                return;
        if (!W_ERROR_IS_OK(status)) {
                composite_error(c, werror_to_ntstatus(status));
                return;
@@ -1942,7 +2611,7 @@ static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req);
 
 static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req)
 {
 
 static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req)
 {
-       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
+       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
@@ -1961,7 +2630,7 @@ static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req)
                NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r);
        }
 
                NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r);
        }
 
-       status = becomeDC_drsuapi_pull_partition_recv(s, &s->domain_part, r);
+       status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part, r);
        if (!W_ERROR_IS_OK(status)) {
                composite_error(c, werror_to_ntstatus(status));
                return;
        if (!W_ERROR_IS_OK(status)) {
                composite_error(c, werror_to_ntstatus(status));
                return;
@@ -2018,7 +2687,7 @@ static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req);
 
 static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req)
 {
 
 static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req)
 {
-       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
+       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
@@ -2051,7 +2720,7 @@ static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req);
 
 static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req)
 {
 
 static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req)
 {
-       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
+       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
@@ -2073,7 +2742,7 @@ static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req)
 
 static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req)
 {
 
 static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req)
 {
-       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
+       struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
                                          struct libnet_BecomeDC_state);
        struct composite_context *c = s->creq;
        struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
@@ -2241,7 +2910,7 @@ struct composite_context *libnet_BecomeDC_send(struct libnet_context *ctx, TALLO
        /* Destination DSA dns_name construction */
        tmp_name        = strlower_talloc(s, s->dest_dsa.netbios_name);
        if (composite_nomem(tmp_name, c)) return c;
        /* Destination DSA dns_name construction */
        tmp_name        = strlower_talloc(s, s->dest_dsa.netbios_name);
        if (composite_nomem(tmp_name, c)) return c;
-       tmp_name        = talloc_asprintf_append(tmp_name, ".%s",s->domain.dns_name);
+       tmp_name        = talloc_asprintf_append_buffer(tmp_name, ".%s",s->domain.dns_name);
        if (composite_nomem(tmp_name, c)) return c;
        s->dest_dsa.dns_name    = tmp_name;
 
        if (composite_nomem(tmp_name, c)) return c;
        s->dest_dsa.dns_name    = tmp_name;