Merge branch 'v4-0-test' of git://git.samba.org/samba into 4-0-local
[samba.git] / source4 / libnet / libnet_become_dc.c
index 491e32806ce28ad8439e3847428df673034ed09f..c9185c749b4bf0181b0a58437a6f1c2f07dfcfa4 100644 (file)
@@ -1,11 +1,11 @@
 /*
    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
-   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,
@@ -14,8 +14,7 @@
    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 "libcli/cldap/cldap.h"
 #include "lib/ldb/include/ldb.h"
 #include "lib/ldb/include/ldb_errors.h"
-#include "lib/db_wrap.h"
+#include "lib/ldb_wrap.h"
 #include "dsdb/samdb/samdb.h"
 #include "dsdb/common/flags.h"
 #include "librpc/gen_ndr/ndr_drsuapi_c.h"
 #include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_misc.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;
@@ -52,6 +699,7 @@ struct libnet_BecomeDC_state {
                struct libnet_BecomeDC_state *s;
                struct dcerpc_binding *binding;
                struct dcerpc_pipe *pipe;
+               DATA_BLOB gensec_skey;
                struct drsuapi_DsBind bind_r;
                struct GUID bind_guid;
                struct drsuapi_DsBindInfoCtr bind_info_ctr;
@@ -60,68 +708,12 @@ struct libnet_BecomeDC_state {
                struct policy_handle bind_handle;
        } drsuapi1, drsuapi2, drsuapi3;
 
-       struct {
-               /* input */
-               const char *dns_name;
-               const char *netbios_name;
-               const struct dom_sid *sid;
-
-               /* constructed */
-               struct GUID guid;
-               const char *dn_str;
-       } domain;
-
-       struct {
-               /* constructed */
-               const char *dns_name;
-               const char *root_dn_str;
-               const char *config_dn_str;
-               const char *schema_dn_str;
-       } forest;
-
-       struct {
-               /* input */
-               const char *address;
+       struct libnet_BecomeDC_Domain domain;
+       struct libnet_BecomeDC_Forest forest;
+       struct libnet_BecomeDC_SourceDSA source_dsa;
+       struct libnet_BecomeDC_DestDSA dest_dsa;
 
-               /* constructed */
-               const char *dns_name;
-               const char *netbios_name;
-               const char *site_name;
-               const char *server_dn_str;
-               const char *ntds_dn_str;
-       } source_dsa;
-
-       struct {
-               /* input */
-               const char *netbios_name;
-
-               /* constructed */
-               const char *dns_name;
-               const char *site_name;
-               struct GUID site_guid;
-               const char *computer_dn_str;
-               const char *server_dn_str;
-               const char *ntds_dn_str;
-               struct GUID ntds_guid;
-               struct GUID invocation_id;
-               uint32_t user_account_control;
-       } dest_dsa;
-
-       struct {
-               uint32_t domain_behavior_version;
-               uint32_t config_behavior_version;
-               uint32_t schema_object_version;
-               uint32_t w2k3_update_revision;
-       } ads_options;
-
-       struct becomeDC_partition {
-               struct drsuapi_DsReplicaObjectIdentifier nc;
-               struct GUID destination_dsa_guid;
-               struct GUID source_dsa_guid;
-               struct drsuapi_DsReplicaHighWaterMark highwatermark;
-               struct drsuapi_DsReplicaCoursorCtrEx *uptodateness_vector;
-               uint32_t replica_flags;
-       } schema;
+       struct libnet_BecomeDC_Partition schema_part, config_part, domain_part;
 
        struct becomeDC_fsmo {
                const char *dns_name;
@@ -131,8 +723,39 @@ struct libnet_BecomeDC_state {
        } infrastructure_fsmo;
 
        struct becomeDC_fsmo rid_manager_fsmo;
+
+       struct libnet_BecomeDC_CheckOptions _co;
+       struct libnet_BecomeDC_PrepareDB _pp;
+       struct libnet_BecomeDC_StoreChunk _sc;
+       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.dest_port        = lp_cldap_port(s->libnet->lp_ctx);
+       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)
@@ -161,37 +784,15 @@ static void becomeDC_recv_cldap(struct cldap_request *req)
        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)
+static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s, 
+                                     struct becomeDC_ldap *ldap)
 {
        char *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, s->libnet->lp_ctx, url,
                                     NULL,
                                     s->libnet->cred,
                                     0, NULL);
@@ -247,7 +848,7 @@ static NTSTATUS becomeDC_ldap1_rootdse(struct libnet_BecomeDC_state *s)
        return NT_STATUS_OK;
 }
 
-static NTSTATUS becomeDC_ldap1_config_behavior_version(struct libnet_BecomeDC_state *s)
+static NTSTATUS becomeDC_ldap1_crossref_behavior_version(struct libnet_BecomeDC_state *s)
 {
        int ret;
        struct ldb_result *r;
@@ -270,7 +871,7 @@ static NTSTATUS becomeDC_ldap1_config_behavior_version(struct libnet_BecomeDC_st
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
-       s->ads_options.config_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
+       s->forest.crossref_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
 
        talloc_free(r);
        return NT_STATUS_OK;
@@ -299,7 +900,7 @@ static NTSTATUS becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_st
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
-       s->ads_options.domain_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
+       s->domain.behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
 
        talloc_free(r);
        return NT_STATUS_OK;
@@ -328,7 +929,7 @@ static NTSTATUS becomeDC_ldap1_schema_object_version(struct libnet_BecomeDC_stat
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
-       s->ads_options.schema_object_version = ldb_msg_find_attr_as_uint(r->msgs[0], "objectVersion", 0);
+       s->forest.schema_object_version = ldb_msg_find_attr_as_uint(r->msgs[0], "objectVersion", 0);
 
        talloc_free(r);
        return NT_STATUS_OK;
@@ -351,14 +952,18 @@ static NTSTATUS becomeDC_ldap1_w2k3_update_revision(struct libnet_BecomeDC_state
        ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
                         "(objectClass=*)", attrs, &r);
        talloc_free(basedn);
-       if (ret != LDB_SUCCESS) {
+       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+               /* w2k doesn't have this object */
+               s->domain.w2k3_update_revision = 0;
+               return NT_STATUS_OK;
+       } else if (ret != LDB_SUCCESS) {
                return NT_STATUS_LDAP(ret);
        } else if (r->count != 1) {
                talloc_free(r);
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
-       s->ads_options.w2k3_update_revision = ldb_msg_find_attr_as_uint(r->msgs[0], "revision", 0);
+       s->domain.w2k3_update_revision = ldb_msg_find_attr_as_uint(r->msgs[0], "revision", 0);
 
        talloc_free(r);
        return NT_STATUS_OK;
@@ -590,6 +1195,17 @@ static NTSTATUS becomeDC_ldap1_site_object(struct libnet_BecomeDC_state *s)
        return NT_STATUS_OK;
 }
 
+static NTSTATUS becomeDC_check_options(struct libnet_BecomeDC_state *s)
+{
+       if (!s->callbacks.check_options) return NT_STATUS_OK;
+
+       s->_co.domain           = &s->domain;
+       s->_co.forest           = &s->forest;
+       s->_co.source_dsa       = &s->source_dsa;
+
+       return s->callbacks.check_options(s->callbacks.private_data, &s->_co);
+}
+
 static NTSTATUS becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state *s)
 {
        int ret;
@@ -844,7 +1460,7 @@ static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s)
        c->status = becomeDC_ldap1_rootdse(s);
        if (!composite_is_ok(c)) return;
 
-       c->status = becomeDC_ldap1_config_behavior_version(s);
+       c->status = becomeDC_ldap1_crossref_behavior_version(s);
        if (!composite_is_ok(c)) return;
 
        c->status = becomeDC_ldap1_domain_behavior_version(s);
@@ -865,6 +1481,9 @@ static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s)
        c->status = becomeDC_ldap1_site_object(s);
        if (!composite_is_ok(c)) return;
 
+       c->status = becomeDC_check_options(s);
+       if (!composite_is_ok(c)) return;
+
        c->status = becomeDC_ldap1_computer_object(s);
        if (!composite_is_ok(c)) return;
 
@@ -894,16 +1513,21 @@ static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
        drsuapi->s = s;
 
        if (!drsuapi->binding) {
-               binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[krb5,seal]", s->source_dsa.dns_name);
-               if (composite_nomem(binding_str, c)) return;
-
+               if (lp_parm_bool(s->libnet->lp_ctx, NULL, "become_dc", "print", false)) {
+                       binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[print,seal]", s->source_dsa.dns_name);
+                       if (composite_nomem(binding_str, c)) return;
+               } else {
+                       binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[seal]", s->source_dsa.dns_name);
+                       if (composite_nomem(binding_str, c)) return;
+               }
                c->status = dcerpc_parse_binding(s, binding_str, &drsuapi->binding);
                talloc_free(binding_str);
                if (!composite_is_ok(c)) return;
        }
 
-       creq = dcerpc_pipe_connect_b_send(s, drsuapi->binding, &dcerpc_table_drsuapi,
-                                         s->libnet->cred, s->libnet->event_ctx);
+       creq = dcerpc_pipe_connect_b_send(s, drsuapi->binding, &ndr_table_drsuapi,
+                                         s->libnet->cred, s->libnet->event_ctx,
+                                         s->libnet->lp_ctx);
        composite_continue(c, creq, recv_fn, s);
 }
 
@@ -921,6 +1545,10 @@ static void becomeDC_drsuapi1_connect_recv(struct composite_context *req)
        c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi1.pipe);
        if (!composite_is_ok(c)) return;
 
+       c->status = gensec_session_key(s->drsuapi1.pipe->conn->security_state.generic_state,
+                                      &s->drsuapi1.gensec_skey);
+       if (!composite_is_ok(c)) return;
+
        becomeDC_drsuapi_bind_send(s, &s->drsuapi1, becomeDC_drsuapi1_bind_recv);
 }
 
@@ -944,7 +1572,7 @@ static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
        bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
        bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
        bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
-       if (s->ads_options.domain_behavior_version == 2) {
+       if (s->domain.behavior_version == 2) {
                /* TODO: find out how this is really triggered! */
                bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
        }
@@ -971,7 +1599,7 @@ static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
        bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
 #endif
        bind_info28->site_guid                  = s->dest_dsa.site_guid;
-       if (s->ads_options.domain_behavior_version == 2) {
+       if (s->domain.behavior_version == 2) {
                /* TODO: find out how this is really triggered! */
                bind_info28->u1                         = 528;
        } else {
@@ -1022,14 +1650,24 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s);
 
 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;
 
+       bool print = false;
+
+       if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
+               print = true;
+       }
+
        c->status = dcerpc_ndr_request_recv(req);
        if (!composite_is_ok(c)) return;
 
+       if (print) {
+               NDR_PRINT_OUT_DEBUG(drsuapi_DsBind, &s->drsuapi1.bind_r);
+       }
+
        status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi1);
        if (!W_ERROR_IS_OK(status)) {
                composite_error(c, werror_to_ntstatus(status));
@@ -1049,10 +1687,23 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
        struct drsuapi_DsReplicaObjectIdentifier *identifier;
        uint32_t num_attrs, i = 0;
        struct drsuapi_DsReplicaAttribute *attrs;
+       struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(s->libnet->lp_ctx);
+       enum ndr_err_code ndr_err;
+       bool w2k3;
 
        /* choose a random invocationId */
        s->dest_dsa.invocation_id = GUID_random();
 
+       /*
+        * if the schema version indicates w2k3, then
+        * also send some w2k3 specific attributes
+        */
+       if (s->forest.schema_object_version >= 30) {
+               w2k3 = true;
+       } else {
+               w2k3 = false;
+       }
+
        r = talloc_zero(s, struct drsuapi_DsAddEntry);
        if (composite_nomem(r, c)) return;
 
@@ -1072,21 +1723,26 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
 
        /* ntSecurityDescriptor */
        {
-               struct drsuapi_DsAttributeValueSecurityDescriptor *vs;
+               struct drsuapi_DsAttributeValue *vs;
+               DATA_BLOB *vd;
                struct security_descriptor *v;
                struct dom_sid *domain_admins_sid;
                const char *domain_admins_sid_str;
 
-               vs = talloc_array(attrs, struct drsuapi_DsAttributeValueSecurityDescriptor, 1);
+               vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
                if (composite_nomem(vs, c)) return;
 
+               vd = talloc_array(vs, DATA_BLOB, 1);
+               if (composite_nomem(vd, c)) return;
+
                domain_admins_sid = dom_sid_add_rid(vs, s->domain.sid, DOMAIN_RID_ADMINS);
                if (composite_nomem(domain_admins_sid, c)) return;
 
                domain_admins_sid_str = dom_sid_string(domain_admins_sid, domain_admins_sid);
                if (composite_nomem(domain_admins_sid_str, c)) return;
 
-               v = security_descriptor_create(vs,
+               v = security_descriptor_dacl_create(vd,
+                                              0,
                                               /* owner: domain admins */
                                               domain_admins_sid_str,
                                               /* owner group: domain admins */
@@ -1130,98 +1786,121 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
                                               NULL);
                if (composite_nomem(v, c)) return;
 
-               vs[0].sd                = v;
+               ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, v,(ndr_push_flags_fn_t)ndr_push_security_descriptor);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
+
+               vs[0].blob              = &vd[0];
 
-               attrs[i].attid                                          = DRSUAPI_ATTRIBUTE_ntSecurityDescriptor;
-               attrs[i].value_ctr.security_descriptor.num_values       = 1;
-               attrs[i].value_ctr.security_descriptor.values           = vs;
+               attrs[i].attid                  = DRSUAPI_ATTRIBUTE_ntSecurityDescriptor;
+               attrs[i].value_ctr.num_values   = 1;
+               attrs[i].value_ctr.values       = vs;
 
                i++;
        }
 
        /* objectClass: nTDSDSA */
        {
-               struct drsuapi_DsAttributeValueObjectClassId *vs;
-               enum drsuapi_DsObjectClassId *v;
+               struct drsuapi_DsAttributeValue *vs;
+               DATA_BLOB *vd;
 
-               vs = talloc_array(attrs, struct drsuapi_DsAttributeValueObjectClassId, 1);
+               vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
                if (composite_nomem(vs, c)) return;
 
-               v = talloc_array(vs, enum drsuapi_DsObjectClassId, 1);
-               if (composite_nomem(v, c)) return;
+               vd = talloc_array(vs, DATA_BLOB, 1);
+               if (composite_nomem(vd, c)) return;
+
+               vd[0] = data_blob_talloc(vd, NULL, 4);
+               if (composite_nomem(vd[0].data, c)) return;
 
                /* value for nTDSDSA */
-               v[0]                    = 0x0017002F;
+               SIVAL(vd[0].data, 0, 0x0017002F);
 
-               vs[0].objectClassId     = &v[0];
+               vs[0].blob              = &vd[0];
 
-               attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_objectClass;
-               attrs[i].value_ctr.object_class_id.num_values   = 1;
-               attrs[i].value_ctr.object_class_id.values       = vs;
+               attrs[i].attid                  = DRSUAPI_ATTRIBUTE_objectClass;
+               attrs[i].value_ctr.num_values   = 1;
+               attrs[i].value_ctr.values       = vs;
 
                i++;
        }
 
        /* objectCategory: CN=NTDS-DSA,CN=Schema,... */
        {
-               struct drsuapi_DsAttributeValueDNString *vs;
-               struct drsuapi_DsReplicaObjectIdentifier3 *v;
+               struct drsuapi_DsAttributeValue *vs;
+               DATA_BLOB *vd;
+               struct drsuapi_DsReplicaObjectIdentifier3 v[1];
 
-               vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 1);
+               vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
                if (composite_nomem(vs, c)) return;
 
-               v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 1);
-               if (composite_nomem(v, c)) return;
+               vd = talloc_array(vs, DATA_BLOB, 1);
+               if (composite_nomem(vd, c)) return;
 
-               /* value for nTDSDSA */
                v[0].guid               = GUID_zero();
                v[0].sid                = s->zero_sid;
-               v[0].dn                 = talloc_asprintf(v, "CN=NTDS-DSA,%s",
+               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;
 
-               vs[0].object            = &v[0];
+               ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], 
+                                              (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
+
+               vs[0].blob              = &vd[0];
 
-               attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_objectCategory;
-               attrs[i].value_ctr.dn_string.num_values         = 1;
-               attrs[i].value_ctr.dn_string.values             = vs;
+               attrs[i].attid                  = DRSUAPI_ATTRIBUTE_objectCategory;
+               attrs[i].value_ctr.num_values   = 1;
+               attrs[i].value_ctr.values       = vs;
 
                i++;
        }
 
        /* invocationId: random guid */
        {
-               struct drsuapi_DsAttributeValueGUID *vs;
-               struct GUID *v;
+               struct drsuapi_DsAttributeValue *vs;
+               DATA_BLOB *vd;
+               const struct GUID *v;
 
-               vs = talloc_array(attrs, struct drsuapi_DsAttributeValueGUID, 1);
+               vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
                if (composite_nomem(vs, c)) return;
 
-               v = talloc_array(vs, struct GUID, 1);
-               if (composite_nomem(v, c)) return;
+               vd = talloc_array(vs, DATA_BLOB, 1);
+               if (composite_nomem(vd, c)) return;
 
-               /* value for nTDSDSA */
-               v[0]                    = s->dest_dsa.invocation_id;
+               v = &s->dest_dsa.invocation_id;
+
+               ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, v, (ndr_push_flags_fn_t)ndr_push_GUID);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
 
-               vs[0].guid              = &v[0];
+               vs[0].blob              = &vd[0];
 
-               attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_invocationId;
-               attrs[i].value_ctr.guid.num_values              = 1;
-               attrs[i].value_ctr.guid.values                  = vs;
+               attrs[i].attid                  = DRSUAPI_ATTRIBUTE_invocationId;
+               attrs[i].value_ctr.num_values   = 1;
+               attrs[i].value_ctr.values       = vs;
 
                i++;
        }
 
        /* hasMasterNCs: ... */
        {
-               struct drsuapi_DsAttributeValueDNString *vs;
-               struct drsuapi_DsReplicaObjectIdentifier3 *v;
+               struct drsuapi_DsAttributeValue *vs;
+               DATA_BLOB *vd;
+               struct drsuapi_DsReplicaObjectIdentifier3 v[3];
 
-               vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 3);
+               vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 3);
                if (composite_nomem(vs, c)) return;
 
-               v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 3);
-               if (composite_nomem(v, c)) return;
+               vd = talloc_array(vs, DATA_BLOB, 3);
+               if (composite_nomem(vd, c)) return;
 
                v[0].guid               = GUID_zero();
                v[0].sid                = s->zero_sid;
@@ -1235,27 +1914,49 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
                v[2].sid                = s->zero_sid;
                v[2].dn                 = s->forest.schema_dn_str;
 
-               vs[0].object            = &v[0];
-               vs[1].object            = &v[1];
-               vs[2].object            = &v[2];
+               ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0],
+                                              (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
+
+               ndr_err = ndr_push_struct_blob(&vd[1], vd, iconv_convenience, &v[1],
+                                              (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
+
+               ndr_err = ndr_push_struct_blob(&vd[2], vd, iconv_convenience, &v[2],
+                                              (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
+
+               vs[0].blob              = &vd[0];
+               vs[1].blob              = &vd[1];
+               vs[2].blob              = &vd[2];
 
-               attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_hasMasterNCs;
-               attrs[i].value_ctr.dn_string.num_values         = 3;
-               attrs[i].value_ctr.dn_string.values             = vs;
+               attrs[i].attid                  = DRSUAPI_ATTRIBUTE_hasMasterNCs;
+               attrs[i].value_ctr.num_values   = 3;
+               attrs[i].value_ctr.values       = vs;
 
                i++;
        }
 
        /* msDS-hasMasterNCs: ... */
-       {
-               struct drsuapi_DsAttributeValueDNString *vs;
-               struct drsuapi_DsReplicaObjectIdentifier3 *v;
+       if (w2k3) {
+               struct drsuapi_DsAttributeValue *vs;
+               DATA_BLOB *vd;
+               struct drsuapi_DsReplicaObjectIdentifier3 v[3];
 
-               vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 3);
+               vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 3);
                if (composite_nomem(vs, c)) return;
 
-               v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 3);
-               if (composite_nomem(v, c)) return;
+               vd = talloc_array(vs, DATA_BLOB, 3);
+               if (composite_nomem(vd, c)) return;
 
                v[0].guid               = GUID_zero();
                v[0].sid                = s->zero_sid;
@@ -1269,129 +1970,180 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
                v[2].sid                = s->zero_sid;
                v[2].dn                 = s->forest.schema_dn_str;
 
-               vs[0].object            = &v[0];
-               vs[1].object            = &v[1];
-               vs[2].object            = &v[2];
+               ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0],
+                                              (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
+
+               ndr_err = ndr_push_struct_blob(&vd[1], vd, iconv_convenience, &v[1],
+                                              (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
+
+               ndr_err = ndr_push_struct_blob(&vd[2], vd, iconv_convenience, &v[2],
+                                              (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
 
-               attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs;
-               attrs[i].value_ctr.dn_string.num_values         = 3;
-               attrs[i].value_ctr.dn_string.values             = vs;
+               vs[0].blob              = &vd[0];
+               vs[1].blob              = &vd[1];
+               vs[2].blob              = &vd[2];
+
+               attrs[i].attid                  = DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs;
+               attrs[i].value_ctr.num_values   = 3;
+               attrs[i].value_ctr.values       = vs;
 
                i++;
        }
 
        /* dMDLocation: CN=Schema,... */
        {
-               struct drsuapi_DsAttributeValueDNString *vs;
-               struct drsuapi_DsReplicaObjectIdentifier3 *v;
+               struct drsuapi_DsAttributeValue *vs;
+               DATA_BLOB *vd;
+               struct drsuapi_DsReplicaObjectIdentifier3 v[1];
 
-               vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 1);
+               vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
                if (composite_nomem(vs, c)) return;
 
-               v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 1);
-               if (composite_nomem(v, c)) return;
+               vd = talloc_array(vs, DATA_BLOB, 1);
+               if (composite_nomem(vd, c)) return;
 
                v[0].guid               = GUID_zero();
                v[0].sid                = s->zero_sid;
                v[0].dn                 = s->forest.schema_dn_str;
 
-               vs[0].object            = &v[0];
+               ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0],
+                                              (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
+
+               vs[0].blob              = &vd[0];
 
-               attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_dMDLocation;
-               attrs[i].value_ctr.dn_string.num_values         = 1;
-               attrs[i].value_ctr.dn_string.values             = vs;
+               attrs[i].attid                  = DRSUAPI_ATTRIBUTE_dMDLocation;
+               attrs[i].value_ctr.num_values   = 1;
+               attrs[i].value_ctr.values       = vs;
 
                i++;
        }
 
        /* msDS-HasDomainNCs: <domain_partition> */
-       {
-               struct drsuapi_DsAttributeValueDNString *vs;
-               struct drsuapi_DsReplicaObjectIdentifier3 *v;
+       if (w2k3) {
+               struct drsuapi_DsAttributeValue *vs;
+               DATA_BLOB *vd;
+               struct drsuapi_DsReplicaObjectIdentifier3 v[1];
 
-               vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 1);
+               vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
                if (composite_nomem(vs, c)) return;
 
-               v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 1);
-               if (composite_nomem(v, c)) return;
+               vd = talloc_array(vs, DATA_BLOB, 1);
+               if (composite_nomem(vd, c)) return;
 
                v[0].guid               = GUID_zero();
                v[0].sid                = s->zero_sid;
                v[0].dn                 = s->domain.dn_str;
 
-               vs[0].object            = &v[0];
+               ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0],
+                                              (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
 
-               attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs;
-               attrs[i].value_ctr.dn_string.num_values         = 1;
-               attrs[i].value_ctr.dn_string.values             = vs;
+               vs[0].blob              = &vd[0];
+
+               attrs[i].attid                  = DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs;
+               attrs[i].value_ctr.num_values   = 1;
+               attrs[i].value_ctr.values       = vs;
 
                i++;
        }
 
        /* msDS-Behavior-Version */
-       {
-               struct drsuapi_DsAttributeValueUINT32 *vs;
-               uint32_t *v;
+       if (w2k3) {
+               struct drsuapi_DsAttributeValue *vs;
+               DATA_BLOB *vd;
 
-               vs = talloc_array(attrs, struct drsuapi_DsAttributeValueUINT32, 1);
+               vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
                if (composite_nomem(vs, c)) return;
 
-               v = talloc_array(vs, uint32_t, 1);
-               if (composite_nomem(v, c)) return;
+               vd = talloc_array(vs, DATA_BLOB, 1);
+               if (composite_nomem(vd, c)) return;
 
-               v[0]                    = 0x00000002;
+               vd[0] = data_blob_talloc(vd, NULL, 4);
+               if (composite_nomem(vd[0].data, c)) return;
 
-               vs[0].value             = &v[0];
+               SIVAL(vd[0].data, 0, DS_BEHAVIOR_WIN2003);
 
-               attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_msDS_Behavior_Version;
-               attrs[i].value_ctr.uint32.num_values            = 1;
-               attrs[i].value_ctr.uint32.values                = vs;
+               vs[0].blob              = &vd[0];
+
+               attrs[i].attid                  = DRSUAPI_ATTRIBUTE_msDS_Behavior_Version;
+               attrs[i].value_ctr.num_values   = 1;
+               attrs[i].value_ctr.values       = vs;
 
                i++;
        }
 
        /* systemFlags */
        {
-               struct drsuapi_DsAttributeValueUINT32 *vs;
-               uint32_t *v;
+               struct drsuapi_DsAttributeValue *vs;
+               DATA_BLOB *vd;
 
-               vs = talloc_array(attrs, struct drsuapi_DsAttributeValueUINT32, 1);
+               vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
                if (composite_nomem(vs, c)) return;
 
-               v = talloc_array(vs, uint32_t, 1);
-               if (composite_nomem(v, c)) return;
+               vd = talloc_array(vs, DATA_BLOB, 1);
+               if (composite_nomem(vd, c)) return;
+
+               vd[0] = data_blob_talloc(vd, NULL, 4);
+               if (composite_nomem(vd[0].data, c)) return;
 
-               v[0]                    = SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE;
+               SIVAL(vd[0].data, 0, SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
 
-               vs[0].value             = &v[0];
+               vs[0].blob              = &vd[0];
 
-               attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_systemFlags;
-               attrs[i].value_ctr.uint32.num_values            = 1;
-               attrs[i].value_ctr.uint32.values                = vs;
+               attrs[i].attid                  = DRSUAPI_ATTRIBUTE_systemFlags;
+               attrs[i].value_ctr.num_values   = 1;
+               attrs[i].value_ctr.values       = vs;
 
                i++;
        }
 
        /* serverReference: ... */
        {
-               struct drsuapi_DsAttributeValueDNString *vs;
-               struct drsuapi_DsReplicaObjectIdentifier3 *v;
+               struct drsuapi_DsAttributeValue *vs;
+               DATA_BLOB *vd;
+               struct drsuapi_DsReplicaObjectIdentifier3 v[1];
 
-               vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 1);
+               vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
                if (composite_nomem(vs, c)) return;
 
-               v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 1);
-               if (composite_nomem(v, c)) return;
+               vd = talloc_array(vs, DATA_BLOB, 1);
+               if (composite_nomem(vd, c)) return;
 
                v[0].guid               = GUID_zero();
                v[0].sid                = s->zero_sid;
                v[0].dn                 = s->dest_dsa.computer_dn_str;
 
-               vs[0].object            = &v[0];
+               ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0],
+                                              (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       c->status = ndr_map_error2ntstatus(ndr_err);
+                       if (!composite_is_ok(c)) return;
+               }
+
+               vs[0].blob              = &vd[0];
 
-               attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_serverReference;
-               attrs[i].value_ctr.dn_string.num_values         = 1;
-               attrs[i].value_ctr.dn_string.values             = vs;
+               attrs[i].attid                  = DRSUAPI_ATTRIBUTE_serverReference;
+               attrs[i].value_ctr.num_values   = 1;
+               attrs[i].value_ctr.values       = vs;
 
                i++;
        }
@@ -1413,18 +2165,29 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
 }
 
 static void becomeDC_drsuapi2_connect_recv(struct composite_context *req);
+static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s);
 
 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);
+       char *binding_str;
+       bool print = false;
+
+       if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
+               print = true;
+       }
 
        c->status = dcerpc_ndr_request_recv(req);
        if (!composite_is_ok(c)) return;
 
+       if (print) {
+               NDR_PRINT_OUT_DEBUG(drsuapi_DsAddEntry, r);
+       }
+
        if (!W_ERROR_IS_OK(r->out.result)) {
                composite_error(c, werror_to_ntstatus(r->out.result));
                return;
@@ -1483,9 +2246,39 @@ static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req)
 
        talloc_free(r);
 
+       s->dest_dsa.ntds_dn_str = talloc_asprintf(s, "CN=NTDS Settings,%s",
+                                                 s->dest_dsa.server_dn_str);
+       if (composite_nomem(s->dest_dsa.ntds_dn_str, 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);
 }
 
+static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s)
+{
+       if (!s->callbacks.prepare_db) return NT_STATUS_OK;
+
+       s->_pp.domain           = &s->domain;
+       s->_pp.forest           = &s->forest;
+       s->_pp.source_dsa       = &s->source_dsa;
+       s->_pp.dest_dsa         = &s->dest_dsa;
+
+       return s->callbacks.prepare_db(s->callbacks.private_data, &s->_pp);
+}
+
 static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req);
 
 static void becomeDC_drsuapi2_connect_recv(struct composite_context *req)
@@ -1497,6 +2290,10 @@ static void becomeDC_drsuapi2_connect_recv(struct composite_context *req)
        c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi2.pipe);
        if (!composite_is_ok(c)) return;
 
+       c->status = gensec_session_key(s->drsuapi2.pipe->conn->security_state.generic_state,
+                                      &s->drsuapi2.gensec_skey);
+       if (!composite_is_ok(c)) return;
+
        becomeDC_drsuapi_bind_send(s, &s->drsuapi2, becomeDC_drsuapi2_bind_recv);
 }
 
@@ -1504,22 +2301,43 @@ static void becomeDC_drsuapi3_connect_recv(struct composite_context *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;
        WERROR status;
 
+       bool print = false;
+
+       if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
+               print = true;
+       }
+
        c->status = dcerpc_ndr_request_recv(req);
        if (!composite_is_ok(c)) return;
 
+       if (print) {
+               NDR_PRINT_OUT_DEBUG(drsuapi_DsBind, &s->drsuapi2.bind_r);
+       }
+
        status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi2);
        if (!W_ERROR_IS_OK(status)) {
                composite_error(c, werror_to_ntstatus(status));
                return;
        }
 
-       /* this avoids the epmapper lookup on the 2nd connection */
-       s->drsuapi3.binding = 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;
+
+       /* 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);
 }
@@ -1535,13 +2353,17 @@ static void becomeDC_drsuapi3_connect_recv(struct composite_context *req)
        c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi3.pipe);
        if (!composite_is_ok(c)) return;
 
+       c->status = gensec_session_key(s->drsuapi3.pipe->conn->security_state.generic_state,
+                                      &s->drsuapi3.gensec_skey);
+       if (!composite_is_ok(c)) return;
+
        becomeDC_drsuapi3_pull_schema_send(s);
 }
 
 static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s,
                                                 struct becomeDC_drsuapi *drsuapi_h,
                                                 struct becomeDC_drsuapi *drsuapi_p,
-                                                struct becomeDC_partition *partition,
+                                                struct libnet_BecomeDC_Partition *partition,
                                                 void (*recv_fn)(struct rpc_request *req))
 {
        struct composite_context *c = s->creq;
@@ -1551,14 +2373,19 @@ static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s
        r = talloc(s, struct drsuapi_DsGetNCChanges);
        if (composite_nomem(r, c)) return;
 
+       r->in.level = talloc(r, int32_t);
+       if (composite_nomem(r->in.level, c)) return;
+       r->out.level = talloc(r, int32_t);
+       if (composite_nomem(r->out.level, c)) return;
+
        r->in.bind_handle       = &drsuapi_h->bind_handle;
        if (drsuapi_h->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
-               r->in.level                             = 8;
+               *r->in.level                            = 8;
                r->in.req.req8.destination_dsa_guid     = partition->destination_dsa_guid;
-               r->in.req.req8.source_dsa_guid          = partition->source_dsa_guid;
+               r->in.req.req8.source_dsa_invocation_id = partition->source_dsa_invocation_id;
                r->in.req.req8.naming_context           = &partition->nc;
                r->in.req.req8.highwatermark            = partition->highwatermark;
-               r->in.req.req8.uptodateness_vector      = partition->uptodateness_vector;
+               r->in.req.req8.uptodateness_vector      = NULL;
                r->in.req.req8.replica_flags            = partition->replica_flags;
                r->in.req.req8.max_object_count         = 133;
                r->in.req.req8.max_ndr_size             = 1336811;
@@ -1566,15 +2393,15 @@ static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s
                r->in.req.req8.h1                       = 0;
                r->in.req.req8.unique_ptr1              = 0;
                r->in.req.req8.unique_ptr2              = 0;
-               r->in.req.req8.ctr12.count              = 0;
-               r->in.req.req8.ctr12.array              = NULL;
+               r->in.req.req8.mapping_ctr.num_mappings = 0;
+               r->in.req.req8.mapping_ctr.mappings     = NULL;
        } else {
-               r->in.level                             = 5;
+               *r->in.level                            = 5;
                r->in.req.req5.destination_dsa_guid     = partition->destination_dsa_guid;
-               r->in.req.req5.source_dsa_guid          = partition->source_dsa_guid;
+               r->in.req.req5.source_dsa_invocation_id = partition->source_dsa_invocation_id;
                r->in.req.req5.naming_context           = &partition->nc;
                r->in.req.req5.highwatermark            = partition->highwatermark;
-               r->in.req.req5.uptodateness_vector      = partition->uptodateness_vector;
+               r->in.req.req5.uptodateness_vector      = NULL;
                r->in.req.req5.replica_flags            = partition->replica_flags;
                r->in.req.req5.max_object_count         = 133;
                r->in.req.req5.max_ndr_size             = 1336770;
@@ -1588,42 +2415,338 @@ 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.
         */
-       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,
+                                                  struct becomeDC_drsuapi *drsuapi_h,
+                                                  struct becomeDC_drsuapi *drsuapi_p,
+                                                  struct libnet_BecomeDC_Partition *partition,
+                                                  struct drsuapi_DsGetNCChanges *r)
+{
+       uint32_t ctr_level = 0;
+       struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
+       struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
+       struct GUID *source_dsa_guid;
+       struct GUID *source_dsa_invocation_id;
+       struct drsuapi_DsReplicaHighWaterMark *new_highwatermark;
+       NTSTATUS nt_status;
+
+       if (!W_ERROR_IS_OK(r->out.result)) {
+               return r->out.result;
+       }
+
+       if (*r->out.level == 1) {
+               ctr_level = 1;
+               ctr1 = &r->out.ctr.ctr1;
+       } else if (*r->out.level == 2) {
+               ctr_level = 1;
+               ctr1 = r->out.ctr.ctr2.ctr.mszip1.ctr1;
+       } else if (*r->out.level == 6) {
+               ctr_level = 6;
+               ctr6 = &r->out.ctr.ctr6;
+       } else if (*r->out.level == 7 &&
+                  r->out.ctr.ctr7.level == 6 &&
+                  r->out.ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP) {
+               ctr_level = 6;
+               ctr6 = r->out.ctr.ctr7.ctr.mszip6.ctr6;
+       } else {
+               return WERR_BAD_NET_RESP;
+       }
+
+       switch (ctr_level) {
+       case 1:
+               source_dsa_guid                 = &ctr1->source_dsa_guid;
+               source_dsa_invocation_id        = &ctr1->source_dsa_invocation_id;
+               new_highwatermark               = &ctr1->new_highwatermark;
+               break;
+       case 6:
+               source_dsa_guid                 = &ctr6->source_dsa_guid;
+               source_dsa_invocation_id        = &ctr6->source_dsa_invocation_id;
+               new_highwatermark               = &ctr6->new_highwatermark;
+               break;
+       }
+
+       partition->highwatermark                = *new_highwatermark;
+       partition->source_dsa_guid              = *source_dsa_guid;
+       partition->source_dsa_invocation_id     = *source_dsa_invocation_id;
+
+       if (!partition->store_chunk) return WERR_OK;
+
+       s->_sc.domain           = &s->domain;
+       s->_sc.forest           = &s->forest;
+       s->_sc.source_dsa       = &s->source_dsa;
+       s->_sc.dest_dsa         = &s->dest_dsa;
+       s->_sc.partition        = partition;
+       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)) {
+               return ntstatus_to_werror(nt_status);
+       }
+
+       return WERR_OK;
+}
+
 static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req);
 
 static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s)
 {
-       s->schema.nc.guid       = GUID_zero();
-       s->schema.nc.sid        = s->zero_sid;
-       s->schema.nc.dn         = s->forest.schema_dn_str;
+       s->schema_part.nc.guid  = GUID_zero();
+       s->schema_part.nc.sid   = s->zero_sid;
+       s->schema_part.nc.dn    = s->forest.schema_dn_str;
+
+       s->schema_part.destination_dsa_guid     = s->drsuapi2.bind_guid;
 
-       s->schema.destination_dsa_guid  = s->drsuapi2.bind_guid;
+       s->schema_part.replica_flags    = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
 
-       s->schema.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
-                               | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
-                               | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
-                               | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
-                               | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
-                               | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
+       s->schema_part.store_chunk      = s->callbacks.schema_chunk;
 
-       becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema,
+       becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part,
                                             becomeDC_drsuapi3_pull_schema_recv);
 }
 
+static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s);
+
 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 drsuapi_DsGetNCChanges);
+       WERROR status;
+
+       bool print = false;
+
+       if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
+               print = true;
+       }
 
        c->status = dcerpc_ndr_request_recv(req);
        if (!composite_is_ok(c)) return;
 
+       if (print) {
+               NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, 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;
+       }
+
+       talloc_free(r);
+
+       if (s->schema_part.highwatermark.tmp_highest_usn > s->schema_part.highwatermark.highest_usn) {
+               becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part,
+                                                    becomeDC_drsuapi3_pull_schema_recv);
+               return;
+       }
+
+       becomeDC_drsuapi3_pull_config_send(s);
+}
+
+static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req);
+
+static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s)
+{
+       s->config_part.nc.guid  = GUID_zero();
+       s->config_part.nc.sid   = s->zero_sid;
+       s->config_part.nc.dn    = s->forest.config_dn_str;
+
+       s->config_part.destination_dsa_guid     = s->drsuapi2.bind_guid;
+
+       s->config_part.replica_flags    = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
+
+       s->config_part.store_chunk      = s->callbacks.config_chunk;
+
+       becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part,
+                                            becomeDC_drsuapi3_pull_config_recv);
+}
+
+static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req)
+{
+       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 drsuapi_DsGetNCChanges);
+       WERROR status;
+
+       bool print = false;
+
+       if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
+               print = true;
+       }
+
+       c->status = dcerpc_ndr_request_recv(req);
+       if (!composite_is_ok(c)) return;
+
+       if (print) {
+               NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, 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;
+       }
+
+       talloc_free(r);
+
+       if (s->config_part.highwatermark.tmp_highest_usn > s->config_part.highwatermark.highest_usn) {
+               becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part,
+                                                    becomeDC_drsuapi3_pull_config_recv);
+               return;
+       }
+
+       becomeDC_connect_ldap2(s);
+}
+
+static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req);
+
+static void becomeDC_drsuapi3_pull_domain_send(struct libnet_BecomeDC_state *s)
+{
+       s->domain_part.nc.guid  = GUID_zero();
+       s->domain_part.nc.sid   = s->zero_sid;
+       s->domain_part.nc.dn    = s->domain.dn_str;
+
+       s->domain_part.destination_dsa_guid     = s->drsuapi2.bind_guid;
+
+       s->domain_part.replica_flags    = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
+                                       | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
+
+       s->domain_part.store_chunk      = s->callbacks.domain_chunk;
+
+       becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part,
+                                            becomeDC_drsuapi3_pull_domain_recv);
+}
+
+static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s,
+                                             struct becomeDC_drsuapi *drsuapi,
+                                             struct libnet_BecomeDC_Partition *partition,
+                                             void (*recv_fn)(struct rpc_request *req));
+static void becomeDC_drsuapi2_update_refs_schema_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_data,
+                                         struct libnet_BecomeDC_state);
+       struct composite_context *c = s->creq;
+       struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
+                                          struct drsuapi_DsGetNCChanges);
+       WERROR status;
+       bool print = false;
+
+       if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
+               print = true;
+       }
+
+       c->status = dcerpc_ndr_request_recv(req);
+       if (!composite_is_ok(c)) return;
+
+       if (print) {
+               NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, 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;
+       }
+
+       talloc_free(r);
+
+       if (s->domain_part.highwatermark.tmp_highest_usn > s->domain_part.highwatermark.highest_usn) {
+               becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part,
+                                                    becomeDC_drsuapi3_pull_domain_recv);
+               return;
+       }
+
+       becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->schema_part,
+                                         becomeDC_drsuapi2_update_refs_schema_recv);
+}
+
+static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s,
+                                             struct becomeDC_drsuapi *drsuapi,
+                                             struct libnet_BecomeDC_Partition *partition,
+                                             void (*recv_fn)(struct rpc_request *req))
+{
+       struct composite_context *c = s->creq;
+       struct rpc_request *req;
+       struct drsuapi_DsReplicaUpdateRefs *r;
+       const char *ntds_guid_str;
+       const char *ntds_dns_name;
+
+       r = talloc(s, struct drsuapi_DsReplicaUpdateRefs);
+       if (composite_nomem(r, c)) return;
+
+       ntds_guid_str = GUID_string(r, &s->dest_dsa.ntds_guid);
+       if (composite_nomem(ntds_guid_str, c)) return;
+
+       ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
+                                       ntds_guid_str,
+                                       s->domain.dns_name);
+       if (composite_nomem(ntds_dns_name, c)) return;
+
+       r->in.bind_handle               = &drsuapi->bind_handle;
+       r->in.level                     = 1;
+       r->in.req.req1.naming_context   = &partition->nc;
+       r->in.req.req1.dest_dsa_dns_name= ntds_dns_name;
+       r->in.req.req1.dest_dsa_guid    = s->dest_dsa.ntds_guid;
+       r->in.req.req1.options          = DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE
+                                       | DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE
+                                       | DRSUAPI_DS_REPLICA_UPDATE_0x00000010;
+
+       req = dcerpc_drsuapi_DsReplicaUpdateRefs_send(drsuapi->pipe, r, r);
+       composite_continue_rpc(c, req, recv_fn, s);
+}
+
+static void becomeDC_drsuapi2_update_refs_config_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_data,
+                                         struct libnet_BecomeDC_state);
+       struct composite_context *c = s->creq;
+       struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
+                                          struct drsuapi_DsReplicaUpdateRefs);
+       bool print = false;
+
+       if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
+               print = true;
+       }
+
+       c->status = dcerpc_ndr_request_recv(req);
+       if (!composite_is_ok(c)) return;
+
+       if (print) {
+               NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaUpdateRefs, r);
+       }
+
        if (!W_ERROR_IS_OK(r->out.result)) {
                composite_error(c, werror_to_ntstatus(r->out.result));
                return;
@@ -1631,7 +2754,54 @@ static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req)
 
        talloc_free(r);
 
-       becomeDC_connect_ldap2(s);
+       becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->config_part,
+                                         becomeDC_drsuapi2_update_refs_config_recv);
+}
+
+static void becomeDC_drsuapi2_update_refs_domain_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_data,
+                                         struct libnet_BecomeDC_state);
+       struct composite_context *c = s->creq;
+       struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
+                                          struct drsuapi_DsReplicaUpdateRefs);
+
+       c->status = dcerpc_ndr_request_recv(req);
+       if (!composite_is_ok(c)) return;
+
+       if (!W_ERROR_IS_OK(r->out.result)) {
+               composite_error(c, werror_to_ntstatus(r->out.result));
+               return;
+       }
+
+       talloc_free(r);
+
+       becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->domain_part,
+                                         becomeDC_drsuapi2_update_refs_domain_recv);
+}
+
+static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req)
+{
+       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 drsuapi_DsReplicaUpdateRefs);
+
+       c->status = dcerpc_ndr_request_recv(req);
+       if (!composite_is_ok(c)) return;
+
+       if (!W_ERROR_IS_OK(r->out.result)) {
+               composite_error(c, werror_to_ntstatus(r->out.result));
+               return;
+       }
+
+       talloc_free(r);
+
+       /* TODO: use DDNS updates and register dns names */
+       composite_done(c);
 }
 
 static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s)
@@ -1745,7 +2915,7 @@ static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s)
        c->status = becomeDC_ldap2_move_computer(s);
        if (!composite_is_ok(c)) return;
 
-       composite_error(c, NT_STATUS_NOT_IMPLEMENTED);
+       becomeDC_drsuapi3_pull_domain_send(s);
 }
 
 struct composite_context *libnet_BecomeDC_send(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
@@ -1780,11 +2950,14 @@ struct composite_context *libnet_BecomeDC_send(struct libnet_context *ctx, TALLO
        if (composite_nomem(s->dest_dsa.netbios_name, c)) return c;
 
        /* Destination DSA dns_name construction */
-       tmp_name                = strlower_talloc(s, s->dest_dsa.netbios_name);
+       tmp_name        = strlower_talloc(s, s->dest_dsa.netbios_name);
+       if (composite_nomem(tmp_name, c)) return c;
+       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    = talloc_asprintf_append(tmp_name, ".%s",
-                                                        s->domain.dns_name);
-       if (composite_nomem(s->dest_dsa.dns_name, c)) return c;
+       s->dest_dsa.dns_name    = tmp_name;
+
+       /* Callback function pointers */
+       s->callbacks = r->in.callbacks;
 
        becomeDC_send_cldap(s);
        return c;