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