2
Unix SMB/CIFS implementation.
4
Copyright (C) Stefan Metzmacher <metze@samba.org> 2006
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 3 of the License, or
9
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program. If not, see <http://www.gnu.org/licenses/>.
21
#include "libnet/libnet.h"
22
#include "libcli/composite/composite.h"
23
#include "libcli/cldap/cldap.h"
24
#include "lib/ldb/include/ldb.h"
25
#include "lib/ldb/include/ldb_errors.h"
26
#include "lib/ldb_wrap.h"
27
#include "dsdb/samdb/samdb.h"
28
#include "dsdb/common/flags.h"
29
#include "librpc/gen_ndr/ndr_drsuapi_c.h"
30
#include "libcli/security/security.h"
31
#include "librpc/gen_ndr/ndr_misc.h"
32
#include "librpc/gen_ndr/ndr_security.h"
33
#include "librpc/gen_ndr/ndr_nbt.h"
34
#include "librpc/gen_ndr/ndr_drsuapi.h"
35
#include "auth/gensec/gensec.h"
36
#include "param/param.h"
38
/*****************************************************************************
39
* Windows 2003 (w2k3) does the following steps when changing the server role
40
* from domain member to domain controller
42
* We mostly do the same.
43
*****************************************************************************/
47
* - using nbt name<1C> request and a samlogon mailslot request
49
* - using a DNS SRV _ldap._tcp.dc._msdcs. request and a CLDAP netlogon request
51
* see: becomeDC_recv_cldap() and becomeDC_send_cldap()
55
* Open 1st LDAP connection to the DC using admin credentials
57
* see: becomeDC_connect_ldap1() and becomeDC_ldap_connect()
61
* LDAP search 1st LDAP connection:
63
* see: becomeDC_ldap1_rootdse()
68
* filter: (objectClass=*)
72
* currentTime: 20061202155100.0Z
73
* subschemaSubentry: CN=Aggregate,CN=Schema,CN=Configuration,<domain_partition>
74
* dsServiceName: CN=<netbios_name>,CN=Servers,CN=<site_name>,CN=Sites,CN=Configuration,<domain_partition>
75
* namingContexts: <domain_partition>
76
* CN=Configuration,<domain_partition>
77
* CN=Schema,CN=Configuration,<domain_partition>
78
* defaultNamingContext: <domain_partition>
79
* schemaNamingContext: CN=Schema,CN=Configuration,<domain_partition>
80
* configurationNamingContext:CN=Configuration,<domain_partition>
81
* rootDomainNamingContext:<domain_partition>
82
* supportedControl: ...
83
* supportedLDAPVersion: 3
85
* supportedLDAPPolicies: ...
86
* highestCommitedUSN: ...
87
* supportedSASLMechanisms:GSSAPI
91
* dnsHostName: <dns_host_name>
92
* ldapServiceName: <domain_dns_name>:<netbios_name>$@<REALM>
93
* serverName: CN=Servers,CN=<site_name>,CN=Sites,CN=Configuration,<domain_partition>
94
* supportedCapabilities: ...
96
* isGlobalCatalogReady: TRUE
97
* domainFunctionality: 0
98
* forestFunctionality: 0
99
* domainControllerFunctionality: 2
103
* LDAP search 1st LDAP connection:
105
* see: becomeDC_ldap1_crossref_behavior_version()
108
* basedn: CN=Configuration,<domain_partition>
110
* filter: (cn=Partitions)
111
* attrs: msDS-Behavior-Version
113
* CN=Partitions,CN=Configuration,<domain_partition>
114
* msDS-Behavior-Version: 0
118
* LDAP search 1st LDAP connection:
120
* NOTE: this seems to be a bug! as the messageID of the LDAP message is corrupted!
122
* not implemented here
125
* basedn: CN=Schema,CN=Configuration,<domain_partition>
127
* filter: (cn=Partitions)
128
* attrs: msDS-Behavior-Version
135
* LDAP search 1st LDAP connection:
137
* see: becomeDC_ldap1_domain_behavior_version()
140
* basedn: <domain_partition>
142
* filter: (objectClass=*)
143
* attrs: msDS-Behavior-Version
146
* msDS-Behavior-Version: 0
150
* LDAP search 1st LDAP connection:
152
* see: becomeDC_ldap1_schema_object_version()
155
* basedn: CN=Schema,CN=Configuration,<domain_partition>
157
* filter: (objectClass=*)
158
* attrs: objectVersion
160
* CN=Schema,CN=Configuration,<domain_partition>
165
* LDAP search 1st LDAP connection:
167
* not implemented, because the information is already there
172
* filter: (objectClass=*)
173
* attrs: defaultNamingContext
177
* defaultNamingContext: <domain_partition>
178
* dnsHostName: <dns_host_name>
182
* LDAP search 1st LDAP connection:
184
* see: becomeDC_ldap1_infrastructure_fsmo()
187
* basedn: <WKGUID=2fbac1870ade11d297c400c04fd8d5cd,domain_partition>
189
* filter: (objectClass=*)
192
* CN=Infrastructure,<domain_partition>
196
* LDAP search 1st LDAP connection:
198
* see: becomeDC_ldap1_w2k3_update_revision()
201
* basedn: CN=Windows2003Update,CN=DomainUpdates,CN=System,<domain_partition>
203
* filter: (objectClass=*)
206
* CN=Windows2003Update,CN=DomainUpdates,CN=System,<domain_partition>
211
* LDAP search 1st LDAP connection:
213
* see: becomeDC_ldap1_infrastructure_fsmo()
216
* basedn: CN=Infrastructure,<domain_partition>
218
* filter: (objectClass=*)
219
* attrs: fSMORoleOwner
221
* CN=Infrastructure,<domain_partition>
222
* fSMORoleOwner: CN=NTDS Settings,<infrastructure_fsmo_server_object>
226
* LDAP search 1st LDAP connection:
228
* see: becomeDC_ldap1_infrastructure_fsmo()
231
* basedn: <infrastructure_fsmo_server_object>
233
* filter: (objectClass=*)
236
* <infrastructure_fsmo_server_object>
237
* dnsHostName: <dns_host_name>
241
* LDAP search 1st LDAP connection:
243
* see: becomeDC_ldap1_infrastructure_fsmo()
246
* basedn: CN=NTDS Settings,<infrastructure_fsmo_server_object>
248
* filter: (objectClass=*)
251
* CN=NTDS Settings,<infrastructure_fsmo_server_object>
252
* objectGUID: <object_guid>
256
* LDAP search 1st LDAP connection:
258
* see: becomeDC_ldap1_rid_manager_fsmo()
261
* basedn: <domain_partition>
263
* filter: (objectClass=*)
264
* attrs: rIDManagerReference
267
* rIDManagerReference: CN=RID Manager$,CN=System,<domain_partition>
271
* LDAP search 1st LDAP connection:
273
* see: becomeDC_ldap1_rid_manager_fsmo()
276
* basedn: CN=RID Manager$,CN=System,<domain_partition>
278
* filter: (objectClass=*)
279
* attrs: fSMORoleOwner
281
* CN=Infrastructure,<domain_partition>
282
* fSMORoleOwner: CN=NTDS Settings,<rid_manager_fsmo_server_object>
286
* LDAP search 1st LDAP connection:
288
* see: becomeDC_ldap1_rid_manager_fsmo()
291
* basedn: <rid_manager_fsmo_server_object>
293
* filter: (objectClass=*)
296
* <rid_manager_fsmo_server_object>
297
* dnsHostName: <dns_host_name>
301
* LDAP search 1st LDAP connection:
303
* see: becomeDC_ldap1_rid_manager_fsmo()
306
* basedn: CN=NTDS Settings,<rid_manager_fsmo_server_object>
308
* filter: (objectClass=*)
309
* attrs: msDs-ReplicationEpoch
311
* CN=NTDS Settings,<rid_manager_fsmo_server_object>
315
* LDAP search 1st LDAP connection:
317
* see: becomeDC_ldap1_site_object()
320
* basedn: CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
322
* filter: (objectClass=*)
325
* CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
328
* cn: <new_dc_site_name>
329
* distinguishedName:CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
335
* showInAdvancedViewOnly: TRUE
336
* name: <new_dc_site_name>
337
* objectGUID: <object_guid>
338
* systemFlags: 1107296256 <0x42000000>
339
* objectCategory: CN=Site,C=Schema,CN=Configuration,<domain_partition>
342
/***************************************************************
343
* Add this stage we call the check_options() callback function
344
* of the caller, to see if he wants us to continue
346
* see: becomeDC_check_options()
347
***************************************************************/
350
* LDAP search 1st LDAP connection:
352
* see: becomeDC_ldap1_computer_object()
355
* basedn: <domain_partition>
357
* filter: (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<new_dc_account_name>))
358
* attrs: distinguishedName
361
* CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
362
* distinguishedName: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
363
* userAccoountControl: 4096 <0x1000>
367
* LDAP search 1st LDAP connection:
369
* see: becomeDC_ldap1_server_object_1()
372
* basedn: CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
374
* filter: (objectClass=*)
378
* <matchedDN:CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
382
* LDAP search 1st LDAP connection:
384
* see: becomeDC_ldap1_server_object_2()
387
* basedn: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
389
* filter: (objectClass=*)
390
* attrs: serverReferenceBL
393
* CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
397
* LDAP add 1st LDAP connection:
399
* see: becomeDC_ldap1_server_object_add()
402
* CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
403
* objectClass: server
404
* systemFlags: 50000000 <0x2FAF080>
405
* serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
411
* LDAP search 1st LDAP connection:
413
* not implemented, maybe we can add that later
416
* basedn: CN=NTDS Settings,CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
418
* filter: (objectClass=*)
422
* <matchedDN:CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
426
* LDAP search 1st LDAP connection:
428
* not implemented because it gives no new information
431
* basedn: CN=Partitions,CN=Configuration,<domain_partition>
433
* filter: (nCName=<domain_partition>)
436
* controls: LDAP_SERVER_EXTENDED_DN_OID:critical=false
438
* <GUID=<hex_guid>>;CN=<domain_netbios_name>,CN=Partitions,<domain_partition>>
439
* nCName: <GUID=<hex_guid>>;<SID=<hex_sid>>;<domain_partition>>
440
* dnsRoot: <domain_dns_name>
444
* LDAP modify 1st LDAP connection:
446
* see: becomeDC_ldap1_server_object_modify()
449
* CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
450
* serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
452
* <attributeOrValueExist>
456
* LDAP modify 1st LDAP connection:
458
* see: becomeDC_ldap1_server_object_modify()
461
* CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
462
* serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
468
* Open 1st DRSUAPI connection to the DC using admin credentials
469
* DsBind with DRSUAPI_DS_BIND_GUID_W2K3 ("6afab99c-6e26-464a-975f-f58f105218bc")
470
* (w2k3 does 2 DsBind() calls here..., where is first is unused and contains garbage at the end)
472
* see: becomeDC_drsuapi_connect_send(), becomeDC_drsuapi1_connect_recv(),
473
* becomeDC_drsuapi_bind_send(), becomeDC_drsuapi_bind_recv() and becomeDC_drsuapi1_bind_recv()
477
* DsAddEntry to create the CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
478
* on the 1st DRSUAPI connection
480
* see: becomeDC_drsuapi1_add_entry_send() and becomeDC_drsuapi1_add_entry_recv()
483
/***************************************************************
484
* Add this stage we call the prepare_db() callback function
485
* of the caller, to see if he wants us to continue
487
* see: becomeDC_prepare_db()
488
***************************************************************/
491
* Open 2nd and 3rd DRSUAPI connection to the DC using admin credentials
492
* - a DsBind with DRSUAPI_DS_BIND_GUID_W2K3 ("6afab99c-6e26-464a-975f-f58f105218bc")
493
* on the 2nd connection
495
* see: becomeDC_drsuapi_connect_send(), becomeDC_drsuapi2_connect_recv(),
496
* becomeDC_drsuapi_bind_send(), becomeDC_drsuapi_bind_recv(), becomeDC_drsuapi2_bind_recv()
497
* and becomeDC_drsuapi3_connect_recv()
501
* replicate CN=Schema,CN=Configuration,...
502
* on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection
504
* see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(),
505
* becomeDC_drsuapi3_pull_schema_send() and becomeDC_drsuapi3_pull_schema_recv()
507
***************************************************************
508
* Add this stage we call the schema_chunk() callback function
509
* for each replication message
510
***************************************************************/
513
* replicate CN=Configuration,...
514
* on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection
516
* see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(),
517
* becomeDC_drsuapi3_pull_config_send() and becomeDC_drsuapi3_pull_config_recv()
519
***************************************************************
520
* Add this stage we call the config_chunk() callback function
521
* for each replication message
522
***************************************************************/
525
* LDAP unbind on the 1st LDAP connection
527
* not implemented, because it's not needed...
531
* Open 2nd LDAP connection to the DC using admin credentials
533
* see: becomeDC_connect_ldap2() and becomeDC_ldap_connect()
537
* LDAP search 2nd LDAP connection:
539
* not implemented because it gives no new information
540
* same as becomeDC_ldap1_computer_object()
543
* basedn: <domain_partition>
545
* filter: (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<new_dc_account_name>))
546
* attrs: distinguishedName
549
* CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
550
* distinguishedName: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
551
* userAccoountControl: 4096 <0x00001000>
555
* LDAP search 2nd LDAP connection:
557
* not implemented because it gives no new information
558
* same as becomeDC_ldap1_computer_object()
561
* basedn: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
563
* filter: (objectClass=*)
564
* attrs: userAccountControl
566
* CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
567
* userAccoountControl: 4096 <0x00001000>
571
* LDAP modify 2nd LDAP connection:
573
* see: becomeDC_ldap2_modify_computer()
576
* CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
577
* userAccoountControl: 532480 <0x82000>
583
* LDAP search 2nd LDAP connection:
585
* see: becomeDC_ldap2_move_computer()
588
* basedn: <WKGUID=2fbac1870ade11d297c400c04fd8d5cd,<domain_partition>>
590
* filter: (objectClass=*)
593
* CN=Domain Controllers,<domain_partition>
597
* LDAP search 2nd LDAP connection:
599
* not implemented because it gives no new information
602
* basedn: CN=Domain Controllers,<domain_partition>
604
* filter: (objectClass=*)
605
* attrs: distinguishedName
607
* CN=Domain Controller,<domain_partition>
608
* distinguishedName: CN=Domain Controllers,<domain_partition>
612
* LDAP modifyRDN 2nd LDAP connection:
614
* see: becomeDC_ldap2_move_computer()
617
* entry: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
618
* newrdn: CN=<new_dc_netbios_name>
620
* newparent: CN=Domain Controllers,<domain_partition>
626
* LDAP unbind on the 2nd LDAP connection
628
* not implemented, because it's not needed...
632
* replicate Domain Partition
633
* on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection
635
* see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(),
636
* becomeDC_drsuapi3_pull_domain_send() and becomeDC_drsuapi3_pull_domain_recv()
638
***************************************************************
639
* Add this stage we call the domain_chunk() callback function
640
* for each replication message
641
***************************************************************/
643
/* call DsReplicaUpdateRefs() for all partitions like this:
644
* req1: struct drsuapi_DsReplicaUpdateRefsRequest1
646
* naming_context: struct drsuapi_DsReplicaObjectIdentifier
647
* __ndr_size : 0x000000ae (174)
648
* __ndr_size_sid : 0x00000000 (0)
649
* guid : 00000000-0000-0000-0000-000000000000
651
* dn : 'CN=Schema,CN=Configuration,DC=w2k3,DC=vmnet1,DC=vm,DC=base'
653
* dest_dsa_dns_name : '4a0df188-a0b8-47ea-bbe5-e614723f16dd._msdcs.w2k3.vmnet1.vm.base'
654
* dest_dsa_guid : 4a0df188-a0b8-47ea-bbe5-e614723f16dd
655
* options : 0x0000001c (28)
656
* 0: DRSUAPI_DS_REPLICA_UPDATE_ASYNCHRONOUS_OPERATION
657
* 0: DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE
658
* 1: DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE
659
* 1: DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE
660
* 1: DRSUAPI_DS_REPLICA_UPDATE_0x00000010
662
* 4a0df188-a0b8-47ea-bbe5-e614723f16dd is the objectGUID the DsAddEntry() returned for the
663
* CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
664
* on the 2nd!!! DRSUAPI connection
666
* see: becomeDC_drsuapi_update_refs_send(), becomeDC_drsuapi2_update_refs_schema_recv(),
667
* becomeDC_drsuapi2_update_refs_config_recv() and becomeDC_drsuapi2_update_refs_domain_recv()
671
* Windows does opens the 4th and 5th DRSUAPI connection...
672
* and does a DsBind() with the objectGUID from DsAddEntry() as bind_guid
673
* on the 4th connection
675
* and then 2 full replications of the domain partition on the 5th connection
676
* with the bind_handle from the 4th connection
678
* not implemented because it gives no new information
681
struct libnet_BecomeDC_state {
682
struct composite_context *creq;
684
struct libnet_context *libnet;
686
struct dom_sid zero_sid;
689
struct cldap_socket *sock;
690
struct cldap_netlogon io;
691
struct NETLOGON_SAM_LOGON_RESPONSE_EX netlogon;
694
struct becomeDC_ldap {
695
struct ldb_context *ldb;
696
const struct ldb_message *rootdse;
699
struct becomeDC_drsuapi {
700
struct libnet_BecomeDC_state *s;
701
struct dcerpc_binding *binding;
702
struct dcerpc_pipe *pipe;
703
DATA_BLOB gensec_skey;
704
struct drsuapi_DsBind bind_r;
705
struct GUID bind_guid;
706
struct drsuapi_DsBindInfoCtr bind_info_ctr;
707
struct drsuapi_DsBindInfo28 local_info28;
708
struct drsuapi_DsBindInfo28 remote_info28;
709
struct policy_handle bind_handle;
710
} drsuapi1, drsuapi2, drsuapi3;
712
struct libnet_BecomeDC_Domain domain;
713
struct libnet_BecomeDC_Forest forest;
714
struct libnet_BecomeDC_SourceDSA source_dsa;
715
struct libnet_BecomeDC_DestDSA dest_dsa;
717
struct libnet_BecomeDC_Partition schema_part, config_part, domain_part;
719
struct becomeDC_fsmo {
720
const char *dns_name;
721
const char *server_dn_str;
722
const char *ntds_dn_str;
723
struct GUID ntds_guid;
724
} infrastructure_fsmo;
726
struct becomeDC_fsmo rid_manager_fsmo;
728
struct libnet_BecomeDC_CheckOptions _co;
729
struct libnet_BecomeDC_PrepareDB _pp;
730
struct libnet_BecomeDC_StoreChunk _sc;
731
struct libnet_BecomeDC_Callbacks callbacks;
734
static void becomeDC_recv_cldap(struct cldap_request *req);
736
static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
738
struct composite_context *c = s->creq;
739
struct cldap_request *req;
741
s->cldap.io.in.dest_address = s->source_dsa.address;
742
s->cldap.io.in.dest_port = lp_cldap_port(s->libnet->lp_ctx);
743
s->cldap.io.in.realm = s->domain.dns_name;
744
s->cldap.io.in.host = s->dest_dsa.netbios_name;
745
s->cldap.io.in.user = NULL;
746
s->cldap.io.in.domain_guid = NULL;
747
s->cldap.io.in.domain_sid = NULL;
748
s->cldap.io.in.acct_control = -1;
749
s->cldap.io.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
750
s->cldap.io.in.map_response = true;
752
s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx,
753
lp_iconv_convenience(s->libnet->lp_ctx));
754
if (composite_nomem(s->cldap.sock, c)) return;
756
req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
757
if (composite_nomem(req, c)) return;
758
req->async.fn = becomeDC_recv_cldap;
759
req->async.private_data = s;
762
static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s);
764
static void becomeDC_recv_cldap(struct cldap_request *req)
766
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
767
struct libnet_BecomeDC_state);
768
struct composite_context *c = s->creq;
770
c->status = cldap_netlogon_recv(req, s, &s->cldap.io);
771
if (!composite_is_ok(c)) return;
773
s->cldap.netlogon = s->cldap.io.out.netlogon.data.nt5_ex;
775
s->domain.dns_name = s->cldap.netlogon.dns_domain;
776
s->domain.netbios_name = s->cldap.netlogon.domain;
777
s->domain.guid = s->cldap.netlogon.domain_uuid;
779
s->forest.dns_name = s->cldap.netlogon.forest;
781
s->source_dsa.dns_name = s->cldap.netlogon.pdc_dns_name;
782
s->source_dsa.netbios_name = s->cldap.netlogon.pdc_name;
783
s->source_dsa.site_name = s->cldap.netlogon.server_site;
785
s->dest_dsa.site_name = s->cldap.netlogon.client_site;
787
becomeDC_connect_ldap1(s);
790
static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s,
791
struct becomeDC_ldap *ldap)
795
url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
796
NT_STATUS_HAVE_NO_MEMORY(url);
798
ldap->ldb = ldb_wrap_connect(s, s->libnet->event_ctx, s->libnet->lp_ctx, url,
803
if (ldap->ldb == NULL) {
804
return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
810
static NTSTATUS becomeDC_ldap1_rootdse(struct libnet_BecomeDC_state *s)
813
struct ldb_result *r;
814
struct ldb_dn *basedn;
815
static const char *attrs[] = {
820
basedn = ldb_dn_new(s, s->ldap1.ldb, NULL);
821
NT_STATUS_HAVE_NO_MEMORY(basedn);
823
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
826
if (ret != LDB_SUCCESS) {
827
return NT_STATUS_LDAP(ret);
828
} else if (r->count != 1) {
830
return NT_STATUS_INVALID_NETWORK_RESPONSE;
833
s->ldap1.rootdse = r->msgs[0];
835
s->domain.dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "defaultNamingContext", NULL);
836
if (!s->domain.dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
838
s->forest.root_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "rootDomainNamingContext", NULL);
839
if (!s->forest.root_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
840
s->forest.config_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "configurationNamingContext", NULL);
841
if (!s->forest.config_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
842
s->forest.schema_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "schemaNamingContext", NULL);
843
if (!s->forest.schema_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
845
s->source_dsa.server_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "serverName", NULL);
846
if (!s->source_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
847
s->source_dsa.ntds_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "dsServiceName", NULL);
848
if (!s->source_dsa.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
853
static NTSTATUS becomeDC_ldap1_crossref_behavior_version(struct libnet_BecomeDC_state *s)
856
struct ldb_result *r;
857
struct ldb_dn *basedn;
858
static const char *attrs[] = {
859
"msDs-Behavior-Version",
863
basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.config_dn_str);
864
NT_STATUS_HAVE_NO_MEMORY(basedn);
866
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_ONELEVEL, attrs,
869
if (ret != LDB_SUCCESS) {
870
return NT_STATUS_LDAP(ret);
871
} else if (r->count != 1) {
873
return NT_STATUS_INVALID_NETWORK_RESPONSE;
876
s->forest.crossref_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
882
static NTSTATUS becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_state *s)
885
struct ldb_result *r;
886
struct ldb_dn *basedn;
887
static const char *attrs[] = {
888
"msDs-Behavior-Version",
892
basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
893
NT_STATUS_HAVE_NO_MEMORY(basedn);
895
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
898
if (ret != LDB_SUCCESS) {
899
return NT_STATUS_LDAP(ret);
900
} else if (r->count != 1) {
902
return NT_STATUS_INVALID_NETWORK_RESPONSE;
905
s->domain.behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
911
static NTSTATUS becomeDC_ldap1_schema_object_version(struct libnet_BecomeDC_state *s)
914
struct ldb_result *r;
915
struct ldb_dn *basedn;
916
static const char *attrs[] = {
921
basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.schema_dn_str);
922
NT_STATUS_HAVE_NO_MEMORY(basedn);
924
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
927
if (ret != LDB_SUCCESS) {
928
return NT_STATUS_LDAP(ret);
929
} else if (r->count != 1) {
931
return NT_STATUS_INVALID_NETWORK_RESPONSE;
934
s->forest.schema_object_version = ldb_msg_find_attr_as_uint(r->msgs[0], "objectVersion", 0);
940
static NTSTATUS becomeDC_ldap1_w2k3_update_revision(struct libnet_BecomeDC_state *s)
943
struct ldb_result *r;
944
struct ldb_dn *basedn;
945
static const char *attrs[] = {
950
basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=Windows2003Update,CN=DomainUpdates,CN=System,%s",
952
NT_STATUS_HAVE_NO_MEMORY(basedn);
954
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
957
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
958
/* w2k doesn't have this object */
959
s->domain.w2k3_update_revision = 0;
961
} else if (ret != LDB_SUCCESS) {
962
return NT_STATUS_LDAP(ret);
963
} else if (r->count != 1) {
965
return NT_STATUS_INVALID_NETWORK_RESPONSE;
968
s->domain.w2k3_update_revision = ldb_msg_find_attr_as_uint(r->msgs[0], "revision", 0);
974
static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state *s)
977
struct ldb_result *r;
978
struct ldb_dn *basedn;
979
struct ldb_dn *ntds_dn;
980
struct ldb_dn *server_dn;
981
static const char *_1_1_attrs[] = {
985
static const char *fsmo_attrs[] = {
989
static const char *dns_attrs[] = {
993
static const char *guid_attrs[] = {
998
basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "<WKGUID=2fbac1870ade11d297c400c04fd8d5cd,%s>",
1000
NT_STATUS_HAVE_NO_MEMORY(basedn);
1002
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
1003
_1_1_attrs, "(objectClass=*)");
1004
talloc_free(basedn);
1005
if (ret != LDB_SUCCESS) {
1006
return NT_STATUS_LDAP(ret);
1007
} else if (r->count != 1) {
1009
return NT_STATUS_INVALID_NETWORK_RESPONSE;
1012
basedn = talloc_steal(s, r->msgs[0]->dn);
1015
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
1016
fsmo_attrs, "(objectClass=*)");
1017
talloc_free(basedn);
1018
if (ret != LDB_SUCCESS) {
1019
return NT_STATUS_LDAP(ret);
1020
} else if (r->count != 1) {
1022
return NT_STATUS_INVALID_NETWORK_RESPONSE;
1025
s->infrastructure_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
1026
if (!s->infrastructure_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1027
talloc_steal(s, s->infrastructure_fsmo.ntds_dn_str);
1031
ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->infrastructure_fsmo.ntds_dn_str);
1032
NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
1034
server_dn = ldb_dn_get_parent(s, ntds_dn);
1035
NT_STATUS_HAVE_NO_MEMORY(server_dn);
1037
s->infrastructure_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
1038
NT_STATUS_HAVE_NO_MEMORY(s->infrastructure_fsmo.server_dn_str);
1040
ret = ldb_search(s->ldap1.ldb, s, &r, server_dn, LDB_SCOPE_BASE,
1041
dns_attrs, "(objectClass=*)");
1042
if (ret != LDB_SUCCESS) {
1043
return NT_STATUS_LDAP(ret);
1044
} else if (r->count != 1) {
1046
return NT_STATUS_INVALID_NETWORK_RESPONSE;
1049
s->infrastructure_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL);
1050
if (!s->infrastructure_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1051
talloc_steal(s, s->infrastructure_fsmo.dns_name);
1055
ret = ldb_search(s->ldap1.ldb, s, &r, ntds_dn, LDB_SCOPE_BASE,
1056
guid_attrs, "(objectClass=*)");
1057
if (ret != LDB_SUCCESS) {
1058
return NT_STATUS_LDAP(ret);
1059
} else if (r->count != 1) {
1061
return NT_STATUS_INVALID_NETWORK_RESPONSE;
1064
s->infrastructure_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
1068
return NT_STATUS_OK;
1071
static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s)
1074
struct ldb_result *r;
1075
struct ldb_dn *basedn;
1076
const char *reference_dn_str;
1077
struct ldb_dn *ntds_dn;
1078
struct ldb_dn *server_dn;
1079
static const char *rid_attrs[] = {
1080
"rIDManagerReference",
1083
static const char *fsmo_attrs[] = {
1087
static const char *dns_attrs[] = {
1091
static const char *guid_attrs[] = {
1096
basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
1097
NT_STATUS_HAVE_NO_MEMORY(basedn);
1099
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
1100
rid_attrs, "(objectClass=*)");
1101
talloc_free(basedn);
1102
if (ret != LDB_SUCCESS) {
1103
return NT_STATUS_LDAP(ret);
1104
} else if (r->count != 1) {
1106
return NT_STATUS_INVALID_NETWORK_RESPONSE;
1109
reference_dn_str = samdb_result_string(r->msgs[0], "rIDManagerReference", NULL);
1110
if (!reference_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1112
basedn = ldb_dn_new(s, s->ldap1.ldb, reference_dn_str);
1113
NT_STATUS_HAVE_NO_MEMORY(basedn);
1117
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
1118
fsmo_attrs, "(objectClass=*)");
1119
talloc_free(basedn);
1120
if (ret != LDB_SUCCESS) {
1121
return NT_STATUS_LDAP(ret);
1122
} else if (r->count != 1) {
1124
return NT_STATUS_INVALID_NETWORK_RESPONSE;
1127
s->rid_manager_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
1128
if (!s->rid_manager_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1129
talloc_steal(s, s->rid_manager_fsmo.ntds_dn_str);
1133
ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->rid_manager_fsmo.ntds_dn_str);
1134
NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
1136
server_dn = ldb_dn_get_parent(s, ntds_dn);
1137
NT_STATUS_HAVE_NO_MEMORY(server_dn);
1139
s->rid_manager_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
1140
NT_STATUS_HAVE_NO_MEMORY(s->rid_manager_fsmo.server_dn_str);
1142
ret = ldb_search(s->ldap1.ldb, s, &r, server_dn, LDB_SCOPE_BASE,
1143
dns_attrs, "(objectClass=*)");
1144
if (ret != LDB_SUCCESS) {
1145
return NT_STATUS_LDAP(ret);
1146
} else if (r->count != 1) {
1148
return NT_STATUS_INVALID_NETWORK_RESPONSE;
1151
s->rid_manager_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL);
1152
if (!s->rid_manager_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1153
talloc_steal(s, s->rid_manager_fsmo.dns_name);
1157
ret = ldb_search(s->ldap1.ldb, s, &r, ntds_dn, LDB_SCOPE_BASE,
1158
guid_attrs, "(objectClass=*)");
1159
if (ret != LDB_SUCCESS) {
1160
return NT_STATUS_LDAP(ret);
1161
} else if (r->count != 1) {
1163
return NT_STATUS_INVALID_NETWORK_RESPONSE;
1166
s->rid_manager_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
1170
return NT_STATUS_OK;
1173
static NTSTATUS becomeDC_ldap1_site_object(struct libnet_BecomeDC_state *s)
1176
struct ldb_result *r;
1177
struct ldb_dn *basedn;
1179
basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Sites,%s",
1180
s->dest_dsa.site_name,
1181
s->forest.config_dn_str);
1182
NT_STATUS_HAVE_NO_MEMORY(basedn);
1184
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
1185
NULL, "(objectClass=*)");
1186
talloc_free(basedn);
1187
if (ret != LDB_SUCCESS) {
1188
return NT_STATUS_LDAP(ret);
1189
} else if (r->count != 1) {
1191
return NT_STATUS_INVALID_NETWORK_RESPONSE;
1194
s->dest_dsa.site_guid = samdb_result_guid(r->msgs[0], "objectGUID");
1197
return NT_STATUS_OK;
1200
static NTSTATUS becomeDC_check_options(struct libnet_BecomeDC_state *s)
1202
if (!s->callbacks.check_options) return NT_STATUS_OK;
1204
s->_co.domain = &s->domain;
1205
s->_co.forest = &s->forest;
1206
s->_co.source_dsa = &s->source_dsa;
1208
return s->callbacks.check_options(s->callbacks.private_data, &s->_co);
1211
static NTSTATUS becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state *s)
1214
struct ldb_result *r;
1215
struct ldb_dn *basedn;
1216
static const char *attrs[] = {
1217
"distinguishedName",
1218
"userAccountControl",
1222
basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
1223
NT_STATUS_HAVE_NO_MEMORY(basedn);
1225
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_SUBTREE, attrs,
1226
"(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))",
1227
s->dest_dsa.netbios_name);
1228
talloc_free(basedn);
1229
if (ret != LDB_SUCCESS) {
1230
return NT_STATUS_LDAP(ret);
1231
} else if (r->count != 1) {
1233
return NT_STATUS_INVALID_NETWORK_RESPONSE;
1236
s->dest_dsa.computer_dn_str = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
1237
if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1238
talloc_steal(s, s->dest_dsa.computer_dn_str);
1240
s->dest_dsa.user_account_control = samdb_result_uint(r->msgs[0], "userAccountControl", 0);
1243
return NT_STATUS_OK;
1246
static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s)
1249
struct ldb_result *r;
1250
struct ldb_dn *basedn;
1251
const char *server_reference_dn_str;
1252
struct ldb_dn *server_reference_dn;
1253
struct ldb_dn *computer_dn;
1255
basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
1256
s->dest_dsa.netbios_name,
1257
s->dest_dsa.site_name,
1258
s->forest.config_dn_str);
1259
NT_STATUS_HAVE_NO_MEMORY(basedn);
1261
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
1262
NULL, "(objectClass=*)");
1263
talloc_free(basedn);
1264
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1265
/* if the object doesn't exist, we'll create it later */
1266
return NT_STATUS_OK;
1267
} else if (ret != LDB_SUCCESS) {
1268
return NT_STATUS_LDAP(ret);
1269
} else if (r->count != 1) {
1271
return NT_STATUS_INVALID_NETWORK_RESPONSE;
1274
server_reference_dn_str = samdb_result_string(r->msgs[0], "serverReference", NULL);
1275
if (server_reference_dn_str) {
1276
server_reference_dn = ldb_dn_new(r, s->ldap1.ldb, server_reference_dn_str);
1277
NT_STATUS_HAVE_NO_MEMORY(server_reference_dn);
1279
computer_dn = ldb_dn_new(r, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
1280
NT_STATUS_HAVE_NO_MEMORY(computer_dn);
1283
* if the server object belongs to another DC in another domain in the forest,
1284
* we should not touch this object!
1286
if (ldb_dn_compare(computer_dn, server_reference_dn) != 0) {
1288
return NT_STATUS_OBJECT_NAME_COLLISION;
1292
/* if the server object is already for the dest_dsa, then we don't need to create it */
1293
s->dest_dsa.server_dn_str = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
1294
if (!s->dest_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1295
talloc_steal(s, s->dest_dsa.server_dn_str);
1298
return NT_STATUS_OK;
1301
static NTSTATUS becomeDC_ldap1_server_object_2(struct libnet_BecomeDC_state *s)
1304
struct ldb_result *r;
1305
struct ldb_dn *basedn;
1306
const char *server_reference_bl_dn_str;
1307
static const char *attrs[] = {
1308
"serverReferenceBL",
1312
/* if the server_dn_str has a valid value, we skip this lookup */
1313
if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
1315
basedn = ldb_dn_new(s, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
1316
NT_STATUS_HAVE_NO_MEMORY(basedn);
1318
ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
1319
attrs, "(objectClass=*)");
1320
talloc_free(basedn);
1321
if (ret != LDB_SUCCESS) {
1322
return NT_STATUS_LDAP(ret);
1323
} else if (r->count != 1) {
1325
return NT_STATUS_INVALID_NETWORK_RESPONSE;
1328
server_reference_bl_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL);
1329
if (!server_reference_bl_dn_str) {
1330
/* if no back link is present, we're done for this function */
1332
return NT_STATUS_OK;
1335
/* if the server object is already for the dest_dsa, then we don't need to create it */
1336
s->dest_dsa.server_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL);
1337
if (s->dest_dsa.server_dn_str) {
1338
/* if a back link is present, we know that the server object is present */
1339
talloc_steal(s, s->dest_dsa.server_dn_str);
1343
return NT_STATUS_OK;
1346
static NTSTATUS becomeDC_ldap1_server_object_add(struct libnet_BecomeDC_state *s)
1349
struct ldb_message *msg;
1350
char *server_dn_str;
1352
/* if the server_dn_str has a valid value, we skip this lookup */
1353
if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
1355
msg = ldb_msg_new(s);
1356
NT_STATUS_HAVE_NO_MEMORY(msg);
1358
msg->dn = ldb_dn_new_fmt(msg, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
1359
s->dest_dsa.netbios_name,
1360
s->dest_dsa.site_name,
1361
s->forest.config_dn_str);
1362
NT_STATUS_HAVE_NO_MEMORY(msg->dn);
1364
ret = ldb_msg_add_string(msg, "objectClass", "server");
1367
return NT_STATUS_NO_MEMORY;
1369
ret = ldb_msg_add_string(msg, "systemFlags", "50000000");
1372
return NT_STATUS_NO_MEMORY;
1374
ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
1377
return NT_STATUS_NO_MEMORY;
1380
server_dn_str = ldb_dn_alloc_linearized(s, msg->dn);
1381
NT_STATUS_HAVE_NO_MEMORY(server_dn_str);
1383
ret = ldb_add(s->ldap1.ldb, msg);
1385
if (ret != LDB_SUCCESS) {
1386
talloc_free(server_dn_str);
1387
return NT_STATUS_LDAP(ret);
1390
s->dest_dsa.server_dn_str = server_dn_str;
1392
return NT_STATUS_OK;
1395
static NTSTATUS becomeDC_ldap1_server_object_modify(struct libnet_BecomeDC_state *s)
1398
struct ldb_message *msg;
1401
/* make a 'modify' msg, and only for serverReference */
1402
msg = ldb_msg_new(s);
1403
NT_STATUS_HAVE_NO_MEMORY(msg);
1404
msg->dn = ldb_dn_new(msg, s->ldap1.ldb, s->dest_dsa.server_dn_str);
1405
NT_STATUS_HAVE_NO_MEMORY(msg->dn);
1407
ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
1410
return NT_STATUS_NO_MEMORY;
1413
/* mark all the message elements (should be just one)
1414
as LDB_FLAG_MOD_ADD */
1415
for (i=0;i<msg->num_elements;i++) {
1416
msg->elements[i].flags = LDB_FLAG_MOD_ADD;
1419
ret = ldb_modify(s->ldap1.ldb, msg);
1420
if (ret == LDB_SUCCESS) {
1422
return NT_STATUS_OK;
1423
} else if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
1424
/* retry with LDB_FLAG_MOD_REPLACE */
1427
return NT_STATUS_LDAP(ret);
1430
/* mark all the message elements (should be just one)
1431
as LDB_FLAG_MOD_REPLACE */
1432
for (i=0;i<msg->num_elements;i++) {
1433
msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1436
ret = ldb_modify(s->ldap1.ldb, msg);
1438
if (ret != LDB_SUCCESS) {
1439
return NT_STATUS_LDAP(ret);
1442
return NT_STATUS_OK;
1445
static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
1446
struct becomeDC_drsuapi *drsuapi,
1447
void (*recv_fn)(struct composite_context *req));
1448
static void becomeDC_drsuapi1_connect_recv(struct composite_context *req);
1449
static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s);
1451
static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s)
1453
struct composite_context *c = s->creq;
1455
c->status = becomeDC_ldap_connect(s, &s->ldap1);
1456
if (!composite_is_ok(c)) return;
1458
c->status = becomeDC_ldap1_rootdse(s);
1459
if (!composite_is_ok(c)) return;
1461
c->status = becomeDC_ldap1_crossref_behavior_version(s);
1462
if (!composite_is_ok(c)) return;
1464
c->status = becomeDC_ldap1_domain_behavior_version(s);
1465
if (!composite_is_ok(c)) return;
1467
c->status = becomeDC_ldap1_schema_object_version(s);
1468
if (!composite_is_ok(c)) return;
1470
c->status = becomeDC_ldap1_w2k3_update_revision(s);
1471
if (!composite_is_ok(c)) return;
1473
c->status = becomeDC_ldap1_infrastructure_fsmo(s);
1474
if (!composite_is_ok(c)) return;
1476
c->status = becomeDC_ldap1_rid_manager_fsmo(s);
1477
if (!composite_is_ok(c)) return;
1479
c->status = becomeDC_ldap1_site_object(s);
1480
if (!composite_is_ok(c)) return;
1482
c->status = becomeDC_check_options(s);
1483
if (!composite_is_ok(c)) return;
1485
c->status = becomeDC_ldap1_computer_object(s);
1486
if (!composite_is_ok(c)) return;
1488
c->status = becomeDC_ldap1_server_object_1(s);
1489
if (!composite_is_ok(c)) return;
1491
c->status = becomeDC_ldap1_server_object_2(s);
1492
if (!composite_is_ok(c)) return;
1494
c->status = becomeDC_ldap1_server_object_add(s);
1495
if (!composite_is_ok(c)) return;
1497
c->status = becomeDC_ldap1_server_object_modify(s);
1498
if (!composite_is_ok(c)) return;
1500
becomeDC_drsuapi_connect_send(s, &s->drsuapi1, becomeDC_drsuapi1_connect_recv);
1503
static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
1504
struct becomeDC_drsuapi *drsuapi,
1505
void (*recv_fn)(struct composite_context *req))
1507
struct composite_context *c = s->creq;
1508
struct composite_context *creq;
1513
if (!drsuapi->binding) {
1514
const char *krb5_str = "";
1515
const char *print_str = "";
1517
* Note: Replication only works with Windows 2000 when 'krb5' is
1518
* passed as auth_type here. If NTLMSSP is used, Windows
1519
* 2000 returns garbage in the DsGetNCChanges() response
1520
* if encrypted password attributes would be in the response.
1521
* That means the replication of the schema and configuration
1522
* partition works fine, but it fails for the domain partition.
1524
if (lp_parm_bool(s->libnet->lp_ctx, NULL, "become_dc",
1525
"force krb5", true))
1529
if (lp_parm_bool(s->libnet->lp_ctx, NULL, "become_dc",
1532
print_str = "print,";
1534
binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[%s%sseal]",
1535
s->source_dsa.dns_name,
1536
krb5_str, print_str);
1537
if (composite_nomem(binding_str, c)) return;
1538
c->status = dcerpc_parse_binding(s, binding_str, &drsuapi->binding);
1539
talloc_free(binding_str);
1540
if (!composite_is_ok(c)) return;
1543
creq = dcerpc_pipe_connect_b_send(s, drsuapi->binding, &ndr_table_drsuapi,
1544
s->libnet->cred, s->libnet->event_ctx,
1546
composite_continue(c, creq, recv_fn, s);
1549
static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
1550
struct becomeDC_drsuapi *drsuapi,
1551
void (*recv_fn)(struct rpc_request *req));
1552
static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req);
1554
static void becomeDC_drsuapi1_connect_recv(struct composite_context *req)
1556
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
1557
struct libnet_BecomeDC_state);
1558
struct composite_context *c = s->creq;
1560
c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi1.pipe);
1561
if (!composite_is_ok(c)) return;
1563
c->status = gensec_session_key(s->drsuapi1.pipe->conn->security_state.generic_state,
1564
&s->drsuapi1.gensec_skey);
1565
if (!composite_is_ok(c)) return;
1567
becomeDC_drsuapi_bind_send(s, &s->drsuapi1, becomeDC_drsuapi1_bind_recv);
1570
static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
1571
struct becomeDC_drsuapi *drsuapi,
1572
void (*recv_fn)(struct rpc_request *req))
1574
struct composite_context *c = s->creq;
1575
struct rpc_request *req;
1576
struct drsuapi_DsBindInfo28 *bind_info28;
1578
GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &drsuapi->bind_guid);
1580
bind_info28 = &drsuapi->local_info28;
1581
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
1582
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
1583
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
1584
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
1585
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
1586
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
1587
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
1588
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
1589
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
1590
if (s->domain.behavior_version == 2) {
1591
/* TODO: find out how this is really triggered! */
1592
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
1594
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
1595
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
1596
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
1597
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
1598
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
1599
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
1600
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
1601
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
1602
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
1603
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_00100000;
1604
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
1605
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
1606
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
1607
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
1608
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
1609
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
1610
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
1611
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
1612
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
1613
#if 0 /* we don't support XPRESS compression yet */
1614
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
1616
bind_info28->site_guid = s->dest_dsa.site_guid;
1617
bind_info28->pid = 0;
1618
bind_info28->repl_epoch = 0;
1620
drsuapi->bind_info_ctr.length = 28;
1621
drsuapi->bind_info_ctr.info.info28 = *bind_info28;
1623
drsuapi->bind_r.in.bind_guid = &drsuapi->bind_guid;
1624
drsuapi->bind_r.in.bind_info = &drsuapi->bind_info_ctr;
1625
drsuapi->bind_r.out.bind_handle = &drsuapi->bind_handle;
1627
req = dcerpc_drsuapi_DsBind_send(drsuapi->pipe, s, &drsuapi->bind_r);
1628
composite_continue_rpc(c, req, recv_fn, s);
1631
static WERROR becomeDC_drsuapi_bind_recv(struct libnet_BecomeDC_state *s,
1632
struct becomeDC_drsuapi *drsuapi)
1634
if (!W_ERROR_IS_OK(drsuapi->bind_r.out.result)) {
1635
return drsuapi->bind_r.out.result;
1638
ZERO_STRUCT(drsuapi->remote_info28);
1639
if (drsuapi->bind_r.out.bind_info) {
1640
switch (drsuapi->bind_r.out.bind_info->length) {
1642
struct drsuapi_DsBindInfo24 *info24;
1643
info24 = &drsuapi->bind_r.out.bind_info->info.info24;
1644
drsuapi->remote_info28.supported_extensions = info24->supported_extensions;
1645
drsuapi->remote_info28.site_guid = info24->site_guid;
1646
drsuapi->remote_info28.pid = info24->pid;
1647
drsuapi->remote_info28.repl_epoch = 0;
1651
struct drsuapi_DsBindInfo48 *info48;
1652
info48 = &drsuapi->bind_r.out.bind_info->info.info48;
1653
drsuapi->remote_info28.supported_extensions = info48->supported_extensions;
1654
drsuapi->remote_info28.site_guid = info48->site_guid;
1655
drsuapi->remote_info28.pid = info48->pid;
1656
drsuapi->remote_info28.repl_epoch = info48->repl_epoch;
1660
drsuapi->remote_info28 = drsuapi->bind_r.out.bind_info->info.info28;
1668
static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s);
1670
static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req)
1672
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
1673
struct libnet_BecomeDC_state);
1674
struct composite_context *c = s->creq;
1679
if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
1683
c->status = dcerpc_ndr_request_recv(req);
1684
if (!composite_is_ok(c)) return;
1687
NDR_PRINT_OUT_DEBUG(drsuapi_DsBind, &s->drsuapi1.bind_r);
1690
status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi1);
1691
if (!W_ERROR_IS_OK(status)) {
1692
composite_error(c, werror_to_ntstatus(status));
1696
becomeDC_drsuapi1_add_entry_send(s);
1699
static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req);
1701
static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
1703
struct composite_context *c = s->creq;
1704
struct rpc_request *req;
1705
struct drsuapi_DsAddEntry *r;
1706
struct drsuapi_DsReplicaObjectIdentifier *identifier;
1707
uint32_t num_attrs, i = 0;
1708
struct drsuapi_DsReplicaAttribute *attrs;
1709
struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(s->libnet->lp_ctx);
1710
enum ndr_err_code ndr_err;
1713
/* choose a random invocationId */
1714
s->dest_dsa.invocation_id = GUID_random();
1717
* if the schema version indicates w2k3, then
1718
* also send some w2k3 specific attributes
1720
if (s->forest.schema_object_version >= 30) {
1726
r = talloc_zero(s, struct drsuapi_DsAddEntry);
1727
if (composite_nomem(r, c)) return;
1729
/* setup identifier */
1730
identifier = talloc(r, struct drsuapi_DsReplicaObjectIdentifier);
1731
if (composite_nomem(identifier, c)) return;
1732
identifier->guid = GUID_zero();
1733
identifier->sid = s->zero_sid;
1734
identifier->dn = talloc_asprintf(identifier, "CN=NTDS Settings,%s",
1735
s->dest_dsa.server_dn_str);
1736
if (composite_nomem(identifier->dn, c)) return;
1738
/* allocate attribute array */
1740
attrs = talloc_array(r, struct drsuapi_DsReplicaAttribute, num_attrs);
1741
if (composite_nomem(attrs, c)) return;
1743
/* ntSecurityDescriptor */
1745
struct drsuapi_DsAttributeValue *vs;
1747
struct security_descriptor *v;
1748
struct dom_sid *domain_admins_sid;
1749
const char *domain_admins_sid_str;
1751
vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1752
if (composite_nomem(vs, c)) return;
1754
vd = talloc_array(vs, DATA_BLOB, 1);
1755
if (composite_nomem(vd, c)) return;
1757
domain_admins_sid = dom_sid_add_rid(vs, s->domain.sid, DOMAIN_RID_ADMINS);
1758
if (composite_nomem(domain_admins_sid, c)) return;
1760
domain_admins_sid_str = dom_sid_string(domain_admins_sid, domain_admins_sid);
1761
if (composite_nomem(domain_admins_sid_str, c)) return;
1763
v = security_descriptor_dacl_create(vd,
1765
/* owner: domain admins */
1766
domain_admins_sid_str,
1767
/* owner group: domain admins */
1768
domain_admins_sid_str,
1769
/* authenticated users */
1770
SID_NT_AUTHENTICATED_USERS,
1771
SEC_ACE_TYPE_ACCESS_ALLOWED,
1772
SEC_STD_READ_CONTROL |
1775
SEC_ADS_LIST_OBJECT,
1778
domain_admins_sid_str,
1779
SEC_ACE_TYPE_ACCESS_ALLOWED,
1781
SEC_ADS_CREATE_CHILD |
1783
SEC_ADS_SELF_WRITE |
1785
SEC_ADS_WRITE_PROP |
1786
SEC_ADS_DELETE_TREE |
1787
SEC_ADS_LIST_OBJECT |
1788
SEC_ADS_CONTROL_ACCESS,
1792
SEC_ACE_TYPE_ACCESS_ALLOWED,
1794
SEC_ADS_CREATE_CHILD |
1795
SEC_ADS_DELETE_CHILD |
1797
SEC_ADS_SELF_WRITE |
1799
SEC_ADS_WRITE_PROP |
1800
SEC_ADS_DELETE_TREE |
1801
SEC_ADS_LIST_OBJECT |
1802
SEC_ADS_CONTROL_ACCESS,
1806
if (composite_nomem(v, c)) return;
1808
ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, v,(ndr_push_flags_fn_t)ndr_push_security_descriptor);
1809
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1810
c->status = ndr_map_error2ntstatus(ndr_err);
1811
if (!composite_is_ok(c)) return;
1814
vs[0].blob = &vd[0];
1816
attrs[i].attid = DRSUAPI_ATTRIBUTE_ntSecurityDescriptor;
1817
attrs[i].value_ctr.num_values = 1;
1818
attrs[i].value_ctr.values = vs;
1823
/* objectClass: nTDSDSA */
1825
struct drsuapi_DsAttributeValue *vs;
1828
vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1829
if (composite_nomem(vs, c)) return;
1831
vd = talloc_array(vs, DATA_BLOB, 1);
1832
if (composite_nomem(vd, c)) return;
1834
vd[0] = data_blob_talloc(vd, NULL, 4);
1835
if (composite_nomem(vd[0].data, c)) return;
1837
/* value for nTDSDSA */
1838
SIVAL(vd[0].data, 0, 0x0017002F);
1840
vs[0].blob = &vd[0];
1842
attrs[i].attid = DRSUAPI_ATTRIBUTE_objectClass;
1843
attrs[i].value_ctr.num_values = 1;
1844
attrs[i].value_ctr.values = vs;
1849
/* objectCategory: CN=NTDS-DSA,CN=Schema,... */
1851
struct drsuapi_DsAttributeValue *vs;
1853
struct drsuapi_DsReplicaObjectIdentifier3 v[1];
1855
vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1856
if (composite_nomem(vs, c)) return;
1858
vd = talloc_array(vs, DATA_BLOB, 1);
1859
if (composite_nomem(vd, c)) return;
1861
v[0].guid = GUID_zero();
1862
v[0].sid = s->zero_sid;
1863
v[0].dn = talloc_asprintf(vd, "CN=NTDS-DSA,%s",
1864
s->forest.schema_dn_str);
1865
if (composite_nomem(v[0].dn, c)) return;
1867
ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0],
1868
(ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1869
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1870
c->status = ndr_map_error2ntstatus(ndr_err);
1871
if (!composite_is_ok(c)) return;
1874
vs[0].blob = &vd[0];
1876
attrs[i].attid = DRSUAPI_ATTRIBUTE_objectCategory;
1877
attrs[i].value_ctr.num_values = 1;
1878
attrs[i].value_ctr.values = vs;
1883
/* invocationId: random guid */
1885
struct drsuapi_DsAttributeValue *vs;
1887
const struct GUID *v;
1889
vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1890
if (composite_nomem(vs, c)) return;
1892
vd = talloc_array(vs, DATA_BLOB, 1);
1893
if (composite_nomem(vd, c)) return;
1895
v = &s->dest_dsa.invocation_id;
1897
ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, v, (ndr_push_flags_fn_t)ndr_push_GUID);
1898
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1899
c->status = ndr_map_error2ntstatus(ndr_err);
1900
if (!composite_is_ok(c)) return;
1903
vs[0].blob = &vd[0];
1905
attrs[i].attid = DRSUAPI_ATTRIBUTE_invocationId;
1906
attrs[i].value_ctr.num_values = 1;
1907
attrs[i].value_ctr.values = vs;
1912
/* hasMasterNCs: ... */
1914
struct drsuapi_DsAttributeValue *vs;
1916
struct drsuapi_DsReplicaObjectIdentifier3 v[3];
1918
vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 3);
1919
if (composite_nomem(vs, c)) return;
1921
vd = talloc_array(vs, DATA_BLOB, 3);
1922
if (composite_nomem(vd, c)) return;
1924
v[0].guid = GUID_zero();
1925
v[0].sid = s->zero_sid;
1926
v[0].dn = s->forest.config_dn_str;
1928
v[1].guid = GUID_zero();
1929
v[1].sid = s->zero_sid;
1930
v[1].dn = s->domain.dn_str;
1932
v[2].guid = GUID_zero();
1933
v[2].sid = s->zero_sid;
1934
v[2].dn = s->forest.schema_dn_str;
1936
ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0],
1937
(ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1938
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1939
c->status = ndr_map_error2ntstatus(ndr_err);
1940
if (!composite_is_ok(c)) return;
1943
ndr_err = ndr_push_struct_blob(&vd[1], vd, iconv_convenience, &v[1],
1944
(ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1945
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1946
c->status = ndr_map_error2ntstatus(ndr_err);
1947
if (!composite_is_ok(c)) return;
1950
ndr_err = ndr_push_struct_blob(&vd[2], vd, iconv_convenience, &v[2],
1951
(ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1952
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1953
c->status = ndr_map_error2ntstatus(ndr_err);
1954
if (!composite_is_ok(c)) return;
1957
vs[0].blob = &vd[0];
1958
vs[1].blob = &vd[1];
1959
vs[2].blob = &vd[2];
1961
attrs[i].attid = DRSUAPI_ATTRIBUTE_hasMasterNCs;
1962
attrs[i].value_ctr.num_values = 3;
1963
attrs[i].value_ctr.values = vs;
1968
/* msDS-hasMasterNCs: ... */
1970
struct drsuapi_DsAttributeValue *vs;
1972
struct drsuapi_DsReplicaObjectIdentifier3 v[3];
1974
vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 3);
1975
if (composite_nomem(vs, c)) return;
1977
vd = talloc_array(vs, DATA_BLOB, 3);
1978
if (composite_nomem(vd, c)) return;
1980
v[0].guid = GUID_zero();
1981
v[0].sid = s->zero_sid;
1982
v[0].dn = s->forest.config_dn_str;
1984
v[1].guid = GUID_zero();
1985
v[1].sid = s->zero_sid;
1986
v[1].dn = s->domain.dn_str;
1988
v[2].guid = GUID_zero();
1989
v[2].sid = s->zero_sid;
1990
v[2].dn = s->forest.schema_dn_str;
1992
ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0],
1993
(ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1994
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1995
c->status = ndr_map_error2ntstatus(ndr_err);
1996
if (!composite_is_ok(c)) return;
1999
ndr_err = ndr_push_struct_blob(&vd[1], vd, iconv_convenience, &v[1],
2000
(ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2001
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2002
c->status = ndr_map_error2ntstatus(ndr_err);
2003
if (!composite_is_ok(c)) return;
2006
ndr_err = ndr_push_struct_blob(&vd[2], vd, iconv_convenience, &v[2],
2007
(ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2008
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2009
c->status = ndr_map_error2ntstatus(ndr_err);
2010
if (!composite_is_ok(c)) return;
2013
vs[0].blob = &vd[0];
2014
vs[1].blob = &vd[1];
2015
vs[2].blob = &vd[2];
2017
attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs;
2018
attrs[i].value_ctr.num_values = 3;
2019
attrs[i].value_ctr.values = vs;
2024
/* dMDLocation: CN=Schema,... */
2026
struct drsuapi_DsAttributeValue *vs;
2028
struct drsuapi_DsReplicaObjectIdentifier3 v[1];
2030
vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
2031
if (composite_nomem(vs, c)) return;
2033
vd = talloc_array(vs, DATA_BLOB, 1);
2034
if (composite_nomem(vd, c)) return;
2036
v[0].guid = GUID_zero();
2037
v[0].sid = s->zero_sid;
2038
v[0].dn = s->forest.schema_dn_str;
2040
ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0],
2041
(ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2042
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2043
c->status = ndr_map_error2ntstatus(ndr_err);
2044
if (!composite_is_ok(c)) return;
2047
vs[0].blob = &vd[0];
2049
attrs[i].attid = DRSUAPI_ATTRIBUTE_dMDLocation;
2050
attrs[i].value_ctr.num_values = 1;
2051
attrs[i].value_ctr.values = vs;
2056
/* msDS-HasDomainNCs: <domain_partition> */
2058
struct drsuapi_DsAttributeValue *vs;
2060
struct drsuapi_DsReplicaObjectIdentifier3 v[1];
2062
vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
2063
if (composite_nomem(vs, c)) return;
2065
vd = talloc_array(vs, DATA_BLOB, 1);
2066
if (composite_nomem(vd, c)) return;
2068
v[0].guid = GUID_zero();
2069
v[0].sid = s->zero_sid;
2070
v[0].dn = s->domain.dn_str;
2072
ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0],
2073
(ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2074
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2075
c->status = ndr_map_error2ntstatus(ndr_err);
2076
if (!composite_is_ok(c)) return;
2079
vs[0].blob = &vd[0];
2081
attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs;
2082
attrs[i].value_ctr.num_values = 1;
2083
attrs[i].value_ctr.values = vs;
2088
/* msDS-Behavior-Version */
2090
struct drsuapi_DsAttributeValue *vs;
2093
vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
2094
if (composite_nomem(vs, c)) return;
2096
vd = talloc_array(vs, DATA_BLOB, 1);
2097
if (composite_nomem(vd, c)) return;
2099
vd[0] = data_blob_talloc(vd, NULL, 4);
2100
if (composite_nomem(vd[0].data, c)) return;
2102
SIVAL(vd[0].data, 0, DS_BEHAVIOR_WIN2008);
2104
vs[0].blob = &vd[0];
2106
attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_Behavior_Version;
2107
attrs[i].value_ctr.num_values = 1;
2108
attrs[i].value_ctr.values = vs;
2115
struct drsuapi_DsAttributeValue *vs;
2118
vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
2119
if (composite_nomem(vs, c)) return;
2121
vd = talloc_array(vs, DATA_BLOB, 1);
2122
if (composite_nomem(vd, c)) return;
2124
vd[0] = data_blob_talloc(vd, NULL, 4);
2125
if (composite_nomem(vd[0].data, c)) return;
2127
SIVAL(vd[0].data, 0, SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2129
vs[0].blob = &vd[0];
2131
attrs[i].attid = DRSUAPI_ATTRIBUTE_systemFlags;
2132
attrs[i].value_ctr.num_values = 1;
2133
attrs[i].value_ctr.values = vs;
2138
/* serverReference: ... */
2140
struct drsuapi_DsAttributeValue *vs;
2142
struct drsuapi_DsReplicaObjectIdentifier3 v[1];
2144
vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
2145
if (composite_nomem(vs, c)) return;
2147
vd = talloc_array(vs, DATA_BLOB, 1);
2148
if (composite_nomem(vd, c)) return;
2150
v[0].guid = GUID_zero();
2151
v[0].sid = s->zero_sid;
2152
v[0].dn = s->dest_dsa.computer_dn_str;
2154
ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0],
2155
(ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2156
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2157
c->status = ndr_map_error2ntstatus(ndr_err);
2158
if (!composite_is_ok(c)) return;
2161
vs[0].blob = &vd[0];
2163
attrs[i].attid = DRSUAPI_ATTRIBUTE_serverReference;
2164
attrs[i].value_ctr.num_values = 1;
2165
attrs[i].value_ctr.values = vs;
2170
/* truncate the attribute list to the attribute count we have filled in */
2173
/* setup request structure */
2174
r->in.bind_handle = &s->drsuapi1.bind_handle;
2176
r->in.req = talloc(s, union drsuapi_DsAddEntryRequest);
2177
r->in.req->req2.first_object.next_object = NULL;
2178
r->in.req->req2.first_object.object.identifier = identifier;
2179
r->in.req->req2.first_object.object.flags = 0x00000000;
2180
r->in.req->req2.first_object.object.attribute_ctr.num_attributes= num_attrs;
2181
r->in.req->req2.first_object.object.attribute_ctr.attributes = attrs;
2183
r->out.level_out = talloc(s, int32_t);
2184
r->out.ctr = talloc(s, union drsuapi_DsAddEntryCtr);
2186
req = dcerpc_drsuapi_DsAddEntry_send(s->drsuapi1.pipe, r, r);
2187
composite_continue_rpc(c, req, becomeDC_drsuapi1_add_entry_recv, s);
2190
static void becomeDC_drsuapi2_connect_recv(struct composite_context *req);
2191
static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s);
2193
static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req)
2195
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
2196
struct libnet_BecomeDC_state);
2197
struct composite_context *c = s->creq;
2198
struct drsuapi_DsAddEntry *r = talloc_get_type(req->ndr.struct_ptr,
2199
struct drsuapi_DsAddEntry);
2203
if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
2207
c->status = dcerpc_ndr_request_recv(req);
2208
if (!composite_is_ok(c)) return;
2211
NDR_PRINT_OUT_DEBUG(drsuapi_DsAddEntry, r);
2214
if (!W_ERROR_IS_OK(r->out.result)) {
2215
composite_error(c, werror_to_ntstatus(r->out.result));
2219
if (*r->out.level_out == 3) {
2220
if (r->out.ctr->ctr3.count != 1) {
2223
if (r->out.ctr->ctr3.level != 1) {
2224
composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
2228
if (!r->out.ctr->ctr3.error) {
2229
composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
2233
status = r->out.ctr->ctr3.error->info1.status;
2235
if (!r->out.ctr->ctr3.error->info1.info) {
2236
composite_error(c, werror_to_ntstatus(status));
2240
/* see if we can get a more detailed error */
2241
switch (r->out.ctr->ctr3.error->info1.level) {
2243
status = r->out.ctr->ctr3.error->info1.info->error1.status;
2249
status = r->out.ctr->ctr3.error->info1.info->errorX.status;
2253
composite_error(c, werror_to_ntstatus(status));
2257
s->dest_dsa.ntds_guid = r->out.ctr->ctr3.objects[0].guid;
2258
} else if (*r->out.level_out == 2) {
2259
if (r->out.ctr->ctr2.count != 1) {
2260
composite_error(c, werror_to_ntstatus(r->out.ctr->ctr2.error.status));
2264
s->dest_dsa.ntds_guid = r->out.ctr->ctr2.objects[0].guid;
2266
composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
2272
s->dest_dsa.ntds_dn_str = talloc_asprintf(s, "CN=NTDS Settings,%s",
2273
s->dest_dsa.server_dn_str);
2274
if (composite_nomem(s->dest_dsa.ntds_dn_str, c)) return;
2276
c->status = becomeDC_prepare_db(s);
2277
if (!composite_is_ok(c)) return;
2279
/* this avoids the epmapper lookup on the 2nd connection */
2280
binding_str = dcerpc_binding_string(s, s->drsuapi1.binding);
2281
if (composite_nomem(binding_str, c)) return;
2283
c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi2.binding);
2284
talloc_free(binding_str);
2285
if (!composite_is_ok(c)) return;
2287
/* w2k3 uses the same assoc_group_id as on the first connection, so we do */
2288
s->drsuapi2.binding->assoc_group_id = s->drsuapi1.pipe->assoc_group_id;
2290
becomeDC_drsuapi_connect_send(s, &s->drsuapi2, becomeDC_drsuapi2_connect_recv);
2293
static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s)
2295
if (!s->callbacks.prepare_db) return NT_STATUS_OK;
2297
s->_pp.domain = &s->domain;
2298
s->_pp.forest = &s->forest;
2299
s->_pp.source_dsa = &s->source_dsa;
2300
s->_pp.dest_dsa = &s->dest_dsa;
2302
return s->callbacks.prepare_db(s->callbacks.private_data, &s->_pp);
2305
static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req);
2307
static void becomeDC_drsuapi2_connect_recv(struct composite_context *req)
2309
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
2310
struct libnet_BecomeDC_state);
2311
struct composite_context *c = s->creq;
2313
c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi2.pipe);
2314
if (!composite_is_ok(c)) return;
2316
c->status = gensec_session_key(s->drsuapi2.pipe->conn->security_state.generic_state,
2317
&s->drsuapi2.gensec_skey);
2318
if (!composite_is_ok(c)) return;
2320
becomeDC_drsuapi_bind_send(s, &s->drsuapi2, becomeDC_drsuapi2_bind_recv);
2323
static void becomeDC_drsuapi3_connect_recv(struct composite_context *req);
2325
static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req)
2327
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
2328
struct libnet_BecomeDC_state);
2329
struct composite_context *c = s->creq;
2335
if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
2339
c->status = dcerpc_ndr_request_recv(req);
2340
if (!composite_is_ok(c)) return;
2343
NDR_PRINT_OUT_DEBUG(drsuapi_DsBind, &s->drsuapi2.bind_r);
2346
status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi2);
2347
if (!W_ERROR_IS_OK(status)) {
2348
composite_error(c, werror_to_ntstatus(status));
2352
/* this avoids the epmapper lookup on the 3rd connection */
2353
binding_str = dcerpc_binding_string(s, s->drsuapi1.binding);
2354
if (composite_nomem(binding_str, c)) return;
2356
c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi3.binding);
2357
talloc_free(binding_str);
2358
if (!composite_is_ok(c)) return;
2360
/* w2k3 uses the same assoc_group_id as on the first connection, so we do */
2361
s->drsuapi3.binding->assoc_group_id = s->drsuapi1.pipe->assoc_group_id;
2362
/* w2k3 uses the concurrent multiplex feature on the 3rd connection, so we do */
2363
s->drsuapi3.binding->flags |= DCERPC_CONCURRENT_MULTIPLEX;
2365
becomeDC_drsuapi_connect_send(s, &s->drsuapi3, becomeDC_drsuapi3_connect_recv);
2368
static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s);
2370
static void becomeDC_drsuapi3_connect_recv(struct composite_context *req)
2372
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
2373
struct libnet_BecomeDC_state);
2374
struct composite_context *c = s->creq;
2376
c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi3.pipe);
2377
if (!composite_is_ok(c)) return;
2379
c->status = gensec_session_key(s->drsuapi3.pipe->conn->security_state.generic_state,
2380
&s->drsuapi3.gensec_skey);
2381
if (!composite_is_ok(c)) return;
2383
becomeDC_drsuapi3_pull_schema_send(s);
2386
static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s,
2387
struct becomeDC_drsuapi *drsuapi_h,
2388
struct becomeDC_drsuapi *drsuapi_p,
2389
struct libnet_BecomeDC_Partition *partition,
2390
void (*recv_fn)(struct rpc_request *req))
2392
struct composite_context *c = s->creq;
2393
struct rpc_request *req;
2394
struct drsuapi_DsGetNCChanges *r;
2396
r = talloc(s, struct drsuapi_DsGetNCChanges);
2397
if (composite_nomem(r, c)) return;
2399
r->out.level_out = talloc(r, int32_t);
2400
if (composite_nomem(r->out.level_out, c)) return;
2401
r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
2402
if (composite_nomem(r->in.req, c)) return;
2403
r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
2404
if (composite_nomem(r->out.ctr, c)) return;
2406
r->in.bind_handle = &drsuapi_h->bind_handle;
2407
if (drsuapi_h->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
2409
r->in.req->req8.destination_dsa_guid = partition->destination_dsa_guid;
2410
r->in.req->req8.source_dsa_invocation_id= partition->source_dsa_invocation_id;
2411
r->in.req->req8.naming_context = &partition->nc;
2412
r->in.req->req8.highwatermark = partition->highwatermark;
2413
r->in.req->req8.uptodateness_vector = NULL;
2414
r->in.req->req8.replica_flags = partition->replica_flags;
2415
r->in.req->req8.max_object_count = 133;
2416
r->in.req->req8.max_ndr_size = 1336811;
2417
r->in.req->req8.extended_op = DRSUAPI_EXOP_NONE;
2418
r->in.req->req8.fsmo_info = 0;
2419
r->in.req->req8.partial_attribute_set = NULL;
2420
r->in.req->req8.partial_attribute_set_ex= NULL;
2421
r->in.req->req8.mapping_ctr.num_mappings= 0;
2422
r->in.req->req8.mapping_ctr.mappings = NULL;
2425
r->in.req->req5.destination_dsa_guid = partition->destination_dsa_guid;
2426
r->in.req->req5.source_dsa_invocation_id= partition->source_dsa_invocation_id;
2427
r->in.req->req5.naming_context = &partition->nc;
2428
r->in.req->req5.highwatermark = partition->highwatermark;
2429
r->in.req->req5.uptodateness_vector = NULL;
2430
r->in.req->req5.replica_flags = partition->replica_flags;
2431
r->in.req->req5.max_object_count = 133;
2432
r->in.req->req5.max_ndr_size = 1336770;
2433
r->in.req->req5.extended_op = DRSUAPI_EXOP_NONE;
2434
r->in.req->req5.fsmo_info = 0;
2438
* we should try to use the drsuapi_p->pipe here, as w2k3 does
2439
* but it seems that some extra flags in the DCERPC Bind call
2440
* are needed for it. Or the same KRB5 TGS is needed on both
2443
req = dcerpc_drsuapi_DsGetNCChanges_send(drsuapi_p->pipe, r, r);
2444
composite_continue_rpc(c, req, recv_fn, s);
2447
static WERROR becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state *s,
2448
struct becomeDC_drsuapi *drsuapi_h,
2449
struct becomeDC_drsuapi *drsuapi_p,
2450
struct libnet_BecomeDC_Partition *partition,
2451
struct drsuapi_DsGetNCChanges *r)
2453
uint32_t ctr_level = 0;
2454
struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
2455
struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
2456
struct GUID *source_dsa_guid;
2457
struct GUID *source_dsa_invocation_id;
2458
struct drsuapi_DsReplicaHighWaterMark *new_highwatermark;
2459
bool more_data = false;
2462
if (!W_ERROR_IS_OK(r->out.result)) {
2463
return r->out.result;
2466
if (*r->out.level_out == 1) {
2468
ctr1 = &r->out.ctr->ctr1;
2469
} else if (*r->out.level_out == 2 &&
2470
r->out.ctr->ctr2.mszip1.ts) {
2472
ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
2473
} else if (*r->out.level_out == 6) {
2475
ctr6 = &r->out.ctr->ctr6;
2476
} else if (*r->out.level_out == 7 &&
2477
r->out.ctr->ctr7.level == 6 &&
2478
r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
2479
r->out.ctr->ctr7.ctr.mszip6.ts) {
2481
ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
2482
} else if (*r->out.level_out == 7 &&
2483
r->out.ctr->ctr7.level == 6 &&
2484
r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
2485
r->out.ctr->ctr7.ctr.xpress6.ts) {
2487
ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
2489
return WERR_BAD_NET_RESP;
2492
if (!ctr1 && ! ctr6) {
2493
return WERR_BAD_NET_RESP;
2496
if (ctr_level == 6) {
2497
if (!W_ERROR_IS_OK(ctr6->drs_error)) {
2498
return ctr6->drs_error;
2502
switch (ctr_level) {
2504
source_dsa_guid = &ctr1->source_dsa_guid;
2505
source_dsa_invocation_id = &ctr1->source_dsa_invocation_id;
2506
new_highwatermark = &ctr1->new_highwatermark;
2507
more_data = ctr1->more_data;
2510
source_dsa_guid = &ctr6->source_dsa_guid;
2511
source_dsa_invocation_id = &ctr6->source_dsa_invocation_id;
2512
new_highwatermark = &ctr6->new_highwatermark;
2513
more_data = ctr6->more_data;
2517
partition->highwatermark = *new_highwatermark;
2518
partition->source_dsa_guid = *source_dsa_guid;
2519
partition->source_dsa_invocation_id = *source_dsa_invocation_id;
2520
partition->more_data = more_data;
2522
if (!partition->store_chunk) return WERR_OK;
2524
s->_sc.domain = &s->domain;
2525
s->_sc.forest = &s->forest;
2526
s->_sc.source_dsa = &s->source_dsa;
2527
s->_sc.dest_dsa = &s->dest_dsa;
2528
s->_sc.partition = partition;
2529
s->_sc.ctr_level = ctr_level;
2533
* we need to use the drsuapi_p->gensec_skey here,
2534
* when we use drsuapi_p->pipe in the for this request
2536
s->_sc.gensec_skey = &drsuapi_p->gensec_skey;
2538
nt_status = partition->store_chunk(s->callbacks.private_data, &s->_sc);
2539
if (!NT_STATUS_IS_OK(nt_status)) {
2540
return ntstatus_to_werror(nt_status);
2546
static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req);
2548
static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s)
2550
s->schema_part.nc.guid = GUID_zero();
2551
s->schema_part.nc.sid = s->zero_sid;
2552
s->schema_part.nc.dn = s->forest.schema_dn_str;
2554
s->schema_part.destination_dsa_guid = s->drsuapi2.bind_guid;
2556
s->schema_part.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
2557
| DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
2558
| DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
2559
| DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
2560
| DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
2561
| DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
2563
s->schema_part.store_chunk = s->callbacks.schema_chunk;
2565
becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part,
2566
becomeDC_drsuapi3_pull_schema_recv);
2569
static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s);
2571
static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req)
2573
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
2574
struct libnet_BecomeDC_state);
2575
struct composite_context *c = s->creq;
2576
struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
2577
struct drsuapi_DsGetNCChanges);
2582
if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
2586
c->status = dcerpc_ndr_request_recv(req);
2587
if (!composite_is_ok(c)) return;
2590
NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r);
2593
status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part, r);
2594
if (!W_ERROR_IS_OK(status)) {
2595
composite_error(c, werror_to_ntstatus(status));
2601
if (s->schema_part.more_data) {
2602
becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part,
2603
becomeDC_drsuapi3_pull_schema_recv);
2607
becomeDC_drsuapi3_pull_config_send(s);
2610
static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req);
2612
static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s)
2614
s->config_part.nc.guid = GUID_zero();
2615
s->config_part.nc.sid = s->zero_sid;
2616
s->config_part.nc.dn = s->forest.config_dn_str;
2618
s->config_part.destination_dsa_guid = s->drsuapi2.bind_guid;
2620
s->config_part.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
2621
| DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
2622
| DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
2623
| DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
2624
| DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
2625
| DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
2627
s->config_part.store_chunk = s->callbacks.config_chunk;
2629
becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part,
2630
becomeDC_drsuapi3_pull_config_recv);
2633
static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req)
2635
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
2636
struct libnet_BecomeDC_state);
2637
struct composite_context *c = s->creq;
2638
struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
2639
struct drsuapi_DsGetNCChanges);
2644
if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
2648
c->status = dcerpc_ndr_request_recv(req);
2649
if (!composite_is_ok(c)) return;
2652
NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r);
2655
status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->config_part, r);
2656
if (!W_ERROR_IS_OK(status)) {
2657
composite_error(c, werror_to_ntstatus(status));
2663
if (s->config_part.more_data) {
2664
becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part,
2665
becomeDC_drsuapi3_pull_config_recv);
2669
becomeDC_connect_ldap2(s);
2672
static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req);
2674
static void becomeDC_drsuapi3_pull_domain_send(struct libnet_BecomeDC_state *s)
2676
s->domain_part.nc.guid = GUID_zero();
2677
s->domain_part.nc.sid = s->zero_sid;
2678
s->domain_part.nc.dn = s->domain.dn_str;
2680
s->domain_part.destination_dsa_guid = s->drsuapi2.bind_guid;
2682
s->domain_part.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
2683
| DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
2684
| DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
2685
| DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
2686
| DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
2687
| DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
2689
s->domain_part.store_chunk = s->callbacks.domain_chunk;
2691
becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part,
2692
becomeDC_drsuapi3_pull_domain_recv);
2695
static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s,
2696
struct becomeDC_drsuapi *drsuapi,
2697
struct libnet_BecomeDC_Partition *partition,
2698
void (*recv_fn)(struct rpc_request *req));
2699
static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req);
2701
static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req)
2703
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
2704
struct libnet_BecomeDC_state);
2705
struct composite_context *c = s->creq;
2706
struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
2707
struct drsuapi_DsGetNCChanges);
2711
if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
2715
c->status = dcerpc_ndr_request_recv(req);
2716
if (!composite_is_ok(c)) return;
2719
NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r);
2722
status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part, r);
2723
if (!W_ERROR_IS_OK(status)) {
2724
composite_error(c, werror_to_ntstatus(status));
2730
if (s->domain_part.more_data) {
2731
becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part,
2732
becomeDC_drsuapi3_pull_domain_recv);
2736
becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->schema_part,
2737
becomeDC_drsuapi2_update_refs_schema_recv);
2740
static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s,
2741
struct becomeDC_drsuapi *drsuapi,
2742
struct libnet_BecomeDC_Partition *partition,
2743
void (*recv_fn)(struct rpc_request *req))
2745
struct composite_context *c = s->creq;
2746
struct rpc_request *req;
2747
struct drsuapi_DsReplicaUpdateRefs *r;
2748
const char *ntds_guid_str;
2749
const char *ntds_dns_name;
2751
r = talloc(s, struct drsuapi_DsReplicaUpdateRefs);
2752
if (composite_nomem(r, c)) return;
2754
ntds_guid_str = GUID_string(r, &s->dest_dsa.ntds_guid);
2755
if (composite_nomem(ntds_guid_str, c)) return;
2757
ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
2759
s->domain.dns_name);
2760
if (composite_nomem(ntds_dns_name, c)) return;
2762
r->in.bind_handle = &drsuapi->bind_handle;
2764
r->in.req.req1.naming_context = &partition->nc;
2765
r->in.req.req1.dest_dsa_dns_name= ntds_dns_name;
2766
r->in.req.req1.dest_dsa_guid = s->dest_dsa.ntds_guid;
2767
r->in.req.req1.options = DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE
2768
| DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE
2769
| DRSUAPI_DS_REPLICA_UPDATE_0x00000010;
2771
req = dcerpc_drsuapi_DsReplicaUpdateRefs_send(drsuapi->pipe, r, r);
2772
composite_continue_rpc(c, req, recv_fn, s);
2775
static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req);
2777
static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req)
2779
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
2780
struct libnet_BecomeDC_state);
2781
struct composite_context *c = s->creq;
2782
struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
2783
struct drsuapi_DsReplicaUpdateRefs);
2786
if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
2790
c->status = dcerpc_ndr_request_recv(req);
2791
if (!composite_is_ok(c)) return;
2794
NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaUpdateRefs, r);
2797
if (!W_ERROR_IS_OK(r->out.result)) {
2798
composite_error(c, werror_to_ntstatus(r->out.result));
2804
becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->config_part,
2805
becomeDC_drsuapi2_update_refs_config_recv);
2808
static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req);
2810
static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req)
2812
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
2813
struct libnet_BecomeDC_state);
2814
struct composite_context *c = s->creq;
2815
struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
2816
struct drsuapi_DsReplicaUpdateRefs);
2818
c->status = dcerpc_ndr_request_recv(req);
2819
if (!composite_is_ok(c)) return;
2821
if (!W_ERROR_IS_OK(r->out.result)) {
2822
composite_error(c, werror_to_ntstatus(r->out.result));
2828
becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->domain_part,
2829
becomeDC_drsuapi2_update_refs_domain_recv);
2832
static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req)
2834
struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
2835
struct libnet_BecomeDC_state);
2836
struct composite_context *c = s->creq;
2837
struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
2838
struct drsuapi_DsReplicaUpdateRefs);
2840
c->status = dcerpc_ndr_request_recv(req);
2841
if (!composite_is_ok(c)) return;
2843
if (!W_ERROR_IS_OK(r->out.result)) {
2844
composite_error(c, werror_to_ntstatus(r->out.result));
2850
/* TODO: use DDNS updates and register dns names */
2854
static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s)
2857
struct ldb_message *msg;
2859
uint32_t user_account_control = UF_SERVER_TRUST_ACCOUNT |
2860
UF_TRUSTED_FOR_DELEGATION;
2862
/* as the value is already as we want it to be, we're done */
2863
if (s->dest_dsa.user_account_control == user_account_control) {
2864
return NT_STATUS_OK;
2867
/* make a 'modify' msg, and only for serverReference */
2868
msg = ldb_msg_new(s);
2869
NT_STATUS_HAVE_NO_MEMORY(msg);
2870
msg->dn = ldb_dn_new(msg, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
2871
NT_STATUS_HAVE_NO_MEMORY(msg->dn);
2873
ret = ldb_msg_add_fmt(msg, "userAccountControl", "%u", user_account_control);
2876
return NT_STATUS_NO_MEMORY;
2879
/* mark all the message elements (should be just one)
2880
as LDB_FLAG_MOD_REPLACE */
2881
for (i=0;i<msg->num_elements;i++) {
2882
msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2885
ret = ldb_modify(s->ldap2.ldb, msg);
2887
if (ret != LDB_SUCCESS) {
2888
return NT_STATUS_LDAP(ret);
2891
s->dest_dsa.user_account_control = user_account_control;
2893
return NT_STATUS_OK;
2896
static NTSTATUS becomeDC_ldap2_move_computer(struct libnet_BecomeDC_state *s)
2899
struct ldb_result *r;
2900
struct ldb_dn *basedn;
2901
struct ldb_dn *old_dn;
2902
struct ldb_dn *new_dn;
2903
static const char *_1_1_attrs[] = {
2908
basedn = ldb_dn_new_fmt(s, s->ldap2.ldb, "<WKGUID=a361b2ffffd211d1aa4b00c04fd7d83a,%s>",
2910
NT_STATUS_HAVE_NO_MEMORY(basedn);
2912
ret = ldb_search(s->ldap2.ldb, s, &r, basedn, LDB_SCOPE_BASE,
2913
_1_1_attrs, "(objectClass=*)");
2914
talloc_free(basedn);
2915
if (ret != LDB_SUCCESS) {
2916
return NT_STATUS_LDAP(ret);
2917
} else if (r->count != 1) {
2919
return NT_STATUS_INVALID_NETWORK_RESPONSE;
2922
old_dn = ldb_dn_new(r, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
2923
NT_STATUS_HAVE_NO_MEMORY(old_dn);
2925
new_dn = r->msgs[0]->dn;
2927
if (!ldb_dn_add_child_fmt(new_dn, "CN=%s", s->dest_dsa.netbios_name)) {
2929
return NT_STATUS_NO_MEMORY;
2932
if (ldb_dn_compare(old_dn, new_dn) == 0) {
2933
/* we don't need to rename if the old and new dn match */
2935
return NT_STATUS_OK;
2938
ret = ldb_rename(s->ldap2.ldb, old_dn, new_dn);
2939
if (ret != LDB_SUCCESS) {
2941
return NT_STATUS_LDAP(ret);
2944
s->dest_dsa.computer_dn_str = ldb_dn_alloc_linearized(s, new_dn);
2945
NT_STATUS_HAVE_NO_MEMORY(s->dest_dsa.computer_dn_str);
2949
return NT_STATUS_OK;
2952
static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s)
2954
struct composite_context *c = s->creq;
2956
c->status = becomeDC_ldap_connect(s, &s->ldap2);
2957
if (!composite_is_ok(c)) return;
2959
c->status = becomeDC_ldap2_modify_computer(s);
2960
if (!composite_is_ok(c)) return;
2962
c->status = becomeDC_ldap2_move_computer(s);
2963
if (!composite_is_ok(c)) return;
2965
becomeDC_drsuapi3_pull_domain_send(s);
2968
struct composite_context *libnet_BecomeDC_send(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
2970
struct composite_context *c;
2971
struct libnet_BecomeDC_state *s;
2974
c = composite_create(mem_ctx, ctx->event_ctx);
2975
if (c == NULL) return NULL;
2977
s = talloc_zero(c, struct libnet_BecomeDC_state);
2978
if (composite_nomem(s, c)) return c;
2979
c->private_data = s;
2984
s->domain.dns_name = talloc_strdup(s, r->in.domain_dns_name);
2985
if (composite_nomem(s->domain.dns_name, c)) return c;
2986
s->domain.netbios_name = talloc_strdup(s, r->in.domain_netbios_name);
2987
if (composite_nomem(s->domain.netbios_name, c)) return c;
2988
s->domain.sid = dom_sid_dup(s, r->in.domain_sid);
2989
if (composite_nomem(s->domain.sid, c)) return c;
2991
/* Source DSA input */
2992
s->source_dsa.address = talloc_strdup(s, r->in.source_dsa_address);
2993
if (composite_nomem(s->source_dsa.address, c)) return c;
2995
/* Destination DSA input */
2996
s->dest_dsa.netbios_name= talloc_strdup(s, r->in.dest_dsa_netbios_name);
2997
if (composite_nomem(s->dest_dsa.netbios_name, c)) return c;
2999
/* Destination DSA dns_name construction */
3000
tmp_name = strlower_talloc(s, s->dest_dsa.netbios_name);
3001
if (composite_nomem(tmp_name, c)) return c;
3002
tmp_name = talloc_asprintf_append_buffer(tmp_name, ".%s",s->domain.dns_name);
3003
if (composite_nomem(tmp_name, c)) return c;
3004
s->dest_dsa.dns_name = tmp_name;
3006
/* Callback function pointers */
3007
s->callbacks = r->in.callbacks;
3009
becomeDC_send_cldap(s);
3013
NTSTATUS libnet_BecomeDC_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
3017
status = composite_wait(c);
3019
ZERO_STRUCT(r->out);
3025
NTSTATUS libnet_BecomeDC(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
3028
struct composite_context *c;
3029
c = libnet_BecomeDC_send(ctx, mem_ctx, r);
3030
status = libnet_BecomeDC_recv(c, mem_ctx, r);