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