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