Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Stefan Metzmacher <metze@samba.org> 2006
5 :
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.
10 :
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.
15 :
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/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "libnet/libnet.h"
22 : #include "libcli/composite/composite.h"
23 : #include "libcli/cldap/cldap.h"
24 : #include <ldb.h>
25 : #include <ldb_errors.h>
26 : #include "ldb_wrap.h"
27 : #include "dsdb/samdb/samdb.h"
28 : #include "../libds/common/flags.h"
29 : #include "librpc/gen_ndr/ndr_drsuapi_c.h"
30 : #include "libcli/security/security.h"
31 : #include "librpc/gen_ndr/ndr_misc.h"
32 : #include "librpc/gen_ndr/ndr_security.h"
33 : #include "librpc/gen_ndr/ndr_nbt.h"
34 : #include "librpc/gen_ndr/ndr_drsuapi.h"
35 : #include "auth/gensec/gensec.h"
36 : #include "param/param.h"
37 : #include "lib/tsocket/tsocket.h"
38 :
39 : /*****************************************************************************
40 : * Windows 2003 (w2k3) does the following steps when changing the server role
41 : * from domain member to domain controller
42 : *
43 : * We mostly do the same.
44 : *****************************************************************************/
45 :
46 : /*
47 : * lookup DC:
48 : * - using nbt name<1C> request and a samlogon mailslot request
49 : * or
50 : * - using a DNS SRV _ldap._tcp.dc._msdcs. request and a CLDAP netlogon request
51 : *
52 : * see: becomeDC_recv_cldap() and becomeDC_send_cldap()
53 : */
54 :
55 : /*
56 : * Open 1st LDAP connection to the DC using admin credentials
57 : *
58 : * see: becomeDC_connect_ldap1() and becomeDC_ldap_connect()
59 : */
60 :
61 : /*
62 : * LDAP search 1st LDAP connection:
63 : *
64 : * see: becomeDC_ldap1_rootdse()
65 : *
66 : * Request:
67 : * basedn: ""
68 : * scope: base
69 : * filter: (objectClass=*)
70 : * attrs: *
71 : * Result:
72 : * ""
73 : * currentTime: 20061202155100.0Z
74 : * subschemaSubentry: CN=Aggregate,CN=Schema,CN=Configuration,<domain_partition>
75 : * dsServiceName: CN=<netbios_name>,CN=Servers,CN=<site_name>,CN=Sites,CN=Configuration,<domain_partition>
76 : * namingContexts: <domain_partition>
77 : * CN=Configuration,<domain_partition>
78 : * CN=Schema,CN=Configuration,<domain_partition>
79 : * defaultNamingContext: <domain_partition>
80 : * schemaNamingContext: CN=Schema,CN=Configuration,<domain_partition>
81 : * configurationNamingContext:CN=Configuration,<domain_partition>
82 : * rootDomainNamingContext:<domain_partition>
83 : * supportedControl: ...
84 : * supportedLDAPVersion: 3
85 : * 2
86 : * supportedLDAPPolicies: ...
87 : * highestCommittedUSN: ...
88 : * supportedSASLMechanisms:GSSAPI
89 : * GSS-SPNEGO
90 : * EXTERNAL
91 : * DIGEST-MD5
92 : * dnsHostName: <dns_host_name>
93 : * ldapServiceName: <domain_dns_name>:<netbios_name>$@<REALM>
94 : * serverName: CN=Servers,CN=<site_name>,CN=Sites,CN=Configuration,<domain_partition>
95 : * supportedCapabilities: ...
96 : * isSynchronized: TRUE
97 : * isGlobalCatalogReady: TRUE
98 : * domainFunctionality: 0
99 : * forestFunctionality: 0
100 : * domainControllerFunctionality: 2
101 : */
102 :
103 : /*
104 : * LDAP search 1st LDAP connection:
105 : *
106 : * see: becomeDC_ldap1_crossref_behavior_version()
107 : *
108 : * Request:
109 : * basedn: CN=Configuration,<domain_partition>
110 : * scope: one
111 : * filter: (cn=Partitions)
112 : * attrs: msDS-Behavior-Version
113 : * Result:
114 : * CN=Partitions,CN=Configuration,<domain_partition>
115 : * msDS-Behavior-Version: 0
116 : */
117 :
118 : /*
119 : * LDAP search 1st LDAP connection:
120 : *
121 : * NOTE: this seems to be a bug! as the messageID of the LDAP message is corrupted!
122 : *
123 : * not implemented here
124 : *
125 : * Request:
126 : * basedn: CN=Schema,CN=Configuration,<domain_partition>
127 : * scope: one
128 : * filter: (cn=Partitions)
129 : * attrs: msDS-Behavior-Version
130 : * Result:
131 : * <none>
132 : *
133 : */
134 :
135 : /*
136 : * LDAP search 1st LDAP connection:
137 : *
138 : * see: becomeDC_ldap1_domain_behavior_version()
139 : *
140 : * Request:
141 : * basedn: <domain_partition>
142 : * scope: base
143 : * filter: (objectClass=*)
144 : * attrs: msDS-Behavior-Version
145 : * Result:
146 : * <domain_partition>
147 : * msDS-Behavior-Version: 0
148 : */
149 :
150 : /*
151 : * LDAP search 1st LDAP connection:
152 : *
153 : * see: becomeDC_ldap1_schema_object_version()
154 : *
155 : * Request:
156 : * basedn: CN=Schema,CN=Configuration,<domain_partition>
157 : * scope: base
158 : * filter: (objectClass=*)
159 : * attrs: objectVersion
160 : * Result:
161 : * CN=Schema,CN=Configuration,<domain_partition>
162 : * objectVersion: 30
163 : */
164 :
165 : /*
166 : * LDAP search 1st LDAP connection:
167 : *
168 : * not implemented, because the information is already there
169 : *
170 : * Request:
171 : * basedn: ""
172 : * scope: base
173 : * filter: (objectClass=*)
174 : * attrs: defaultNamingContext
175 : * dnsHostName
176 : * Result:
177 : * ""
178 : * defaultNamingContext: <domain_partition>
179 : * dnsHostName: <dns_host_name>
180 : */
181 :
182 : /*
183 : * LDAP search 1st LDAP connection:
184 : *
185 : * see: becomeDC_ldap1_infrastructure_fsmo()
186 : *
187 : * Request:
188 : * basedn: <WKGUID=2fbac1870ade11d297c400c04fd8d5cd,domain_partition>
189 : * scope: base
190 : * filter: (objectClass=*)
191 : * attrs: 1.1
192 : * Result:
193 : * CN=Infrastructure,<domain_partition>
194 : */
195 :
196 : /*
197 : * LDAP search 1st LDAP connection:
198 : *
199 : * see: becomeDC_ldap1_w2k3_update_revision()
200 : *
201 : * Request:
202 : * basedn: CN=Windows2003Update,CN=DomainUpdates,CN=System,<domain_partition>
203 : * scope: base
204 : * filter: (objectClass=*)
205 : * attrs: revision
206 : * Result:
207 : * CN=Windows2003Update,CN=DomainUpdates,CN=System,<domain_partition>
208 : * revision: 8
209 : */
210 :
211 : /*
212 : * LDAP search 1st LDAP connection:
213 : *
214 : * see: becomeDC_ldap1_infrastructure_fsmo()
215 : *
216 : * Request:
217 : * basedn: CN=Infrastructure,<domain_partition>
218 : * scope: base
219 : * filter: (objectClass=*)
220 : * attrs: fSMORoleOwner
221 : * Result:
222 : * CN=Infrastructure,<domain_partition>
223 : * fSMORoleOwner: CN=NTDS Settings,<infrastructure_fsmo_server_object>
224 : */
225 :
226 : /*
227 : * LDAP search 1st LDAP connection:
228 : *
229 : * see: becomeDC_ldap1_infrastructure_fsmo()
230 : *
231 : * Request:
232 : * basedn: <infrastructure_fsmo_server_object>
233 : * scope: base
234 : * filter: (objectClass=*)
235 : * attrs: dnsHostName
236 : * Result:
237 : * <infrastructure_fsmo_server_object>
238 : * dnsHostName: <dns_host_name>
239 : */
240 :
241 : /*
242 : * LDAP search 1st LDAP connection:
243 : *
244 : * see: becomeDC_ldap1_infrastructure_fsmo()
245 : *
246 : * Request:
247 : * basedn: CN=NTDS Settings,<infrastructure_fsmo_server_object>
248 : * scope: base
249 : * filter: (objectClass=*)
250 : * attrs: objectGUID
251 : * Result:
252 : * CN=NTDS Settings,<infrastructure_fsmo_server_object>
253 : * objectGUID: <object_guid>
254 : */
255 :
256 : /*
257 : * LDAP search 1st LDAP connection:
258 : *
259 : * see: becomeDC_ldap1_rid_manager_fsmo()
260 : *
261 : * Request:
262 : * basedn: <domain_partition>
263 : * scope: base
264 : * filter: (objectClass=*)
265 : * attrs: rIDManagerReference
266 : * Result:
267 : * <domain_partition>
268 : * rIDManagerReference: CN=RID Manager$,CN=System,<domain_partition>
269 : */
270 :
271 : /*
272 : * LDAP search 1st LDAP connection:
273 : *
274 : * see: becomeDC_ldap1_rid_manager_fsmo()
275 : *
276 : * Request:
277 : * basedn: CN=RID Manager$,CN=System,<domain_partition>
278 : * scope: base
279 : * filter: (objectClass=*)
280 : * attrs: fSMORoleOwner
281 : * Result:
282 : * CN=Infrastructure,<domain_partition>
283 : * fSMORoleOwner: CN=NTDS Settings,<rid_manager_fsmo_server_object>
284 : */
285 :
286 : /*
287 : * LDAP search 1st LDAP connection:
288 : *
289 : * see: becomeDC_ldap1_rid_manager_fsmo()
290 : *
291 : * Request:
292 : * basedn: <rid_manager_fsmo_server_object>
293 : * scope: base
294 : * filter: (objectClass=*)
295 : * attrs: dnsHostName
296 : * Result:
297 : * <rid_manager_fsmo_server_object>
298 : * dnsHostName: <dns_host_name>
299 : */
300 :
301 : /*
302 : * LDAP search 1st LDAP connection:
303 : *
304 : * see: becomeDC_ldap1_rid_manager_fsmo()
305 : *
306 : * Request:
307 : * basedn: CN=NTDS Settings,<rid_manager_fsmo_server_object>
308 : * scope: base
309 : * filter: (objectClass=*)
310 : * attrs: msDs-ReplicationEpoch
311 : * Result:
312 : * CN=NTDS Settings,<rid_manager_fsmo_server_object>
313 : */
314 :
315 : /*
316 : * LDAP search 1st LDAP connection:
317 : *
318 : * see: becomeDC_ldap1_site_object()
319 : *
320 : * Request:
321 : * basedn: CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
322 : * scope: base
323 : * filter: (objectClass=*)
324 : * attrs:
325 : * Result:
326 : * CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
327 : * objectClass: top
328 : * site
329 : * cn: <new_dc_site_name>
330 : * distinguishedName:CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
331 : * instanceType: 4
332 : * whenCreated: ...
333 : * whenChanged: ...
334 : * uSNCreated: ...
335 : * uSNChanged: ...
336 : * showInAdvancedViewOnly: TRUE
337 : * name: <new_dc_site_name>
338 : * objectGUID: <object_guid>
339 : * systemFlags: 1107296256 <0x42000000>
340 : * objectCategory: CN=Site,CN=Schema,CN=Configuration,<domain_partition>
341 : */
342 :
343 : /***************************************************************
344 : * Add this stage we call the check_options() callback function
345 : * of the caller, to see if he wants us to continue
346 : *
347 : * see: becomeDC_check_options()
348 : ***************************************************************/
349 :
350 : /*
351 : * LDAP search 1st LDAP connection:
352 : *
353 : * see: becomeDC_ldap1_computer_object()
354 : *
355 : * Request:
356 : * basedn: <domain_partition>
357 : * scope: sub
358 : * filter: (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<new_dc_account_name>))
359 : * attrs: distinguishedName
360 : * userAccountControl
361 : * Result:
362 : * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
363 : * distinguishedName: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
364 : * userAccountControl: 4096 <0x1000>
365 : */
366 :
367 : /*
368 : * LDAP search 1st LDAP connection:
369 : *
370 : * see: becomeDC_ldap1_server_object_1()
371 : *
372 : * Request:
373 : * basedn: CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
374 : * scope: base
375 : * filter: (objectClass=*)
376 : * attrs:
377 : * Result:
378 : * <noSuchObject>
379 : * <matchedDN:CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
380 : */
381 :
382 : /*
383 : * LDAP search 1st LDAP connection:
384 : *
385 : * see: becomeDC_ldap1_server_object_2()
386 : *
387 : * Request:
388 : * basedn: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
389 : * scope: base
390 : * filter: (objectClass=*)
391 : * attrs: serverReferenceBL
392 : * typesOnly: TRUE!!!
393 : * Result:
394 : * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
395 : */
396 :
397 : /*
398 : * LDAP add 1st LDAP connection:
399 : *
400 : * see: becomeDC_ldap1_server_object_add()
401 : *
402 : * Request:
403 : * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
404 : * objectClass: server
405 : * systemFlags: 50000000 <0x2FAF080>
406 : * serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
407 : * Result:
408 : * <success>
409 : */
410 :
411 : /*
412 : * LDAP search 1st LDAP connection:
413 : *
414 : * not implemented, maybe we can add that later
415 : *
416 : * Request:
417 : * basedn: CN=NTDS Settings,CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>
418 : * scope: base
419 : * filter: (objectClass=*)
420 : * attrs:
421 : * Result:
422 : * <noSuchObject>
423 : * <matchedDN:CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
424 : */
425 :
426 : /*
427 : * LDAP search 1st LDAP connection:
428 : *
429 : * not implemented because it gives no new information
430 : *
431 : * Request:
432 : * basedn: CN=Partitions,CN=Configuration,<domain_partition>
433 : * scope: sub
434 : * filter: (nCName=<domain_partition>)
435 : * attrs: nCName
436 : * dnsRoot
437 : * controls: LDAP_SERVER_EXTENDED_DN_OID:critical=false
438 : * Result:
439 : * <GUID=<hex_guid>>;CN=<domain_netbios_name>,CN=Partitions,<domain_partition>>
440 : * nCName: <GUID=<hex_guid>>;<SID=<hex_sid>>;<domain_partition>>
441 : * dnsRoot: <domain_dns_name>
442 : */
443 :
444 : /*
445 : * LDAP modify 1st LDAP connection:
446 : *
447 : * see: becomeDC_ldap1_server_object_modify()
448 : *
449 : * Request (add):
450 : * CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
451 : * serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
452 : * Result:
453 : * <attributeOrValueExist>
454 : */
455 :
456 : /*
457 : * LDAP modify 1st LDAP connection:
458 : *
459 : * see: becomeDC_ldap1_server_object_modify()
460 : *
461 : * Request (replace):
462 : * CN=<new_dc_netbios_name>,CN=Servers,CN=<new_dc_site_name>,CN=Sites,CN=Configuration,<domain_partition>>
463 : * serverReference:CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
464 : * Result:
465 : * <success>
466 : */
467 :
468 : /*
469 : * Open 1st DRSUAPI connection to the DC using admin credentials
470 : * DsBind with DRSUAPI_DS_BIND_GUID_W2K3 ("6afab99c-6e26-464a-975f-f58f105218bc")
471 : * (w2k3 does 2 DsBind() calls here..., where is first is unused and contains garbage at the end)
472 : *
473 : * see: becomeDC_drsuapi_connect_send(), becomeDC_drsuapi1_connect_recv(),
474 : * becomeDC_drsuapi_bind_send(), becomeDC_drsuapi_bind_recv() and becomeDC_drsuapi1_bind_recv()
475 : */
476 :
477 : /*
478 : * DsAddEntry to create the CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
479 : * on the 1st DRSUAPI connection
480 : *
481 : * see: becomeDC_drsuapi1_add_entry_send() and becomeDC_drsuapi1_add_entry_recv()
482 : */
483 :
484 : /***************************************************************
485 : * Add this stage we call the prepare_db() callback function
486 : * of the caller, to see if he wants us to continue
487 : *
488 : * see: becomeDC_prepare_db()
489 : ***************************************************************/
490 :
491 : /*
492 : * Open 2nd and 3rd DRSUAPI connection to the DC using admin credentials
493 : * - a DsBind with DRSUAPI_DS_BIND_GUID_W2K3 ("6afab99c-6e26-464a-975f-f58f105218bc")
494 : * on the 2nd connection
495 : *
496 : * see: becomeDC_drsuapi_connect_send(), becomeDC_drsuapi2_connect_recv(),
497 : * becomeDC_drsuapi_bind_send(), becomeDC_drsuapi_bind_recv(), becomeDC_drsuapi2_bind_recv()
498 : * and becomeDC_drsuapi3_connect_recv()
499 : */
500 :
501 : /*
502 : * replicate CN=Schema,CN=Configuration,...
503 : * on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection
504 : *
505 : * see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(),
506 : * becomeDC_drsuapi3_pull_schema_send() and becomeDC_drsuapi3_pull_schema_recv()
507 : *
508 : ***************************************************************
509 : * Add this stage we call the schema_chunk() callback function
510 : * for each replication message
511 : ***************************************************************/
512 :
513 : /*
514 : * replicate CN=Configuration,...
515 : * on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection
516 : *
517 : * see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(),
518 : * becomeDC_drsuapi3_pull_config_send() and becomeDC_drsuapi3_pull_config_recv()
519 : *
520 : ***************************************************************
521 : * Add this stage we call the config_chunk() callback function
522 : * for each replication message
523 : ***************************************************************/
524 :
525 : /*
526 : * LDAP unbind on the 1st LDAP connection
527 : *
528 : * not implemented, because it's not needed...
529 : */
530 :
531 : /*
532 : * Open 2nd LDAP connection to the DC using admin credentials
533 : *
534 : * see: becomeDC_connect_ldap2() and becomeDC_ldap_connect()
535 : */
536 :
537 : /*
538 : * LDAP search 2nd LDAP connection:
539 : *
540 : * not implemented because it gives no new information
541 : * same as becomeDC_ldap1_computer_object()
542 : *
543 : * Request:
544 : * basedn: <domain_partition>
545 : * scope: sub
546 : * filter: (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<new_dc_account_name>))
547 : * attrs: distinguishedName
548 : * userAccountControl
549 : * Result:
550 : * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
551 : * distinguishedName: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
552 : * userAccountControl: 4096 <0x00001000>
553 : */
554 :
555 : /*
556 : * LDAP search 2nd LDAP connection:
557 : *
558 : * not implemented because it gives no new information
559 : * same as becomeDC_ldap1_computer_object()
560 : *
561 : * Request:
562 : * basedn: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
563 : * scope: base
564 : * filter: (objectClass=*)
565 : * attrs: userAccountControl
566 : * Result:
567 : * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
568 : * userAccountControl: 4096 <0x00001000>
569 : */
570 :
571 : /*
572 : * LDAP modify 2nd LDAP connection:
573 : *
574 : * see: becomeDC_ldap2_modify_computer()
575 : *
576 : * Request (replace):
577 : * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
578 : * userAccountControl: 532480 <0x82000>
579 : * Result:
580 : * <success>
581 : */
582 :
583 : /*
584 : * LDAP search 2nd LDAP connection:
585 : *
586 : * see: becomeDC_ldap2_move_computer()
587 : *
588 : * Request:
589 : * basedn: <WKGUID=2fbac1870ade11d297c400c04fd8d5cd,<domain_partition>>
590 : * scope: base
591 : * filter: (objectClass=*)
592 : * attrs: 1.1
593 : * Result:
594 : * CN=Domain Controllers,<domain_partition>
595 : */
596 :
597 : /*
598 : * LDAP search 2nd LDAP connection:
599 : *
600 : * not implemented because it gives no new information
601 : *
602 : * Request:
603 : * basedn: CN=Domain Controllers,<domain_partition>
604 : * scope: base
605 : * filter: (objectClass=*)
606 : * attrs: distinguishedName
607 : * Result:
608 : * CN=Domain Controller,<domain_partition>
609 : * distinguishedName: CN=Domain Controllers,<domain_partition>
610 : */
611 :
612 : /*
613 : * LDAP modifyRDN 2nd LDAP connection:
614 : *
615 : * see: becomeDC_ldap2_move_computer()
616 : *
617 : * Request:
618 : * entry: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
619 : * newrdn: CN=<new_dc_netbios_name>
620 : * deleteoldrdn: TRUE
621 : * newparent: CN=Domain Controllers,<domain_partition>
622 : * Result:
623 : * <success>
624 : */
625 :
626 : /*
627 : * LDAP unbind on the 2nd LDAP connection
628 : *
629 : * not implemented, because it's not needed...
630 : */
631 :
632 : /*
633 : * replicate Domain Partition
634 : * on the 3rd DRSUAPI connection and the bind_handle from the 2nd connection
635 : *
636 : * see: becomeDC_drsuapi_pull_partition_send(), becomeDC_drsuapi_pull_partition_recv(),
637 : * becomeDC_drsuapi3_pull_domain_send() and becomeDC_drsuapi3_pull_domain_recv()
638 : *
639 : ***************************************************************
640 : * Add this stage we call the domain_chunk() callback function
641 : * for each replication message
642 : ***************************************************************/
643 :
644 : /* call DsReplicaUpdateRefs() for all partitions like this:
645 : * req1: struct drsuapi_DsReplicaUpdateRefsRequest1
646 : *
647 : * naming_context: struct drsuapi_DsReplicaObjectIdentifier
648 : * __ndr_size : 0x000000ae (174)
649 : * __ndr_size_sid : 0x00000000 (0)
650 : * guid : 00000000-0000-0000-0000-000000000000
651 : * sid : S-0-0
652 : * dn : 'CN=Schema,CN=Configuration,DC=w2k3,DC=vmnet1,DC=vm,DC=base'
653 : *
654 : * dest_dsa_dns_name : '4a0df188-a0b8-47ea-bbe5-e614723f16dd._msdcs.w2k3.vmnet1.vm.base'
655 : * dest_dsa_guid : 4a0df188-a0b8-47ea-bbe5-e614723f16dd
656 : * options : 0x0000001c (28)
657 : * 0: DRSUAPI_DS_REPLICA_UPDATE_ASYNCHRONOUS_OPERATION
658 : * 0: DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE
659 : * 1: DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE
660 : * 1: DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE
661 : * 1: DRSUAPI_DS_REPLICA_UPDATE_0x00000010
662 : *
663 : * 4a0df188-a0b8-47ea-bbe5-e614723f16dd is the objectGUID the DsAddEntry() returned for the
664 : * CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
665 : * on the 2nd!!! DRSUAPI connection
666 : *
667 : * see: becomeDC_drsuapi_update_refs_send(), becomeDC_drsuapi2_update_refs_schema_recv(),
668 : * becomeDC_drsuapi2_update_refs_config_recv() and becomeDC_drsuapi2_update_refs_domain_recv()
669 : */
670 :
671 : /*
672 : * Windows does opens the 4th and 5th DRSUAPI connection...
673 : * and does a DsBind() with the objectGUID from DsAddEntry() as bind_guid
674 : * on the 4th connection
675 : *
676 : * and then 2 full replications of the domain partition on the 5th connection
677 : * with the bind_handle from the 4th connection
678 : *
679 : * not implemented because it gives no new information
680 : */
681 :
682 : struct libnet_BecomeDC_state {
683 : struct composite_context *creq;
684 :
685 : struct libnet_context *libnet;
686 :
687 : struct dom_sid zero_sid;
688 :
689 : struct {
690 : struct cldap_socket *sock;
691 : struct cldap_netlogon io;
692 : struct NETLOGON_SAM_LOGON_RESPONSE_EX netlogon;
693 : } cldap;
694 :
695 : struct becomeDC_ldap {
696 : struct ldb_context *ldb;
697 : const struct ldb_message *rootdse;
698 : } ldap1, ldap2;
699 :
700 : struct becomeDC_drsuapi {
701 : struct libnet_BecomeDC_state *s;
702 : struct dcerpc_binding *binding;
703 : struct dcerpc_pipe *pipe;
704 : struct dcerpc_binding_handle *drsuapi_handle;
705 : DATA_BLOB gensec_skey;
706 : struct drsuapi_DsBind bind_r;
707 : struct GUID bind_guid;
708 : struct drsuapi_DsBindInfoCtr bind_info_ctr;
709 : struct drsuapi_DsBindInfo28 local_info28;
710 : struct drsuapi_DsBindInfo28 remote_info28;
711 : struct policy_handle bind_handle;
712 : } drsuapi1, drsuapi2, drsuapi3;
713 :
714 : void *ndr_struct_ptr;
715 :
716 : struct libnet_BecomeDC_Domain domain;
717 : struct libnet_BecomeDC_Forest forest;
718 : struct libnet_BecomeDC_SourceDSA source_dsa;
719 : struct libnet_BecomeDC_DestDSA dest_dsa;
720 :
721 : struct libnet_BecomeDC_Partition schema_part, config_part, domain_part;
722 :
723 : struct becomeDC_fsmo {
724 : const char *dns_name;
725 : const char *server_dn_str;
726 : const char *ntds_dn_str;
727 : struct GUID ntds_guid;
728 : } infrastructure_fsmo;
729 :
730 : struct becomeDC_fsmo rid_manager_fsmo;
731 :
732 : struct libnet_BecomeDC_CheckOptions _co;
733 : struct libnet_BecomeDC_PrepareDB _pp;
734 : struct libnet_BecomeDC_StoreChunk _sc;
735 : struct libnet_BecomeDC_Callbacks callbacks;
736 :
737 : bool rodc_join;
738 : bool critical_only;
739 : };
740 :
741 24 : static int32_t get_dc_function_level(struct loadparm_context *lp_ctx)
742 : {
743 : /* per default we are (Windows) 2008 R2 compatible */
744 24 : return lpcfg_parm_int(lp_ctx, NULL, "ads", "dc function level",
745 : DS_DOMAIN_FUNCTION_2008_R2);
746 : }
747 :
748 : static void becomeDC_recv_cldap(struct tevent_req *req);
749 :
750 4 : static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
751 : {
752 4 : struct composite_context *c = s->creq;
753 2 : struct tevent_req *req;
754 2 : struct tsocket_address *dest_address;
755 2 : int ret;
756 :
757 4 : s->cldap.io.in.dest_address = NULL;
758 4 : s->cldap.io.in.dest_port = 0;
759 4 : s->cldap.io.in.realm = s->domain.dns_name;
760 4 : s->cldap.io.in.host = s->dest_dsa.netbios_name;
761 4 : s->cldap.io.in.user = NULL;
762 4 : s->cldap.io.in.domain_guid = NULL;
763 4 : s->cldap.io.in.domain_sid = NULL;
764 4 : s->cldap.io.in.acct_control = -1;
765 4 : s->cldap.io.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
766 4 : s->cldap.io.in.map_response = true;
767 :
768 4 : ret = tsocket_address_inet_from_strings(s, "ip",
769 : s->source_dsa.address,
770 : lpcfg_cldap_port(s->libnet->lp_ctx),
771 : &dest_address);
772 4 : if (ret != 0) {
773 0 : c->status = map_nt_error_from_unix_common(errno);
774 0 : if (!composite_is_ok(c)) return;
775 : }
776 :
777 4 : c->status = cldap_socket_init(s, NULL, dest_address, &s->cldap.sock);
778 4 : if (!composite_is_ok(c)) return;
779 :
780 8 : req = cldap_netlogon_send(s, s->libnet->event_ctx,
781 4 : s->cldap.sock, &s->cldap.io);
782 4 : if (composite_nomem(req, c)) return;
783 4 : tevent_req_set_callback(req, becomeDC_recv_cldap, s);
784 : }
785 :
786 : static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s);
787 :
788 4 : static void becomeDC_recv_cldap(struct tevent_req *req)
789 : {
790 4 : struct libnet_BecomeDC_state *s = tevent_req_callback_data(req,
791 : struct libnet_BecomeDC_state);
792 4 : struct composite_context *c = s->creq;
793 :
794 4 : c->status = cldap_netlogon_recv(req, s, &s->cldap.io);
795 4 : talloc_free(req);
796 4 : if (!composite_is_ok(c)) {
797 0 : DEBUG(0,("Failed to send, receive or parse CLDAP reply from server %s for our host %s: %s\n",
798 : s->cldap.io.in.dest_address,
799 : s->cldap.io.in.host,
800 : nt_errstr(c->status)));
801 0 : return;
802 : }
803 4 : s->cldap.netlogon = s->cldap.io.out.netlogon.data.nt5_ex;
804 :
805 4 : s->domain.dns_name = s->cldap.netlogon.dns_domain;
806 4 : s->domain.netbios_name = s->cldap.netlogon.domain_name;
807 4 : s->domain.guid = s->cldap.netlogon.domain_uuid;
808 :
809 4 : s->forest.dns_name = s->cldap.netlogon.forest;
810 :
811 4 : s->source_dsa.dns_name = s->cldap.netlogon.pdc_dns_name;
812 4 : s->source_dsa.netbios_name = s->cldap.netlogon.pdc_name;
813 4 : s->source_dsa.site_name = s->cldap.netlogon.server_site;
814 :
815 4 : s->dest_dsa.site_name = s->cldap.netlogon.client_site;
816 :
817 4 : DEBUG(0,("CLDAP response: forest=%s dns=%s netbios=%s server_site=%s client_site=%s\n",
818 : s->forest.dns_name, s->domain.dns_name, s->domain.netbios_name,
819 : s->source_dsa.site_name, s->dest_dsa.site_name));
820 4 : if (!s->dest_dsa.site_name || strcmp(s->dest_dsa.site_name, "") == 0) {
821 0 : DEBUG(0,("Got empty client site - using server site name %s\n",
822 : s->source_dsa.site_name));
823 0 : s->dest_dsa.site_name = s->source_dsa.site_name;
824 : }
825 :
826 4 : becomeDC_connect_ldap1(s);
827 : }
828 :
829 8 : static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s,
830 : struct becomeDC_ldap *ldap)
831 : {
832 4 : char *url;
833 :
834 8 : url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
835 8 : NT_STATUS_HAVE_NO_MEMORY(url);
836 :
837 16 : ldap->ldb = ldb_wrap_connect(s, s->libnet->event_ctx, s->libnet->lp_ctx, url,
838 : NULL,
839 8 : s->libnet->cred,
840 : 0);
841 8 : talloc_free(url);
842 8 : if (ldap->ldb == NULL) {
843 0 : return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
844 : }
845 :
846 8 : return NT_STATUS_OK;
847 : }
848 :
849 4 : static NTSTATUS becomeDC_ldap1_rootdse(struct libnet_BecomeDC_state *s)
850 : {
851 2 : int ret;
852 2 : struct ldb_result *r;
853 2 : struct ldb_dn *basedn;
854 2 : static const char *attrs[] = {
855 : "*",
856 : NULL
857 : };
858 :
859 4 : basedn = ldb_dn_new(s, s->ldap1.ldb, NULL);
860 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
861 :
862 4 : ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
863 : "(objectClass=*)");
864 4 : talloc_free(basedn);
865 4 : if (ret != LDB_SUCCESS) {
866 0 : return NT_STATUS_LDAP(ret);
867 4 : } else if (r->count != 1) {
868 0 : talloc_free(r);
869 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
870 : }
871 :
872 4 : s->ldap1.rootdse = r->msgs[0];
873 :
874 4 : s->domain.dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "defaultNamingContext", NULL);
875 4 : if (!s->domain.dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
876 :
877 4 : s->forest.root_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "rootDomainNamingContext", NULL);
878 4 : if (!s->forest.root_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
879 4 : s->forest.config_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "configurationNamingContext", NULL);
880 4 : if (!s->forest.config_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
881 4 : s->forest.schema_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "schemaNamingContext", NULL);
882 4 : if (!s->forest.schema_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
883 :
884 4 : s->source_dsa.server_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "serverName", NULL);
885 4 : if (!s->source_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
886 4 : s->source_dsa.ntds_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "dsServiceName", NULL);
887 4 : if (!s->source_dsa.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
888 :
889 4 : return NT_STATUS_OK;
890 : }
891 :
892 4 : static NTSTATUS becomeDC_ldap1_crossref_behavior_version(struct libnet_BecomeDC_state *s)
893 : {
894 2 : int ret;
895 2 : struct ldb_result *r;
896 2 : struct ldb_dn *basedn;
897 2 : static const char *attrs[] = {
898 : "msDs-Behavior-Version",
899 : NULL
900 : };
901 :
902 4 : basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.config_dn_str);
903 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
904 :
905 4 : ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_ONELEVEL, attrs,
906 : "(cn=Partitions)");
907 4 : talloc_free(basedn);
908 4 : if (ret != LDB_SUCCESS) {
909 0 : return NT_STATUS_LDAP(ret);
910 4 : } else if (r->count != 1) {
911 0 : talloc_free(r);
912 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
913 : }
914 :
915 4 : s->forest.crossref_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
916 8 : if (s->forest.crossref_behavior_version >
917 4 : get_dc_function_level(s->libnet->lp_ctx)) {
918 0 : talloc_free(r);
919 0 : DEBUG(0,("The servers function level %u is above 'ads:dc function level' of %u\n",
920 : s->forest.crossref_behavior_version,
921 : get_dc_function_level(s->libnet->lp_ctx)));
922 0 : return NT_STATUS_NOT_SUPPORTED;
923 : }
924 :
925 4 : talloc_free(r);
926 4 : return NT_STATUS_OK;
927 : }
928 :
929 4 : static NTSTATUS becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_state *s)
930 : {
931 2 : int ret;
932 2 : struct ldb_result *r;
933 2 : struct ldb_dn *basedn;
934 2 : static const char *attrs[] = {
935 : "msDs-Behavior-Version",
936 : NULL
937 : };
938 :
939 4 : basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
940 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
941 :
942 4 : ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
943 : "(objectClass=*)");
944 4 : talloc_free(basedn);
945 4 : if (ret != LDB_SUCCESS) {
946 0 : return NT_STATUS_LDAP(ret);
947 4 : } else if (r->count != 1) {
948 0 : talloc_free(r);
949 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
950 : }
951 :
952 4 : s->domain.behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
953 8 : if (s->domain.behavior_version >
954 4 : get_dc_function_level(s->libnet->lp_ctx)) {
955 0 : talloc_free(r);
956 0 : DEBUG(0,("The servers function level %u is above 'ads:dc function level' of %u\n",
957 : s->forest.crossref_behavior_version,
958 : get_dc_function_level(s->libnet->lp_ctx)));
959 0 : return NT_STATUS_NOT_SUPPORTED;
960 : }
961 :
962 4 : talloc_free(r);
963 4 : return NT_STATUS_OK;
964 : }
965 :
966 4 : static NTSTATUS becomeDC_ldap1_schema_object_version(struct libnet_BecomeDC_state *s)
967 : {
968 2 : int ret;
969 2 : struct ldb_result *r;
970 2 : struct ldb_dn *basedn;
971 2 : static const char *attrs[] = {
972 : "objectVersion",
973 : NULL
974 : };
975 :
976 4 : basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.schema_dn_str);
977 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
978 :
979 4 : ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
980 : "(objectClass=*)");
981 4 : talloc_free(basedn);
982 4 : if (ret != LDB_SUCCESS) {
983 0 : return NT_STATUS_LDAP(ret);
984 4 : } else if (r->count != 1) {
985 0 : talloc_free(r);
986 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
987 : }
988 :
989 4 : s->forest.schema_object_version = ldb_msg_find_attr_as_uint(r->msgs[0], "objectVersion", 0);
990 :
991 4 : talloc_free(r);
992 4 : return NT_STATUS_OK;
993 : }
994 :
995 4 : static NTSTATUS becomeDC_ldap1_w2k3_update_revision(struct libnet_BecomeDC_state *s)
996 : {
997 2 : int ret;
998 2 : struct ldb_result *r;
999 2 : struct ldb_dn *basedn;
1000 2 : static const char *attrs[] = {
1001 : "revision",
1002 : NULL
1003 : };
1004 :
1005 4 : basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=Windows2003Update,CN=DomainUpdates,CN=System,%s",
1006 : s->domain.dn_str);
1007 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
1008 :
1009 4 : ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
1010 : "(objectClass=*)");
1011 4 : talloc_free(basedn);
1012 4 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1013 : /* w2k doesn't have this object */
1014 0 : s->domain.w2k3_update_revision = 0;
1015 0 : return NT_STATUS_OK;
1016 4 : } else if (ret != LDB_SUCCESS) {
1017 0 : return NT_STATUS_LDAP(ret);
1018 4 : } else if (r->count != 1) {
1019 0 : talloc_free(r);
1020 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1021 : }
1022 :
1023 4 : s->domain.w2k3_update_revision = ldb_msg_find_attr_as_uint(r->msgs[0], "revision", 0);
1024 :
1025 4 : talloc_free(r);
1026 4 : return NT_STATUS_OK;
1027 : }
1028 :
1029 4 : static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state *s)
1030 : {
1031 2 : int ret;
1032 2 : struct ldb_result *r;
1033 2 : struct ldb_dn *basedn;
1034 2 : struct ldb_dn *ntds_dn;
1035 2 : struct ldb_dn *server_dn;
1036 2 : static const char *dns_attrs[] = {
1037 : "dnsHostName",
1038 : NULL
1039 : };
1040 2 : static const char *guid_attrs[] = {
1041 : "objectGUID",
1042 : NULL
1043 : };
1044 :
1045 4 : ret = dsdb_wellknown_dn(s->ldap1.ldb, s,
1046 : ldb_get_default_basedn(s->ldap1.ldb),
1047 : DS_GUID_INFRASTRUCTURE_CONTAINER,
1048 : &basedn);
1049 4 : if (ret != LDB_SUCCESS) {
1050 0 : DEBUG(0,("Failed to get well known DN for DS_GUID_INFRASTRUCTURE_CONTAINER on %s: %s\n",
1051 : ldb_dn_get_linearized(ldb_get_default_basedn(s->ldap1.ldb)),
1052 : ldb_errstring(s->ldap1.ldb)));
1053 0 : return NT_STATUS_LDAP(ret);
1054 : }
1055 :
1056 4 : ret = samdb_reference_dn(s->ldap1.ldb, s, basedn, "fSMORoleOwner", &ntds_dn);
1057 4 : if (ret != LDB_SUCCESS) {
1058 0 : DEBUG(0,("Failed to get reference DN from fsmoRoleOwner on %s: %s\n",
1059 : ldb_dn_get_linearized(basedn),
1060 : ldb_errstring(s->ldap1.ldb)));
1061 0 : talloc_free(basedn);
1062 0 : return NT_STATUS_LDAP(ret);
1063 : }
1064 :
1065 4 : s->infrastructure_fsmo.ntds_dn_str = ldb_dn_get_linearized(ntds_dn);
1066 4 : NT_STATUS_HAVE_NO_MEMORY(s->infrastructure_fsmo.ntds_dn_str);
1067 :
1068 4 : server_dn = ldb_dn_get_parent(s, ntds_dn);
1069 4 : NT_STATUS_HAVE_NO_MEMORY(server_dn);
1070 :
1071 4 : s->infrastructure_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
1072 4 : NT_STATUS_HAVE_NO_MEMORY(s->infrastructure_fsmo.server_dn_str);
1073 :
1074 4 : ret = ldb_search(s->ldap1.ldb, s, &r, server_dn, LDB_SCOPE_BASE,
1075 : dns_attrs, "(objectClass=*)");
1076 4 : if (ret != LDB_SUCCESS) {
1077 0 : DEBUG(0,("Failed to get server DN %s: %s\n",
1078 : ldb_dn_get_linearized(server_dn),
1079 : ldb_errstring(s->ldap1.ldb)));
1080 0 : return NT_STATUS_LDAP(ret);
1081 4 : } else if (r->count != 1) {
1082 0 : talloc_free(r);
1083 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1084 : }
1085 :
1086 4 : s->infrastructure_fsmo.dns_name = ldb_msg_find_attr_as_string(r->msgs[0], "dnsHostName", NULL);
1087 4 : if (!s->infrastructure_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1088 4 : talloc_steal(s, s->infrastructure_fsmo.dns_name);
1089 :
1090 4 : talloc_free(r);
1091 :
1092 4 : ldb_dn_remove_extended_components(ntds_dn);
1093 4 : ret = ldb_search(s->ldap1.ldb, s, &r, ntds_dn, LDB_SCOPE_BASE,
1094 : guid_attrs, "(objectClass=*)");
1095 4 : if (ret != LDB_SUCCESS) {
1096 0 : DEBUG(0,("Failed to get NTDS Settings DN %s: %s\n",
1097 : ldb_dn_get_linearized(ntds_dn),
1098 : ldb_errstring(s->ldap1.ldb)));
1099 0 : return NT_STATUS_LDAP(ret);
1100 4 : } else if (r->count != 1) {
1101 0 : talloc_free(r);
1102 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1103 : }
1104 :
1105 4 : s->infrastructure_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
1106 :
1107 4 : talloc_free(r);
1108 :
1109 4 : return NT_STATUS_OK;
1110 : }
1111 :
1112 4 : static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s)
1113 : {
1114 2 : int ret;
1115 2 : struct ldb_result *r;
1116 2 : struct ldb_dn *basedn;
1117 2 : const char *reference_dn_str;
1118 2 : struct ldb_dn *ntds_dn;
1119 2 : struct ldb_dn *server_dn;
1120 2 : static const char *rid_attrs[] = {
1121 : "rIDManagerReference",
1122 : NULL
1123 : };
1124 2 : static const char *fsmo_attrs[] = {
1125 : "fSMORoleOwner",
1126 : NULL
1127 : };
1128 2 : static const char *dns_attrs[] = {
1129 : "dnsHostName",
1130 : NULL
1131 : };
1132 2 : static const char *guid_attrs[] = {
1133 : "objectGUID",
1134 : NULL
1135 : };
1136 :
1137 4 : basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
1138 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
1139 :
1140 4 : ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
1141 : rid_attrs, "(objectClass=*)");
1142 4 : talloc_free(basedn);
1143 4 : if (ret != LDB_SUCCESS) {
1144 0 : return NT_STATUS_LDAP(ret);
1145 4 : } else if (r->count != 1) {
1146 0 : talloc_free(r);
1147 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1148 : }
1149 :
1150 4 : reference_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "rIDManagerReference", NULL);
1151 4 : if (!reference_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1152 :
1153 4 : basedn = ldb_dn_new(s, s->ldap1.ldb, reference_dn_str);
1154 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
1155 :
1156 4 : talloc_free(r);
1157 :
1158 4 : ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
1159 : fsmo_attrs, "(objectClass=*)");
1160 4 : talloc_free(basedn);
1161 4 : if (ret != LDB_SUCCESS) {
1162 0 : return NT_STATUS_LDAP(ret);
1163 4 : } else if (r->count != 1) {
1164 0 : talloc_free(r);
1165 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1166 : }
1167 :
1168 4 : s->rid_manager_fsmo.ntds_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "fSMORoleOwner", NULL);
1169 4 : if (!s->rid_manager_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1170 4 : talloc_steal(s, s->rid_manager_fsmo.ntds_dn_str);
1171 :
1172 4 : talloc_free(r);
1173 :
1174 4 : ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->rid_manager_fsmo.ntds_dn_str);
1175 4 : NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
1176 :
1177 4 : server_dn = ldb_dn_get_parent(s, ntds_dn);
1178 4 : NT_STATUS_HAVE_NO_MEMORY(server_dn);
1179 :
1180 4 : s->rid_manager_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
1181 4 : NT_STATUS_HAVE_NO_MEMORY(s->rid_manager_fsmo.server_dn_str);
1182 :
1183 4 : ret = ldb_search(s->ldap1.ldb, s, &r, server_dn, LDB_SCOPE_BASE,
1184 : dns_attrs, "(objectClass=*)");
1185 4 : if (ret != LDB_SUCCESS) {
1186 0 : return NT_STATUS_LDAP(ret);
1187 4 : } else if (r->count != 1) {
1188 0 : talloc_free(r);
1189 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1190 : }
1191 :
1192 4 : s->rid_manager_fsmo.dns_name = ldb_msg_find_attr_as_string(r->msgs[0], "dnsHostName", NULL);
1193 4 : if (!s->rid_manager_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1194 4 : talloc_steal(s, s->rid_manager_fsmo.dns_name);
1195 :
1196 4 : talloc_free(r);
1197 :
1198 4 : ret = ldb_search(s->ldap1.ldb, s, &r, ntds_dn, LDB_SCOPE_BASE,
1199 : guid_attrs, "(objectClass=*)");
1200 4 : if (ret != LDB_SUCCESS) {
1201 0 : return NT_STATUS_LDAP(ret);
1202 4 : } else if (r->count != 1) {
1203 0 : talloc_free(r);
1204 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1205 : }
1206 :
1207 4 : s->rid_manager_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
1208 :
1209 4 : talloc_free(r);
1210 :
1211 4 : return NT_STATUS_OK;
1212 : }
1213 :
1214 4 : static NTSTATUS becomeDC_ldap1_site_object(struct libnet_BecomeDC_state *s)
1215 : {
1216 2 : int ret;
1217 2 : struct ldb_result *r;
1218 2 : struct ldb_dn *basedn;
1219 :
1220 4 : basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Sites,%s",
1221 : s->dest_dsa.site_name,
1222 : s->forest.config_dn_str);
1223 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
1224 :
1225 4 : ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
1226 : NULL, "(objectClass=*)");
1227 4 : talloc_free(basedn);
1228 4 : if (ret != LDB_SUCCESS) {
1229 0 : return NT_STATUS_LDAP(ret);
1230 4 : } else if (r->count != 1) {
1231 0 : talloc_free(r);
1232 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1233 : }
1234 :
1235 4 : s->dest_dsa.site_guid = samdb_result_guid(r->msgs[0], "objectGUID");
1236 :
1237 4 : talloc_free(r);
1238 4 : return NT_STATUS_OK;
1239 : }
1240 :
1241 4 : static NTSTATUS becomeDC_check_options(struct libnet_BecomeDC_state *s)
1242 : {
1243 4 : if (!s->callbacks.check_options) return NT_STATUS_OK;
1244 :
1245 4 : s->_co.domain = &s->domain;
1246 4 : s->_co.forest = &s->forest;
1247 4 : s->_co.source_dsa = &s->source_dsa;
1248 :
1249 4 : return s->callbacks.check_options(s->callbacks.private_data, &s->_co);
1250 : }
1251 :
1252 4 : static NTSTATUS becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state *s)
1253 : {
1254 2 : int ret;
1255 2 : struct ldb_result *r;
1256 2 : struct ldb_dn *basedn;
1257 2 : static const char *attrs[] = {
1258 : "distinguishedName",
1259 : "userAccountControl",
1260 : NULL
1261 : };
1262 :
1263 4 : basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
1264 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
1265 :
1266 4 : ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_SUBTREE, attrs,
1267 : "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))",
1268 : s->dest_dsa.netbios_name);
1269 4 : talloc_free(basedn);
1270 4 : if (ret != LDB_SUCCESS) {
1271 0 : return NT_STATUS_LDAP(ret);
1272 4 : } else if (r->count != 1) {
1273 0 : talloc_free(r);
1274 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1275 : }
1276 :
1277 4 : s->dest_dsa.computer_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "distinguishedName", NULL);
1278 4 : if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1279 4 : talloc_steal(s, s->dest_dsa.computer_dn_str);
1280 :
1281 4 : s->dest_dsa.user_account_control = ldb_msg_find_attr_as_uint(r->msgs[0], "userAccountControl", 0);
1282 :
1283 4 : talloc_free(r);
1284 4 : return NT_STATUS_OK;
1285 : }
1286 :
1287 4 : static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s)
1288 : {
1289 2 : int ret;
1290 2 : struct ldb_result *r;
1291 2 : struct ldb_dn *basedn;
1292 2 : const char *server_reference_dn_str;
1293 2 : struct ldb_dn *server_reference_dn;
1294 2 : struct ldb_dn *computer_dn;
1295 :
1296 4 : basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
1297 : s->dest_dsa.netbios_name,
1298 : s->dest_dsa.site_name,
1299 : s->forest.config_dn_str);
1300 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
1301 :
1302 4 : ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
1303 : NULL, "(objectClass=*)");
1304 4 : talloc_free(basedn);
1305 4 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1306 : /* if the object doesn't exist, we'll create it later */
1307 4 : return NT_STATUS_OK;
1308 0 : } else if (ret != LDB_SUCCESS) {
1309 0 : return NT_STATUS_LDAP(ret);
1310 0 : } else if (r->count != 1) {
1311 0 : talloc_free(r);
1312 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1313 : }
1314 :
1315 0 : server_reference_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "serverReference", NULL);
1316 0 : if (server_reference_dn_str) {
1317 0 : server_reference_dn = ldb_dn_new(r, s->ldap1.ldb, server_reference_dn_str);
1318 0 : NT_STATUS_HAVE_NO_MEMORY(server_reference_dn);
1319 :
1320 0 : computer_dn = ldb_dn_new(r, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
1321 0 : NT_STATUS_HAVE_NO_MEMORY(computer_dn);
1322 :
1323 : /*
1324 : * if the server object belongs to another DC in another domain
1325 : * in the forest, we should not touch this object!
1326 : */
1327 0 : if (ldb_dn_compare(computer_dn, server_reference_dn) != 0) {
1328 0 : talloc_free(r);
1329 0 : return NT_STATUS_OBJECT_NAME_COLLISION;
1330 : }
1331 : }
1332 :
1333 : /* if the server object is already for the dest_dsa, then we don't need to create it */
1334 0 : s->dest_dsa.server_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "distinguishedName", NULL);
1335 0 : if (!s->dest_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
1336 0 : talloc_steal(s, s->dest_dsa.server_dn_str);
1337 :
1338 0 : talloc_free(r);
1339 0 : return NT_STATUS_OK;
1340 : }
1341 :
1342 4 : static NTSTATUS becomeDC_ldap1_server_object_2(struct libnet_BecomeDC_state *s)
1343 : {
1344 2 : int ret;
1345 2 : struct ldb_result *r;
1346 2 : struct ldb_dn *basedn;
1347 2 : const char *server_reference_bl_dn_str;
1348 2 : static const char *attrs[] = {
1349 : "serverReferenceBL",
1350 : NULL
1351 : };
1352 :
1353 : /* if the server_dn_str has a valid value, we skip this lookup */
1354 4 : if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
1355 :
1356 4 : basedn = ldb_dn_new(s, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
1357 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
1358 :
1359 4 : ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE,
1360 : attrs, "(objectClass=*)");
1361 4 : talloc_free(basedn);
1362 4 : if (ret != LDB_SUCCESS) {
1363 0 : return NT_STATUS_LDAP(ret);
1364 4 : } else if (r->count != 1) {
1365 0 : talloc_free(r);
1366 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1367 : }
1368 :
1369 4 : server_reference_bl_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "serverReferenceBL", NULL);
1370 4 : if (!server_reference_bl_dn_str) {
1371 : /* if no back link is present, we're done for this function */
1372 4 : talloc_free(r);
1373 4 : return NT_STATUS_OK;
1374 : }
1375 :
1376 : /* if the server object is already for the dest_dsa, then we don't need to create it */
1377 0 : s->dest_dsa.server_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "serverReferenceBL", NULL);
1378 0 : if (s->dest_dsa.server_dn_str) {
1379 : /* if a back link is present, we know that the server object is present */
1380 0 : talloc_steal(s, s->dest_dsa.server_dn_str);
1381 : }
1382 :
1383 0 : talloc_free(r);
1384 0 : return NT_STATUS_OK;
1385 : }
1386 :
1387 4 : static NTSTATUS becomeDC_ldap1_server_object_add(struct libnet_BecomeDC_state *s)
1388 : {
1389 2 : int ret;
1390 2 : struct ldb_message *msg;
1391 2 : char *server_dn_str;
1392 :
1393 : /* if the server_dn_str has a valid value, we skip this lookup */
1394 4 : if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
1395 :
1396 4 : msg = ldb_msg_new(s);
1397 4 : NT_STATUS_HAVE_NO_MEMORY(msg);
1398 :
1399 4 : msg->dn = ldb_dn_new_fmt(msg, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
1400 : s->dest_dsa.netbios_name,
1401 : s->dest_dsa.site_name,
1402 : s->forest.config_dn_str);
1403 4 : NT_STATUS_HAVE_NO_MEMORY(msg->dn);
1404 :
1405 4 : ret = ldb_msg_add_string(msg, "objectClass", "server");
1406 4 : if (ret != 0) {
1407 0 : talloc_free(msg);
1408 0 : return NT_STATUS_NO_MEMORY;
1409 : }
1410 4 : ret = ldb_msg_add_string(msg, "systemFlags", "50000000");
1411 4 : if (ret != 0) {
1412 0 : talloc_free(msg);
1413 0 : return NT_STATUS_NO_MEMORY;
1414 : }
1415 4 : ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
1416 4 : if (ret != 0) {
1417 0 : talloc_free(msg);
1418 0 : return NT_STATUS_NO_MEMORY;
1419 : }
1420 :
1421 4 : server_dn_str = ldb_dn_alloc_linearized(s, msg->dn);
1422 4 : NT_STATUS_HAVE_NO_MEMORY(server_dn_str);
1423 :
1424 4 : ret = ldb_add(s->ldap1.ldb, msg);
1425 4 : talloc_free(msg);
1426 4 : if (ret != LDB_SUCCESS) {
1427 0 : talloc_free(server_dn_str);
1428 0 : return NT_STATUS_LDAP(ret);
1429 : }
1430 :
1431 4 : s->dest_dsa.server_dn_str = server_dn_str;
1432 :
1433 4 : return NT_STATUS_OK;
1434 : }
1435 :
1436 4 : static NTSTATUS becomeDC_ldap1_server_object_modify(struct libnet_BecomeDC_state *s)
1437 : {
1438 2 : int ret;
1439 2 : struct ldb_message *msg;
1440 2 : unsigned int i;
1441 :
1442 : /* make a 'modify' msg, and only for serverReference */
1443 4 : msg = ldb_msg_new(s);
1444 4 : NT_STATUS_HAVE_NO_MEMORY(msg);
1445 4 : msg->dn = ldb_dn_new(msg, s->ldap1.ldb, s->dest_dsa.server_dn_str);
1446 4 : NT_STATUS_HAVE_NO_MEMORY(msg->dn);
1447 :
1448 4 : ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
1449 4 : if (ret != 0) {
1450 0 : talloc_free(msg);
1451 0 : return NT_STATUS_NO_MEMORY;
1452 : }
1453 :
1454 : /* mark all the message elements (should be just one)
1455 : as LDB_FLAG_MOD_ADD */
1456 8 : for (i=0;i<msg->num_elements;i++) {
1457 4 : msg->elements[i].flags = LDB_FLAG_MOD_ADD;
1458 : }
1459 :
1460 4 : ret = ldb_modify(s->ldap1.ldb, msg);
1461 4 : if (ret == LDB_SUCCESS) {
1462 0 : talloc_free(msg);
1463 0 : return NT_STATUS_OK;
1464 4 : } else if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
1465 : /* retry with LDB_FLAG_MOD_REPLACE */
1466 : } else {
1467 0 : talloc_free(msg);
1468 0 : return NT_STATUS_LDAP(ret);
1469 : }
1470 :
1471 : /* mark all the message elements (should be just one)
1472 : as LDB_FLAG_MOD_REPLACE */
1473 8 : for (i=0;i<msg->num_elements;i++) {
1474 4 : msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1475 : }
1476 :
1477 4 : ret = ldb_modify(s->ldap1.ldb, msg);
1478 4 : talloc_free(msg);
1479 4 : if (ret != LDB_SUCCESS) {
1480 0 : return NT_STATUS_LDAP(ret);
1481 : }
1482 :
1483 4 : return NT_STATUS_OK;
1484 : }
1485 :
1486 : static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
1487 : struct becomeDC_drsuapi *drsuapi,
1488 : void (*recv_fn)(struct composite_context *req));
1489 : static void becomeDC_drsuapi1_connect_recv(struct composite_context *req);
1490 : static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s);
1491 :
1492 4 : static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s)
1493 : {
1494 4 : struct composite_context *c = s->creq;
1495 :
1496 4 : c->status = becomeDC_ldap_connect(s, &s->ldap1);
1497 4 : if (!composite_is_ok(c)) return;
1498 :
1499 4 : c->status = becomeDC_ldap1_rootdse(s);
1500 4 : if (!composite_is_ok(c)) return;
1501 :
1502 4 : c->status = becomeDC_ldap1_crossref_behavior_version(s);
1503 4 : if (!composite_is_ok(c)) return;
1504 :
1505 4 : c->status = becomeDC_ldap1_domain_behavior_version(s);
1506 4 : if (!composite_is_ok(c)) return;
1507 :
1508 4 : c->status = becomeDC_ldap1_schema_object_version(s);
1509 4 : if (!composite_is_ok(c)) return;
1510 :
1511 4 : c->status = becomeDC_ldap1_w2k3_update_revision(s);
1512 4 : if (!composite_is_ok(c)) return;
1513 :
1514 4 : c->status = becomeDC_ldap1_infrastructure_fsmo(s);
1515 4 : if (!composite_is_ok(c)) return;
1516 :
1517 4 : c->status = becomeDC_ldap1_rid_manager_fsmo(s);
1518 4 : if (!composite_is_ok(c)) return;
1519 :
1520 4 : c->status = becomeDC_ldap1_site_object(s);
1521 4 : if (!composite_is_ok(c)) return;
1522 :
1523 4 : c->status = becomeDC_check_options(s);
1524 4 : if (!composite_is_ok(c)) return;
1525 :
1526 4 : c->status = becomeDC_ldap1_computer_object(s);
1527 4 : if (!composite_is_ok(c)) return;
1528 :
1529 4 : c->status = becomeDC_ldap1_server_object_1(s);
1530 4 : if (!composite_is_ok(c)) return;
1531 :
1532 4 : c->status = becomeDC_ldap1_server_object_2(s);
1533 4 : if (!composite_is_ok(c)) return;
1534 :
1535 4 : c->status = becomeDC_ldap1_server_object_add(s);
1536 4 : if (!composite_is_ok(c)) return;
1537 :
1538 4 : c->status = becomeDC_ldap1_server_object_modify(s);
1539 4 : if (!composite_is_ok(c)) return;
1540 :
1541 4 : becomeDC_drsuapi_connect_send(s, &s->drsuapi1, becomeDC_drsuapi1_connect_recv);
1542 : }
1543 :
1544 12 : static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
1545 : struct becomeDC_drsuapi *drsuapi,
1546 : void (*recv_fn)(struct composite_context *req))
1547 : {
1548 12 : struct composite_context *c = s->creq;
1549 6 : struct composite_context *creq;
1550 6 : char *binding_str;
1551 :
1552 12 : drsuapi->s = s;
1553 :
1554 12 : if (!drsuapi->binding) {
1555 4 : const char *krb5_str = "";
1556 4 : const char *print_str = "";
1557 : /*
1558 : * Note: Replication only works with Windows 2000 when 'krb5' is
1559 : * passed as auth_type here. If NTLMSSP is used, Windows
1560 : * 2000 returns garbage in the DsGetNCChanges() response
1561 : * if encrypted password attributes would be in the
1562 : * response. That means the replication of the schema and
1563 : * configuration partition works fine, but it fails for
1564 : * the domain partition.
1565 : */
1566 4 : if (lpcfg_parm_bool(s->libnet->lp_ctx, NULL, "become_dc",
1567 : "force krb5", true))
1568 : {
1569 4 : krb5_str = "krb5,";
1570 : }
1571 4 : if (lpcfg_parm_bool(s->libnet->lp_ctx, NULL, "become_dc",
1572 : "print", false))
1573 : {
1574 0 : print_str = "print,";
1575 : }
1576 4 : binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[%s%sseal,target_hostname=%s]",
1577 : s->source_dsa.address,
1578 : krb5_str, print_str,
1579 : s->source_dsa.dns_name);
1580 4 : if (composite_nomem(binding_str, c)) return;
1581 4 : c->status = dcerpc_parse_binding(s, binding_str, &drsuapi->binding);
1582 4 : talloc_free(binding_str);
1583 4 : if (!composite_is_ok(c)) return;
1584 : }
1585 :
1586 12 : if (DEBUGLEVEL >= 10) {
1587 0 : c->status = dcerpc_binding_set_flags(drsuapi->binding,
1588 : DCERPC_DEBUG_PRINT_BOTH,
1589 : 0);
1590 0 : if (!composite_is_ok(c)) return;
1591 : }
1592 :
1593 24 : creq = dcerpc_pipe_connect_b_send(s, drsuapi->binding, &ndr_table_drsuapi,
1594 6 : s->libnet->cred, s->libnet->event_ctx,
1595 12 : s->libnet->lp_ctx);
1596 12 : composite_continue(c, creq, recv_fn, s);
1597 : }
1598 :
1599 : static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
1600 : struct becomeDC_drsuapi *drsuapi,
1601 : void (*recv_fn)(struct tevent_req *subreq));
1602 : static void becomeDC_drsuapi1_bind_recv(struct tevent_req *subreq);
1603 :
1604 4 : static void becomeDC_drsuapi1_connect_recv(struct composite_context *req)
1605 : {
1606 4 : struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
1607 : struct libnet_BecomeDC_state);
1608 4 : struct composite_context *c = s->creq;
1609 :
1610 4 : c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi1.pipe);
1611 4 : if (!composite_is_ok(c)) return;
1612 :
1613 4 : s->drsuapi1.drsuapi_handle = s->drsuapi1.pipe->binding_handle;
1614 :
1615 4 : c->status = gensec_session_key(s->drsuapi1.pipe->conn->security_state.generic_state,
1616 : s,
1617 : &s->drsuapi1.gensec_skey);
1618 4 : if (!composite_is_ok(c)) return;
1619 :
1620 4 : becomeDC_drsuapi_bind_send(s, &s->drsuapi1, becomeDC_drsuapi1_bind_recv);
1621 : }
1622 :
1623 8 : static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
1624 : struct becomeDC_drsuapi *drsuapi,
1625 : void (*recv_fn)(struct tevent_req *subreq))
1626 : {
1627 8 : struct composite_context *c = s->creq;
1628 4 : struct drsuapi_DsBindInfo28 *bind_info28;
1629 4 : struct tevent_req *subreq;
1630 :
1631 8 : GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &drsuapi->bind_guid);
1632 :
1633 8 : bind_info28 = &drsuapi->local_info28;
1634 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
1635 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
1636 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
1637 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
1638 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
1639 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
1640 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
1641 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
1642 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
1643 8 : if (s->domain.behavior_version >= DS_DOMAIN_FUNCTION_2003) {
1644 : /* TODO: find out how this is really triggered! */
1645 4 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
1646 : }
1647 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
1648 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
1649 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
1650 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
1651 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
1652 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
1653 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
1654 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
1655 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
1656 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V5;
1657 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
1658 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
1659 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
1660 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
1661 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
1662 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
1663 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
1664 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
1665 8 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
1666 : #if 0 /* we don't support XPRESS compression yet */
1667 : bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
1668 : #endif
1669 8 : bind_info28->site_guid = s->dest_dsa.site_guid;
1670 8 : bind_info28->pid = 0;
1671 8 : bind_info28->repl_epoch = 0;
1672 :
1673 8 : drsuapi->bind_info_ctr.length = 28;
1674 8 : drsuapi->bind_info_ctr.info.info28 = *bind_info28;
1675 :
1676 8 : drsuapi->bind_r.in.bind_guid = &drsuapi->bind_guid;
1677 8 : drsuapi->bind_r.in.bind_info = &drsuapi->bind_info_ctr;
1678 8 : drsuapi->bind_r.out.bind_handle = &drsuapi->bind_handle;
1679 :
1680 8 : subreq = dcerpc_drsuapi_DsBind_r_send(s, c->event_ctx,
1681 : drsuapi->drsuapi_handle,
1682 : &drsuapi->bind_r);
1683 8 : if (composite_nomem(subreq, c)) return;
1684 8 : tevent_req_set_callback(subreq, recv_fn, s);
1685 : }
1686 :
1687 8 : static WERROR becomeDC_drsuapi_bind_recv(struct libnet_BecomeDC_state *s,
1688 : struct becomeDC_drsuapi *drsuapi)
1689 : {
1690 8 : if (!W_ERROR_IS_OK(drsuapi->bind_r.out.result)) {
1691 4 : return drsuapi->bind_r.out.result;
1692 : }
1693 :
1694 8 : ZERO_STRUCT(drsuapi->remote_info28);
1695 8 : if (drsuapi->bind_r.out.bind_info) {
1696 8 : switch (drsuapi->bind_r.out.bind_info->length) {
1697 0 : case 24: {
1698 0 : struct drsuapi_DsBindInfo24 *info24;
1699 0 : info24 = &drsuapi->bind_r.out.bind_info->info.info24;
1700 0 : drsuapi->remote_info28.supported_extensions = info24->supported_extensions;
1701 0 : drsuapi->remote_info28.site_guid = info24->site_guid;
1702 0 : drsuapi->remote_info28.pid = info24->pid;
1703 0 : drsuapi->remote_info28.repl_epoch = 0;
1704 0 : break;
1705 : }
1706 8 : case 28: {
1707 8 : drsuapi->remote_info28 = drsuapi->bind_r.out.bind_info->info.info28;
1708 8 : break;
1709 : }
1710 0 : case 32: {
1711 0 : struct drsuapi_DsBindInfo32 *info32;
1712 0 : info32 = &drsuapi->bind_r.out.bind_info->info.info32;
1713 0 : drsuapi->remote_info28.supported_extensions = info32->supported_extensions;
1714 0 : drsuapi->remote_info28.site_guid = info32->site_guid;
1715 0 : drsuapi->remote_info28.pid = info32->pid;
1716 0 : drsuapi->remote_info28.repl_epoch = info32->repl_epoch;
1717 0 : break;
1718 : }
1719 0 : case 48: {
1720 0 : struct drsuapi_DsBindInfo48 *info48;
1721 0 : info48 = &drsuapi->bind_r.out.bind_info->info.info48;
1722 0 : drsuapi->remote_info28.supported_extensions = info48->supported_extensions;
1723 0 : drsuapi->remote_info28.site_guid = info48->site_guid;
1724 0 : drsuapi->remote_info28.pid = info48->pid;
1725 0 : drsuapi->remote_info28.repl_epoch = info48->repl_epoch;
1726 0 : break;
1727 : }
1728 0 : case 52: {
1729 0 : struct drsuapi_DsBindInfo52 *info52;
1730 0 : info52 = &drsuapi->bind_r.out.bind_info->info.info52;
1731 0 : drsuapi->remote_info28.supported_extensions = info52->supported_extensions;
1732 0 : drsuapi->remote_info28.site_guid = info52->site_guid;
1733 0 : drsuapi->remote_info28.pid = info52->pid;
1734 0 : drsuapi->remote_info28.repl_epoch = info52->repl_epoch;
1735 0 : break;
1736 : }
1737 0 : default:
1738 0 : DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
1739 : drsuapi->bind_r.out.bind_info->length));
1740 0 : break;
1741 : }
1742 : }
1743 :
1744 8 : return WERR_OK;
1745 : }
1746 :
1747 : static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s);
1748 :
1749 4 : static void becomeDC_drsuapi1_bind_recv(struct tevent_req *subreq)
1750 : {
1751 4 : struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq,
1752 : struct libnet_BecomeDC_state);
1753 4 : struct composite_context *c = s->creq;
1754 2 : WERROR status;
1755 :
1756 4 : c->status = dcerpc_drsuapi_DsBind_r_recv(subreq, s);
1757 4 : TALLOC_FREE(subreq);
1758 4 : if (!composite_is_ok(c)) return;
1759 :
1760 4 : status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi1);
1761 4 : if (!W_ERROR_IS_OK(status)) {
1762 0 : composite_error(c, werror_to_ntstatus(status));
1763 0 : return;
1764 : }
1765 :
1766 4 : becomeDC_drsuapi1_add_entry_send(s);
1767 : }
1768 :
1769 : static void becomeDC_drsuapi1_add_entry_recv(struct tevent_req *subreq);
1770 :
1771 4 : static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
1772 : {
1773 4 : struct composite_context *c = s->creq;
1774 2 : struct drsuapi_DsAddEntry *r;
1775 2 : struct drsuapi_DsReplicaObjectIdentifier *identifier;
1776 4 : uint32_t num_attrs, i = 0;
1777 2 : struct drsuapi_DsReplicaAttribute *attrs;
1778 2 : enum ndr_err_code ndr_err;
1779 2 : bool w2k3;
1780 2 : struct tevent_req *subreq;
1781 :
1782 : /* choose a random invocationId */
1783 4 : s->dest_dsa.invocation_id = GUID_random();
1784 :
1785 : /*
1786 : * if the schema version indicates w2k3, then also send some w2k3
1787 : * specific attributes.
1788 : */
1789 4 : if (s->forest.schema_object_version >= 30) {
1790 2 : w2k3 = true;
1791 : } else {
1792 0 : w2k3 = false;
1793 : }
1794 :
1795 4 : r = talloc_zero(s, struct drsuapi_DsAddEntry);
1796 4 : if (composite_nomem(r, c)) return;
1797 :
1798 : /* setup identifier */
1799 4 : identifier = talloc(r, struct drsuapi_DsReplicaObjectIdentifier);
1800 4 : if (composite_nomem(identifier, c)) return;
1801 4 : identifier->guid = GUID_zero();
1802 4 : identifier->sid = s->zero_sid;
1803 4 : identifier->dn = talloc_asprintf(identifier, "CN=NTDS Settings,%s",
1804 : s->dest_dsa.server_dn_str);
1805 4 : if (composite_nomem(identifier->dn, c)) return;
1806 :
1807 : /* allocate attribute array */
1808 4 : num_attrs = 12;
1809 4 : attrs = talloc_array(r, struct drsuapi_DsReplicaAttribute, num_attrs);
1810 4 : if (composite_nomem(attrs, c)) return;
1811 :
1812 : /* ntSecurityDescriptor */
1813 : {
1814 2 : struct drsuapi_DsAttributeValue *vs;
1815 2 : DATA_BLOB *vd;
1816 2 : struct security_descriptor *v;
1817 2 : struct dom_sid *domain_admins_sid;
1818 2 : const char *domain_admins_sid_str;
1819 :
1820 4 : vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1821 4 : if (composite_nomem(vs, c)) return;
1822 :
1823 4 : vd = talloc_array(vs, DATA_BLOB, 1);
1824 4 : if (composite_nomem(vd, c)) return;
1825 :
1826 4 : domain_admins_sid = dom_sid_add_rid(vs, s->domain.sid, DOMAIN_RID_ADMINS);
1827 4 : if (composite_nomem(domain_admins_sid, c)) return;
1828 :
1829 4 : domain_admins_sid_str = dom_sid_string(domain_admins_sid, domain_admins_sid);
1830 4 : if (composite_nomem(domain_admins_sid_str, c)) return;
1831 :
1832 4 : v = security_descriptor_dacl_create(vd,
1833 : 0,
1834 : /* owner: domain admins */
1835 : domain_admins_sid_str,
1836 : /* owner group: domain admins */
1837 : domain_admins_sid_str,
1838 : /* authenticated users */
1839 : SID_NT_AUTHENTICATED_USERS,
1840 : SEC_ACE_TYPE_ACCESS_ALLOWED,
1841 : SEC_STD_READ_CONTROL |
1842 : SEC_ADS_LIST |
1843 : SEC_ADS_READ_PROP |
1844 : SEC_ADS_LIST_OBJECT,
1845 : 0,
1846 : /* domain admins */
1847 : domain_admins_sid_str,
1848 : SEC_ACE_TYPE_ACCESS_ALLOWED,
1849 : SEC_STD_REQUIRED |
1850 : SEC_ADS_CREATE_CHILD |
1851 : SEC_ADS_LIST |
1852 : SEC_ADS_SELF_WRITE |
1853 : SEC_ADS_READ_PROP |
1854 : SEC_ADS_WRITE_PROP |
1855 : SEC_ADS_DELETE_TREE |
1856 : SEC_ADS_LIST_OBJECT |
1857 : SEC_ADS_CONTROL_ACCESS,
1858 : 0,
1859 : /* system */
1860 : SID_NT_SYSTEM,
1861 : SEC_ACE_TYPE_ACCESS_ALLOWED,
1862 : SEC_STD_REQUIRED |
1863 : SEC_ADS_CREATE_CHILD |
1864 : SEC_ADS_DELETE_CHILD |
1865 : SEC_ADS_LIST |
1866 : SEC_ADS_SELF_WRITE |
1867 : SEC_ADS_READ_PROP |
1868 : SEC_ADS_WRITE_PROP |
1869 : SEC_ADS_DELETE_TREE |
1870 : SEC_ADS_LIST_OBJECT |
1871 : SEC_ADS_CONTROL_ACCESS,
1872 : 0,
1873 : /* end */
1874 : NULL);
1875 4 : if (composite_nomem(v, c)) return;
1876 :
1877 4 : ndr_err = ndr_push_struct_blob(&vd[0], vd, v,
1878 : (ndr_push_flags_fn_t)ndr_push_security_descriptor);
1879 4 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1880 0 : c->status = ndr_map_error2ntstatus(ndr_err);
1881 0 : if (!composite_is_ok(c)) return;
1882 : }
1883 :
1884 4 : vs[0].blob = &vd[0];
1885 :
1886 4 : attrs[i].attid = DRSUAPI_ATTID_ntSecurityDescriptor;
1887 4 : attrs[i].value_ctr.num_values = 1;
1888 4 : attrs[i].value_ctr.values = vs;
1889 :
1890 4 : i++;
1891 : }
1892 :
1893 : /* objectClass: nTDSDSA */
1894 : {
1895 2 : struct drsuapi_DsAttributeValue *vs;
1896 2 : DATA_BLOB *vd;
1897 :
1898 4 : vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1899 4 : if (composite_nomem(vs, c)) return;
1900 :
1901 4 : vd = talloc_array(vs, DATA_BLOB, 1);
1902 4 : if (composite_nomem(vd, c)) return;
1903 :
1904 4 : vd[0] = data_blob_talloc(vd, NULL, 4);
1905 4 : if (composite_nomem(vd[0].data, c)) return;
1906 :
1907 : /* value for nTDSDSA */
1908 4 : SIVAL(vd[0].data, 0, 0x0017002F);
1909 :
1910 4 : vs[0].blob = &vd[0];
1911 :
1912 4 : attrs[i].attid = DRSUAPI_ATTID_objectClass;
1913 4 : attrs[i].value_ctr.num_values = 1;
1914 4 : attrs[i].value_ctr.values = vs;
1915 :
1916 4 : i++;
1917 : }
1918 :
1919 : /* objectCategory: CN=NTDS-DSA,CN=Schema,... or CN=NTDS-DSA-RO,CN=Schema,... */
1920 : {
1921 2 : struct drsuapi_DsAttributeValue *vs;
1922 2 : DATA_BLOB *vd;
1923 2 : struct drsuapi_DsReplicaObjectIdentifier3 v[1];
1924 :
1925 4 : vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1926 4 : if (composite_nomem(vs, c)) return;
1927 :
1928 4 : vd = talloc_array(vs, DATA_BLOB, 1);
1929 4 : if (composite_nomem(vd, c)) return;
1930 :
1931 4 : v[0].guid = GUID_zero();
1932 4 : v[0].sid = s->zero_sid;
1933 :
1934 4 : if (s->rodc_join) {
1935 0 : v[0].dn = talloc_asprintf(vd, "CN=NTDS-DSA-RO,%s",
1936 : s->forest.schema_dn_str);
1937 : } else {
1938 4 : v[0].dn = talloc_asprintf(vd, "CN=NTDS-DSA,%s",
1939 : s->forest.schema_dn_str);
1940 : }
1941 4 : if (composite_nomem(v[0].dn, c)) return;
1942 :
1943 4 : ndr_err = ndr_push_struct_blob(&vd[0], vd, &v[0],
1944 : (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1945 4 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1946 0 : c->status = ndr_map_error2ntstatus(ndr_err);
1947 0 : if (!composite_is_ok(c)) return;
1948 : }
1949 :
1950 4 : vs[0].blob = &vd[0];
1951 :
1952 4 : attrs[i].attid = DRSUAPI_ATTID_objectCategory;
1953 4 : attrs[i].value_ctr.num_values = 1;
1954 4 : attrs[i].value_ctr.values = vs;
1955 :
1956 4 : i++;
1957 : }
1958 :
1959 : /* invocationId: random guid */
1960 : {
1961 2 : struct drsuapi_DsAttributeValue *vs;
1962 2 : DATA_BLOB *vd;
1963 2 : const struct GUID *v;
1964 :
1965 4 : vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1966 4 : if (composite_nomem(vs, c)) return;
1967 :
1968 4 : vd = talloc_array(vs, DATA_BLOB, 1);
1969 4 : if (composite_nomem(vd, c)) return;
1970 :
1971 4 : v = &s->dest_dsa.invocation_id;
1972 :
1973 4 : c->status = GUID_to_ndr_blob(v, vd, &vd[0]);
1974 4 : if (!composite_is_ok(c)) return;
1975 :
1976 4 : vs[0].blob = &vd[0];
1977 :
1978 4 : attrs[i].attid = DRSUAPI_ATTID_invocationId;
1979 4 : attrs[i].value_ctr.num_values = 1;
1980 4 : attrs[i].value_ctr.values = vs;
1981 :
1982 4 : i++;
1983 : }
1984 :
1985 : /* hasMasterNCs: ... */
1986 : {
1987 2 : struct drsuapi_DsAttributeValue *vs;
1988 2 : DATA_BLOB *vd;
1989 2 : struct drsuapi_DsReplicaObjectIdentifier3 v[3];
1990 :
1991 4 : vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 3);
1992 4 : if (composite_nomem(vs, c)) return;
1993 :
1994 4 : vd = talloc_array(vs, DATA_BLOB, 3);
1995 4 : if (composite_nomem(vd, c)) return;
1996 :
1997 4 : v[0].guid = GUID_zero();
1998 4 : v[0].sid = s->zero_sid;
1999 4 : v[0].dn = s->forest.config_dn_str;
2000 :
2001 4 : v[1].guid = GUID_zero();
2002 4 : v[1].sid = s->zero_sid;
2003 4 : v[1].dn = s->domain.dn_str;
2004 :
2005 4 : v[2].guid = GUID_zero();
2006 4 : v[2].sid = s->zero_sid;
2007 4 : v[2].dn = s->forest.schema_dn_str;
2008 :
2009 4 : ndr_err = ndr_push_struct_blob(&vd[0], vd, &v[0],
2010 : (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2011 4 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2012 0 : c->status = ndr_map_error2ntstatus(ndr_err);
2013 0 : if (!composite_is_ok(c)) return;
2014 : }
2015 :
2016 4 : ndr_err = ndr_push_struct_blob(&vd[1], vd, &v[1],
2017 : (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2018 4 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2019 0 : c->status = ndr_map_error2ntstatus(ndr_err);
2020 0 : if (!composite_is_ok(c)) return;
2021 : }
2022 :
2023 4 : ndr_err = ndr_push_struct_blob(&vd[2], vd, &v[2],
2024 : (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2025 4 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2026 0 : c->status = ndr_map_error2ntstatus(ndr_err);
2027 0 : if (!composite_is_ok(c)) return;
2028 : }
2029 :
2030 4 : vs[0].blob = &vd[0];
2031 4 : vs[1].blob = &vd[1];
2032 4 : vs[2].blob = &vd[2];
2033 :
2034 4 : attrs[i].attid = DRSUAPI_ATTID_hasMasterNCs;
2035 4 : attrs[i].value_ctr.num_values = 3;
2036 4 : attrs[i].value_ctr.values = vs;
2037 :
2038 4 : i++;
2039 : }
2040 :
2041 : /* msDS-hasMasterNCs: ... */
2042 4 : if (w2k3) {
2043 2 : struct drsuapi_DsAttributeValue *vs;
2044 2 : DATA_BLOB *vd;
2045 2 : struct drsuapi_DsReplicaObjectIdentifier3 v[3];
2046 :
2047 4 : vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 3);
2048 4 : if (composite_nomem(vs, c)) return;
2049 :
2050 4 : vd = talloc_array(vs, DATA_BLOB, 3);
2051 4 : if (composite_nomem(vd, c)) return;
2052 :
2053 4 : v[0].guid = GUID_zero();
2054 4 : v[0].sid = s->zero_sid;
2055 4 : v[0].dn = s->forest.config_dn_str;
2056 :
2057 4 : v[1].guid = GUID_zero();
2058 4 : v[1].sid = s->zero_sid;
2059 4 : v[1].dn = s->domain.dn_str;
2060 :
2061 4 : v[2].guid = GUID_zero();
2062 4 : v[2].sid = s->zero_sid;
2063 4 : v[2].dn = s->forest.schema_dn_str;
2064 :
2065 4 : ndr_err = ndr_push_struct_blob(&vd[0], vd, &v[0],
2066 : (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2067 4 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2068 0 : c->status = ndr_map_error2ntstatus(ndr_err);
2069 0 : if (!composite_is_ok(c)) return;
2070 : }
2071 :
2072 4 : ndr_err = ndr_push_struct_blob(&vd[1], vd, &v[1],
2073 : (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2074 4 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2075 0 : c->status = ndr_map_error2ntstatus(ndr_err);
2076 0 : if (!composite_is_ok(c)) return;
2077 : }
2078 :
2079 4 : ndr_err = ndr_push_struct_blob(&vd[2], vd, &v[2],
2080 : (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2081 4 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2082 0 : c->status = ndr_map_error2ntstatus(ndr_err);
2083 0 : if (!composite_is_ok(c)) return;
2084 : }
2085 :
2086 4 : vs[0].blob = &vd[0];
2087 4 : vs[1].blob = &vd[1];
2088 4 : vs[2].blob = &vd[2];
2089 :
2090 4 : attrs[i].attid = DRSUAPI_ATTID_msDS_hasMasterNCs;
2091 4 : attrs[i].value_ctr.num_values = 3;
2092 4 : attrs[i].value_ctr.values = vs;
2093 :
2094 4 : i++;
2095 : }
2096 :
2097 : /* dMDLocation: CN=Schema,... */
2098 : {
2099 2 : struct drsuapi_DsAttributeValue *vs;
2100 2 : DATA_BLOB *vd;
2101 2 : struct drsuapi_DsReplicaObjectIdentifier3 v[1];
2102 :
2103 4 : vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
2104 4 : if (composite_nomem(vs, c)) return;
2105 :
2106 4 : vd = talloc_array(vs, DATA_BLOB, 1);
2107 4 : if (composite_nomem(vd, c)) return;
2108 :
2109 4 : v[0].guid = GUID_zero();
2110 4 : v[0].sid = s->zero_sid;
2111 4 : v[0].dn = s->forest.schema_dn_str;
2112 :
2113 4 : ndr_err = ndr_push_struct_blob(&vd[0], vd, &v[0],
2114 : (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2115 4 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2116 0 : c->status = ndr_map_error2ntstatus(ndr_err);
2117 0 : if (!composite_is_ok(c)) return;
2118 : }
2119 :
2120 4 : vs[0].blob = &vd[0];
2121 :
2122 4 : attrs[i].attid = DRSUAPI_ATTID_dMDLocation;
2123 4 : attrs[i].value_ctr.num_values = 1;
2124 4 : attrs[i].value_ctr.values = vs;
2125 :
2126 4 : i++;
2127 : }
2128 :
2129 : /* msDS-HasDomainNCs: <domain_partition> */
2130 4 : if (w2k3) {
2131 2 : struct drsuapi_DsAttributeValue *vs;
2132 2 : DATA_BLOB *vd;
2133 2 : struct drsuapi_DsReplicaObjectIdentifier3 v[1];
2134 :
2135 4 : vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
2136 4 : if (composite_nomem(vs, c)) return;
2137 :
2138 4 : vd = talloc_array(vs, DATA_BLOB, 1);
2139 4 : if (composite_nomem(vd, c)) return;
2140 :
2141 4 : v[0].guid = GUID_zero();
2142 4 : v[0].sid = s->zero_sid;
2143 4 : v[0].dn = s->domain.dn_str;
2144 :
2145 4 : ndr_err = ndr_push_struct_blob(&vd[0], vd, &v[0],
2146 : (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2147 4 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2148 0 : c->status = ndr_map_error2ntstatus(ndr_err);
2149 0 : if (!composite_is_ok(c)) return;
2150 : }
2151 :
2152 4 : vs[0].blob = &vd[0];
2153 :
2154 4 : attrs[i].attid = DRSUAPI_ATTID_msDS_HasDomainNCs;
2155 4 : attrs[i].value_ctr.num_values = 1;
2156 4 : attrs[i].value_ctr.values = vs;
2157 :
2158 4 : i++;
2159 : }
2160 :
2161 : /* msDS-Behavior-Version */
2162 4 : if (w2k3) {
2163 2 : struct drsuapi_DsAttributeValue *vs;
2164 2 : DATA_BLOB *vd;
2165 :
2166 4 : vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
2167 4 : if (composite_nomem(vs, c)) return;
2168 :
2169 4 : vd = talloc_array(vs, DATA_BLOB, 1);
2170 4 : if (composite_nomem(vd, c)) return;
2171 :
2172 4 : vd[0] = data_blob_talloc(vd, NULL, 4);
2173 4 : if (composite_nomem(vd[0].data, c)) return;
2174 :
2175 4 : SIVAL(vd[0].data, 0, get_dc_function_level(s->libnet->lp_ctx));
2176 :
2177 4 : vs[0].blob = &vd[0];
2178 :
2179 4 : attrs[i].attid = DRSUAPI_ATTID_msDS_Behavior_Version;
2180 4 : attrs[i].value_ctr.num_values = 1;
2181 4 : attrs[i].value_ctr.values = vs;
2182 :
2183 4 : i++;
2184 : }
2185 :
2186 : /* systemFlags */
2187 : {
2188 2 : struct drsuapi_DsAttributeValue *vs;
2189 2 : DATA_BLOB *vd;
2190 :
2191 4 : vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
2192 4 : if (composite_nomem(vs, c)) return;
2193 :
2194 4 : vd = talloc_array(vs, DATA_BLOB, 1);
2195 4 : if (composite_nomem(vd, c)) return;
2196 :
2197 4 : vd[0] = data_blob_talloc(vd, NULL, 4);
2198 4 : if (composite_nomem(vd[0].data, c)) return;
2199 :
2200 4 : if (s->rodc_join) {
2201 0 : SIVAL(vd[0].data, 0, SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
2202 : } else {
2203 4 : SIVAL(vd[0].data, 0, SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2204 : }
2205 :
2206 4 : vs[0].blob = &vd[0];
2207 :
2208 4 : attrs[i].attid = DRSUAPI_ATTID_systemFlags;
2209 4 : attrs[i].value_ctr.num_values = 1;
2210 4 : attrs[i].value_ctr.values = vs;
2211 :
2212 4 : i++;
2213 : }
2214 :
2215 : /* serverReference: ... */
2216 : {
2217 2 : struct drsuapi_DsAttributeValue *vs;
2218 2 : DATA_BLOB *vd;
2219 2 : struct drsuapi_DsReplicaObjectIdentifier3 v[1];
2220 :
2221 4 : vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
2222 4 : if (composite_nomem(vs, c)) return;
2223 :
2224 4 : vd = talloc_array(vs, DATA_BLOB, 1);
2225 4 : if (composite_nomem(vd, c)) return;
2226 :
2227 4 : v[0].guid = GUID_zero();
2228 4 : v[0].sid = s->zero_sid;
2229 4 : v[0].dn = s->dest_dsa.computer_dn_str;
2230 :
2231 4 : ndr_err = ndr_push_struct_blob(&vd[0], vd, &v[0],
2232 : (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
2233 4 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2234 0 : c->status = ndr_map_error2ntstatus(ndr_err);
2235 0 : if (!composite_is_ok(c)) return;
2236 : }
2237 :
2238 4 : vs[0].blob = &vd[0];
2239 :
2240 4 : attrs[i].attid = DRSUAPI_ATTID_serverReference;
2241 4 : attrs[i].value_ctr.num_values = 1;
2242 4 : attrs[i].value_ctr.values = vs;
2243 :
2244 4 : i++;
2245 : }
2246 :
2247 : /* options:... */
2248 4 : if (s->rodc_join) {
2249 0 : struct drsuapi_DsAttributeValue *vs;
2250 0 : DATA_BLOB *vd;
2251 :
2252 0 : vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
2253 0 : if (composite_nomem(vs, c)) return;
2254 :
2255 0 : vd = talloc_array(vs, DATA_BLOB, 1);
2256 0 : if (composite_nomem(vd, c)) return;
2257 :
2258 0 : vd[0] = data_blob_talloc(vd, NULL, 4);
2259 0 : if (composite_nomem(vd[0].data, c)) return;
2260 :
2261 0 : SIVAL(vd[0].data, 0, DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL);
2262 :
2263 0 : vs[0].blob = &vd[0];
2264 :
2265 0 : attrs[i].attid = DRSUAPI_ATTID_options;
2266 0 : attrs[i].value_ctr.num_values = 1;
2267 0 : attrs[i].value_ctr.values = vs;
2268 :
2269 0 : i++;
2270 : }
2271 :
2272 : /* truncate the attribute list to the attribute count we have filled in */
2273 4 : num_attrs = i;
2274 :
2275 : /* setup request structure */
2276 4 : r->in.bind_handle = &s->drsuapi1.bind_handle;
2277 4 : r->in.level = 2;
2278 4 : r->in.req = talloc(s, union drsuapi_DsAddEntryRequest);
2279 4 : r->in.req->req2.first_object.next_object = NULL;
2280 4 : r->in.req->req2.first_object.object.identifier = identifier;
2281 4 : r->in.req->req2.first_object.object.flags = 0x00000000;
2282 4 : r->in.req->req2.first_object.object.attribute_ctr.num_attributes= num_attrs;
2283 4 : r->in.req->req2.first_object.object.attribute_ctr.attributes = attrs;
2284 :
2285 4 : r->out.level_out = talloc(s, uint32_t);
2286 4 : r->out.ctr = talloc(s, union drsuapi_DsAddEntryCtr);
2287 :
2288 4 : s->ndr_struct_ptr = r;
2289 4 : subreq = dcerpc_drsuapi_DsAddEntry_r_send(s, c->event_ctx,
2290 : s->drsuapi1.drsuapi_handle, r);
2291 4 : if (composite_nomem(subreq, c)) return;
2292 4 : tevent_req_set_callback(subreq, becomeDC_drsuapi1_add_entry_recv, s);
2293 : }
2294 :
2295 : static void becomeDC_drsuapi2_connect_recv(struct composite_context *req);
2296 : static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s);
2297 :
2298 4 : static void becomeDC_drsuapi1_add_entry_recv(struct tevent_req *subreq)
2299 : {
2300 4 : struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq,
2301 : struct libnet_BecomeDC_state);
2302 4 : struct composite_context *c = s->creq;
2303 4 : struct drsuapi_DsAddEntry *r = talloc_get_type_abort(s->ndr_struct_ptr,
2304 : struct drsuapi_DsAddEntry);
2305 2 : char *binding_str;
2306 2 : uint32_t assoc_group_id;
2307 :
2308 4 : s->ndr_struct_ptr = NULL;
2309 :
2310 4 : c->status = dcerpc_drsuapi_DsAddEntry_r_recv(subreq, r);
2311 4 : TALLOC_FREE(subreq);
2312 4 : if (!composite_is_ok(c)) return;
2313 :
2314 4 : if (!W_ERROR_IS_OK(r->out.result)) {
2315 0 : composite_error(c, werror_to_ntstatus(r->out.result));
2316 0 : return;
2317 : }
2318 :
2319 4 : if (*r->out.level_out == 3) {
2320 2 : WERROR status;
2321 4 : union drsuapi_DsAddEntry_ErrData *err_data = r->out.ctr->ctr3.err_data;
2322 :
2323 : /* check for errors */
2324 4 : status = err_data ? err_data->v1.status : WERR_OK;
2325 4 : if (!W_ERROR_IS_OK(status)) {
2326 0 : struct drsuapi_DsAddEntryErrorInfo_Attr_V1 *attr_err;
2327 0 : struct drsuapi_DsAddEntry_AttrErrListItem_V1 *attr_err_li;
2328 0 : struct drsuapi_DsAddEntryErrorInfo_Name_V1 *name_err;
2329 0 : struct drsuapi_DsAddEntryErrorInfo_Referr_V1 *ref_err;
2330 0 : struct drsuapi_DsAddEntry_RefErrListItem_V1 *ref_li;
2331 :
2332 0 : if (r->out.ctr->ctr3.err_ver != 1) {
2333 0 : composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
2334 0 : return;
2335 : }
2336 :
2337 0 : DEBUG(0,("DsAddEntry (R3) of '%s' failed: "
2338 : "Errors: dir_err = %d, status = %s;\n",
2339 : r->in.req->req3.first_object.object.identifier->dn,
2340 : err_data->v1.dir_err,
2341 : win_errstr(err_data->v1.status)));
2342 :
2343 0 : if (!err_data->v1.info) {
2344 0 : DEBUG(0, ("DsAddEntry (R3): no error info returned!\n"));
2345 0 : composite_error(c, werror_to_ntstatus(status));
2346 0 : return;
2347 : }
2348 :
2349 : /* dump more detailed error */
2350 0 : switch (err_data->v1.dir_err) {
2351 0 : case DRSUAPI_DIRERR_ATTRIBUTE:
2352 : /* Dump attribute errors */
2353 0 : attr_err = &err_data->v1.info->attr_err;
2354 0 : DEBUGADD(0,(" Attribute Error: object = %s, count = %d;\n",
2355 : attr_err->id->dn,
2356 : attr_err->count));
2357 0 : attr_err_li = &attr_err->first;
2358 0 : for (; attr_err_li; attr_err_li = attr_err_li->next) {
2359 0 : struct drsuapi_DsAddEntry_AttrErr_V1 *err = &attr_err_li->err_data;
2360 0 : DEBUGADD(0,(" Error: err = %s, problem = 0x%08X, attid = 0x%08X;\n",
2361 : win_errstr(err->extended_err),
2362 : err->problem,
2363 : err->attid));
2364 : /* TODO: should we print attribute value here? */
2365 : }
2366 0 : break;
2367 0 : case DRSUAPI_DIRERR_NAME:
2368 : /* Dump Name resolution error */
2369 0 : name_err = &err_data->v1.info->name_err;
2370 0 : DEBUGADD(0,(" Name Error: err = %s, problem = 0x%08X, id_matched = %s;\n",
2371 : win_errstr(name_err->extended_err),
2372 : name_err->problem,
2373 : name_err->id_matched->dn));
2374 0 : break;
2375 0 : case DRSUAPI_DIRERR_REFERRAL:
2376 : /* Dump Referral errors */
2377 0 : ref_err = &err_data->v1.info->referral_err;
2378 0 : DEBUGADD(0,(" Referral Error: extended_err = %s\n",
2379 : win_errstr(ref_err->extended_err)));
2380 0 : ref_li = &ref_err->refer;
2381 0 : for (; ref_li; ref_li = ref_li->next) {
2382 0 : struct drsuapi_DsaAddressListItem_V1 *addr;
2383 0 : DEBUGADD(0,(" Referral: id_target = %s, ref_type = 0x%04X,",
2384 : ref_li->id_target->dn,
2385 : ref_li->ref_type));
2386 0 : if (ref_li->is_choice_set) {
2387 0 : DEBUGADD(0,(" choice = 0x%02X, ",
2388 : ref_li->choice));
2389 : }
2390 0 : DEBUGADD(0,(" add_list ("));
2391 0 : for (addr = ref_li->addr_list; addr; addr = addr->next) {
2392 0 : DEBUGADD(0,("%s", addr->address->string));
2393 0 : if (addr->next) {
2394 0 : DEBUGADD(0,(", "));
2395 : }
2396 : }
2397 0 : DEBUGADD(0,(");\n"));
2398 : }
2399 0 : break;
2400 0 : case DRSUAPI_DIRERR_SECURITY:
2401 : /* Dump Security error. */
2402 0 : DEBUGADD(0,(" Security Error: extended_err = %s, problem = 0x%08X\n",
2403 : win_errstr(err_data->v1.info->security_err.extended_err),
2404 : err_data->v1.info->security_err.problem));
2405 0 : break;
2406 0 : case DRSUAPI_DIRERR_SERVICE:
2407 : /* Dump Service error. */
2408 0 : DEBUGADD(0,(" Service Error: extended_err = %s, problem = 0x%08X\n",
2409 : win_errstr(err_data->v1.info->service_err.extended_err),
2410 : err_data->v1.info->service_err.problem));
2411 0 : break;
2412 0 : case DRSUAPI_DIRERR_UPDATE:
2413 : /* Dump Update error. */
2414 0 : DEBUGADD(0,(" Update Error: extended_err = %s, problem = 0x%08X\n",
2415 : win_errstr(err_data->v1.info->update_err.extended_err),
2416 : err_data->v1.info->update_err.problem));
2417 0 : break;
2418 0 : case DRSUAPI_DIRERR_SYSTEM:
2419 : /* System error. */
2420 0 : DEBUGADD(0,(" System Error: extended_err = %s, problem = 0x%08X\n",
2421 : win_errstr(err_data->v1.info->system_err.extended_err),
2422 : err_data->v1.info->system_err.problem));
2423 0 : break;
2424 0 : case DRSUAPI_DIRERR_OK: /* mute compiler warnings */
2425 : default:
2426 0 : DEBUGADD(0,(" Unknown DIRERR error class returned!\n"));
2427 0 : break;
2428 : }
2429 :
2430 0 : composite_error(c, werror_to_ntstatus(status));
2431 0 : return;
2432 : }
2433 :
2434 4 : if (1 != r->out.ctr->ctr3.count) {
2435 0 : DEBUG(0,("DsAddEntry - Ctr3: something very wrong had happened - "
2436 : "method succeeded but objects returned are %d (expected 1).\n",
2437 : r->out.ctr->ctr3.count));
2438 0 : composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
2439 0 : return;
2440 : }
2441 :
2442 4 : s->dest_dsa.ntds_guid = r->out.ctr->ctr3.objects[0].guid;
2443 :
2444 0 : } else if (*r->out.level_out == 2) {
2445 0 : if (DRSUAPI_DIRERR_OK != r->out.ctr->ctr2.dir_err) {
2446 0 : DEBUG(0,("DsAddEntry failed with: dir_err = %d, extended_err = %s\n",
2447 : r->out.ctr->ctr2.dir_err,
2448 : win_errstr(r->out.ctr->ctr2.extended_err)));
2449 0 : composite_error(c, werror_to_ntstatus(r->out.ctr->ctr2.extended_err));
2450 0 : return;
2451 : }
2452 :
2453 0 : if (1 != r->out.ctr->ctr2.count) {
2454 0 : DEBUG(0,("DsAddEntry: something very wrong had happened - "
2455 : "method succeeded but objects returned are %d (expected 1). "
2456 : "Errors: dir_err = %d, extended_err = %s\n",
2457 : r->out.ctr->ctr2.count,
2458 : r->out.ctr->ctr2.dir_err,
2459 : win_errstr(r->out.ctr->ctr2.extended_err)));
2460 0 : composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
2461 0 : return;
2462 : }
2463 :
2464 0 : s->dest_dsa.ntds_guid = r->out.ctr->ctr2.objects[0].guid;
2465 : } else {
2466 0 : composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
2467 0 : return;
2468 : }
2469 :
2470 4 : talloc_free(r);
2471 :
2472 4 : s->dest_dsa.ntds_dn_str = talloc_asprintf(s, "CN=NTDS Settings,%s",
2473 : s->dest_dsa.server_dn_str);
2474 4 : if (composite_nomem(s->dest_dsa.ntds_dn_str, c)) return;
2475 :
2476 4 : c->status = becomeDC_prepare_db(s);
2477 4 : if (!composite_is_ok(c)) return;
2478 :
2479 : /* this avoids the epmapper lookup on the 2nd connection */
2480 4 : binding_str = dcerpc_binding_string(s, s->drsuapi1.binding);
2481 4 : if (composite_nomem(binding_str, c)) return;
2482 :
2483 4 : c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi2.binding);
2484 4 : talloc_free(binding_str);
2485 4 : if (!composite_is_ok(c)) return;
2486 :
2487 4 : if (DEBUGLEVEL >= 10) {
2488 0 : c->status = dcerpc_binding_set_flags(s->drsuapi2.binding,
2489 : DCERPC_DEBUG_PRINT_BOTH,
2490 : 0);
2491 0 : if (!composite_is_ok(c)) return;
2492 : }
2493 :
2494 : /* w2k3 uses the same assoc_group_id as on the first connection, so we do */
2495 4 : assoc_group_id = dcerpc_binding_get_assoc_group_id(s->drsuapi1.pipe->binding);
2496 4 : c->status = dcerpc_binding_set_assoc_group_id(s->drsuapi2.binding, assoc_group_id);
2497 4 : if (!composite_is_ok(c)) return;
2498 :
2499 4 : becomeDC_drsuapi_connect_send(s, &s->drsuapi2, becomeDC_drsuapi2_connect_recv);
2500 : }
2501 :
2502 4 : static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s)
2503 : {
2504 4 : if (!s->callbacks.prepare_db) return NT_STATUS_OK;
2505 :
2506 4 : s->_pp.domain = &s->domain;
2507 4 : s->_pp.forest = &s->forest;
2508 4 : s->_pp.source_dsa = &s->source_dsa;
2509 4 : s->_pp.dest_dsa = &s->dest_dsa;
2510 :
2511 4 : return s->callbacks.prepare_db(s->callbacks.private_data, &s->_pp);
2512 : }
2513 :
2514 : static void becomeDC_drsuapi2_bind_recv(struct tevent_req *subreq);
2515 :
2516 4 : static void becomeDC_drsuapi2_connect_recv(struct composite_context *req)
2517 : {
2518 4 : struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
2519 : struct libnet_BecomeDC_state);
2520 4 : struct composite_context *c = s->creq;
2521 :
2522 4 : c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi2.pipe);
2523 4 : if (!composite_is_ok(c)) return;
2524 :
2525 4 : s->drsuapi2.drsuapi_handle = s->drsuapi2.pipe->binding_handle;
2526 :
2527 4 : c->status = gensec_session_key(s->drsuapi2.pipe->conn->security_state.generic_state,
2528 : s,
2529 : &s->drsuapi2.gensec_skey);
2530 4 : if (!composite_is_ok(c)) return;
2531 :
2532 4 : becomeDC_drsuapi_bind_send(s, &s->drsuapi2, becomeDC_drsuapi2_bind_recv);
2533 : }
2534 :
2535 : static void becomeDC_drsuapi3_connect_recv(struct composite_context *req);
2536 :
2537 4 : static void becomeDC_drsuapi2_bind_recv(struct tevent_req *subreq)
2538 : {
2539 4 : struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq,
2540 : struct libnet_BecomeDC_state);
2541 4 : struct composite_context *c = s->creq;
2542 2 : char *binding_str;
2543 2 : uint32_t assoc_group_id;
2544 2 : WERROR status;
2545 :
2546 4 : c->status = dcerpc_drsuapi_DsBind_r_recv(subreq, s);
2547 4 : TALLOC_FREE(subreq);
2548 4 : if (!composite_is_ok(c)) return;
2549 :
2550 4 : status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi2);
2551 4 : if (!W_ERROR_IS_OK(status)) {
2552 0 : composite_error(c, werror_to_ntstatus(status));
2553 0 : return;
2554 : }
2555 :
2556 : /* this avoids the epmapper lookup on the 3rd connection */
2557 4 : binding_str = dcerpc_binding_string(s, s->drsuapi1.binding);
2558 4 : if (composite_nomem(binding_str, c)) return;
2559 :
2560 4 : c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi3.binding);
2561 4 : talloc_free(binding_str);
2562 4 : if (!composite_is_ok(c)) return;
2563 :
2564 4 : if (DEBUGLEVEL >= 10) {
2565 0 : c->status = dcerpc_binding_set_flags(s->drsuapi3.binding,
2566 : DCERPC_DEBUG_PRINT_BOTH,
2567 : 0);
2568 0 : if (!composite_is_ok(c)) return;
2569 : }
2570 :
2571 : /* w2k3 uses the same assoc_group_id as on the first connection, so we do */
2572 4 : assoc_group_id = dcerpc_binding_get_assoc_group_id(s->drsuapi1.pipe->binding);
2573 4 : c->status = dcerpc_binding_set_assoc_group_id(s->drsuapi3.binding, assoc_group_id);
2574 4 : if (!composite_is_ok(c)) return;
2575 : /* w2k3 uses the concurrent multiplex feature on the 3rd connection, so we do */
2576 4 : c->status = dcerpc_binding_set_flags(s->drsuapi3.binding,
2577 : DCERPC_CONCURRENT_MULTIPLEX,
2578 : 0);
2579 4 : if (!composite_is_ok(c)) return;
2580 :
2581 4 : becomeDC_drsuapi_connect_send(s, &s->drsuapi3, becomeDC_drsuapi3_connect_recv);
2582 : }
2583 :
2584 : static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s);
2585 :
2586 4 : static void becomeDC_drsuapi3_connect_recv(struct composite_context *req)
2587 : {
2588 4 : struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
2589 : struct libnet_BecomeDC_state);
2590 4 : struct composite_context *c = s->creq;
2591 :
2592 4 : c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi3.pipe);
2593 4 : if (!composite_is_ok(c)) return;
2594 :
2595 4 : s->drsuapi3.drsuapi_handle = s->drsuapi3.pipe->binding_handle;
2596 :
2597 4 : c->status = gensec_session_key(s->drsuapi3.pipe->conn->security_state.generic_state,
2598 : s,
2599 : &s->drsuapi3.gensec_skey);
2600 4 : if (!composite_is_ok(c)) return;
2601 :
2602 4 : becomeDC_drsuapi3_pull_schema_send(s);
2603 : }
2604 :
2605 108 : static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s,
2606 : struct becomeDC_drsuapi *drsuapi_h,
2607 : struct becomeDC_drsuapi *drsuapi_p,
2608 : struct libnet_BecomeDC_Partition *partition,
2609 : void (*recv_fn)(struct tevent_req *subreq))
2610 : {
2611 108 : struct composite_context *c = s->creq;
2612 54 : struct drsuapi_DsGetNCChanges *r;
2613 54 : struct tevent_req *subreq;
2614 :
2615 108 : r = talloc(s, struct drsuapi_DsGetNCChanges);
2616 108 : if (composite_nomem(r, c)) return;
2617 :
2618 108 : r->out.level_out = talloc(r, uint32_t);
2619 108 : if (composite_nomem(r->out.level_out, c)) return;
2620 108 : r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
2621 108 : if (composite_nomem(r->in.req, c)) return;
2622 108 : r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
2623 108 : if (composite_nomem(r->out.ctr, c)) return;
2624 :
2625 108 : r->in.bind_handle = &drsuapi_h->bind_handle;
2626 108 : if (drsuapi_h->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
2627 108 : r->in.level = 8;
2628 108 : r->in.req->req8.destination_dsa_guid = partition->destination_dsa_guid;
2629 108 : r->in.req->req8.source_dsa_invocation_id= partition->source_dsa_invocation_id;
2630 108 : r->in.req->req8.naming_context = &partition->nc;
2631 108 : r->in.req->req8.highwatermark = partition->highwatermark;
2632 108 : r->in.req->req8.uptodateness_vector = NULL;
2633 108 : r->in.req->req8.replica_flags = partition->replica_flags;
2634 108 : r->in.req->req8.max_object_count = 133;
2635 108 : r->in.req->req8.max_ndr_size = 1336811;
2636 108 : r->in.req->req8.extended_op = DRSUAPI_EXOP_NONE;
2637 108 : r->in.req->req8.fsmo_info = 0;
2638 108 : r->in.req->req8.partial_attribute_set = NULL;
2639 108 : r->in.req->req8.partial_attribute_set_ex= NULL;
2640 108 : r->in.req->req8.mapping_ctr.num_mappings= 0;
2641 108 : r->in.req->req8.mapping_ctr.mappings = NULL;
2642 : } else {
2643 0 : r->in.level = 5;
2644 0 : r->in.req->req5.destination_dsa_guid = partition->destination_dsa_guid;
2645 0 : r->in.req->req5.source_dsa_invocation_id= partition->source_dsa_invocation_id;
2646 0 : r->in.req->req5.naming_context = &partition->nc;
2647 0 : r->in.req->req5.highwatermark = partition->highwatermark;
2648 0 : r->in.req->req5.uptodateness_vector = NULL;
2649 0 : r->in.req->req5.replica_flags = partition->replica_flags;
2650 0 : r->in.req->req5.max_object_count = 133;
2651 0 : r->in.req->req5.max_ndr_size = 1336770;
2652 0 : r->in.req->req5.extended_op = DRSUAPI_EXOP_NONE;
2653 0 : r->in.req->req5.fsmo_info = 0;
2654 : }
2655 :
2656 : /*
2657 : * we should try to use the drsuapi_p->pipe here, as w2k3 does
2658 : * but it seems that some extra flags in the DCERPC Bind call
2659 : * are needed for it. Or the same KRB5 TGS is needed on both
2660 : * connections.
2661 : */
2662 108 : s->ndr_struct_ptr = r;
2663 108 : subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(s, c->event_ctx,
2664 : drsuapi_p->drsuapi_handle,
2665 : r);
2666 108 : if (composite_nomem(subreq, c)) return;
2667 108 : tevent_req_set_callback(subreq, recv_fn, s);
2668 : }
2669 :
2670 108 : static WERROR becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state *s,
2671 : struct becomeDC_drsuapi *drsuapi_h,
2672 : struct becomeDC_drsuapi *drsuapi_p,
2673 : struct libnet_BecomeDC_Partition *partition,
2674 : struct drsuapi_DsGetNCChanges *r)
2675 : {
2676 108 : uint32_t req_level = r->in.level;
2677 108 : struct drsuapi_DsGetNCChangesRequest5 *req5 = NULL;
2678 108 : struct drsuapi_DsGetNCChangesRequest8 *req8 = NULL;
2679 108 : struct drsuapi_DsGetNCChangesRequest10 *req10 = NULL;
2680 108 : uint32_t ctr_level = 0;
2681 108 : struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
2682 108 : struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
2683 108 : struct GUID *source_dsa_guid = NULL;
2684 108 : struct GUID *source_dsa_invocation_id = NULL;
2685 108 : struct drsuapi_DsReplicaHighWaterMark *new_highwatermark = NULL;
2686 108 : bool more_data = false;
2687 54 : WERROR werr;
2688 :
2689 108 : if (!W_ERROR_IS_OK(r->out.result)) {
2690 54 : return r->out.result;
2691 : }
2692 :
2693 108 : switch (r->in.level) {
2694 0 : case 0:
2695 : /* none */
2696 0 : break;
2697 0 : case 5:
2698 0 : req5 = &r->in.req->req5;
2699 0 : break;
2700 108 : case 8:
2701 108 : req8 = &r->in.req->req8;
2702 108 : break;
2703 0 : case 10:
2704 0 : req10 = &r->in.req->req10;
2705 0 : break;
2706 0 : default:
2707 0 : return WERR_INVALID_PARAMETER;
2708 : }
2709 :
2710 108 : if (*r->out.level_out == 1) {
2711 0 : ctr_level = 1;
2712 0 : ctr1 = &r->out.ctr->ctr1;
2713 108 : } else if (*r->out.level_out == 2 &&
2714 0 : r->out.ctr->ctr2.mszip1.ts) {
2715 0 : ctr_level = 1;
2716 0 : ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
2717 108 : } else if (*r->out.level_out == 6) {
2718 108 : ctr_level = 6;
2719 108 : ctr6 = &r->out.ctr->ctr6;
2720 0 : } else if (*r->out.level_out == 7 &&
2721 0 : r->out.ctr->ctr7.level == 6 &&
2722 0 : r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
2723 0 : r->out.ctr->ctr7.ctr.mszip6.ts) {
2724 0 : ctr_level = 6;
2725 0 : ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
2726 0 : } else if (*r->out.level_out == 7 &&
2727 0 : r->out.ctr->ctr7.level == 6 &&
2728 0 : r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_WIN2K3_LZ77_DIRECT2 &&
2729 0 : r->out.ctr->ctr7.ctr.xpress6.ts) {
2730 0 : ctr_level = 6;
2731 0 : ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
2732 : } else {
2733 0 : return WERR_BAD_NET_RESP;
2734 : }
2735 :
2736 108 : if (!ctr1 && ! ctr6) {
2737 0 : return WERR_BAD_NET_RESP;
2738 : }
2739 :
2740 108 : if (ctr_level == 6) {
2741 108 : if (!W_ERROR_IS_OK(ctr6->drs_error)) {
2742 0 : return ctr6->drs_error;
2743 : }
2744 : }
2745 :
2746 108 : switch (ctr_level) {
2747 0 : case 1:
2748 0 : source_dsa_guid = &ctr1->source_dsa_guid;
2749 0 : source_dsa_invocation_id = &ctr1->source_dsa_invocation_id;
2750 0 : new_highwatermark = &ctr1->new_highwatermark;
2751 0 : more_data = ctr1->more_data;
2752 0 : break;
2753 108 : case 6:
2754 108 : source_dsa_guid = &ctr6->source_dsa_guid;
2755 108 : source_dsa_invocation_id = &ctr6->source_dsa_invocation_id;
2756 108 : new_highwatermark = &ctr6->new_highwatermark;
2757 108 : more_data = ctr6->more_data;
2758 108 : break;
2759 : }
2760 :
2761 108 : partition->highwatermark = *new_highwatermark;
2762 108 : partition->source_dsa_guid = *source_dsa_guid;
2763 108 : partition->source_dsa_invocation_id = *source_dsa_invocation_id;
2764 108 : partition->more_data = more_data;
2765 :
2766 108 : if (!partition->store_chunk) return WERR_OK;
2767 :
2768 108 : s->_sc.domain = &s->domain;
2769 108 : s->_sc.forest = &s->forest;
2770 108 : s->_sc.source_dsa = &s->source_dsa;
2771 108 : s->_sc.dest_dsa = &s->dest_dsa;
2772 108 : s->_sc.partition = partition;
2773 108 : s->_sc.req_level = req_level;
2774 108 : s->_sc.req5 = req5;
2775 108 : s->_sc.req8 = req8;
2776 108 : s->_sc.req10 = req10;
2777 108 : s->_sc.ctr_level = ctr_level;
2778 108 : s->_sc.ctr1 = ctr1;
2779 108 : s->_sc.ctr6 = ctr6;
2780 : /*
2781 : * we need to use the drsuapi_p->gensec_skey here,
2782 : * when we use drsuapi_p->pipe in the for this request
2783 : */
2784 108 : s->_sc.gensec_skey = &drsuapi_p->gensec_skey;
2785 :
2786 108 : werr = partition->store_chunk(s->callbacks.private_data, &s->_sc);
2787 108 : if (!W_ERROR_IS_OK(werr)) {
2788 0 : return werr;
2789 : }
2790 :
2791 108 : return WERR_OK;
2792 : }
2793 :
2794 : static void becomeDC_drsuapi3_pull_schema_recv(struct tevent_req *subreq);
2795 :
2796 4 : static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s)
2797 : {
2798 4 : s->schema_part.nc.guid = GUID_zero();
2799 4 : s->schema_part.nc.sid = s->zero_sid;
2800 4 : s->schema_part.nc.dn = s->forest.schema_dn_str;
2801 :
2802 4 : s->schema_part.destination_dsa_guid = s->drsuapi2.bind_guid;
2803 :
2804 4 : s->schema_part.replica_flags = DRSUAPI_DRS_WRIT_REP
2805 : | DRSUAPI_DRS_INIT_SYNC
2806 : | DRSUAPI_DRS_PER_SYNC
2807 : | DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
2808 : | DRSUAPI_DRS_NEVER_SYNCED
2809 : | DRSUAPI_DRS_USE_COMPRESSION
2810 : | DRSUAPI_DRS_GET_ANC;
2811 4 : if (s->rodc_join) {
2812 0 : s->schema_part.replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
2813 : }
2814 :
2815 4 : s->schema_part.store_chunk = s->callbacks.schema_chunk;
2816 :
2817 4 : becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part,
2818 : becomeDC_drsuapi3_pull_schema_recv);
2819 4 : }
2820 :
2821 : static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s);
2822 :
2823 48 : static void becomeDC_drsuapi3_pull_schema_recv(struct tevent_req *subreq)
2824 : {
2825 48 : struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq,
2826 : struct libnet_BecomeDC_state);
2827 48 : struct composite_context *c = s->creq;
2828 48 : struct drsuapi_DsGetNCChanges *r = talloc_get_type_abort(s->ndr_struct_ptr,
2829 : struct drsuapi_DsGetNCChanges);
2830 24 : WERROR status;
2831 :
2832 48 : s->ndr_struct_ptr = NULL;
2833 :
2834 48 : c->status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
2835 48 : TALLOC_FREE(subreq);
2836 92 : if (!composite_is_ok(c)) return;
2837 :
2838 48 : status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part, r);
2839 48 : if (!W_ERROR_IS_OK(status)) {
2840 0 : composite_error(c, werror_to_ntstatus(status));
2841 0 : return;
2842 : }
2843 :
2844 48 : talloc_free(r);
2845 :
2846 48 : if (s->schema_part.more_data) {
2847 44 : becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part,
2848 : becomeDC_drsuapi3_pull_schema_recv);
2849 44 : return;
2850 : }
2851 :
2852 4 : becomeDC_drsuapi3_pull_config_send(s);
2853 : }
2854 :
2855 : static void becomeDC_drsuapi3_pull_config_recv(struct tevent_req *subreq);
2856 :
2857 4 : static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s)
2858 : {
2859 4 : s->config_part.nc.guid = GUID_zero();
2860 4 : s->config_part.nc.sid = s->zero_sid;
2861 4 : s->config_part.nc.dn = s->forest.config_dn_str;
2862 :
2863 4 : s->config_part.destination_dsa_guid = s->drsuapi2.bind_guid;
2864 :
2865 4 : s->config_part.replica_flags = DRSUAPI_DRS_WRIT_REP
2866 : | DRSUAPI_DRS_INIT_SYNC
2867 : | DRSUAPI_DRS_PER_SYNC
2868 : | DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
2869 : | DRSUAPI_DRS_NEVER_SYNCED
2870 : | DRSUAPI_DRS_USE_COMPRESSION
2871 : | DRSUAPI_DRS_GET_ANC;
2872 4 : if (s->rodc_join) {
2873 0 : s->schema_part.replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
2874 : }
2875 :
2876 4 : s->config_part.store_chunk = s->callbacks.config_chunk;
2877 :
2878 4 : becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part,
2879 : becomeDC_drsuapi3_pull_config_recv);
2880 4 : }
2881 :
2882 52 : static void becomeDC_drsuapi3_pull_config_recv(struct tevent_req *subreq)
2883 : {
2884 52 : struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq,
2885 : struct libnet_BecomeDC_state);
2886 52 : struct composite_context *c = s->creq;
2887 52 : struct drsuapi_DsGetNCChanges *r = talloc_get_type_abort(s->ndr_struct_ptr,
2888 : struct drsuapi_DsGetNCChanges);
2889 26 : WERROR status;
2890 :
2891 52 : s->ndr_struct_ptr = NULL;
2892 :
2893 52 : c->status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
2894 52 : TALLOC_FREE(subreq);
2895 100 : if (!composite_is_ok(c)) return;
2896 :
2897 52 : status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->config_part, r);
2898 52 : if (!W_ERROR_IS_OK(status)) {
2899 0 : composite_error(c, werror_to_ntstatus(status));
2900 0 : return;
2901 : }
2902 :
2903 52 : talloc_free(r);
2904 :
2905 52 : if (s->config_part.more_data) {
2906 48 : becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part,
2907 : becomeDC_drsuapi3_pull_config_recv);
2908 48 : return;
2909 : }
2910 :
2911 4 : becomeDC_connect_ldap2(s);
2912 : }
2913 :
2914 : static void becomeDC_drsuapi3_pull_domain_recv(struct tevent_req *subreq);
2915 :
2916 4 : static void becomeDC_drsuapi3_pull_domain_send(struct libnet_BecomeDC_state *s)
2917 : {
2918 4 : s->domain_part.nc.guid = GUID_zero();
2919 4 : s->domain_part.nc.sid = s->zero_sid;
2920 4 : s->domain_part.nc.dn = s->domain.dn_str;
2921 :
2922 4 : s->domain_part.destination_dsa_guid = s->drsuapi2.bind_guid;
2923 :
2924 4 : s->domain_part.replica_flags = DRSUAPI_DRS_WRIT_REP
2925 : | DRSUAPI_DRS_INIT_SYNC
2926 : | DRSUAPI_DRS_PER_SYNC
2927 : | DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS
2928 : | DRSUAPI_DRS_NEVER_SYNCED
2929 : | DRSUAPI_DRS_USE_COMPRESSION
2930 : | DRSUAPI_DRS_GET_ANC;
2931 4 : if (s->critical_only) {
2932 4 : s->domain_part.replica_flags |= DRSUAPI_DRS_CRITICAL_ONLY;
2933 : }
2934 4 : if (s->rodc_join) {
2935 0 : s->schema_part.replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
2936 : }
2937 :
2938 4 : s->domain_part.store_chunk = s->callbacks.domain_chunk;
2939 :
2940 4 : becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part,
2941 : becomeDC_drsuapi3_pull_domain_recv);
2942 4 : }
2943 :
2944 : static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s,
2945 : struct becomeDC_drsuapi *drsuapi,
2946 : struct libnet_BecomeDC_Partition *partition,
2947 : void (*recv_fn)(struct tevent_req *subreq));
2948 : static void becomeDC_drsuapi2_update_refs_schema_recv(struct tevent_req *subreq);
2949 :
2950 8 : static void becomeDC_drsuapi3_pull_domain_recv(struct tevent_req *subreq)
2951 : {
2952 8 : struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq,
2953 : struct libnet_BecomeDC_state);
2954 8 : struct composite_context *c = s->creq;
2955 8 : struct drsuapi_DsGetNCChanges *r = talloc_get_type_abort(s->ndr_struct_ptr,
2956 : struct drsuapi_DsGetNCChanges);
2957 4 : WERROR status;
2958 :
2959 8 : s->ndr_struct_ptr = NULL;
2960 :
2961 8 : c->status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
2962 8 : TALLOC_FREE(subreq);
2963 12 : if (!composite_is_ok(c)) return;
2964 :
2965 8 : status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part, r);
2966 8 : if (!W_ERROR_IS_OK(status)) {
2967 0 : composite_error(c, werror_to_ntstatus(status));
2968 0 : return;
2969 : }
2970 :
2971 8 : talloc_free(r);
2972 :
2973 8 : if (s->domain_part.more_data) {
2974 0 : becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part,
2975 : becomeDC_drsuapi3_pull_domain_recv);
2976 0 : return;
2977 : }
2978 :
2979 8 : if (s->critical_only) {
2980 : /* Remove the critical and ANC */
2981 4 : s->domain_part.replica_flags ^= DRSUAPI_DRS_CRITICAL_ONLY | DRSUAPI_DRS_GET_ANC;
2982 4 : s->critical_only = false;
2983 4 : becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part,
2984 : becomeDC_drsuapi3_pull_domain_recv);
2985 4 : return;
2986 : }
2987 4 : becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->schema_part,
2988 : becomeDC_drsuapi2_update_refs_schema_recv);
2989 : }
2990 :
2991 12 : static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s,
2992 : struct becomeDC_drsuapi *drsuapi,
2993 : struct libnet_BecomeDC_Partition *partition,
2994 : void (*recv_fn)(struct tevent_req *subreq))
2995 : {
2996 12 : struct composite_context *c = s->creq;
2997 6 : struct drsuapi_DsReplicaUpdateRefs *r;
2998 6 : const char *ntds_guid_str;
2999 6 : const char *ntds_dns_name;
3000 6 : struct tevent_req *subreq;
3001 :
3002 12 : r = talloc(s, struct drsuapi_DsReplicaUpdateRefs);
3003 12 : if (composite_nomem(r, c)) return;
3004 :
3005 12 : ntds_guid_str = GUID_string(r, &s->dest_dsa.ntds_guid);
3006 12 : if (composite_nomem(ntds_guid_str, c)) return;
3007 :
3008 12 : ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
3009 : ntds_guid_str,
3010 : s->forest.dns_name);
3011 12 : if (composite_nomem(ntds_dns_name, c)) return;
3012 :
3013 12 : r->in.bind_handle = &drsuapi->bind_handle;
3014 12 : r->in.level = 1;
3015 12 : r->in.req.req1.naming_context = &partition->nc;
3016 12 : r->in.req.req1.dest_dsa_dns_name= ntds_dns_name;
3017 12 : r->in.req.req1.dest_dsa_guid = s->dest_dsa.ntds_guid;
3018 12 : r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
3019 :
3020 : /* I think this is how we mark ourselves as a RODC */
3021 12 : if (!lpcfg_parm_bool(s->libnet->lp_ctx, NULL, "repl", "RODC", false)) {
3022 12 : r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
3023 : }
3024 :
3025 12 : s->ndr_struct_ptr = r;
3026 12 : subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(s, c->event_ctx,
3027 : drsuapi->drsuapi_handle,
3028 : r);
3029 12 : if (composite_nomem(subreq, c)) return;
3030 12 : tevent_req_set_callback(subreq, recv_fn, s);
3031 : }
3032 :
3033 : static void becomeDC_drsuapi2_update_refs_config_recv(struct tevent_req *subreq);
3034 :
3035 4 : static void becomeDC_drsuapi2_update_refs_schema_recv(struct tevent_req *subreq)
3036 : {
3037 4 : struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq,
3038 : struct libnet_BecomeDC_state);
3039 4 : struct composite_context *c = s->creq;
3040 4 : struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type_abort(s->ndr_struct_ptr,
3041 : struct drsuapi_DsReplicaUpdateRefs);
3042 :
3043 4 : s->ndr_struct_ptr = NULL;
3044 :
3045 4 : c->status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
3046 4 : TALLOC_FREE(subreq);
3047 4 : if (!composite_is_ok(c)) return;
3048 :
3049 4 : if (!W_ERROR_IS_OK(r->out.result)) {
3050 0 : composite_error(c, werror_to_ntstatus(r->out.result));
3051 0 : return;
3052 : }
3053 :
3054 4 : talloc_free(r);
3055 :
3056 4 : becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->config_part,
3057 : becomeDC_drsuapi2_update_refs_config_recv);
3058 : }
3059 :
3060 : static void becomeDC_drsuapi2_update_refs_domain_recv(struct tevent_req *subreq);
3061 :
3062 4 : static void becomeDC_drsuapi2_update_refs_config_recv(struct tevent_req *subreq)
3063 : {
3064 4 : struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq,
3065 : struct libnet_BecomeDC_state);
3066 4 : struct composite_context *c = s->creq;
3067 4 : struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(s->ndr_struct_ptr,
3068 : struct drsuapi_DsReplicaUpdateRefs);
3069 :
3070 4 : s->ndr_struct_ptr = NULL;
3071 :
3072 4 : c->status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
3073 4 : TALLOC_FREE(subreq);
3074 4 : if (!composite_is_ok(c)) return;
3075 :
3076 4 : if (!W_ERROR_IS_OK(r->out.result)) {
3077 0 : composite_error(c, werror_to_ntstatus(r->out.result));
3078 0 : return;
3079 : }
3080 :
3081 4 : talloc_free(r);
3082 :
3083 4 : becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->domain_part,
3084 : becomeDC_drsuapi2_update_refs_domain_recv);
3085 : }
3086 :
3087 4 : static void becomeDC_drsuapi2_update_refs_domain_recv(struct tevent_req *subreq)
3088 : {
3089 4 : struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq,
3090 : struct libnet_BecomeDC_state);
3091 4 : struct composite_context *c = s->creq;
3092 4 : struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(s->ndr_struct_ptr,
3093 : struct drsuapi_DsReplicaUpdateRefs);
3094 :
3095 4 : s->ndr_struct_ptr = NULL;
3096 :
3097 4 : c->status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
3098 4 : TALLOC_FREE(subreq);
3099 4 : if (!composite_is_ok(c)) return;
3100 :
3101 4 : if (!W_ERROR_IS_OK(r->out.result)) {
3102 0 : composite_error(c, werror_to_ntstatus(r->out.result));
3103 0 : return;
3104 : }
3105 :
3106 4 : talloc_free(r);
3107 :
3108 : /* TODO: use DDNS updates and register dns names */
3109 4 : composite_done(c);
3110 : }
3111 :
3112 4 : static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s)
3113 : {
3114 2 : int ret;
3115 2 : struct ldb_message *msg;
3116 2 : unsigned int i;
3117 4 : uint32_t user_account_control = UF_SERVER_TRUST_ACCOUNT |
3118 : UF_TRUSTED_FOR_DELEGATION;
3119 :
3120 : /* as the value is already as we want it to be, we're done */
3121 4 : if (s->dest_dsa.user_account_control == user_account_control) {
3122 0 : return NT_STATUS_OK;
3123 : }
3124 :
3125 : /* make a 'modify' msg, and only for serverReference */
3126 4 : msg = ldb_msg_new(s);
3127 4 : NT_STATUS_HAVE_NO_MEMORY(msg);
3128 4 : msg->dn = ldb_dn_new(msg, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
3129 4 : NT_STATUS_HAVE_NO_MEMORY(msg->dn);
3130 :
3131 4 : ret = samdb_msg_add_uint(s->ldap2.ldb, msg, msg, "userAccountControl",
3132 : user_account_control);
3133 4 : if (ret != LDB_SUCCESS) {
3134 0 : talloc_free(msg);
3135 0 : return NT_STATUS_NO_MEMORY;
3136 : }
3137 :
3138 : /* mark all the message elements (should be just one)
3139 : as LDB_FLAG_MOD_REPLACE */
3140 8 : for (i=0;i<msg->num_elements;i++) {
3141 4 : msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3142 : }
3143 :
3144 4 : ret = ldb_modify(s->ldap2.ldb, msg);
3145 4 : talloc_free(msg);
3146 4 : if (ret != LDB_SUCCESS) {
3147 0 : return NT_STATUS_LDAP(ret);
3148 : }
3149 :
3150 4 : s->dest_dsa.user_account_control = user_account_control;
3151 :
3152 4 : return NT_STATUS_OK;
3153 : }
3154 :
3155 4 : static NTSTATUS becomeDC_ldap2_move_computer(struct libnet_BecomeDC_state *s)
3156 : {
3157 2 : int ret;
3158 2 : struct ldb_dn *old_dn;
3159 2 : struct ldb_dn *new_dn;
3160 :
3161 4 : ret = dsdb_wellknown_dn(s->ldap2.ldb, s,
3162 : ldb_get_default_basedn(s->ldap2.ldb),
3163 : DS_GUID_DOMAIN_CONTROLLERS_CONTAINER,
3164 : &new_dn);
3165 4 : if (ret != LDB_SUCCESS) {
3166 0 : return NT_STATUS_LDAP(ret);
3167 : }
3168 :
3169 4 : if (!ldb_dn_add_child_fmt(new_dn, "CN=%s", s->dest_dsa.netbios_name)) {
3170 0 : talloc_free(new_dn);
3171 0 : return NT_STATUS_NO_MEMORY;
3172 : }
3173 :
3174 4 : old_dn = ldb_dn_new(new_dn, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
3175 4 : NT_STATUS_HAVE_NO_MEMORY(old_dn);
3176 :
3177 4 : if (ldb_dn_compare(old_dn, new_dn) == 0) {
3178 : /* we don't need to rename if the old and new dn match */
3179 0 : talloc_free(new_dn);
3180 0 : return NT_STATUS_OK;
3181 : }
3182 :
3183 4 : ret = ldb_rename(s->ldap2.ldb, old_dn, new_dn);
3184 4 : if (ret != LDB_SUCCESS) {
3185 0 : talloc_free(new_dn);
3186 0 : return NT_STATUS_LDAP(ret);
3187 : }
3188 :
3189 4 : s->dest_dsa.computer_dn_str = ldb_dn_alloc_linearized(s, new_dn);
3190 4 : NT_STATUS_HAVE_NO_MEMORY(s->dest_dsa.computer_dn_str);
3191 :
3192 4 : talloc_free(new_dn);
3193 :
3194 4 : return NT_STATUS_OK;
3195 : }
3196 :
3197 4 : static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s)
3198 : {
3199 4 : struct composite_context *c = s->creq;
3200 :
3201 4 : c->status = becomeDC_ldap_connect(s, &s->ldap2);
3202 4 : if (!composite_is_ok(c)) return;
3203 :
3204 4 : c->status = becomeDC_ldap2_modify_computer(s);
3205 4 : if (!composite_is_ok(c)) return;
3206 :
3207 4 : c->status = becomeDC_ldap2_move_computer(s);
3208 4 : if (!composite_is_ok(c)) return;
3209 :
3210 4 : s->critical_only = true;
3211 4 : becomeDC_drsuapi3_pull_domain_send(s);
3212 : }
3213 :
3214 4 : struct composite_context *libnet_BecomeDC_send(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
3215 : {
3216 2 : struct composite_context *c;
3217 2 : struct libnet_BecomeDC_state *s;
3218 2 : char *tmp_name;
3219 :
3220 4 : c = composite_create(mem_ctx, ctx->event_ctx);
3221 4 : if (c == NULL) return NULL;
3222 :
3223 4 : s = talloc_zero(c, struct libnet_BecomeDC_state);
3224 4 : if (composite_nomem(s, c)) return c;
3225 4 : c->private_data = s;
3226 4 : s->creq = c;
3227 4 : s->libnet = ctx;
3228 :
3229 : /* Domain input */
3230 4 : s->domain.dns_name = talloc_strdup(s, r->in.domain_dns_name);
3231 4 : if (composite_nomem(s->domain.dns_name, c)) return c;
3232 4 : s->domain.netbios_name = talloc_strdup(s, r->in.domain_netbios_name);
3233 4 : if (composite_nomem(s->domain.netbios_name, c)) return c;
3234 4 : s->domain.sid = dom_sid_dup(s, r->in.domain_sid);
3235 4 : if (composite_nomem(s->domain.sid, c)) return c;
3236 :
3237 : /* Source DSA input */
3238 4 : s->source_dsa.address = talloc_strdup(s, r->in.source_dsa_address);
3239 4 : if (composite_nomem(s->source_dsa.address, c)) return c;
3240 :
3241 : /* Destination DSA input */
3242 4 : s->dest_dsa.netbios_name= talloc_strdup(s, r->in.dest_dsa_netbios_name);
3243 4 : if (composite_nomem(s->dest_dsa.netbios_name, c)) return c;
3244 :
3245 : /* Destination DSA dns_name construction */
3246 4 : tmp_name = strlower_talloc(s, s->dest_dsa.netbios_name);
3247 4 : if (composite_nomem(tmp_name, c)) return c;
3248 4 : tmp_name = talloc_asprintf_append_buffer(tmp_name, ".%s",s->domain.dns_name);
3249 4 : if (composite_nomem(tmp_name, c)) return c;
3250 4 : s->dest_dsa.dns_name = tmp_name;
3251 :
3252 : /* Callback function pointers */
3253 4 : s->callbacks = r->in.callbacks;
3254 :
3255 : /* RODC join*/
3256 4 : s->rodc_join = r->in.rodc_join;
3257 :
3258 4 : becomeDC_send_cldap(s);
3259 4 : return c;
3260 : }
3261 :
3262 4 : NTSTATUS libnet_BecomeDC_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
3263 : {
3264 2 : NTSTATUS status;
3265 :
3266 4 : status = composite_wait(c);
3267 :
3268 4 : ZERO_STRUCT(r->out);
3269 :
3270 4 : talloc_free(c);
3271 4 : return status;
3272 : }
3273 :
3274 4 : NTSTATUS libnet_BecomeDC(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
3275 : {
3276 2 : NTSTATUS status;
3277 2 : struct composite_context *c;
3278 4 : c = libnet_BecomeDC_send(ctx, mem_ctx, r);
3279 4 : status = libnet_BecomeDC_recv(c, mem_ctx, r);
3280 4 : return status;
3281 : }
|