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