/*
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,
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;
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;
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;
} 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)
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);
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;
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;
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;
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;
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;
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;
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);
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;
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);
}
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);
}
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;
}
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 {
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));
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;
/* 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 */
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;
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;
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++;
}
}
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;
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)
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);
}
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);
}
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;
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;
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;
* 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;
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)
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)
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;