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 "source3/libads/netlogon_ping.h"
26 #include <ldb_errors.h>
28 #include "dsdb/samdb/samdb.h"
29 #include "../libds/common/flags.h"
30 #include "librpc/gen_ndr/ndr_drsuapi_c.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_misc.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "librpc/gen_ndr/ndr_nbt.h"
35 #include "librpc/gen_ndr/ndr_drsuapi.h"
36 #include "auth/gensec/gensec.h"
37 #include "param/param.h"
38 #include "lib/tsocket/tsocket.h"
40 /*****************************************************************************
41 * Windows 2003 (w2k3) does the following steps when changing the server role
42 * from domain member to domain controller
44 * We mostly do the same.
45 *****************************************************************************/
49 * - using nbt name<1C> request and a samlogon mailslot request
51 * - using a DNS SRV _ldap._tcp.dc._msdcs. request and a CLDAP netlogon request
53 * see: becomeDC_recv_cldap() and becomeDC_send_cldap()
57 * Open 1st LDAP connection to the DC using admin credentials
59 * see: becomeDC_connect_ldap1() and becomeDC_ldap_connect()
63 * LDAP search 1st LDAP connection:
65 * see: becomeDC_ldap1_rootdse()
70 * filter: (objectClass=*)
74 * currentTime: 20061202155100.0Z
75 * subschemaSubentry: CN=Aggregate,CN=Schema,CN=Configuration,<domain_partition>
76 * dsServiceName: CN=<netbios_name>,CN=Servers,CN=<site_name>,CN=Sites,CN=Configuration,<domain_partition>
77 * namingContexts: <domain_partition>
78 * CN=Configuration,<domain_partition>
79 * CN=Schema,CN=Configuration,<domain_partition>
80 * defaultNamingContext: <domain_partition>
81 * schemaNamingContext: CN=Schema,CN=Configuration,<domain_partition>
82 * configurationNamingContext:CN=Configuration,<domain_partition>
83 * rootDomainNamingContext:<domain_partition>
84 * supportedControl: ...
85 * supportedLDAPVersion: 3
87 * supportedLDAPPolicies: ...
88 * highestCommittedUSN: ...
89 * supportedSASLMechanisms:GSSAPI
93 * dnsHostName: <dns_host_name>
94 * ldapServiceName: <domain_dns_name>:<netbios_name>$@<REALM>
95 * serverName: CN=Servers,CN=<site_name>,CN=Sites,CN=Configuration,<domain_partition>
96 * supportedCapabilities: ...
97 * isSynchronized: TRUE
98 * isGlobalCatalogReady: TRUE
99 * domainFunctionality: 0
100 * forestFunctionality: 0
101 * domainControllerFunctionality: 2
105 * LDAP search 1st LDAP connection:
107 * see: becomeDC_ldap1_crossref_behavior_version()
110 * basedn: CN=Configuration,<domain_partition>
112 * filter: (cn=Partitions)
113 * attrs: msDS-Behavior-Version
115 * CN=Partitions,CN=Configuration,<domain_partition>
116 * msDS-Behavior-Version: 0
120 * LDAP search 1st LDAP connection:
122 * NOTE: this seems to be a bug! as the messageID of the LDAP message is corrupted!
124 * not implemented here
127 * basedn: CN=Schema,CN=Configuration,<domain_partition>
129 * filter: (cn=Partitions)
130 * attrs: msDS-Behavior-Version
137 * LDAP search 1st LDAP connection:
139 * see: becomeDC_ldap1_domain_behavior_version()
142 * basedn: <domain_partition>
144 * filter: (objectClass=*)
145 * attrs: msDS-Behavior-Version
148 * msDS-Behavior-Version: 0
152 * LDAP search 1st LDAP connection:
154 * see: becomeDC_ldap1_schema_object_version()
157 * basedn: CN=Schema,CN=Configuration,<domain_partition>
159 * filter: (objectClass=*)
160 * attrs: objectVersion
162 * CN=Schema,CN=Configuration,<domain_partition>
167 * LDAP search 1st LDAP connection:
169 * not implemented, because the information is already there
174 * filter: (objectClass=*)
175 * attrs: defaultNamingContext
179 * defaultNamingContext: <domain_partition>
180 * dnsHostName: <dns_host_name>
184 * LDAP search 1st LDAP connection:
186 * see: becomeDC_ldap1_infrastructure_fsmo()
189 * basedn: <WKGUID=2fbac1870ade11d297c400c04fd8d5cd,domain_partition>
191 * filter: (objectClass=*)
194 * CN=Infrastructure,<domain_partition>
198 * LDAP search 1st LDAP connection:
200 * see: becomeDC_ldap1_w2k3_update_revision()
203 * basedn: CN=Windows2003Update,CN=DomainUpdates,CN=System,<domain_partition>
205 * filter: (objectClass=*)
208 * CN=Windows2003Update,CN=DomainUpdates,CN=System,<domain_partition>
213 * LDAP search 1st LDAP connection:
215 * see: becomeDC_ldap1_infrastructure_fsmo()
218 * basedn: CN=Infrastructure,<domain_partition>
220 * filter: (objectClass=*)
221 * attrs: fSMORoleOwner
223 * CN=Infrastructure,<domain_partition>
224 * fSMORoleOwner: CN=NTDS Settings,<infrastructure_fsmo_server_object>
228 * LDAP search 1st LDAP connection:
230 * see: becomeDC_ldap1_infrastructure_fsmo()
233 * basedn: <infrastructure_fsmo_server_object>
235 * filter: (objectClass=*)
238 * <infrastructure_fsmo_server_object>
239 * dnsHostName: <dns_host_name>
243 * LDAP search 1st LDAP connection:
245 * see: becomeDC_ldap1_infrastructure_fsmo()
248 * basedn: CN=NTDS Settings,<infrastructure_fsmo_server_object>
250 * filter: (objectClass=*)
253 * CN=NTDS Settings,<infrastructure_fsmo_server_object>
254 * objectGUID: <object_guid>
258 * LDAP search 1st LDAP connection:
260 * see: becomeDC_ldap1_rid_manager_fsmo()
263 * basedn: <domain_partition>
265 * filter: (objectClass=*)
266 * attrs: rIDManagerReference
269 * rIDManagerReference: CN=RID Manager$,CN=System,<domain_partition>
273 * LDAP search 1st LDAP connection:
275 * see: becomeDC_ldap1_rid_manager_fsmo()
278 * basedn: CN=RID Manager$,CN=System,<domain_partition>
280 * filter: (objectClass=*)
281 * attrs: fSMORoleOwner
283 * CN=Infrastructure,<domain_partition>
284 * fSMORoleOwner: CN=NTDS Settings,<rid_manager_fsmo_server_object>
288 * LDAP search 1st LDAP connection:
290 * see: becomeDC_ldap1_rid_manager_fsmo()
293 * basedn: <rid_manager_fsmo_server_object>
295 * filter: (objectClass=*)
298 * <rid_manager_fsmo_server_object>
299 * dnsHostName: <dns_host_name>
303 * LDAP search 1st LDAP connection:
305 * see: becomeDC_ldap1_rid_manager_fsmo()
308 * basedn: CN=NTDS Settings,<rid_manager_fsmo_server_object>
310 * filter: (objectClass=*)
311 * attrs: msDs-ReplicationEpoch
313 * CN=NTDS Settings,<rid_manager_fsmo_server_object>
317 * LDAP search 1st LDAP connection:
319 * see: becomeDC_ldap1_site_object()
322 * basedn: CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
324 * filter: (objectClass=*)
327 * CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
330 * cn: <new_dc_site_name>
331 * distinguishedName:CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
337 * showInAdvancedViewOnly: TRUE
338 * name: <new_dc_site_name>
339 * objectGUID: <object_guid>
340 * systemFlags: 1107296256 <0x42000000>
341 * objectCategory: CN=Site,CN=Schema,CN=Configuration,<domain_partition>
344 /***************************************************************
345 * Add this stage we call the check_options() callback function
346 * of the caller, to see if he wants us to continue
348 * see: becomeDC_check_options()
349 ***************************************************************/
352 * LDAP search 1st LDAP connection:
354 * see: becomeDC_ldap1_computer_object()
357 * basedn: <domain_partition>
359 * filter: (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<new_dc_account_name>))
360 * attrs: distinguishedName
363 * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
364 * distinguishedName: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
365 * userAccountControl: 4096 <0x1000>
369 * LDAP search 1st LDAP connection:
371 * see: becomeDC_ldap1_server_object_1()
374 * basedn: CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
376 * filter: (objectClass=*)
380 * <matchedDN:CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
384 * LDAP search 1st LDAP connection:
386 * see: becomeDC_ldap1_server_object_2()
389 * basedn: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
391 * filter: (objectClass=*)
392 * attrs: serverReferenceBL
395 * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
399 * LDAP add 1st LDAP connection:
401 * see: becomeDC_ldap1_server_object_add()
404 * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
405 * objectClass: server
406 * systemFlags: 50000000 <0x2FAF080>
407 * serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
413 * LDAP search 1st LDAP connection:
415 * not implemented, maybe we can add that later
418 * basedn: CN=NTDS Settings,CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
420 * filter: (objectClass=*)
424 * <matchedDN:CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
428 * LDAP search 1st LDAP connection:
430 * not implemented because it gives no new information
433 * basedn: CN=Partitions,CN=Configuration,<domain_partition>
435 * filter: (nCName=<domain_partition>)
438 * controls: LDAP_SERVER_EXTENDED_DN_OID:critical=false
440 * <GUID=<hex_guid>>;CN=<domain_netbios_name>,CN=Partitions,<domain_partition>>
441 * nCName: <GUID=<hex_guid>>;<SID=<hex_sid>>;<domain_partition>>
442 * dnsRoot: <domain_dns_name>
446 * LDAP modify 1st LDAP connection:
448 * see: becomeDC_ldap1_server_object_modify()
451 * CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
452 * serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
454 * <attributeOrValueExist>
458 * LDAP modify 1st LDAP connection:
460 * see: becomeDC_ldap1_server_object_modify()
463 * CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
464 * serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
470 * Open 1st DRSUAPI connection to the DC using admin credentials
471 * DsBind with DRSUAPI_DS_BIND_GUID_W2K3 ("6afab99c-6e26-464a-975f-f58f105218bc")
472 * (w2k3 does 2 DsBind() calls here..., where is first is unused and contains garbage at the end)
474 * see: becomeDC_drsuapi_connect_send(), becomeDC_drsuapi1_connect_recv(),
475 * becomeDC_drsuapi_bind_send(), becomeDC_drsuapi_bind_recv() and becomeDC_drsuapi1_bind_recv()
479 * DsAddEntry to create the CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
480 * on the 1st DRSUAPI connection
482 * see: becomeDC_drsuapi1_add_entry_send() and becomeDC_drsuapi1_add_entry_recv()
485 /***************************************************************
486 * Add this stage we call the prepare_db() callback function
487 * of the caller, to see if he wants us to continue
489 * see: becomeDC_prepare_db()
490 ***************************************************************/
493 * Open 2nd and 3rd DRSUAPI connection to the DC using admin credentials
494 * - a DsBind with DRSUAPI_DS_BIND_GUID_W2K3 ("6afab99c-6e26-464a-975f-f58f105218bc")
495 * on the 2nd connection
497 * see: becomeDC_drsuapi_connect_send(), becomeDC_drsuapi2_connect_recv(),
498 * becomeDC_drsuapi_bind_send(), becomeDC_drsuapi_bind_recv(), becomeDC_drsuapi2_bind_recv()
499 * and becomeDC_drsuapi3_connect_recv()
503 * replicate CN=Schema,CN=Configuration,...
504 * on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection
506 * see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(),
507 * becomeDC_drsuapi3_pull_schema_send() and becomeDC_drsuapi3_pull_schema_recv()
509 ***************************************************************
510 * Add this stage we call the schema_chunk() callback function
511 * for each replication message
512 ***************************************************************/
515 * replicate CN=Configuration,...
516 * on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection
518 * see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(),
519 * becomeDC_drsuapi3_pull_config_send() and becomeDC_drsuapi3_pull_config_recv()
521 ***************************************************************
522 * Add this stage we call the config_chunk() callback function
523 * for each replication message
524 ***************************************************************/
527 * LDAP unbind on the 1st LDAP connection
529 * not implemented, because it's not needed...
533 * Open 2nd LDAP connection to the DC using admin credentials
535 * see: becomeDC_connect_ldap2() and becomeDC_ldap_connect()
539 * LDAP search 2nd LDAP connection:
541 * not implemented because it gives no new information
542 * same as becomeDC_ldap1_computer_object()
545 * basedn: <domain_partition>
547 * filter: (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<new_dc_account_name>))
548 * attrs: distinguishedName
551 * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
552 * distinguishedName: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
553 * userAccountControl: 4096 <0x00001000>
557 * LDAP search 2nd LDAP connection:
559 * not implemented because it gives no new information
560 * same as becomeDC_ldap1_computer_object()
563 * basedn: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
565 * filter: (objectClass=*)
566 * attrs: userAccountControl
568 * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
569 * userAccountControl: 4096 <0x00001000>
573 * LDAP modify 2nd LDAP connection:
575 * see: becomeDC_ldap2_modify_computer()
578 * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
579 * userAccountControl: 532480 <0x82000>
585 * LDAP search 2nd LDAP connection:
587 * see: becomeDC_ldap2_move_computer()
590 * basedn: <WKGUID=2fbac1870ade11d297c400c04fd8d5cd,<domain_partition>>
592 * filter: (objectClass=*)
595 * CN=Domain Controllers,<domain_partition>
599 * LDAP search 2nd LDAP connection:
601 * not implemented because it gives no new information
604 * basedn: CN=Domain Controllers,<domain_partition>
606 * filter: (objectClass=*)
607 * attrs: distinguishedName
609 * CN=Domain Controller,<domain_partition>
610 * distinguishedName: CN=Domain Controllers,<domain_partition>
614 * LDAP modifyRDN 2nd LDAP connection:
616 * see: becomeDC_ldap2_move_computer()
619 * entry: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
620 * newrdn: CN=<new_dc_netbios_name>
622 * newparent: CN=Domain Controllers,<domain_partition>
628 * LDAP unbind on the 2nd LDAP connection
630 * not implemented, because it's not needed...
634 * replicate Domain Partition
635 * on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection
637 * see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(),
638 * becomeDC_drsuapi3_pull_domain_send() and becomeDC_drsuapi3_pull_domain_recv()
640 ***************************************************************
641 * Add this stage we call the domain_chunk() callback function
642 * for each replication message
643 ***************************************************************/
645 /* call DsReplicaUpdateRefs() for all partitions like this:
646 * req1: struct drsuapi_DsReplicaUpdateRefsRequest1
648 * naming_context: struct drsuapi_DsReplicaObjectIdentifier
649 * __ndr_size : 0x000000ae (174)
650 * __ndr_size_sid : 0x00000000 (0)
651 * guid : 00000000-0000-0000-0000-000000000000
653 * dn : 'CN=Schema,CN=Configuration,DC=w2k3,DC=vmnet1,DC=vm,DC=base'
655 * dest_dsa_dns_name : '4a0df188-a0b8-47ea-bbe5-e614723f16dd._msdcs.w2k3.vmnet1.vm.base'
656 * dest_dsa_guid : 4a0df188-a0b8-47ea-bbe5-e614723f16dd
657 * options : 0x0000001c (28)
658 * 0: DRSUAPI_DS_REPLICA_UPDATE_ASYNCHRONOUS_OPERATION
659 * 0: DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE
660 * 1: DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE
661 * 1: DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE
662 * 1: DRSUAPI_DS_REPLICA_UPDATE_0x00000010
664 * 4a0df188-a0b8-47ea-bbe5-e614723f16dd is the objectGUID the DsAddEntry() returned for the
665 * CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
666 * on the 2nd!!! DRSUAPI connection
668 * see: becomeDC_drsuapi_update_refs_send(), becomeDC_drsuapi2_update_refs_schema_recv(),
669 * becomeDC_drsuapi2_update_refs_config_recv() and becomeDC_drsuapi2_update_refs_domain_recv()
673 * Windows does opens the 4th and 5th DRSUAPI connection...
674 * and does a DsBind() with the objectGUID from DsAddEntry() as bind_guid
675 * on the 4th connection
677 * and then 2 full replications of the domain partition on the 5th connection
678 * with the bind_handle from the 4th connection
680 * not implemented because it gives no new information
683 struct libnet_BecomeDC_state
{
684 struct composite_context
*creq
;
686 struct libnet_context
*libnet
;
688 struct dom_sid zero_sid
;
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 struct dcerpc_binding_handle
*drsuapi_handle
;
704 DATA_BLOB gensec_skey
;
705 struct drsuapi_DsBind bind_r
;
706 struct GUID bind_guid
;
707 struct drsuapi_DsBindInfoCtr bind_info_ctr
;
708 struct drsuapi_DsBindInfo28 local_info28
;
709 struct drsuapi_DsBindInfo28 remote_info28
;
710 struct policy_handle bind_handle
;
711 } drsuapi1
, drsuapi2
, drsuapi3
;
713 void *ndr_struct_ptr
;
715 struct libnet_BecomeDC_Domain domain
;
716 struct libnet_BecomeDC_Forest forest
;
717 struct libnet_BecomeDC_SourceDSA source_dsa
;
718 struct libnet_BecomeDC_DestDSA dest_dsa
;
720 struct libnet_BecomeDC_Partition schema_part
, config_part
, domain_part
;
722 struct becomeDC_fsmo
{
723 const char *dns_name
;
724 const char *server_dn_str
;
725 const char *ntds_dn_str
;
726 struct GUID ntds_guid
;
727 } infrastructure_fsmo
;
729 struct becomeDC_fsmo rid_manager_fsmo
;
731 struct libnet_BecomeDC_CheckOptions _co
;
732 struct libnet_BecomeDC_PrepareDB _pp
;
733 struct libnet_BecomeDC_StoreChunk _sc
;
734 struct libnet_BecomeDC_Callbacks callbacks
;
740 static int32_t get_dc_function_level(struct loadparm_context
*lp_ctx
)
742 /* per default we are (Windows) 2008 R2 compatible */
743 return lpcfg_parm_int(lp_ctx
, NULL
, "ads", "dc function level",
744 DS_DOMAIN_FUNCTION_2008_R2
);
747 static void becomeDC_recv_cldap(struct tevent_req
*req
);
749 static void becomeDC_send_cldap(struct libnet_BecomeDC_state
*s
)
751 struct composite_context
*c
= s
->creq
;
752 struct libnet_context
*libnet
= s
->libnet
;
753 struct tevent_req
*req
;
754 struct tsocket_address
*dest_address
;
757 ret
= tsocket_address_inet_from_strings(
758 s
, "ip", s
->source_dsa
.address
, 389, &dest_address
);
760 c
->status
= map_nt_error_from_unix_common(errno
);
761 if (!composite_is_ok(c
)) return;
764 req
= netlogon_pings_send(s
, /* mem_ctx */
765 libnet
->event_ctx
, /* ev */
766 lpcfg_client_netlogon_ping_protocol(
767 libnet
->lp_ctx
), /* proto */
768 &dest_address
, /* servers*/
770 (struct netlogon_ping_filter
){
771 .ntversion
= NETLOGON_NT_VERSION_5
|
772 NETLOGON_NT_VERSION_5EX
,
774 .domain
= s
->domain
.dns_name
,
775 .hostname
= s
->dest_dsa
.netbios_name
,
778 tevent_timeval_current_ofs(2,
781 if (composite_nomem(req
, c
)) return;
782 tevent_req_set_callback(req
, becomeDC_recv_cldap
, s
);
785 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state
*s
);
787 static void becomeDC_recv_cldap(struct tevent_req
*req
)
789 struct libnet_BecomeDC_state
*s
= tevent_req_callback_data(req
,
790 struct libnet_BecomeDC_state
);
791 struct composite_context
*c
= s
->creq
;
792 struct netlogon_samlogon_response
**responses
= NULL
;
793 struct netlogon_samlogon_response
*resp
= NULL
;
795 c
->status
= netlogon_pings_recv(req
, s
, &responses
);
797 if (!composite_is_ok(c
)) {
798 DBG_ERR("Failed to send, receive or parse CLDAP reply "
799 "for our host %s: %s\n",
800 s
->dest_dsa
.netbios_name
,
801 nt_errstr(c
->status
));
806 map_netlogon_samlogon_response(resp
);
807 s
->cldap
.netlogon
= resp
->data
.nt5_ex
;
809 s
->domain
.dns_name
= s
->cldap
.netlogon
.dns_domain
;
810 s
->domain
.netbios_name
= s
->cldap
.netlogon
.domain_name
;
811 s
->domain
.guid
= s
->cldap
.netlogon
.domain_uuid
;
813 s
->forest
.dns_name
= s
->cldap
.netlogon
.forest
;
815 s
->source_dsa
.dns_name
= s
->cldap
.netlogon
.pdc_dns_name
;
816 s
->source_dsa
.netbios_name
= s
->cldap
.netlogon
.pdc_name
;
817 s
->source_dsa
.site_name
= s
->cldap
.netlogon
.server_site
;
819 s
->dest_dsa
.site_name
= s
->cldap
.netlogon
.client_site
;
821 DEBUG(0,("CLDAP response: forest=%s dns=%s netbios=%s server_site=%s client_site=%s\n",
822 s
->forest
.dns_name
, s
->domain
.dns_name
, s
->domain
.netbios_name
,
823 s
->source_dsa
.site_name
, s
->dest_dsa
.site_name
));
824 if (!s
->dest_dsa
.site_name
|| (s
->dest_dsa
.site_name
[0] == '\0')) {
825 DEBUG(0,("Got empty client site - using server site name %s\n",
826 s
->source_dsa
.site_name
));
827 s
->dest_dsa
.site_name
= s
->source_dsa
.site_name
;
830 becomeDC_connect_ldap1(s
);
833 static NTSTATUS
becomeDC_ldap_connect(struct libnet_BecomeDC_state
*s
,
834 struct becomeDC_ldap
*ldap
)
838 url
= talloc_asprintf(s
, "ldap://%s/", s
->source_dsa
.dns_name
);
839 NT_STATUS_HAVE_NO_MEMORY(url
);
841 ldap
->ldb
= ldb_wrap_connect(s
, s
->libnet
->event_ctx
, s
->libnet
->lp_ctx
, url
,
846 if (ldap
->ldb
== NULL
) {
847 return NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
853 static NTSTATUS
becomeDC_ldap1_rootdse(struct libnet_BecomeDC_state
*s
)
856 struct ldb_result
*r
;
857 struct ldb_dn
*basedn
;
858 static const char *attrs
[] = {
863 basedn
= ldb_dn_new(s
, s
->ldap1
.ldb
, NULL
);
864 NT_STATUS_HAVE_NO_MEMORY(basedn
);
866 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, basedn
, LDB_SCOPE_BASE
, 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
->ldap1
.rootdse
= r
->msgs
[0];
878 s
->domain
.dn_str
= ldb_msg_find_attr_as_string(s
->ldap1
.rootdse
, "defaultNamingContext", NULL
);
879 if (!s
->domain
.dn_str
) return NT_STATUS_INVALID_NETWORK_RESPONSE
;
881 s
->forest
.root_dn_str
= ldb_msg_find_attr_as_string(s
->ldap1
.rootdse
, "rootDomainNamingContext", NULL
);
882 if (!s
->forest
.root_dn_str
) return NT_STATUS_INVALID_NETWORK_RESPONSE
;
883 s
->forest
.config_dn_str
= ldb_msg_find_attr_as_string(s
->ldap1
.rootdse
, "configurationNamingContext", NULL
);
884 if (!s
->forest
.config_dn_str
) return NT_STATUS_INVALID_NETWORK_RESPONSE
;
885 s
->forest
.schema_dn_str
= ldb_msg_find_attr_as_string(s
->ldap1
.rootdse
, "schemaNamingContext", NULL
);
886 if (!s
->forest
.schema_dn_str
) return NT_STATUS_INVALID_NETWORK_RESPONSE
;
888 s
->source_dsa
.server_dn_str
= ldb_msg_find_attr_as_string(s
->ldap1
.rootdse
, "serverName", NULL
);
889 if (!s
->source_dsa
.server_dn_str
) return NT_STATUS_INVALID_NETWORK_RESPONSE
;
890 s
->source_dsa
.ntds_dn_str
= ldb_msg_find_attr_as_string(s
->ldap1
.rootdse
, "dsServiceName", NULL
);
891 if (!s
->source_dsa
.ntds_dn_str
) return NT_STATUS_INVALID_NETWORK_RESPONSE
;
896 static NTSTATUS
becomeDC_ldap1_crossref_behavior_version(struct libnet_BecomeDC_state
*s
)
899 struct ldb_result
*r
;
900 struct ldb_dn
*basedn
;
901 static const char *attrs
[] = {
902 "msDs-Behavior-Version",
906 basedn
= ldb_dn_new(s
, s
->ldap1
.ldb
, s
->forest
.config_dn_str
);
907 NT_STATUS_HAVE_NO_MEMORY(basedn
);
909 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, basedn
, LDB_SCOPE_ONELEVEL
, attrs
,
912 if (ret
!= LDB_SUCCESS
) {
913 return NT_STATUS_LDAP(ret
);
914 } else if (r
->count
!= 1) {
916 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
919 s
->forest
.crossref_behavior_version
= ldb_msg_find_attr_as_uint(r
->msgs
[0], "msDs-Behavior-Version", 0);
920 if (s
->forest
.crossref_behavior_version
>
921 get_dc_function_level(s
->libnet
->lp_ctx
)) {
923 DEBUG(0,("The servers function level %u is above 'ads:dc function level' of %u\n",
924 s
->forest
.crossref_behavior_version
,
925 get_dc_function_level(s
->libnet
->lp_ctx
)));
926 return NT_STATUS_NOT_SUPPORTED
;
933 static NTSTATUS
becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_state
*s
)
936 struct ldb_result
*r
;
937 struct ldb_dn
*basedn
;
938 static const char *attrs
[] = {
939 "msDs-Behavior-Version",
943 basedn
= ldb_dn_new(s
, s
->ldap1
.ldb
, s
->domain
.dn_str
);
944 NT_STATUS_HAVE_NO_MEMORY(basedn
);
946 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, basedn
, LDB_SCOPE_BASE
, attrs
,
949 if (ret
!= LDB_SUCCESS
) {
950 return NT_STATUS_LDAP(ret
);
951 } else if (r
->count
!= 1) {
953 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
956 s
->domain
.behavior_version
= ldb_msg_find_attr_as_uint(r
->msgs
[0], "msDs-Behavior-Version", 0);
957 if (s
->domain
.behavior_version
>
958 get_dc_function_level(s
->libnet
->lp_ctx
)) {
960 DEBUG(0,("The servers function level %u is above 'ads:dc function level' of %u\n",
961 s
->forest
.crossref_behavior_version
,
962 get_dc_function_level(s
->libnet
->lp_ctx
)));
963 return NT_STATUS_NOT_SUPPORTED
;
970 static NTSTATUS
becomeDC_ldap1_schema_object_version(struct libnet_BecomeDC_state
*s
)
973 struct ldb_result
*r
;
974 struct ldb_dn
*basedn
;
975 static const char *attrs
[] = {
980 basedn
= ldb_dn_new(s
, s
->ldap1
.ldb
, s
->forest
.schema_dn_str
);
981 NT_STATUS_HAVE_NO_MEMORY(basedn
);
983 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, basedn
, LDB_SCOPE_BASE
, attrs
,
986 if (ret
!= LDB_SUCCESS
) {
987 return NT_STATUS_LDAP(ret
);
988 } else if (r
->count
!= 1) {
990 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
993 s
->forest
.schema_object_version
= ldb_msg_find_attr_as_uint(r
->msgs
[0], "objectVersion", 0);
999 static NTSTATUS
becomeDC_ldap1_w2k3_update_revision(struct libnet_BecomeDC_state
*s
)
1002 struct ldb_result
*r
;
1003 struct ldb_dn
*basedn
;
1004 static const char *attrs
[] = {
1009 basedn
= ldb_dn_new_fmt(s
, s
->ldap1
.ldb
, "CN=Windows2003Update,CN=DomainUpdates,CN=System,%s",
1011 NT_STATUS_HAVE_NO_MEMORY(basedn
);
1013 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, basedn
, LDB_SCOPE_BASE
, attrs
,
1015 talloc_free(basedn
);
1016 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
1017 /* w2k doesn't have this object */
1018 s
->domain
.w2k3_update_revision
= 0;
1019 return NT_STATUS_OK
;
1020 } else if (ret
!= LDB_SUCCESS
) {
1021 return NT_STATUS_LDAP(ret
);
1022 } else if (r
->count
!= 1) {
1024 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1027 s
->domain
.w2k3_update_revision
= ldb_msg_find_attr_as_uint(r
->msgs
[0], "revision", 0);
1030 return NT_STATUS_OK
;
1033 static NTSTATUS
becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state
*s
)
1036 struct ldb_result
*r
;
1037 struct ldb_dn
*basedn
;
1038 struct ldb_dn
*ntds_dn
;
1039 struct ldb_dn
*server_dn
;
1040 static const char *dns_attrs
[] = {
1044 static const char *guid_attrs
[] = {
1049 ret
= dsdb_wellknown_dn(s
->ldap1
.ldb
, s
,
1050 ldb_get_default_basedn(s
->ldap1
.ldb
),
1051 DS_GUID_INFRASTRUCTURE_CONTAINER
,
1053 if (ret
!= LDB_SUCCESS
) {
1054 DEBUG(0,("Failed to get well known DN for DS_GUID_INFRASTRUCTURE_CONTAINER on %s: %s\n",
1055 ldb_dn_get_linearized(ldb_get_default_basedn(s
->ldap1
.ldb
)),
1056 ldb_errstring(s
->ldap1
.ldb
)));
1057 return NT_STATUS_LDAP(ret
);
1060 ret
= samdb_reference_dn(s
->ldap1
.ldb
, s
, basedn
, "fSMORoleOwner", &ntds_dn
);
1061 if (ret
!= LDB_SUCCESS
) {
1062 DEBUG(0,("Failed to get reference DN from fsmoRoleOwner on %s: %s\n",
1063 ldb_dn_get_linearized(basedn
),
1064 ldb_errstring(s
->ldap1
.ldb
)));
1065 talloc_free(basedn
);
1066 return NT_STATUS_LDAP(ret
);
1069 s
->infrastructure_fsmo
.ntds_dn_str
= ldb_dn_get_linearized(ntds_dn
);
1070 NT_STATUS_HAVE_NO_MEMORY(s
->infrastructure_fsmo
.ntds_dn_str
);
1072 server_dn
= ldb_dn_get_parent(s
, ntds_dn
);
1073 NT_STATUS_HAVE_NO_MEMORY(server_dn
);
1075 s
->infrastructure_fsmo
.server_dn_str
= ldb_dn_alloc_linearized(s
, server_dn
);
1076 NT_STATUS_HAVE_NO_MEMORY(s
->infrastructure_fsmo
.server_dn_str
);
1078 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, server_dn
, LDB_SCOPE_BASE
,
1079 dns_attrs
, "(objectClass=*)");
1080 if (ret
!= LDB_SUCCESS
) {
1081 DEBUG(0,("Failed to get server DN %s: %s\n",
1082 ldb_dn_get_linearized(server_dn
),
1083 ldb_errstring(s
->ldap1
.ldb
)));
1084 return NT_STATUS_LDAP(ret
);
1085 } else if (r
->count
!= 1) {
1087 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1090 s
->infrastructure_fsmo
.dns_name
= ldb_msg_find_attr_as_string(r
->msgs
[0], "dnsHostName", NULL
);
1091 if (!s
->infrastructure_fsmo
.dns_name
) return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1092 talloc_steal(s
, s
->infrastructure_fsmo
.dns_name
);
1096 ldb_dn_remove_extended_components(ntds_dn
);
1097 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, ntds_dn
, LDB_SCOPE_BASE
,
1098 guid_attrs
, "(objectClass=*)");
1099 if (ret
!= LDB_SUCCESS
) {
1100 DEBUG(0,("Failed to get NTDS Settings DN %s: %s\n",
1101 ldb_dn_get_linearized(ntds_dn
),
1102 ldb_errstring(s
->ldap1
.ldb
)));
1103 return NT_STATUS_LDAP(ret
);
1104 } else if (r
->count
!= 1) {
1106 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1109 s
->infrastructure_fsmo
.ntds_guid
= samdb_result_guid(r
->msgs
[0], "objectGUID");
1113 return NT_STATUS_OK
;
1116 static NTSTATUS
becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state
*s
)
1119 struct ldb_result
*r
;
1120 struct ldb_dn
*basedn
;
1121 const char *reference_dn_str
;
1122 struct ldb_dn
*ntds_dn
;
1123 struct ldb_dn
*server_dn
;
1124 static const char *rid_attrs
[] = {
1125 "rIDManagerReference",
1128 static const char *fsmo_attrs
[] = {
1132 static const char *dns_attrs
[] = {
1136 static const char *guid_attrs
[] = {
1141 basedn
= ldb_dn_new(s
, s
->ldap1
.ldb
, s
->domain
.dn_str
);
1142 NT_STATUS_HAVE_NO_MEMORY(basedn
);
1144 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, basedn
, LDB_SCOPE_BASE
,
1145 rid_attrs
, "(objectClass=*)");
1146 talloc_free(basedn
);
1147 if (ret
!= LDB_SUCCESS
) {
1148 return NT_STATUS_LDAP(ret
);
1149 } else if (r
->count
!= 1) {
1151 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1154 reference_dn_str
= ldb_msg_find_attr_as_string(r
->msgs
[0], "rIDManagerReference", NULL
);
1155 if (!reference_dn_str
) return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1157 basedn
= ldb_dn_new(s
, s
->ldap1
.ldb
, reference_dn_str
);
1158 NT_STATUS_HAVE_NO_MEMORY(basedn
);
1162 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, basedn
, LDB_SCOPE_BASE
,
1163 fsmo_attrs
, "(objectClass=*)");
1164 talloc_free(basedn
);
1165 if (ret
!= LDB_SUCCESS
) {
1166 return NT_STATUS_LDAP(ret
);
1167 } else if (r
->count
!= 1) {
1169 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1172 s
->rid_manager_fsmo
.ntds_dn_str
= ldb_msg_find_attr_as_string(r
->msgs
[0], "fSMORoleOwner", NULL
);
1173 if (!s
->rid_manager_fsmo
.ntds_dn_str
) return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1174 talloc_steal(s
, s
->rid_manager_fsmo
.ntds_dn_str
);
1178 ntds_dn
= ldb_dn_new(s
, s
->ldap1
.ldb
, s
->rid_manager_fsmo
.ntds_dn_str
);
1179 NT_STATUS_HAVE_NO_MEMORY(ntds_dn
);
1181 server_dn
= ldb_dn_get_parent(s
, ntds_dn
);
1182 NT_STATUS_HAVE_NO_MEMORY(server_dn
);
1184 s
->rid_manager_fsmo
.server_dn_str
= ldb_dn_alloc_linearized(s
, server_dn
);
1185 NT_STATUS_HAVE_NO_MEMORY(s
->rid_manager_fsmo
.server_dn_str
);
1187 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, server_dn
, LDB_SCOPE_BASE
,
1188 dns_attrs
, "(objectClass=*)");
1189 if (ret
!= LDB_SUCCESS
) {
1190 return NT_STATUS_LDAP(ret
);
1191 } else if (r
->count
!= 1) {
1193 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1196 s
->rid_manager_fsmo
.dns_name
= ldb_msg_find_attr_as_string(r
->msgs
[0], "dnsHostName", NULL
);
1197 if (!s
->rid_manager_fsmo
.dns_name
) return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1198 talloc_steal(s
, s
->rid_manager_fsmo
.dns_name
);
1202 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, ntds_dn
, LDB_SCOPE_BASE
,
1203 guid_attrs
, "(objectClass=*)");
1204 if (ret
!= LDB_SUCCESS
) {
1205 return NT_STATUS_LDAP(ret
);
1206 } else if (r
->count
!= 1) {
1208 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1211 s
->rid_manager_fsmo
.ntds_guid
= samdb_result_guid(r
->msgs
[0], "objectGUID");
1215 return NT_STATUS_OK
;
1218 static NTSTATUS
becomeDC_ldap1_site_object(struct libnet_BecomeDC_state
*s
)
1221 struct ldb_result
*r
;
1222 struct ldb_dn
*basedn
;
1224 basedn
= ldb_dn_new_fmt(s
, s
->ldap1
.ldb
, "CN=%s,CN=Sites,%s",
1225 s
->dest_dsa
.site_name
,
1226 s
->forest
.config_dn_str
);
1227 NT_STATUS_HAVE_NO_MEMORY(basedn
);
1229 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, basedn
, LDB_SCOPE_BASE
,
1230 NULL
, "(objectClass=*)");
1231 talloc_free(basedn
);
1232 if (ret
!= LDB_SUCCESS
) {
1233 return NT_STATUS_LDAP(ret
);
1234 } else if (r
->count
!= 1) {
1236 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1239 s
->dest_dsa
.site_guid
= samdb_result_guid(r
->msgs
[0], "objectGUID");
1242 return NT_STATUS_OK
;
1245 static NTSTATUS
becomeDC_check_options(struct libnet_BecomeDC_state
*s
)
1247 if (!s
->callbacks
.check_options
) return NT_STATUS_OK
;
1249 s
->_co
.domain
= &s
->domain
;
1250 s
->_co
.forest
= &s
->forest
;
1251 s
->_co
.source_dsa
= &s
->source_dsa
;
1253 return s
->callbacks
.check_options(s
->callbacks
.private_data
, &s
->_co
);
1256 static NTSTATUS
becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state
*s
)
1259 struct ldb_result
*r
;
1260 struct ldb_dn
*basedn
;
1261 static const char *attrs
[] = {
1262 "distinguishedName",
1263 "userAccountControl",
1267 basedn
= ldb_dn_new(s
, s
->ldap1
.ldb
, s
->domain
.dn_str
);
1268 NT_STATUS_HAVE_NO_MEMORY(basedn
);
1270 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, basedn
, LDB_SCOPE_SUBTREE
, attrs
,
1271 "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))",
1272 s
->dest_dsa
.netbios_name
);
1273 talloc_free(basedn
);
1274 if (ret
!= LDB_SUCCESS
) {
1275 return NT_STATUS_LDAP(ret
);
1276 } else if (r
->count
!= 1) {
1278 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1281 s
->dest_dsa
.computer_dn_str
= ldb_msg_find_attr_as_string(r
->msgs
[0], "distinguishedName", NULL
);
1282 if (!s
->dest_dsa
.computer_dn_str
) return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1283 talloc_steal(s
, s
->dest_dsa
.computer_dn_str
);
1285 s
->dest_dsa
.user_account_control
= ldb_msg_find_attr_as_uint(r
->msgs
[0], "userAccountControl", 0);
1288 return NT_STATUS_OK
;
1291 static NTSTATUS
becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state
*s
)
1294 struct ldb_result
*r
;
1295 struct ldb_dn
*basedn
;
1296 const char *server_reference_dn_str
;
1297 struct ldb_dn
*server_reference_dn
;
1298 struct ldb_dn
*computer_dn
;
1300 basedn
= ldb_dn_new_fmt(s
, s
->ldap1
.ldb
, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
1301 s
->dest_dsa
.netbios_name
,
1302 s
->dest_dsa
.site_name
,
1303 s
->forest
.config_dn_str
);
1304 NT_STATUS_HAVE_NO_MEMORY(basedn
);
1306 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, basedn
, LDB_SCOPE_BASE
,
1307 NULL
, "(objectClass=*)");
1308 talloc_free(basedn
);
1309 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
1310 /* if the object doesn't exist, we'll create it later */
1311 return NT_STATUS_OK
;
1312 } else if (ret
!= LDB_SUCCESS
) {
1313 return NT_STATUS_LDAP(ret
);
1314 } else if (r
->count
!= 1) {
1316 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1319 server_reference_dn_str
= ldb_msg_find_attr_as_string(r
->msgs
[0], "serverReference", NULL
);
1320 if (server_reference_dn_str
) {
1321 server_reference_dn
= ldb_dn_new(r
, s
->ldap1
.ldb
, server_reference_dn_str
);
1322 NT_STATUS_HAVE_NO_MEMORY(server_reference_dn
);
1324 computer_dn
= ldb_dn_new(r
, s
->ldap1
.ldb
, s
->dest_dsa
.computer_dn_str
);
1325 NT_STATUS_HAVE_NO_MEMORY(computer_dn
);
1328 * if the server object belongs to another DC in another domain
1329 * in the forest, we should not touch this object!
1331 if (ldb_dn_compare(computer_dn
, server_reference_dn
) != 0) {
1333 return NT_STATUS_OBJECT_NAME_COLLISION
;
1337 /* if the server object is already for the dest_dsa, then we don't need to create it */
1338 s
->dest_dsa
.server_dn_str
= ldb_msg_find_attr_as_string(r
->msgs
[0], "distinguishedName", NULL
);
1339 if (!s
->dest_dsa
.server_dn_str
) return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1340 talloc_steal(s
, s
->dest_dsa
.server_dn_str
);
1343 return NT_STATUS_OK
;
1346 static NTSTATUS
becomeDC_ldap1_server_object_2(struct libnet_BecomeDC_state
*s
)
1349 struct ldb_result
*r
;
1350 struct ldb_dn
*basedn
;
1351 const char *server_reference_bl_dn_str
;
1352 static const char *attrs
[] = {
1353 "serverReferenceBL",
1357 /* if the server_dn_str has a valid value, we skip this lookup */
1358 if (s
->dest_dsa
.server_dn_str
) return NT_STATUS_OK
;
1360 basedn
= ldb_dn_new(s
, s
->ldap1
.ldb
, s
->dest_dsa
.computer_dn_str
);
1361 NT_STATUS_HAVE_NO_MEMORY(basedn
);
1363 ret
= ldb_search(s
->ldap1
.ldb
, s
, &r
, basedn
, LDB_SCOPE_BASE
,
1364 attrs
, "(objectClass=*)");
1365 talloc_free(basedn
);
1366 if (ret
!= LDB_SUCCESS
) {
1367 return NT_STATUS_LDAP(ret
);
1368 } else if (r
->count
!= 1) {
1370 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1373 server_reference_bl_dn_str
= ldb_msg_find_attr_as_string(r
->msgs
[0], "serverReferenceBL", NULL
);
1374 if (!server_reference_bl_dn_str
) {
1375 /* if no back link is present, we're done for this function */
1377 return NT_STATUS_OK
;
1380 /* if the server object is already for the dest_dsa, then we don't need to create it */
1381 s
->dest_dsa
.server_dn_str
= ldb_msg_find_attr_as_string(r
->msgs
[0], "serverReferenceBL", NULL
);
1382 if (s
->dest_dsa
.server_dn_str
) {
1383 /* if a back link is present, we know that the server object is present */
1384 talloc_steal(s
, s
->dest_dsa
.server_dn_str
);
1388 return NT_STATUS_OK
;
1391 static NTSTATUS
becomeDC_ldap1_server_object_add(struct libnet_BecomeDC_state
*s
)
1394 struct ldb_message
*msg
;
1395 char *server_dn_str
;
1397 /* if the server_dn_str has a valid value, we skip this lookup */
1398 if (s
->dest_dsa
.server_dn_str
) return NT_STATUS_OK
;
1400 msg
= ldb_msg_new(s
);
1401 NT_STATUS_HAVE_NO_MEMORY(msg
);
1403 msg
->dn
= ldb_dn_new_fmt(msg
, s
->ldap1
.ldb
, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
1404 s
->dest_dsa
.netbios_name
,
1405 s
->dest_dsa
.site_name
,
1406 s
->forest
.config_dn_str
);
1407 NT_STATUS_HAVE_NO_MEMORY(msg
->dn
);
1409 ret
= ldb_msg_add_string(msg
, "objectClass", "server");
1412 return NT_STATUS_NO_MEMORY
;
1414 ret
= ldb_msg_add_string(msg
, "systemFlags", "50000000");
1417 return NT_STATUS_NO_MEMORY
;
1419 ret
= ldb_msg_add_string(msg
, "serverReference", s
->dest_dsa
.computer_dn_str
);
1422 return NT_STATUS_NO_MEMORY
;
1425 server_dn_str
= ldb_dn_alloc_linearized(s
, msg
->dn
);
1426 NT_STATUS_HAVE_NO_MEMORY(server_dn_str
);
1428 ret
= ldb_add(s
->ldap1
.ldb
, msg
);
1430 if (ret
!= LDB_SUCCESS
) {
1431 talloc_free(server_dn_str
);
1432 return NT_STATUS_LDAP(ret
);
1435 s
->dest_dsa
.server_dn_str
= server_dn_str
;
1437 return NT_STATUS_OK
;
1440 static NTSTATUS
becomeDC_ldap1_server_object_modify(struct libnet_BecomeDC_state
*s
)
1443 struct ldb_message
*msg
;
1446 /* make a 'modify' msg, and only for serverReference */
1447 msg
= ldb_msg_new(s
);
1448 NT_STATUS_HAVE_NO_MEMORY(msg
);
1449 msg
->dn
= ldb_dn_new(msg
, s
->ldap1
.ldb
, s
->dest_dsa
.server_dn_str
);
1450 NT_STATUS_HAVE_NO_MEMORY(msg
->dn
);
1452 ret
= ldb_msg_add_string(msg
, "serverReference", s
->dest_dsa
.computer_dn_str
);
1455 return NT_STATUS_NO_MEMORY
;
1458 /* mark all the message elements (should be just one)
1459 as LDB_FLAG_MOD_ADD */
1460 for (i
=0;i
<msg
->num_elements
;i
++) {
1461 msg
->elements
[i
].flags
= LDB_FLAG_MOD_ADD
;
1464 ret
= ldb_modify(s
->ldap1
.ldb
, msg
);
1465 if (ret
== LDB_SUCCESS
) {
1467 return NT_STATUS_OK
;
1468 } else if (ret
== LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
) {
1469 /* retry with LDB_FLAG_MOD_REPLACE */
1472 return NT_STATUS_LDAP(ret
);
1475 /* mark all the message elements (should be just one)
1476 as LDB_FLAG_MOD_REPLACE */
1477 for (i
=0;i
<msg
->num_elements
;i
++) {
1478 msg
->elements
[i
].flags
= LDB_FLAG_MOD_REPLACE
;
1481 ret
= ldb_modify(s
->ldap1
.ldb
, msg
);
1483 if (ret
!= LDB_SUCCESS
) {
1484 return NT_STATUS_LDAP(ret
);
1487 return NT_STATUS_OK
;
1490 static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state
*s
,
1491 struct becomeDC_drsuapi
*drsuapi
,
1492 void (*recv_fn
)(struct composite_context
*req
));
1493 static void becomeDC_drsuapi1_connect_recv(struct composite_context
*req
);
1494 static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state
*s
);
1496 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state
*s
)
1498 struct composite_context
*c
= s
->creq
;
1500 c
->status
= becomeDC_ldap_connect(s
, &s
->ldap1
);
1501 if (!composite_is_ok(c
)) return;
1503 c
->status
= becomeDC_ldap1_rootdse(s
);
1504 if (!composite_is_ok(c
)) return;
1506 c
->status
= becomeDC_ldap1_crossref_behavior_version(s
);
1507 if (!composite_is_ok(c
)) return;
1509 c
->status
= becomeDC_ldap1_domain_behavior_version(s
);
1510 if (!composite_is_ok(c
)) return;
1512 c
->status
= becomeDC_ldap1_schema_object_version(s
);
1513 if (!composite_is_ok(c
)) return;
1515 c
->status
= becomeDC_ldap1_w2k3_update_revision(s
);
1516 if (!composite_is_ok(c
)) return;
1518 c
->status
= becomeDC_ldap1_infrastructure_fsmo(s
);
1519 if (!composite_is_ok(c
)) return;
1521 c
->status
= becomeDC_ldap1_rid_manager_fsmo(s
);
1522 if (!composite_is_ok(c
)) return;
1524 c
->status
= becomeDC_ldap1_site_object(s
);
1525 if (!composite_is_ok(c
)) return;
1527 c
->status
= becomeDC_check_options(s
);
1528 if (!composite_is_ok(c
)) return;
1530 c
->status
= becomeDC_ldap1_computer_object(s
);
1531 if (!composite_is_ok(c
)) return;
1533 c
->status
= becomeDC_ldap1_server_object_1(s
);
1534 if (!composite_is_ok(c
)) return;
1536 c
->status
= becomeDC_ldap1_server_object_2(s
);
1537 if (!composite_is_ok(c
)) return;
1539 c
->status
= becomeDC_ldap1_server_object_add(s
);
1540 if (!composite_is_ok(c
)) return;
1542 c
->status
= becomeDC_ldap1_server_object_modify(s
);
1543 if (!composite_is_ok(c
)) return;
1545 becomeDC_drsuapi_connect_send(s
, &s
->drsuapi1
, becomeDC_drsuapi1_connect_recv
);
1548 static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state
*s
,
1549 struct becomeDC_drsuapi
*drsuapi
,
1550 void (*recv_fn
)(struct composite_context
*req
))
1552 struct composite_context
*c
= s
->creq
;
1553 struct composite_context
*creq
;
1558 if (!drsuapi
->binding
) {
1559 const char *krb5_str
= "";
1560 const char *print_str
= "";
1562 * Note: Replication only works with Windows 2000 when 'krb5' is
1563 * passed as auth_type here. If NTLMSSP is used, Windows
1564 * 2000 returns garbage in the DsGetNCChanges() response
1565 * if encrypted password attributes would be in the
1566 * response. That means the replication of the schema and
1567 * configuration partition works fine, but it fails for
1568 * the domain partition.
1570 if (lpcfg_parm_bool(s
->libnet
->lp_ctx
, NULL
, "become_dc",
1571 "force krb5", true))
1575 if (lpcfg_parm_bool(s
->libnet
->lp_ctx
, NULL
, "become_dc",
1578 print_str
= "print,";
1580 binding_str
= talloc_asprintf(s
, "ncacn_ip_tcp:%s[%s%sseal,target_hostname=%s]",
1581 s
->source_dsa
.address
,
1582 krb5_str
, print_str
,
1583 s
->source_dsa
.dns_name
);
1584 if (composite_nomem(binding_str
, c
)) return;
1585 c
->status
= dcerpc_parse_binding(s
, binding_str
, &drsuapi
->binding
);
1586 talloc_free(binding_str
);
1587 if (!composite_is_ok(c
)) return;
1590 if (DEBUGLEVEL
>= 10) {
1591 c
->status
= dcerpc_binding_set_flags(drsuapi
->binding
,
1592 DCERPC_DEBUG_PRINT_BOTH
,
1594 if (!composite_is_ok(c
)) return;
1597 creq
= dcerpc_pipe_connect_b_send(s
, drsuapi
->binding
, &ndr_table_drsuapi
,
1598 s
->libnet
->cred
, s
->libnet
->event_ctx
,
1600 composite_continue(c
, creq
, recv_fn
, s
);
1603 static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state
*s
,
1604 struct becomeDC_drsuapi
*drsuapi
,
1605 void (*recv_fn
)(struct tevent_req
*subreq
));
1606 static void becomeDC_drsuapi1_bind_recv(struct tevent_req
*subreq
);
1608 static void becomeDC_drsuapi1_connect_recv(struct composite_context
*req
)
1610 struct libnet_BecomeDC_state
*s
= talloc_get_type(req
->async
.private_data
,
1611 struct libnet_BecomeDC_state
);
1612 struct composite_context
*c
= s
->creq
;
1614 c
->status
= dcerpc_pipe_connect_b_recv(req
, s
, &s
->drsuapi1
.pipe
);
1615 if (!composite_is_ok(c
)) return;
1617 s
->drsuapi1
.drsuapi_handle
= s
->drsuapi1
.pipe
->binding_handle
;
1619 c
->status
= dcerpc_binding_handle_auth_session_key(
1620 s
->drsuapi1
.drsuapi_handle
,
1622 &s
->drsuapi1
.gensec_skey
);
1623 if (!composite_is_ok(c
)) return;
1625 becomeDC_drsuapi_bind_send(s
, &s
->drsuapi1
, becomeDC_drsuapi1_bind_recv
);
1628 static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state
*s
,
1629 struct becomeDC_drsuapi
*drsuapi
,
1630 void (*recv_fn
)(struct tevent_req
*subreq
))
1632 struct composite_context
*c
= s
->creq
;
1633 struct drsuapi_DsBindInfo28
*bind_info28
;
1634 struct tevent_req
*subreq
;
1636 GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3
, &drsuapi
->bind_guid
);
1638 bind_info28
= &drsuapi
->local_info28
;
1639 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_BASE
;
1640 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION
;
1641 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI
;
1642 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2
;
1643 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS
;
1644 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1
;
1645 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION
;
1646 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE
;
1647 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2
;
1648 if (s
->domain
.behavior_version
>= DS_DOMAIN_FUNCTION_2003
) {
1649 /* TODO: find out how this is really triggered! */
1650 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION
;
1652 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2
;
1653 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD
;
1654 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND
;
1655 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO
;
1656 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION
;
1657 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01
;
1658 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP
;
1659 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY
;
1660 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3
;
1661 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V5
;
1662 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2
;
1663 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6
;
1664 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS
;
1665 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
;
1666 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5
;
1667 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6
;
1668 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3
;
1669 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7
;
1670 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT
;
1671 #if 0 /* we don't support XPRESS compression yet */
1672 bind_info28
->supported_extensions
|= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS
;
1674 bind_info28
->site_guid
= s
->dest_dsa
.site_guid
;
1675 bind_info28
->pid
= 0;
1676 bind_info28
->repl_epoch
= 0;
1678 drsuapi
->bind_info_ctr
.length
= 28;
1679 drsuapi
->bind_info_ctr
.info
.info28
= *bind_info28
;
1681 drsuapi
->bind_r
.in
.bind_guid
= &drsuapi
->bind_guid
;
1682 drsuapi
->bind_r
.in
.bind_info
= &drsuapi
->bind_info_ctr
;
1683 drsuapi
->bind_r
.out
.bind_handle
= &drsuapi
->bind_handle
;
1685 subreq
= dcerpc_drsuapi_DsBind_r_send(s
, c
->event_ctx
,
1686 drsuapi
->drsuapi_handle
,
1688 if (composite_nomem(subreq
, c
)) return;
1689 tevent_req_set_callback(subreq
, recv_fn
, s
);
1692 static WERROR
becomeDC_drsuapi_bind_recv(struct libnet_BecomeDC_state
*s
,
1693 struct becomeDC_drsuapi
*drsuapi
)
1695 if (!W_ERROR_IS_OK(drsuapi
->bind_r
.out
.result
)) {
1696 return drsuapi
->bind_r
.out
.result
;
1699 ZERO_STRUCT(drsuapi
->remote_info28
);
1700 if (drsuapi
->bind_r
.out
.bind_info
) {
1701 switch (drsuapi
->bind_r
.out
.bind_info
->length
) {
1703 struct drsuapi_DsBindInfo24
*info24
;
1704 info24
= &drsuapi
->bind_r
.out
.bind_info
->info
.info24
;
1705 drsuapi
->remote_info28
.supported_extensions
= info24
->supported_extensions
;
1706 drsuapi
->remote_info28
.site_guid
= info24
->site_guid
;
1707 drsuapi
->remote_info28
.pid
= info24
->pid
;
1708 drsuapi
->remote_info28
.repl_epoch
= 0;
1712 drsuapi
->remote_info28
= drsuapi
->bind_r
.out
.bind_info
->info
.info28
;
1716 struct drsuapi_DsBindInfo32
*info32
;
1717 info32
= &drsuapi
->bind_r
.out
.bind_info
->info
.info32
;
1718 drsuapi
->remote_info28
.supported_extensions
= info32
->supported_extensions
;
1719 drsuapi
->remote_info28
.site_guid
= info32
->site_guid
;
1720 drsuapi
->remote_info28
.pid
= info32
->pid
;
1721 drsuapi
->remote_info28
.repl_epoch
= info32
->repl_epoch
;
1725 struct drsuapi_DsBindInfo48
*info48
;
1726 info48
= &drsuapi
->bind_r
.out
.bind_info
->info
.info48
;
1727 drsuapi
->remote_info28
.supported_extensions
= info48
->supported_extensions
;
1728 drsuapi
->remote_info28
.site_guid
= info48
->site_guid
;
1729 drsuapi
->remote_info28
.pid
= info48
->pid
;
1730 drsuapi
->remote_info28
.repl_epoch
= info48
->repl_epoch
;
1734 struct drsuapi_DsBindInfo52
*info52
;
1735 info52
= &drsuapi
->bind_r
.out
.bind_info
->info
.info52
;
1736 drsuapi
->remote_info28
.supported_extensions
= info52
->supported_extensions
;
1737 drsuapi
->remote_info28
.site_guid
= info52
->site_guid
;
1738 drsuapi
->remote_info28
.pid
= info52
->pid
;
1739 drsuapi
->remote_info28
.repl_epoch
= info52
->repl_epoch
;
1743 DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
1744 drsuapi
->bind_r
.out
.bind_info
->length
));
1752 static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state
*s
);
1754 static void becomeDC_drsuapi1_bind_recv(struct tevent_req
*subreq
)
1756 struct libnet_BecomeDC_state
*s
= tevent_req_callback_data(subreq
,
1757 struct libnet_BecomeDC_state
);
1758 struct composite_context
*c
= s
->creq
;
1761 c
->status
= dcerpc_drsuapi_DsBind_r_recv(subreq
, s
);
1762 TALLOC_FREE(subreq
);
1763 if (!composite_is_ok(c
)) return;
1765 status
= becomeDC_drsuapi_bind_recv(s
, &s
->drsuapi1
);
1766 if (!W_ERROR_IS_OK(status
)) {
1767 composite_error(c
, werror_to_ntstatus(status
));
1771 becomeDC_drsuapi1_add_entry_send(s
);
1774 static void becomeDC_drsuapi1_add_entry_recv(struct tevent_req
*subreq
);
1776 static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state
*s
)
1778 struct composite_context
*c
= s
->creq
;
1779 struct drsuapi_DsAddEntry
*r
;
1780 struct drsuapi_DsReplicaObjectIdentifier
*identifier
;
1781 uint32_t num_attrs
, i
= 0;
1782 struct drsuapi_DsReplicaAttribute
*attrs
;
1783 enum ndr_err_code ndr_err
;
1785 struct tevent_req
*subreq
;
1787 /* choose a random invocationId */
1788 s
->dest_dsa
.invocation_id
= GUID_random();
1791 * if the schema version indicates w2k3, then also send some w2k3
1792 * specific attributes.
1794 if (s
->forest
.schema_object_version
>= 30) {
1800 r
= talloc_zero(s
, struct drsuapi_DsAddEntry
);
1801 if (composite_nomem(r
, c
)) return;
1803 /* setup identifier */
1804 identifier
= talloc(r
, struct drsuapi_DsReplicaObjectIdentifier
);
1805 if (composite_nomem(identifier
, c
)) return;
1806 identifier
->guid
= GUID_zero();
1807 identifier
->sid
= s
->zero_sid
;
1808 identifier
->dn
= talloc_asprintf(identifier
, "CN=NTDS Settings,%s",
1809 s
->dest_dsa
.server_dn_str
);
1810 if (composite_nomem(identifier
->dn
, c
)) return;
1812 /* allocate attribute array */
1814 attrs
= talloc_array(r
, struct drsuapi_DsReplicaAttribute
, num_attrs
);
1815 if (composite_nomem(attrs
, c
)) return;
1817 /* ntSecurityDescriptor */
1819 struct drsuapi_DsAttributeValue
*vs
;
1821 struct security_descriptor
*v
;
1822 struct dom_sid
*domain_admins_sid
;
1823 const char *domain_admins_sid_str
;
1825 vs
= talloc_array(attrs
, struct drsuapi_DsAttributeValue
, 1);
1826 if (composite_nomem(vs
, c
)) return;
1828 vd
= talloc_array(vs
, DATA_BLOB
, 1);
1829 if (composite_nomem(vd
, c
)) return;
1831 domain_admins_sid
= dom_sid_add_rid(vs
, s
->domain
.sid
, DOMAIN_RID_ADMINS
);
1832 if (composite_nomem(domain_admins_sid
, c
)) return;
1834 domain_admins_sid_str
= dom_sid_string(domain_admins_sid
, domain_admins_sid
);
1835 if (composite_nomem(domain_admins_sid_str
, c
)) return;
1837 v
= security_descriptor_dacl_create(vd
,
1839 /* owner: domain admins */
1840 domain_admins_sid_str
,
1841 /* owner group: domain admins */
1842 domain_admins_sid_str
,
1843 /* authenticated users */
1844 SID_NT_AUTHENTICATED_USERS
,
1845 SEC_ACE_TYPE_ACCESS_ALLOWED
,
1846 SEC_STD_READ_CONTROL
|
1849 SEC_ADS_LIST_OBJECT
,
1852 domain_admins_sid_str
,
1853 SEC_ACE_TYPE_ACCESS_ALLOWED
,
1855 SEC_ADS_CREATE_CHILD
|
1857 SEC_ADS_SELF_WRITE
|
1859 SEC_ADS_WRITE_PROP
|
1860 SEC_ADS_DELETE_TREE
|
1861 SEC_ADS_LIST_OBJECT
|
1862 SEC_ADS_CONTROL_ACCESS
,
1866 SEC_ACE_TYPE_ACCESS_ALLOWED
,
1868 SEC_ADS_CREATE_CHILD
|
1869 SEC_ADS_DELETE_CHILD
|
1871 SEC_ADS_SELF_WRITE
|
1873 SEC_ADS_WRITE_PROP
|
1874 SEC_ADS_DELETE_TREE
|
1875 SEC_ADS_LIST_OBJECT
|
1876 SEC_ADS_CONTROL_ACCESS
,
1880 if (composite_nomem(v
, c
)) return;
1882 ndr_err
= ndr_push_struct_blob(&vd
[0], vd
, v
,
1883 (ndr_push_flags_fn_t
)ndr_push_security_descriptor
);
1884 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1885 c
->status
= ndr_map_error2ntstatus(ndr_err
);
1886 if (!composite_is_ok(c
)) return;
1889 vs
[0].blob
= &vd
[0];
1891 attrs
[i
].attid
= DRSUAPI_ATTID_ntSecurityDescriptor
;
1892 attrs
[i
].value_ctr
.num_values
= 1;
1893 attrs
[i
].value_ctr
.values
= vs
;
1898 /* objectClass: nTDSDSA */
1900 struct drsuapi_DsAttributeValue
*vs
;
1903 vs
= talloc_array(attrs
, struct drsuapi_DsAttributeValue
, 1);
1904 if (composite_nomem(vs
, c
)) return;
1906 vd
= talloc_array(vs
, DATA_BLOB
, 1);
1907 if (composite_nomem(vd
, c
)) return;
1909 vd
[0] = data_blob_talloc(vd
, NULL
, 4);
1910 if (composite_nomem(vd
[0].data
, c
)) return;
1912 /* value for nTDSDSA */
1913 SIVAL(vd
[0].data
, 0, 0x0017002F);
1915 vs
[0].blob
= &vd
[0];
1917 attrs
[i
].attid
= DRSUAPI_ATTID_objectClass
;
1918 attrs
[i
].value_ctr
.num_values
= 1;
1919 attrs
[i
].value_ctr
.values
= vs
;
1924 /* objectCategory: CN=NTDS-DSA,CN=Schema,... or CN=NTDS-DSA-RO,CN=Schema,... */
1926 struct drsuapi_DsAttributeValue
*vs
;
1928 struct drsuapi_DsReplicaObjectIdentifier3 v
[1];
1930 vs
= talloc_array(attrs
, struct drsuapi_DsAttributeValue
, 1);
1931 if (composite_nomem(vs
, c
)) return;
1933 vd
= talloc_array(vs
, DATA_BLOB
, 1);
1934 if (composite_nomem(vd
, c
)) return;
1936 v
[0].guid
= GUID_zero();
1937 v
[0].sid
= s
->zero_sid
;
1940 v
[0].dn
= talloc_asprintf(vd
, "CN=NTDS-DSA-RO,%s",
1941 s
->forest
.schema_dn_str
);
1943 v
[0].dn
= talloc_asprintf(vd
, "CN=NTDS-DSA,%s",
1944 s
->forest
.schema_dn_str
);
1946 if (composite_nomem(v
[0].dn
, c
)) return;
1948 ndr_err
= ndr_push_struct_blob(&vd
[0], vd
, &v
[0],
1949 (ndr_push_flags_fn_t
)ndr_push_drsuapi_DsReplicaObjectIdentifier3
);
1950 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1951 c
->status
= ndr_map_error2ntstatus(ndr_err
);
1952 if (!composite_is_ok(c
)) return;
1955 vs
[0].blob
= &vd
[0];
1957 attrs
[i
].attid
= DRSUAPI_ATTID_objectCategory
;
1958 attrs
[i
].value_ctr
.num_values
= 1;
1959 attrs
[i
].value_ctr
.values
= vs
;
1964 /* invocationId: random guid */
1966 struct drsuapi_DsAttributeValue
*vs
;
1968 const struct GUID
*v
;
1970 vs
= talloc_array(attrs
, struct drsuapi_DsAttributeValue
, 1);
1971 if (composite_nomem(vs
, c
)) return;
1973 vd
= talloc_array(vs
, DATA_BLOB
, 1);
1974 if (composite_nomem(vd
, c
)) return;
1976 v
= &s
->dest_dsa
.invocation_id
;
1978 c
->status
= GUID_to_ndr_blob(v
, vd
, &vd
[0]);
1979 if (!composite_is_ok(c
)) return;
1981 vs
[0].blob
= &vd
[0];
1983 attrs
[i
].attid
= DRSUAPI_ATTID_invocationId
;
1984 attrs
[i
].value_ctr
.num_values
= 1;
1985 attrs
[i
].value_ctr
.values
= vs
;
1990 /* hasMasterNCs: ... */
1992 struct drsuapi_DsAttributeValue
*vs
;
1994 struct drsuapi_DsReplicaObjectIdentifier3 v
[3];
1996 vs
= talloc_array(attrs
, struct drsuapi_DsAttributeValue
, 3);
1997 if (composite_nomem(vs
, c
)) return;
1999 vd
= talloc_array(vs
, DATA_BLOB
, 3);
2000 if (composite_nomem(vd
, c
)) return;
2002 v
[0].guid
= GUID_zero();
2003 v
[0].sid
= s
->zero_sid
;
2004 v
[0].dn
= s
->forest
.config_dn_str
;
2006 v
[1].guid
= GUID_zero();
2007 v
[1].sid
= s
->zero_sid
;
2008 v
[1].dn
= s
->domain
.dn_str
;
2010 v
[2].guid
= GUID_zero();
2011 v
[2].sid
= s
->zero_sid
;
2012 v
[2].dn
= s
->forest
.schema_dn_str
;
2014 ndr_err
= ndr_push_struct_blob(&vd
[0], vd
, &v
[0],
2015 (ndr_push_flags_fn_t
)ndr_push_drsuapi_DsReplicaObjectIdentifier3
);
2016 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2017 c
->status
= ndr_map_error2ntstatus(ndr_err
);
2018 if (!composite_is_ok(c
)) return;
2021 ndr_err
= ndr_push_struct_blob(&vd
[1], vd
, &v
[1],
2022 (ndr_push_flags_fn_t
)ndr_push_drsuapi_DsReplicaObjectIdentifier3
);
2023 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2024 c
->status
= ndr_map_error2ntstatus(ndr_err
);
2025 if (!composite_is_ok(c
)) return;
2028 ndr_err
= ndr_push_struct_blob(&vd
[2], vd
, &v
[2],
2029 (ndr_push_flags_fn_t
)ndr_push_drsuapi_DsReplicaObjectIdentifier3
);
2030 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2031 c
->status
= ndr_map_error2ntstatus(ndr_err
);
2032 if (!composite_is_ok(c
)) return;
2035 vs
[0].blob
= &vd
[0];
2036 vs
[1].blob
= &vd
[1];
2037 vs
[2].blob
= &vd
[2];
2039 attrs
[i
].attid
= DRSUAPI_ATTID_hasMasterNCs
;
2040 attrs
[i
].value_ctr
.num_values
= 3;
2041 attrs
[i
].value_ctr
.values
= vs
;
2046 /* msDS-hasMasterNCs: ... */
2048 struct drsuapi_DsAttributeValue
*vs
;
2050 struct drsuapi_DsReplicaObjectIdentifier3 v
[3];
2052 vs
= talloc_array(attrs
, struct drsuapi_DsAttributeValue
, 3);
2053 if (composite_nomem(vs
, c
)) return;
2055 vd
= talloc_array(vs
, DATA_BLOB
, 3);
2056 if (composite_nomem(vd
, c
)) return;
2058 v
[0].guid
= GUID_zero();
2059 v
[0].sid
= s
->zero_sid
;
2060 v
[0].dn
= s
->forest
.config_dn_str
;
2062 v
[1].guid
= GUID_zero();
2063 v
[1].sid
= s
->zero_sid
;
2064 v
[1].dn
= s
->domain
.dn_str
;
2066 v
[2].guid
= GUID_zero();
2067 v
[2].sid
= s
->zero_sid
;
2068 v
[2].dn
= s
->forest
.schema_dn_str
;
2070 ndr_err
= ndr_push_struct_blob(&vd
[0], vd
, &v
[0],
2071 (ndr_push_flags_fn_t
)ndr_push_drsuapi_DsReplicaObjectIdentifier3
);
2072 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2073 c
->status
= ndr_map_error2ntstatus(ndr_err
);
2074 if (!composite_is_ok(c
)) return;
2077 ndr_err
= ndr_push_struct_blob(&vd
[1], vd
, &v
[1],
2078 (ndr_push_flags_fn_t
)ndr_push_drsuapi_DsReplicaObjectIdentifier3
);
2079 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2080 c
->status
= ndr_map_error2ntstatus(ndr_err
);
2081 if (!composite_is_ok(c
)) return;
2084 ndr_err
= ndr_push_struct_blob(&vd
[2], vd
, &v
[2],
2085 (ndr_push_flags_fn_t
)ndr_push_drsuapi_DsReplicaObjectIdentifier3
);
2086 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2087 c
->status
= ndr_map_error2ntstatus(ndr_err
);
2088 if (!composite_is_ok(c
)) return;
2091 vs
[0].blob
= &vd
[0];
2092 vs
[1].blob
= &vd
[1];
2093 vs
[2].blob
= &vd
[2];
2095 attrs
[i
].attid
= DRSUAPI_ATTID_msDS_hasMasterNCs
;
2096 attrs
[i
].value_ctr
.num_values
= 3;
2097 attrs
[i
].value_ctr
.values
= vs
;
2102 /* dMDLocation: CN=Schema,... */
2104 struct drsuapi_DsAttributeValue
*vs
;
2106 struct drsuapi_DsReplicaObjectIdentifier3 v
[1];
2108 vs
= talloc_array(attrs
, struct drsuapi_DsAttributeValue
, 1);
2109 if (composite_nomem(vs
, c
)) return;
2111 vd
= talloc_array(vs
, DATA_BLOB
, 1);
2112 if (composite_nomem(vd
, c
)) return;
2114 v
[0].guid
= GUID_zero();
2115 v
[0].sid
= s
->zero_sid
;
2116 v
[0].dn
= s
->forest
.schema_dn_str
;
2118 ndr_err
= ndr_push_struct_blob(&vd
[0], vd
, &v
[0],
2119 (ndr_push_flags_fn_t
)ndr_push_drsuapi_DsReplicaObjectIdentifier3
);
2120 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2121 c
->status
= ndr_map_error2ntstatus(ndr_err
);
2122 if (!composite_is_ok(c
)) return;
2125 vs
[0].blob
= &vd
[0];
2127 attrs
[i
].attid
= DRSUAPI_ATTID_dMDLocation
;
2128 attrs
[i
].value_ctr
.num_values
= 1;
2129 attrs
[i
].value_ctr
.values
= vs
;
2134 /* msDS-HasDomainNCs: <domain_partition> */
2136 struct drsuapi_DsAttributeValue
*vs
;
2138 struct drsuapi_DsReplicaObjectIdentifier3 v
[1];
2140 vs
= talloc_array(attrs
, struct drsuapi_DsAttributeValue
, 1);
2141 if (composite_nomem(vs
, c
)) return;
2143 vd
= talloc_array(vs
, DATA_BLOB
, 1);
2144 if (composite_nomem(vd
, c
)) return;
2146 v
[0].guid
= GUID_zero();
2147 v
[0].sid
= s
->zero_sid
;
2148 v
[0].dn
= s
->domain
.dn_str
;
2150 ndr_err
= ndr_push_struct_blob(&vd
[0], vd
, &v
[0],
2151 (ndr_push_flags_fn_t
)ndr_push_drsuapi_DsReplicaObjectIdentifier3
);
2152 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2153 c
->status
= ndr_map_error2ntstatus(ndr_err
);
2154 if (!composite_is_ok(c
)) return;
2157 vs
[0].blob
= &vd
[0];
2159 attrs
[i
].attid
= DRSUAPI_ATTID_msDS_HasDomainNCs
;
2160 attrs
[i
].value_ctr
.num_values
= 1;
2161 attrs
[i
].value_ctr
.values
= vs
;
2166 /* msDS-Behavior-Version */
2168 struct drsuapi_DsAttributeValue
*vs
;
2171 vs
= talloc_array(attrs
, struct drsuapi_DsAttributeValue
, 1);
2172 if (composite_nomem(vs
, c
)) return;
2174 vd
= talloc_array(vs
, DATA_BLOB
, 1);
2175 if (composite_nomem(vd
, c
)) return;
2177 vd
[0] = data_blob_talloc(vd
, NULL
, 4);
2178 if (composite_nomem(vd
[0].data
, c
)) return;
2180 SIVAL(vd
[0].data
, 0, get_dc_function_level(s
->libnet
->lp_ctx
));
2182 vs
[0].blob
= &vd
[0];
2184 attrs
[i
].attid
= DRSUAPI_ATTID_msDS_Behavior_Version
;
2185 attrs
[i
].value_ctr
.num_values
= 1;
2186 attrs
[i
].value_ctr
.values
= vs
;
2193 struct drsuapi_DsAttributeValue
*vs
;
2196 vs
= talloc_array(attrs
, struct drsuapi_DsAttributeValue
, 1);
2197 if (composite_nomem(vs
, c
)) return;
2199 vd
= talloc_array(vs
, DATA_BLOB
, 1);
2200 if (composite_nomem(vd
, c
)) return;
2202 vd
[0] = data_blob_talloc(vd
, NULL
, 4);
2203 if (composite_nomem(vd
[0].data
, c
)) return;
2206 SIVAL(vd
[0].data
, 0, SYSTEM_FLAG_CONFIG_ALLOW_RENAME
);
2208 SIVAL(vd
[0].data
, 0, SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE
);
2211 vs
[0].blob
= &vd
[0];
2213 attrs
[i
].attid
= DRSUAPI_ATTID_systemFlags
;
2214 attrs
[i
].value_ctr
.num_values
= 1;
2215 attrs
[i
].value_ctr
.values
= vs
;
2220 /* serverReference: ... */
2222 struct drsuapi_DsAttributeValue
*vs
;
2224 struct drsuapi_DsReplicaObjectIdentifier3 v
[1];
2226 vs
= talloc_array(attrs
, struct drsuapi_DsAttributeValue
, 1);
2227 if (composite_nomem(vs
, c
)) return;
2229 vd
= talloc_array(vs
, DATA_BLOB
, 1);
2230 if (composite_nomem(vd
, c
)) return;
2232 v
[0].guid
= GUID_zero();
2233 v
[0].sid
= s
->zero_sid
;
2234 v
[0].dn
= s
->dest_dsa
.computer_dn_str
;
2236 ndr_err
= ndr_push_struct_blob(&vd
[0], vd
, &v
[0],
2237 (ndr_push_flags_fn_t
)ndr_push_drsuapi_DsReplicaObjectIdentifier3
);
2238 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2239 c
->status
= ndr_map_error2ntstatus(ndr_err
);
2240 if (!composite_is_ok(c
)) return;
2243 vs
[0].blob
= &vd
[0];
2245 attrs
[i
].attid
= DRSUAPI_ATTID_serverReference
;
2246 attrs
[i
].value_ctr
.num_values
= 1;
2247 attrs
[i
].value_ctr
.values
= vs
;
2254 struct drsuapi_DsAttributeValue
*vs
;
2257 vs
= talloc_array(attrs
, struct drsuapi_DsAttributeValue
, 1);
2258 if (composite_nomem(vs
, c
)) return;
2260 vd
= talloc_array(vs
, DATA_BLOB
, 1);
2261 if (composite_nomem(vd
, c
)) return;
2263 vd
[0] = data_blob_talloc(vd
, NULL
, 4);
2264 if (composite_nomem(vd
[0].data
, c
)) return;
2266 SIVAL(vd
[0].data
, 0, DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL
);
2268 vs
[0].blob
= &vd
[0];
2270 attrs
[i
].attid
= DRSUAPI_ATTID_options
;
2271 attrs
[i
].value_ctr
.num_values
= 1;
2272 attrs
[i
].value_ctr
.values
= vs
;
2277 /* truncate the attribute list to the attribute count we have filled in */
2280 /* setup request structure */
2281 r
->in
.bind_handle
= &s
->drsuapi1
.bind_handle
;
2283 r
->in
.req
= talloc(s
, union drsuapi_DsAddEntryRequest
);
2284 r
->in
.req
->req2
.first_object
.next_object
= NULL
;
2285 r
->in
.req
->req2
.first_object
.object
.identifier
= identifier
;
2286 r
->in
.req
->req2
.first_object
.object
.flags
= 0x00000000;
2287 r
->in
.req
->req2
.first_object
.object
.attribute_ctr
.num_attributes
= num_attrs
;
2288 r
->in
.req
->req2
.first_object
.object
.attribute_ctr
.attributes
= attrs
;
2290 r
->out
.level_out
= talloc(s
, uint32_t);
2291 r
->out
.ctr
= talloc(s
, union drsuapi_DsAddEntryCtr
);
2293 s
->ndr_struct_ptr
= r
;
2294 subreq
= dcerpc_drsuapi_DsAddEntry_r_send(s
, c
->event_ctx
,
2295 s
->drsuapi1
.drsuapi_handle
, r
);
2296 if (composite_nomem(subreq
, c
)) return;
2297 tevent_req_set_callback(subreq
, becomeDC_drsuapi1_add_entry_recv
, s
);
2300 static void becomeDC_drsuapi2_connect_recv(struct composite_context
*req
);
2301 static NTSTATUS
becomeDC_prepare_db(struct libnet_BecomeDC_state
*s
);
2303 static void becomeDC_drsuapi1_add_entry_recv(struct tevent_req
*subreq
)
2305 struct libnet_BecomeDC_state
*s
= tevent_req_callback_data(subreq
,
2306 struct libnet_BecomeDC_state
);
2307 struct composite_context
*c
= s
->creq
;
2308 struct drsuapi_DsAddEntry
*r
= talloc_get_type_abort(s
->ndr_struct_ptr
,
2309 struct drsuapi_DsAddEntry
);
2310 const struct dcerpc_binding
*bd1
= NULL
;
2312 uint32_t assoc_group_id
;
2314 s
->ndr_struct_ptr
= NULL
;
2316 c
->status
= dcerpc_drsuapi_DsAddEntry_r_recv(subreq
, r
);
2317 TALLOC_FREE(subreq
);
2318 if (!composite_is_ok(c
)) return;
2320 if (!W_ERROR_IS_OK(r
->out
.result
)) {
2321 composite_error(c
, werror_to_ntstatus(r
->out
.result
));
2325 if (*r
->out
.level_out
== 3) {
2327 union drsuapi_DsAddEntry_ErrData
*err_data
= r
->out
.ctr
->ctr3
.err_data
;
2329 /* check for errors */
2330 status
= err_data
? err_data
->v1
.status
: WERR_OK
;
2331 if (!W_ERROR_IS_OK(status
)) {
2332 struct drsuapi_DsAddEntryErrorInfo_Attr_V1
*attr_err
;
2333 struct drsuapi_DsAddEntry_AttrErrListItem_V1
*attr_err_li
;
2334 struct drsuapi_DsAddEntryErrorInfo_Name_V1
*name_err
;
2335 struct drsuapi_DsAddEntryErrorInfo_Referr_V1
*ref_err
;
2336 struct drsuapi_DsAddEntry_RefErrListItem_V1
*ref_li
;
2338 if (r
->out
.ctr
->ctr3
.err_ver
!= 1) {
2339 composite_error(c
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2343 DEBUG(0,("DsAddEntry (R3) of '%s' failed: "
2344 "Errors: dir_err = %d, status = %s;\n",
2345 r
->in
.req
->req3
.first_object
.object
.identifier
->dn
,
2346 err_data
->v1
.dir_err
,
2347 win_errstr(err_data
->v1
.status
)));
2349 if (!err_data
->v1
.info
) {
2350 DEBUG(0, ("DsAddEntry (R3): no error info returned!\n"));
2351 composite_error(c
, werror_to_ntstatus(status
));
2355 /* dump more detailed error */
2356 switch (err_data
->v1
.dir_err
) {
2357 case DRSUAPI_DIRERR_ATTRIBUTE
:
2358 /* Dump attribute errors */
2359 attr_err
= &err_data
->v1
.info
->attr_err
;
2360 DEBUGADD(0,(" Attribute Error: object = %s, count = %d;\n",
2363 attr_err_li
= &attr_err
->first
;
2364 for (; attr_err_li
; attr_err_li
= attr_err_li
->next
) {
2365 struct drsuapi_DsAddEntry_AttrErr_V1
*err
= &attr_err_li
->err_data
;
2366 DEBUGADD(0,(" Error: err = %s, problem = 0x%08X, attid = 0x%08X;\n",
2367 win_errstr(err
->extended_err
),
2370 /* TODO: should we print attribute value here? */
2373 case DRSUAPI_DIRERR_NAME
:
2374 /* Dump Name resolution error */
2375 name_err
= &err_data
->v1
.info
->name_err
;
2376 DEBUGADD(0,(" Name Error: err = %s, problem = 0x%08X, id_matched = %s;\n",
2377 win_errstr(name_err
->extended_err
),
2379 name_err
->id_matched
->dn
));
2381 case DRSUAPI_DIRERR_REFERRAL
:
2382 /* Dump Referral errors */
2383 ref_err
= &err_data
->v1
.info
->referral_err
;
2384 DEBUGADD(0,(" Referral Error: extended_err = %s\n",
2385 win_errstr(ref_err
->extended_err
)));
2386 ref_li
= &ref_err
->refer
;
2387 for (; ref_li
; ref_li
= ref_li
->next
) {
2388 struct drsuapi_DsaAddressListItem_V1
*addr
;
2389 DEBUGADD(0,(" Referral: id_target = %s, ref_type = 0x%04X,",
2390 ref_li
->id_target
->dn
,
2392 if (ref_li
->is_choice_set
) {
2393 DEBUGADD(0,(" choice = 0x%02X, ",
2396 DEBUGADD(0,(" add_list ("));
2397 for (addr
= ref_li
->addr_list
; addr
; addr
= addr
->next
) {
2398 DEBUGADD(0,("%s", addr
->address
->string
));
2403 DEBUGADD(0,(");\n"));
2406 case DRSUAPI_DIRERR_SECURITY
:
2407 /* Dump Security error. */
2408 DEBUGADD(0,(" Security Error: extended_err = %s, problem = 0x%08X\n",
2409 win_errstr(err_data
->v1
.info
->security_err
.extended_err
),
2410 err_data
->v1
.info
->security_err
.problem
));
2412 case DRSUAPI_DIRERR_SERVICE
:
2413 /* Dump Service error. */
2414 DEBUGADD(0,(" Service Error: extended_err = %s, problem = 0x%08X\n",
2415 win_errstr(err_data
->v1
.info
->service_err
.extended_err
),
2416 err_data
->v1
.info
->service_err
.problem
));
2418 case DRSUAPI_DIRERR_UPDATE
:
2419 /* Dump Update error. */
2420 DEBUGADD(0,(" Update Error: extended_err = %s, problem = 0x%08X\n",
2421 win_errstr(err_data
->v1
.info
->update_err
.extended_err
),
2422 err_data
->v1
.info
->update_err
.problem
));
2424 case DRSUAPI_DIRERR_SYSTEM
:
2426 DEBUGADD(0,(" System Error: extended_err = %s, problem = 0x%08X\n",
2427 win_errstr(err_data
->v1
.info
->system_err
.extended_err
),
2428 err_data
->v1
.info
->system_err
.problem
));
2430 case DRSUAPI_DIRERR_OK
: /* mute compiler warnings */
2432 DEBUGADD(0,(" Unknown DIRERR error class returned!\n"));
2436 composite_error(c
, werror_to_ntstatus(status
));
2440 if (1 != r
->out
.ctr
->ctr3
.count
) {
2441 DEBUG(0,("DsAddEntry - Ctr3: something very wrong had happened - "
2442 "method succeeded but objects returned are %d (expected 1).\n",
2443 r
->out
.ctr
->ctr3
.count
));
2444 composite_error(c
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2448 s
->dest_dsa
.ntds_guid
= r
->out
.ctr
->ctr3
.objects
[0].guid
;
2450 } else if (*r
->out
.level_out
== 2) {
2451 if (DRSUAPI_DIRERR_OK
!= r
->out
.ctr
->ctr2
.dir_err
) {
2452 DEBUG(0,("DsAddEntry failed with: dir_err = %d, extended_err = %s\n",
2453 r
->out
.ctr
->ctr2
.dir_err
,
2454 win_errstr(r
->out
.ctr
->ctr2
.extended_err
)));
2455 composite_error(c
, werror_to_ntstatus(r
->out
.ctr
->ctr2
.extended_err
));
2459 if (1 != r
->out
.ctr
->ctr2
.count
) {
2460 DEBUG(0,("DsAddEntry: something very wrong had happened - "
2461 "method succeeded but objects returned are %d (expected 1). "
2462 "Errors: dir_err = %d, extended_err = %s\n",
2463 r
->out
.ctr
->ctr2
.count
,
2464 r
->out
.ctr
->ctr2
.dir_err
,
2465 win_errstr(r
->out
.ctr
->ctr2
.extended_err
)));
2466 composite_error(c
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2470 s
->dest_dsa
.ntds_guid
= r
->out
.ctr
->ctr2
.objects
[0].guid
;
2472 composite_error(c
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2478 s
->dest_dsa
.ntds_dn_str
= talloc_asprintf(s
, "CN=NTDS Settings,%s",
2479 s
->dest_dsa
.server_dn_str
);
2480 if (composite_nomem(s
->dest_dsa
.ntds_dn_str
, c
)) return;
2482 c
->status
= becomeDC_prepare_db(s
);
2483 if (!composite_is_ok(c
)) return;
2485 /* this avoids the epmapper lookup on the 2nd connection */
2486 binding_str
= dcerpc_binding_string(s
, s
->drsuapi1
.binding
);
2487 if (composite_nomem(binding_str
, c
)) return;
2489 c
->status
= dcerpc_parse_binding(s
, binding_str
, &s
->drsuapi2
.binding
);
2490 talloc_free(binding_str
);
2491 if (!composite_is_ok(c
)) return;
2493 if (DEBUGLEVEL
>= 10) {
2494 c
->status
= dcerpc_binding_set_flags(s
->drsuapi2
.binding
,
2495 DCERPC_DEBUG_PRINT_BOTH
,
2497 if (!composite_is_ok(c
)) return;
2500 /* w2k3 uses the same assoc_group_id as on the first connection, so we do */
2501 bd1
= dcerpc_binding_handle_get_binding(s
->drsuapi1
.pipe
->binding_handle
);
2502 assoc_group_id
= dcerpc_binding_get_assoc_group_id(bd1
);
2503 c
->status
= dcerpc_binding_set_assoc_group_id(s
->drsuapi2
.binding
, assoc_group_id
);
2504 if (!composite_is_ok(c
)) return;
2506 becomeDC_drsuapi_connect_send(s
, &s
->drsuapi2
, becomeDC_drsuapi2_connect_recv
);
2509 static NTSTATUS
becomeDC_prepare_db(struct libnet_BecomeDC_state
*s
)
2511 if (!s
->callbacks
.prepare_db
) return NT_STATUS_OK
;
2513 s
->_pp
.domain
= &s
->domain
;
2514 s
->_pp
.forest
= &s
->forest
;
2515 s
->_pp
.source_dsa
= &s
->source_dsa
;
2516 s
->_pp
.dest_dsa
= &s
->dest_dsa
;
2518 return s
->callbacks
.prepare_db(s
->callbacks
.private_data
, &s
->_pp
);
2521 static void becomeDC_drsuapi2_bind_recv(struct tevent_req
*subreq
);
2523 static void becomeDC_drsuapi2_connect_recv(struct composite_context
*req
)
2525 struct libnet_BecomeDC_state
*s
= talloc_get_type(req
->async
.private_data
,
2526 struct libnet_BecomeDC_state
);
2527 struct composite_context
*c
= s
->creq
;
2529 c
->status
= dcerpc_pipe_connect_b_recv(req
, s
, &s
->drsuapi2
.pipe
);
2530 if (!composite_is_ok(c
)) return;
2532 s
->drsuapi2
.drsuapi_handle
= s
->drsuapi2
.pipe
->binding_handle
;
2534 c
->status
= dcerpc_binding_handle_auth_session_key(
2535 s
->drsuapi2
.drsuapi_handle
,
2537 &s
->drsuapi2
.gensec_skey
);
2538 if (!composite_is_ok(c
)) return;
2540 becomeDC_drsuapi_bind_send(s
, &s
->drsuapi2
, becomeDC_drsuapi2_bind_recv
);
2543 static void becomeDC_drsuapi3_connect_recv(struct composite_context
*req
);
2545 static void becomeDC_drsuapi2_bind_recv(struct tevent_req
*subreq
)
2547 struct libnet_BecomeDC_state
*s
= tevent_req_callback_data(subreq
,
2548 struct libnet_BecomeDC_state
);
2549 struct composite_context
*c
= s
->creq
;
2550 const struct dcerpc_binding
*bd1
= NULL
;
2552 uint32_t assoc_group_id
;
2555 c
->status
= dcerpc_drsuapi_DsBind_r_recv(subreq
, s
);
2556 TALLOC_FREE(subreq
);
2557 if (!composite_is_ok(c
)) return;
2559 status
= becomeDC_drsuapi_bind_recv(s
, &s
->drsuapi2
);
2560 if (!W_ERROR_IS_OK(status
)) {
2561 composite_error(c
, werror_to_ntstatus(status
));
2565 /* this avoids the epmapper lookup on the 3rd connection */
2566 binding_str
= dcerpc_binding_string(s
, s
->drsuapi1
.binding
);
2567 if (composite_nomem(binding_str
, c
)) return;
2569 c
->status
= dcerpc_parse_binding(s
, binding_str
, &s
->drsuapi3
.binding
);
2570 talloc_free(binding_str
);
2571 if (!composite_is_ok(c
)) return;
2573 if (DEBUGLEVEL
>= 10) {
2574 c
->status
= dcerpc_binding_set_flags(s
->drsuapi3
.binding
,
2575 DCERPC_DEBUG_PRINT_BOTH
,
2577 if (!composite_is_ok(c
)) return;
2580 /* w2k3 uses the same assoc_group_id as on the first connection, so we do */
2581 bd1
= dcerpc_binding_handle_get_binding(s
->drsuapi1
.pipe
->binding_handle
);
2582 assoc_group_id
= dcerpc_binding_get_assoc_group_id(bd1
);
2583 c
->status
= dcerpc_binding_set_assoc_group_id(s
->drsuapi3
.binding
, assoc_group_id
);
2584 if (!composite_is_ok(c
)) return;
2585 /* w2k3 uses the concurrent multiplex feature on the 3rd connection, so we do */
2586 c
->status
= dcerpc_binding_set_flags(s
->drsuapi3
.binding
,
2587 DCERPC_CONCURRENT_MULTIPLEX
,
2589 if (!composite_is_ok(c
)) return;
2591 becomeDC_drsuapi_connect_send(s
, &s
->drsuapi3
, becomeDC_drsuapi3_connect_recv
);
2594 static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state
*s
);
2596 static void becomeDC_drsuapi3_connect_recv(struct composite_context
*req
)
2598 struct libnet_BecomeDC_state
*s
= talloc_get_type(req
->async
.private_data
,
2599 struct libnet_BecomeDC_state
);
2600 struct composite_context
*c
= s
->creq
;
2602 c
->status
= dcerpc_pipe_connect_b_recv(req
, s
, &s
->drsuapi3
.pipe
);
2603 if (!composite_is_ok(c
)) return;
2605 s
->drsuapi3
.drsuapi_handle
= s
->drsuapi3
.pipe
->binding_handle
;
2607 c
->status
= dcerpc_binding_handle_auth_session_key(
2608 s
->drsuapi3
.drsuapi_handle
,
2610 &s
->drsuapi3
.gensec_skey
);
2611 if (!composite_is_ok(c
)) return;
2613 becomeDC_drsuapi3_pull_schema_send(s
);
2616 static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state
*s
,
2617 struct becomeDC_drsuapi
*drsuapi_h
,
2618 struct becomeDC_drsuapi
*drsuapi_p
,
2619 struct libnet_BecomeDC_Partition
*partition
,
2620 void (*recv_fn
)(struct tevent_req
*subreq
))
2622 struct composite_context
*c
= s
->creq
;
2623 struct drsuapi_DsGetNCChanges
*r
;
2624 struct tevent_req
*subreq
;
2626 r
= talloc(s
, struct drsuapi_DsGetNCChanges
);
2627 if (composite_nomem(r
, c
)) return;
2629 r
->out
.level_out
= talloc(r
, uint32_t);
2630 if (composite_nomem(r
->out
.level_out
, c
)) return;
2631 r
->in
.req
= talloc(r
, union drsuapi_DsGetNCChangesRequest
);
2632 if (composite_nomem(r
->in
.req
, c
)) return;
2633 r
->out
.ctr
= talloc(r
, union drsuapi_DsGetNCChangesCtr
);
2634 if (composite_nomem(r
->out
.ctr
, c
)) return;
2636 r
->in
.bind_handle
= &drsuapi_h
->bind_handle
;
2637 if (drsuapi_h
->remote_info28
.supported_extensions
& DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
) {
2639 r
->in
.req
->req8
.destination_dsa_guid
= partition
->destination_dsa_guid
;
2640 r
->in
.req
->req8
.source_dsa_invocation_id
= partition
->source_dsa_invocation_id
;
2641 r
->in
.req
->req8
.naming_context
= &partition
->nc
;
2642 r
->in
.req
->req8
.highwatermark
= partition
->highwatermark
;
2643 r
->in
.req
->req8
.uptodateness_vector
= NULL
;
2644 r
->in
.req
->req8
.replica_flags
= partition
->replica_flags
;
2645 r
->in
.req
->req8
.max_object_count
= 133;
2646 r
->in
.req
->req8
.max_ndr_size
= 1336811;
2647 r
->in
.req
->req8
.extended_op
= DRSUAPI_EXOP_NONE
;
2648 r
->in
.req
->req8
.fsmo_info
= 0;
2649 r
->in
.req
->req8
.partial_attribute_set
= NULL
;
2650 r
->in
.req
->req8
.partial_attribute_set_ex
= NULL
;
2651 r
->in
.req
->req8
.mapping_ctr
.num_mappings
= 0;
2652 r
->in
.req
->req8
.mapping_ctr
.mappings
= NULL
;
2655 r
->in
.req
->req5
.destination_dsa_guid
= partition
->destination_dsa_guid
;
2656 r
->in
.req
->req5
.source_dsa_invocation_id
= partition
->source_dsa_invocation_id
;
2657 r
->in
.req
->req5
.naming_context
= &partition
->nc
;
2658 r
->in
.req
->req5
.highwatermark
= partition
->highwatermark
;
2659 r
->in
.req
->req5
.uptodateness_vector
= NULL
;
2660 r
->in
.req
->req5
.replica_flags
= partition
->replica_flags
;
2661 r
->in
.req
->req5
.max_object_count
= 133;
2662 r
->in
.req
->req5
.max_ndr_size
= 1336770;
2663 r
->in
.req
->req5
.extended_op
= DRSUAPI_EXOP_NONE
;
2664 r
->in
.req
->req5
.fsmo_info
= 0;
2668 * we should try to use the drsuapi_p->pipe here, as w2k3 does
2669 * but it seems that some extra flags in the DCERPC Bind call
2670 * are needed for it. Or the same KRB5 TGS is needed on both
2673 s
->ndr_struct_ptr
= r
;
2674 subreq
= dcerpc_drsuapi_DsGetNCChanges_r_send(s
, c
->event_ctx
,
2675 drsuapi_p
->drsuapi_handle
,
2677 if (composite_nomem(subreq
, c
)) return;
2678 tevent_req_set_callback(subreq
, recv_fn
, s
);
2681 static WERROR
becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state
*s
,
2682 struct becomeDC_drsuapi
*drsuapi_h
,
2683 struct becomeDC_drsuapi
*drsuapi_p
,
2684 struct libnet_BecomeDC_Partition
*partition
,
2685 struct drsuapi_DsGetNCChanges
*r
)
2687 uint32_t req_level
= r
->in
.level
;
2688 struct drsuapi_DsGetNCChangesRequest5
*req5
= NULL
;
2689 struct drsuapi_DsGetNCChangesRequest8
*req8
= NULL
;
2690 struct drsuapi_DsGetNCChangesRequest10
*req10
= NULL
;
2691 uint32_t ctr_level
= 0;
2692 struct drsuapi_DsGetNCChangesCtr1
*ctr1
= NULL
;
2693 struct drsuapi_DsGetNCChangesCtr6
*ctr6
= NULL
;
2694 struct GUID
*source_dsa_guid
= NULL
;
2695 struct GUID
*source_dsa_invocation_id
= NULL
;
2696 struct drsuapi_DsReplicaHighWaterMark
*new_highwatermark
= NULL
;
2697 bool more_data
= false;
2700 if (!W_ERROR_IS_OK(r
->out
.result
)) {
2701 return r
->out
.result
;
2704 switch (r
->in
.level
) {
2709 req5
= &r
->in
.req
->req5
;
2712 req8
= &r
->in
.req
->req8
;
2715 req10
= &r
->in
.req
->req10
;
2718 return WERR_INVALID_PARAMETER
;
2721 if (*r
->out
.level_out
== 1) {
2723 ctr1
= &r
->out
.ctr
->ctr1
;
2724 } else if (*r
->out
.level_out
== 2 &&
2725 r
->out
.ctr
->ctr2
.mszip1
.ts
) {
2727 ctr1
= &r
->out
.ctr
->ctr2
.mszip1
.ts
->ctr1
;
2728 } else if (*r
->out
.level_out
== 6) {
2730 ctr6
= &r
->out
.ctr
->ctr6
;
2731 } else if (*r
->out
.level_out
== 7 &&
2732 r
->out
.ctr
->ctr7
.level
== 6 &&
2733 r
->out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_MSZIP
&&
2734 r
->out
.ctr
->ctr7
.ctr
.mszip6
.ts
) {
2736 ctr6
= &r
->out
.ctr
->ctr7
.ctr
.mszip6
.ts
->ctr6
;
2737 } else if (*r
->out
.level_out
== 7 &&
2738 r
->out
.ctr
->ctr7
.level
== 6 &&
2739 r
->out
.ctr
->ctr7
.type
== DRSUAPI_COMPRESSION_TYPE_WIN2K3_LZ77_DIRECT2
&&
2740 r
->out
.ctr
->ctr7
.ctr
.xpress6
.ts
) {
2742 ctr6
= &r
->out
.ctr
->ctr7
.ctr
.xpress6
.ts
->ctr6
;
2744 return WERR_BAD_NET_RESP
;
2747 if (!ctr1
&& ! ctr6
) {
2748 return WERR_BAD_NET_RESP
;
2751 if (ctr_level
== 6) {
2752 if (!W_ERROR_IS_OK(ctr6
->drs_error
)) {
2753 return ctr6
->drs_error
;
2757 switch (ctr_level
) {
2759 source_dsa_guid
= &ctr1
->source_dsa_guid
;
2760 source_dsa_invocation_id
= &ctr1
->source_dsa_invocation_id
;
2761 new_highwatermark
= &ctr1
->new_highwatermark
;
2762 more_data
= ctr1
->more_data
;
2765 source_dsa_guid
= &ctr6
->source_dsa_guid
;
2766 source_dsa_invocation_id
= &ctr6
->source_dsa_invocation_id
;
2767 new_highwatermark
= &ctr6
->new_highwatermark
;
2768 more_data
= ctr6
->more_data
;
2772 partition
->highwatermark
= *new_highwatermark
;
2773 partition
->source_dsa_guid
= *source_dsa_guid
;
2774 partition
->source_dsa_invocation_id
= *source_dsa_invocation_id
;
2775 partition
->more_data
= more_data
;
2777 if (!partition
->store_chunk
) return WERR_OK
;
2779 s
->_sc
.domain
= &s
->domain
;
2780 s
->_sc
.forest
= &s
->forest
;
2781 s
->_sc
.source_dsa
= &s
->source_dsa
;
2782 s
->_sc
.dest_dsa
= &s
->dest_dsa
;
2783 s
->_sc
.partition
= partition
;
2784 s
->_sc
.req_level
= req_level
;
2787 s
->_sc
.req10
= req10
;
2788 s
->_sc
.ctr_level
= ctr_level
;
2792 * we need to use the drsuapi_p->gensec_skey here,
2793 * when we use drsuapi_p->pipe in the for this request
2795 s
->_sc
.gensec_skey
= &drsuapi_p
->gensec_skey
;
2797 werr
= partition
->store_chunk(s
->callbacks
.private_data
, &s
->_sc
);
2798 if (!W_ERROR_IS_OK(werr
)) {
2805 static void becomeDC_drsuapi3_pull_schema_recv(struct tevent_req
*subreq
);
2807 static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state
*s
)
2809 s
->schema_part
.nc
.guid
= GUID_zero();
2810 s
->schema_part
.nc
.sid
= s
->zero_sid
;
2811 s
->schema_part
.nc
.dn
= s
->forest
.schema_dn_str
;
2813 s
->schema_part
.destination_dsa_guid
= s
->drsuapi2
.bind_guid
;
2815 s
->schema_part
.replica_flags
= DRSUAPI_DRS_WRIT_REP
2816 | DRSUAPI_DRS_INIT_SYNC
2817 | DRSUAPI_DRS_PER_SYNC
2818 | DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
2819 | DRSUAPI_DRS_NEVER_SYNCED
2820 | DRSUAPI_DRS_USE_COMPRESSION
2821 | DRSUAPI_DRS_GET_ANC
;
2823 s
->schema_part
.replica_flags
&= ~DRSUAPI_DRS_WRIT_REP
;
2826 s
->schema_part
.store_chunk
= s
->callbacks
.schema_chunk
;
2828 becomeDC_drsuapi_pull_partition_send(s
, &s
->drsuapi2
, &s
->drsuapi3
, &s
->schema_part
,
2829 becomeDC_drsuapi3_pull_schema_recv
);
2832 static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state
*s
);
2834 static void becomeDC_drsuapi3_pull_schema_recv(struct tevent_req
*subreq
)
2836 struct libnet_BecomeDC_state
*s
= tevent_req_callback_data(subreq
,
2837 struct libnet_BecomeDC_state
);
2838 struct composite_context
*c
= s
->creq
;
2839 struct drsuapi_DsGetNCChanges
*r
= talloc_get_type_abort(s
->ndr_struct_ptr
,
2840 struct drsuapi_DsGetNCChanges
);
2843 s
->ndr_struct_ptr
= NULL
;
2845 c
->status
= dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq
, r
);
2846 TALLOC_FREE(subreq
);
2847 if (!composite_is_ok(c
)) return;
2849 status
= becomeDC_drsuapi_pull_partition_recv(s
, &s
->drsuapi2
, &s
->drsuapi3
, &s
->schema_part
, r
);
2850 if (!W_ERROR_IS_OK(status
)) {
2851 composite_error(c
, werror_to_ntstatus(status
));
2857 if (s
->schema_part
.more_data
) {
2858 becomeDC_drsuapi_pull_partition_send(s
, &s
->drsuapi2
, &s
->drsuapi3
, &s
->schema_part
,
2859 becomeDC_drsuapi3_pull_schema_recv
);
2863 becomeDC_drsuapi3_pull_config_send(s
);
2866 static void becomeDC_drsuapi3_pull_config_recv(struct tevent_req
*subreq
);
2868 static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state
*s
)
2870 s
->config_part
.nc
.guid
= GUID_zero();
2871 s
->config_part
.nc
.sid
= s
->zero_sid
;
2872 s
->config_part
.nc
.dn
= s
->forest
.config_dn_str
;
2874 s
->config_part
.destination_dsa_guid
= s
->drsuapi2
.bind_guid
;
2876 s
->config_part
.replica_flags
= DRSUAPI_DRS_WRIT_REP
2877 | DRSUAPI_DRS_INIT_SYNC
2878 | DRSUAPI_DRS_PER_SYNC
2879 | DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
2880 | DRSUAPI_DRS_NEVER_SYNCED
2881 | DRSUAPI_DRS_USE_COMPRESSION
2882 | DRSUAPI_DRS_GET_ANC
;
2884 s
->schema_part
.replica_flags
&= ~DRSUAPI_DRS_WRIT_REP
;
2887 s
->config_part
.store_chunk
= s
->callbacks
.config_chunk
;
2889 becomeDC_drsuapi_pull_partition_send(s
, &s
->drsuapi2
, &s
->drsuapi3
, &s
->config_part
,
2890 becomeDC_drsuapi3_pull_config_recv
);
2893 static void becomeDC_drsuapi3_pull_config_recv(struct tevent_req
*subreq
)
2895 struct libnet_BecomeDC_state
*s
= tevent_req_callback_data(subreq
,
2896 struct libnet_BecomeDC_state
);
2897 struct composite_context
*c
= s
->creq
;
2898 struct drsuapi_DsGetNCChanges
*r
= talloc_get_type_abort(s
->ndr_struct_ptr
,
2899 struct drsuapi_DsGetNCChanges
);
2902 s
->ndr_struct_ptr
= NULL
;
2904 c
->status
= dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq
, r
);
2905 TALLOC_FREE(subreq
);
2906 if (!composite_is_ok(c
)) return;
2908 status
= becomeDC_drsuapi_pull_partition_recv(s
, &s
->drsuapi2
, &s
->drsuapi3
, &s
->config_part
, r
);
2909 if (!W_ERROR_IS_OK(status
)) {
2910 composite_error(c
, werror_to_ntstatus(status
));
2916 if (s
->config_part
.more_data
) {
2917 becomeDC_drsuapi_pull_partition_send(s
, &s
->drsuapi2
, &s
->drsuapi3
, &s
->config_part
,
2918 becomeDC_drsuapi3_pull_config_recv
);
2922 becomeDC_connect_ldap2(s
);
2925 static void becomeDC_drsuapi3_pull_domain_recv(struct tevent_req
*subreq
);
2927 static void becomeDC_drsuapi3_pull_domain_send(struct libnet_BecomeDC_state
*s
)
2929 s
->domain_part
.nc
.guid
= GUID_zero();
2930 s
->domain_part
.nc
.sid
= s
->zero_sid
;
2931 s
->domain_part
.nc
.dn
= s
->domain
.dn_str
;
2933 s
->domain_part
.destination_dsa_guid
= s
->drsuapi2
.bind_guid
;
2935 s
->domain_part
.replica_flags
= DRSUAPI_DRS_WRIT_REP
2936 | DRSUAPI_DRS_INIT_SYNC
2937 | DRSUAPI_DRS_PER_SYNC
2938 | DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
2939 | DRSUAPI_DRS_NEVER_SYNCED
2940 | DRSUAPI_DRS_USE_COMPRESSION
2941 | DRSUAPI_DRS_GET_ANC
;
2942 if (s
->critical_only
) {
2943 s
->domain_part
.replica_flags
|= DRSUAPI_DRS_CRITICAL_ONLY
;
2946 s
->schema_part
.replica_flags
&= ~DRSUAPI_DRS_WRIT_REP
;
2949 s
->domain_part
.store_chunk
= s
->callbacks
.domain_chunk
;
2951 becomeDC_drsuapi_pull_partition_send(s
, &s
->drsuapi2
, &s
->drsuapi3
, &s
->domain_part
,
2952 becomeDC_drsuapi3_pull_domain_recv
);
2955 static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state
*s
,
2956 struct becomeDC_drsuapi
*drsuapi
,
2957 struct libnet_BecomeDC_Partition
*partition
,
2958 void (*recv_fn
)(struct tevent_req
*subreq
));
2959 static void becomeDC_drsuapi2_update_refs_schema_recv(struct tevent_req
*subreq
);
2961 static void becomeDC_drsuapi3_pull_domain_recv(struct tevent_req
*subreq
)
2963 struct libnet_BecomeDC_state
*s
= tevent_req_callback_data(subreq
,
2964 struct libnet_BecomeDC_state
);
2965 struct composite_context
*c
= s
->creq
;
2966 struct drsuapi_DsGetNCChanges
*r
= talloc_get_type_abort(s
->ndr_struct_ptr
,
2967 struct drsuapi_DsGetNCChanges
);
2970 s
->ndr_struct_ptr
= NULL
;
2972 c
->status
= dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq
, r
);
2973 TALLOC_FREE(subreq
);
2974 if (!composite_is_ok(c
)) return;
2976 status
= becomeDC_drsuapi_pull_partition_recv(s
, &s
->drsuapi2
, &s
->drsuapi3
, &s
->domain_part
, r
);
2977 if (!W_ERROR_IS_OK(status
)) {
2978 composite_error(c
, werror_to_ntstatus(status
));
2984 if (s
->domain_part
.more_data
) {
2985 becomeDC_drsuapi_pull_partition_send(s
, &s
->drsuapi2
, &s
->drsuapi3
, &s
->domain_part
,
2986 becomeDC_drsuapi3_pull_domain_recv
);
2990 if (s
->critical_only
) {
2991 /* Remove the critical and ANC */
2992 s
->domain_part
.replica_flags
^= DRSUAPI_DRS_CRITICAL_ONLY
| DRSUAPI_DRS_GET_ANC
;
2993 s
->critical_only
= false;
2994 becomeDC_drsuapi_pull_partition_send(s
, &s
->drsuapi2
, &s
->drsuapi3
, &s
->domain_part
,
2995 becomeDC_drsuapi3_pull_domain_recv
);
2998 becomeDC_drsuapi_update_refs_send(s
, &s
->drsuapi2
, &s
->schema_part
,
2999 becomeDC_drsuapi2_update_refs_schema_recv
);
3002 static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state
*s
,
3003 struct becomeDC_drsuapi
*drsuapi
,
3004 struct libnet_BecomeDC_Partition
*partition
,
3005 void (*recv_fn
)(struct tevent_req
*subreq
))
3007 struct composite_context
*c
= s
->creq
;
3008 struct drsuapi_DsReplicaUpdateRefs
*r
;
3009 const char *ntds_guid_str
;
3010 const char *ntds_dns_name
;
3011 struct tevent_req
*subreq
;
3013 r
= talloc(s
, struct drsuapi_DsReplicaUpdateRefs
);
3014 if (composite_nomem(r
, c
)) return;
3016 ntds_guid_str
= GUID_string(r
, &s
->dest_dsa
.ntds_guid
);
3017 if (composite_nomem(ntds_guid_str
, c
)) return;
3019 ntds_dns_name
= talloc_asprintf(r
, "%s._msdcs.%s",
3021 s
->forest
.dns_name
);
3022 if (composite_nomem(ntds_dns_name
, c
)) return;
3024 r
->in
.bind_handle
= &drsuapi
->bind_handle
;
3026 r
->in
.req
.req1
.naming_context
= &partition
->nc
;
3027 r
->in
.req
.req1
.dest_dsa_dns_name
= ntds_dns_name
;
3028 r
->in
.req
.req1
.dest_dsa_guid
= s
->dest_dsa
.ntds_guid
;
3029 r
->in
.req
.req1
.options
= DRSUAPI_DRS_ADD_REF
| DRSUAPI_DRS_DEL_REF
;
3031 /* I think this is how we mark ourselves as a RODC */
3032 if (!lpcfg_parm_bool(s
->libnet
->lp_ctx
, NULL
, "repl", "RODC", false)) {
3033 r
->in
.req
.req1
.options
|= DRSUAPI_DRS_WRIT_REP
;
3036 s
->ndr_struct_ptr
= r
;
3037 subreq
= dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(s
, c
->event_ctx
,
3038 drsuapi
->drsuapi_handle
,
3040 if (composite_nomem(subreq
, c
)) return;
3041 tevent_req_set_callback(subreq
, recv_fn
, s
);
3044 static void becomeDC_drsuapi2_update_refs_config_recv(struct tevent_req
*subreq
);
3046 static void becomeDC_drsuapi2_update_refs_schema_recv(struct tevent_req
*subreq
)
3048 struct libnet_BecomeDC_state
*s
= tevent_req_callback_data(subreq
,
3049 struct libnet_BecomeDC_state
);
3050 struct composite_context
*c
= s
->creq
;
3051 struct drsuapi_DsReplicaUpdateRefs
*r
= talloc_get_type_abort(s
->ndr_struct_ptr
,
3052 struct drsuapi_DsReplicaUpdateRefs
);
3054 s
->ndr_struct_ptr
= NULL
;
3056 c
->status
= dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq
, r
);
3057 TALLOC_FREE(subreq
);
3058 if (!composite_is_ok(c
)) return;
3060 if (!W_ERROR_IS_OK(r
->out
.result
)) {
3061 composite_error(c
, werror_to_ntstatus(r
->out
.result
));
3067 becomeDC_drsuapi_update_refs_send(s
, &s
->drsuapi2
, &s
->config_part
,
3068 becomeDC_drsuapi2_update_refs_config_recv
);
3071 static void becomeDC_drsuapi2_update_refs_domain_recv(struct tevent_req
*subreq
);
3073 static void becomeDC_drsuapi2_update_refs_config_recv(struct tevent_req
*subreq
)
3075 struct libnet_BecomeDC_state
*s
= tevent_req_callback_data(subreq
,
3076 struct libnet_BecomeDC_state
);
3077 struct composite_context
*c
= s
->creq
;
3078 struct drsuapi_DsReplicaUpdateRefs
*r
= talloc_get_type(s
->ndr_struct_ptr
,
3079 struct drsuapi_DsReplicaUpdateRefs
);
3081 s
->ndr_struct_ptr
= NULL
;
3083 c
->status
= dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq
, r
);
3084 TALLOC_FREE(subreq
);
3085 if (!composite_is_ok(c
)) return;
3087 if (!W_ERROR_IS_OK(r
->out
.result
)) {
3088 composite_error(c
, werror_to_ntstatus(r
->out
.result
));
3094 becomeDC_drsuapi_update_refs_send(s
, &s
->drsuapi2
, &s
->domain_part
,
3095 becomeDC_drsuapi2_update_refs_domain_recv
);
3098 static void becomeDC_drsuapi2_update_refs_domain_recv(struct tevent_req
*subreq
)
3100 struct libnet_BecomeDC_state
*s
= tevent_req_callback_data(subreq
,
3101 struct libnet_BecomeDC_state
);
3102 struct composite_context
*c
= s
->creq
;
3103 struct drsuapi_DsReplicaUpdateRefs
*r
= talloc_get_type(s
->ndr_struct_ptr
,
3104 struct drsuapi_DsReplicaUpdateRefs
);
3106 s
->ndr_struct_ptr
= NULL
;
3108 c
->status
= dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq
, r
);
3109 TALLOC_FREE(subreq
);
3110 if (!composite_is_ok(c
)) return;
3112 if (!W_ERROR_IS_OK(r
->out
.result
)) {
3113 composite_error(c
, werror_to_ntstatus(r
->out
.result
));
3119 /* TODO: use DDNS updates and register dns names */
3123 static NTSTATUS
becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state
*s
)
3126 struct ldb_message
*msg
;
3128 uint32_t user_account_control
= UF_SERVER_TRUST_ACCOUNT
|
3129 UF_TRUSTED_FOR_DELEGATION
;
3131 /* as the value is already as we want it to be, we're done */
3132 if (s
->dest_dsa
.user_account_control
== user_account_control
) {
3133 return NT_STATUS_OK
;
3136 /* make a 'modify' msg, and only for serverReference */
3137 msg
= ldb_msg_new(s
);
3138 NT_STATUS_HAVE_NO_MEMORY(msg
);
3139 msg
->dn
= ldb_dn_new(msg
, s
->ldap2
.ldb
, s
->dest_dsa
.computer_dn_str
);
3140 NT_STATUS_HAVE_NO_MEMORY(msg
->dn
);
3142 ret
= samdb_msg_add_uint(s
->ldap2
.ldb
, msg
, msg
, "userAccountControl",
3143 user_account_control
);
3144 if (ret
!= LDB_SUCCESS
) {
3146 return NT_STATUS_NO_MEMORY
;
3149 /* mark all the message elements (should be just one)
3150 as LDB_FLAG_MOD_REPLACE */
3151 for (i
=0;i
<msg
->num_elements
;i
++) {
3152 msg
->elements
[i
].flags
= LDB_FLAG_MOD_REPLACE
;
3155 ret
= ldb_modify(s
->ldap2
.ldb
, msg
);
3157 if (ret
!= LDB_SUCCESS
) {
3158 return NT_STATUS_LDAP(ret
);
3161 s
->dest_dsa
.user_account_control
= user_account_control
;
3163 return NT_STATUS_OK
;
3166 static NTSTATUS
becomeDC_ldap2_move_computer(struct libnet_BecomeDC_state
*s
)
3169 struct ldb_dn
*old_dn
;
3170 struct ldb_dn
*new_dn
;
3172 ret
= dsdb_wellknown_dn(s
->ldap2
.ldb
, s
,
3173 ldb_get_default_basedn(s
->ldap2
.ldb
),
3174 DS_GUID_DOMAIN_CONTROLLERS_CONTAINER
,
3176 if (ret
!= LDB_SUCCESS
) {
3177 return NT_STATUS_LDAP(ret
);
3180 if (!ldb_dn_add_child_fmt(new_dn
, "CN=%s", s
->dest_dsa
.netbios_name
)) {
3181 talloc_free(new_dn
);
3182 return NT_STATUS_NO_MEMORY
;
3185 old_dn
= ldb_dn_new(new_dn
, s
->ldap2
.ldb
, s
->dest_dsa
.computer_dn_str
);
3186 NT_STATUS_HAVE_NO_MEMORY(old_dn
);
3188 if (ldb_dn_compare(old_dn
, new_dn
) == 0) {
3189 /* we don't need to rename if the old and new dn match */
3190 talloc_free(new_dn
);
3191 return NT_STATUS_OK
;
3194 ret
= ldb_rename(s
->ldap2
.ldb
, old_dn
, new_dn
);
3195 if (ret
!= LDB_SUCCESS
) {
3196 talloc_free(new_dn
);
3197 return NT_STATUS_LDAP(ret
);
3200 s
->dest_dsa
.computer_dn_str
= ldb_dn_alloc_linearized(s
, new_dn
);
3201 NT_STATUS_HAVE_NO_MEMORY(s
->dest_dsa
.computer_dn_str
);
3203 talloc_free(new_dn
);
3205 return NT_STATUS_OK
;
3208 static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state
*s
)
3210 struct composite_context
*c
= s
->creq
;
3212 c
->status
= becomeDC_ldap_connect(s
, &s
->ldap2
);
3213 if (!composite_is_ok(c
)) return;
3215 c
->status
= becomeDC_ldap2_modify_computer(s
);
3216 if (!composite_is_ok(c
)) return;
3218 c
->status
= becomeDC_ldap2_move_computer(s
);
3219 if (!composite_is_ok(c
)) return;
3221 s
->critical_only
= true;
3222 becomeDC_drsuapi3_pull_domain_send(s
);
3225 struct composite_context
*libnet_BecomeDC_send(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, struct libnet_BecomeDC
*r
)
3227 struct composite_context
*c
;
3228 struct libnet_BecomeDC_state
*s
;
3231 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
3232 if (c
== NULL
) return NULL
;
3234 s
= talloc_zero(c
, struct libnet_BecomeDC_state
);
3235 if (composite_nomem(s
, c
)) return c
;
3236 c
->private_data
= s
;
3241 s
->domain
.dns_name
= talloc_strdup(s
, r
->in
.domain_dns_name
);
3242 if (composite_nomem(s
->domain
.dns_name
, c
)) return c
;
3243 s
->domain
.netbios_name
= talloc_strdup(s
, r
->in
.domain_netbios_name
);
3244 if (composite_nomem(s
->domain
.netbios_name
, c
)) return c
;
3245 s
->domain
.sid
= dom_sid_dup(s
, r
->in
.domain_sid
);
3246 if (composite_nomem(s
->domain
.sid
, c
)) return c
;
3248 /* Source DSA input */
3249 s
->source_dsa
.address
= talloc_strdup(s
, r
->in
.source_dsa_address
);
3250 if (composite_nomem(s
->source_dsa
.address
, c
)) return c
;
3252 /* Destination DSA input */
3253 s
->dest_dsa
.netbios_name
= talloc_strdup(s
, r
->in
.dest_dsa_netbios_name
);
3254 if (composite_nomem(s
->dest_dsa
.netbios_name
, c
)) return c
;
3256 /* Destination DSA dns_name construction */
3257 tmp_name
= strlower_talloc(s
, s
->dest_dsa
.netbios_name
);
3258 if (composite_nomem(tmp_name
, c
)) return c
;
3259 tmp_name
= talloc_asprintf_append_buffer(tmp_name
, ".%s",s
->domain
.dns_name
);
3260 if (composite_nomem(tmp_name
, c
)) return c
;
3261 s
->dest_dsa
.dns_name
= tmp_name
;
3263 /* Callback function pointers */
3264 s
->callbacks
= r
->in
.callbacks
;
3267 s
->rodc_join
= r
->in
.rodc_join
;
3269 becomeDC_send_cldap(s
);
3273 NTSTATUS
libnet_BecomeDC_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
, struct libnet_BecomeDC
*r
)
3277 status
= composite_wait(c
);
3279 ZERO_STRUCT(r
->out
);
3285 NTSTATUS
libnet_BecomeDC(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, struct libnet_BecomeDC
*r
)
3288 struct composite_context
*c
;
3289 c
= libnet_BecomeDC_send(ctx
, mem_ctx
, r
);
3290 status
= libnet_BecomeDC_recv(c
, mem_ctx
, r
);