r20708: fix crash bug! we can't use stack memory for async requests...
[samba.git] / source4 / libnet / libnet_become_dc.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher      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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "libnet/libnet.h"
23 #include "libcli/composite/composite.h"
24 #include "libcli/cldap/cldap.h"
25 #include "lib/ldb/include/ldb.h"
26 #include "lib/ldb/include/ldb_errors.h"
27 #include "lib/db_wrap.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "dsdb/common/flags.h"
30 #include "librpc/gen_ndr/ndr_drsuapi_c.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_misc.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "librpc/gen_ndr/ndr_drsuapi.h"
35
36 struct libnet_BecomeDC_state {
37         struct composite_context *creq;
38
39         struct libnet_context *libnet;
40
41         struct dom_sid zero_sid;
42
43         struct {
44                 struct cldap_socket *sock;
45                 struct cldap_netlogon io;
46                 struct nbt_cldap_netlogon_5 netlogon5;
47         } cldap;
48
49         struct becomeDC_ldap {
50                 struct ldb_context *ldb;
51                 const struct ldb_message *rootdse;
52         } ldap1, ldap2;
53
54         struct becomeDC_drsuapi {
55                 struct libnet_BecomeDC_state *s;
56                 struct dcerpc_binding *binding;
57                 struct dcerpc_pipe *pipe;
58                 struct drsuapi_DsBind bind_r;
59                 struct GUID bind_guid;
60                 struct drsuapi_DsBindInfoCtr bind_info_ctr;
61                 struct drsuapi_DsBindInfo28 local_info28;
62                 struct drsuapi_DsBindInfo28 remote_info28;
63                 struct policy_handle bind_handle;
64         } drsuapi1, drsuapi2, drsuapi3;
65
66         struct libnet_BecomeDC_Domain domain;
67         struct libnet_BecomeDC_Forest forest;
68         struct libnet_BecomeDC_SourceDSA source_dsa;
69         struct libnet_BecomeDC_DestDSA dest_dsa;
70
71         struct libnet_BecomeDC_Partition schema_part, config_part, domain_part;
72
73         struct becomeDC_fsmo {
74                 const char *dns_name;
75                 const char *server_dn_str;
76                 const char *ntds_dn_str;
77                 struct GUID ntds_guid;
78         } infrastructure_fsmo;
79
80         struct becomeDC_fsmo rid_manager_fsmo;
81
82         struct libnet_BecomeDC_CheckOptions _co;
83         struct libnet_BecomeDC_PrepareDB _pp;
84         struct libnet_BecomeDC_StoreChunk _sc;
85         struct libnet_BecomeDC_Callbacks callbacks;
86 };
87
88 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s);
89
90 static void becomeDC_recv_cldap(struct cldap_request *req)
91 {
92         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
93                                           struct libnet_BecomeDC_state);
94         struct composite_context *c = s->creq;
95
96         c->status = cldap_netlogon_recv(req, s, &s->cldap.io);
97         if (!composite_is_ok(c)) return;
98
99         s->cldap.netlogon5 = s->cldap.io.out.netlogon.logon5;
100
101         s->domain.dns_name              = s->cldap.netlogon5.dns_domain;
102         s->domain.netbios_name          = s->cldap.netlogon5.domain;
103         s->domain.guid                  = s->cldap.netlogon5.domain_uuid;
104
105         s->forest.dns_name              = s->cldap.netlogon5.forest;
106
107         s->source_dsa.dns_name          = s->cldap.netlogon5.pdc_dns_name;
108         s->source_dsa.netbios_name      = s->cldap.netlogon5.pdc_name;
109         s->source_dsa.site_name         = s->cldap.netlogon5.server_site;
110
111         s->dest_dsa.site_name           = s->cldap.netlogon5.client_site;
112
113         becomeDC_connect_ldap1(s);
114 }
115
116 static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
117 {
118         struct composite_context *c = s->creq;
119         struct cldap_request *req;
120
121         s->cldap.io.in.dest_address     = s->source_dsa.address;
122         s->cldap.io.in.realm            = s->domain.dns_name;
123         s->cldap.io.in.host             = s->dest_dsa.netbios_name;
124         s->cldap.io.in.user             = NULL;
125         s->cldap.io.in.domain_guid      = NULL;
126         s->cldap.io.in.domain_sid       = NULL;
127         s->cldap.io.in.acct_control     = -1;
128         s->cldap.io.in.version          = 6;
129
130         s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx);
131         if (composite_nomem(s->cldap.sock, c)) return;
132
133         req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
134         if (composite_nomem(req, c)) return;
135         req->async.fn           = becomeDC_recv_cldap;
136         req->async.private      = s;
137 }
138
139 static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s, struct becomeDC_ldap *ldap)
140 {
141         char *url;
142
143         url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
144         NT_STATUS_HAVE_NO_MEMORY(url);
145
146         ldap->ldb = ldb_wrap_connect(s, url,
147                                      NULL,
148                                      s->libnet->cred,
149                                      0, NULL);
150         talloc_free(url);
151         if (ldap->ldb == NULL) {
152                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
153         }
154
155         return NT_STATUS_OK;
156 }
157
158 static NTSTATUS becomeDC_ldap1_rootdse(struct libnet_BecomeDC_state *s)
159 {
160         int ret;
161         struct ldb_result *r;
162         struct ldb_dn *basedn;
163         static const char *attrs[] = {
164                 "*",
165                 NULL
166         };
167
168         basedn = ldb_dn_new(s, s->ldap1.ldb, NULL);
169         NT_STATUS_HAVE_NO_MEMORY(basedn);
170
171         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, 
172                          "(objectClass=*)", attrs, &r);
173         talloc_free(basedn);
174         if (ret != LDB_SUCCESS) {
175                 return NT_STATUS_LDAP(ret);
176         } else if (r->count != 1) {
177                 talloc_free(r);
178                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
179         }
180         talloc_steal(s, r);
181
182         s->ldap1.rootdse = r->msgs[0];
183
184         s->domain.dn_str        = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "defaultNamingContext", NULL);
185         if (!s->domain.dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
186
187         s->forest.root_dn_str   = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "rootDomainNamingContext", NULL);
188         if (!s->forest.root_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
189         s->forest.config_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "configurationNamingContext", NULL);
190         if (!s->forest.config_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
191         s->forest.schema_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "schemaNamingContext", NULL);
192         if (!s->forest.schema_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
193
194         s->source_dsa.server_dn_str     = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "serverName", NULL);
195         if (!s->source_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
196         s->source_dsa.ntds_dn_str       = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "dsServiceName", NULL);
197         if (!s->source_dsa.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
198
199         return NT_STATUS_OK;
200 }
201
202 static NTSTATUS becomeDC_ldap1_crossref_behavior_version(struct libnet_BecomeDC_state *s)
203 {
204         int ret;
205         struct ldb_result *r;
206         struct ldb_dn *basedn;
207         static const char *attrs[] = {
208                 "msDs-Behavior-Version",
209                 NULL
210         };
211
212         basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.config_dn_str);
213         NT_STATUS_HAVE_NO_MEMORY(basedn);
214
215         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_ONELEVEL,
216                          "(cn=Partitions)", attrs, &r);
217         talloc_free(basedn);
218         if (ret != LDB_SUCCESS) {
219                 return NT_STATUS_LDAP(ret);
220         } else if (r->count != 1) {
221                 talloc_free(r);
222                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
223         }
224
225         s->forest.crossref_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
226
227         talloc_free(r);
228         return NT_STATUS_OK;
229 }
230
231 static NTSTATUS becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_state *s)
232 {
233         int ret;
234         struct ldb_result *r;
235         struct ldb_dn *basedn;
236         static const char *attrs[] = {
237                 "msDs-Behavior-Version",
238                 NULL
239         };
240
241         basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
242         NT_STATUS_HAVE_NO_MEMORY(basedn);
243
244         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
245                          "(objectClass=*)", attrs, &r);
246         talloc_free(basedn);
247         if (ret != LDB_SUCCESS) {
248                 return NT_STATUS_LDAP(ret);
249         } else if (r->count != 1) {
250                 talloc_free(r);
251                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
252         }
253
254         s->domain.behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
255
256         talloc_free(r);
257         return NT_STATUS_OK;
258 }
259
260 static NTSTATUS becomeDC_ldap1_schema_object_version(struct libnet_BecomeDC_state *s)
261 {
262         int ret;
263         struct ldb_result *r;
264         struct ldb_dn *basedn;
265         static const char *attrs[] = {
266                 "objectVersion",
267                 NULL
268         };
269
270         basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.schema_dn_str);
271         NT_STATUS_HAVE_NO_MEMORY(basedn);
272
273         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
274                          "(objectClass=*)", attrs, &r);
275         talloc_free(basedn);
276         if (ret != LDB_SUCCESS) {
277                 return NT_STATUS_LDAP(ret);
278         } else if (r->count != 1) {
279                 talloc_free(r);
280                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
281         }
282
283         s->forest.schema_object_version = ldb_msg_find_attr_as_uint(r->msgs[0], "objectVersion", 0);
284
285         talloc_free(r);
286         return NT_STATUS_OK;
287 }
288
289 static NTSTATUS becomeDC_ldap1_w2k3_update_revision(struct libnet_BecomeDC_state *s)
290 {
291         int ret;
292         struct ldb_result *r;
293         struct ldb_dn *basedn;
294         static const char *attrs[] = {
295                 "revision",
296                 NULL
297         };
298
299         basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=Windows2003Update,CN=DomainUpdates,CN=System,%s",
300                                 s->domain.dn_str);
301         NT_STATUS_HAVE_NO_MEMORY(basedn);
302
303         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
304                          "(objectClass=*)", attrs, &r);
305         talloc_free(basedn);
306         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
307                 /* w2k doesn't have this object */
308                 s->domain.w2k3_update_revision = 0;
309                 return NT_STATUS_OK;
310         } else if (ret != LDB_SUCCESS) {
311                 return NT_STATUS_LDAP(ret);
312         } else if (r->count != 1) {
313                 talloc_free(r);
314                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
315         }
316
317         s->domain.w2k3_update_revision = ldb_msg_find_attr_as_uint(r->msgs[0], "revision", 0);
318
319         talloc_free(r);
320         return NT_STATUS_OK;
321 }
322
323 static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state *s)
324 {
325         int ret;
326         struct ldb_result *r;
327         struct ldb_dn *basedn;
328         struct ldb_dn *ntds_dn;
329         struct ldb_dn *server_dn;
330         static const char *_1_1_attrs[] = {
331                 "1.1",
332                 NULL
333         };
334         static const char *fsmo_attrs[] = {
335                 "fSMORoleOwner",
336                 NULL
337         };
338         static const char *dns_attrs[] = {
339                 "dnsHostName",
340                 NULL
341         };
342         static const char *guid_attrs[] = {
343                 "objectGUID",
344                 NULL
345         };
346
347         basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "<WKGUID=2fbac1870ade11d297c400c04fd8d5cd,%s>",
348                                 s->domain.dn_str);
349         NT_STATUS_HAVE_NO_MEMORY(basedn);
350
351         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
352                          "(objectClass=*)", _1_1_attrs, &r);
353         talloc_free(basedn);
354         if (ret != LDB_SUCCESS) {
355                 return NT_STATUS_LDAP(ret);
356         } else if (r->count != 1) {
357                 talloc_free(r);
358                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
359         }
360
361         basedn = talloc_steal(s, r->msgs[0]->dn);
362         talloc_free(r);
363
364         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
365                          "(objectClass=*)", fsmo_attrs, &r);
366         talloc_free(basedn);
367         if (ret != LDB_SUCCESS) {
368                 return NT_STATUS_LDAP(ret);
369         } else if (r->count != 1) {
370                 talloc_free(r);
371                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
372         }
373
374         s->infrastructure_fsmo.ntds_dn_str      = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
375         if (!s->infrastructure_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
376         talloc_steal(s, s->infrastructure_fsmo.ntds_dn_str);
377
378         talloc_free(r);
379
380         ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->infrastructure_fsmo.ntds_dn_str);
381         NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
382
383         server_dn = ldb_dn_get_parent(s, ntds_dn);
384         NT_STATUS_HAVE_NO_MEMORY(server_dn);
385
386         s->infrastructure_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
387         NT_STATUS_HAVE_NO_MEMORY(s->infrastructure_fsmo.server_dn_str);
388
389         ret = ldb_search(s->ldap1.ldb, server_dn, LDB_SCOPE_BASE,
390                          "(objectClass=*)", dns_attrs, &r);
391         if (ret != LDB_SUCCESS) {
392                 return NT_STATUS_LDAP(ret);
393         } else if (r->count != 1) {
394                 talloc_free(r);
395                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
396         }
397
398         s->infrastructure_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL);
399         if (!s->infrastructure_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
400         talloc_steal(s, s->infrastructure_fsmo.dns_name);
401
402         talloc_free(r);
403
404         ret = ldb_search(s->ldap1.ldb, ntds_dn, LDB_SCOPE_BASE,
405                          "(objectClass=*)", guid_attrs, &r);
406         if (ret != LDB_SUCCESS) {
407                 return NT_STATUS_LDAP(ret);
408         } else if (r->count != 1) {
409                 talloc_free(r);
410                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
411         }
412
413         s->infrastructure_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
414
415         talloc_free(r);
416
417         return NT_STATUS_OK;
418 }
419
420 static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s)
421 {
422         int ret;
423         struct ldb_result *r;
424         struct ldb_dn *basedn;
425         const char *reference_dn_str;
426         struct ldb_dn *ntds_dn;
427         struct ldb_dn *server_dn;
428         static const char *rid_attrs[] = {
429                 "rIDManagerReference",
430                 NULL
431         };
432         static const char *fsmo_attrs[] = {
433                 "fSMORoleOwner",
434                 NULL
435         };
436         static const char *dns_attrs[] = {
437                 "dnsHostName",
438                 NULL
439         };
440         static const char *guid_attrs[] = {
441                 "objectGUID",
442                 NULL
443         };
444
445         basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
446         NT_STATUS_HAVE_NO_MEMORY(basedn);
447
448         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
449                          "(objectClass=*)", rid_attrs, &r);
450         talloc_free(basedn);
451         if (ret != LDB_SUCCESS) {
452                 return NT_STATUS_LDAP(ret);
453         } else if (r->count != 1) {
454                 talloc_free(r);
455                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
456         }
457
458         reference_dn_str        = samdb_result_string(r->msgs[0], "rIDManagerReference", NULL);
459         if (!reference_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
460
461         basedn = ldb_dn_new(s, s->ldap1.ldb, reference_dn_str);
462         NT_STATUS_HAVE_NO_MEMORY(basedn);
463
464         talloc_free(r);
465
466         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
467                          "(objectClass=*)", fsmo_attrs, &r);
468         talloc_free(basedn);
469         if (ret != LDB_SUCCESS) {
470                 return NT_STATUS_LDAP(ret);
471         } else if (r->count != 1) {
472                 talloc_free(r);
473                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
474         }
475
476         s->rid_manager_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
477         if (!s->rid_manager_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
478         talloc_steal(s, s->rid_manager_fsmo.ntds_dn_str);
479
480         talloc_free(r);
481
482         ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->rid_manager_fsmo.ntds_dn_str);
483         NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
484
485         server_dn = ldb_dn_get_parent(s, ntds_dn);
486         NT_STATUS_HAVE_NO_MEMORY(server_dn);
487
488         s->rid_manager_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
489         NT_STATUS_HAVE_NO_MEMORY(s->rid_manager_fsmo.server_dn_str);
490
491         ret = ldb_search(s->ldap1.ldb, server_dn, LDB_SCOPE_BASE,
492                          "(objectClass=*)", dns_attrs, &r);
493         if (ret != LDB_SUCCESS) {
494                 return NT_STATUS_LDAP(ret);
495         } else if (r->count != 1) {
496                 talloc_free(r);
497                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
498         }
499
500         s->rid_manager_fsmo.dns_name    = samdb_result_string(r->msgs[0], "dnsHostName", NULL);
501         if (!s->rid_manager_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
502         talloc_steal(s, s->rid_manager_fsmo.dns_name);
503
504         talloc_free(r);
505
506         ret = ldb_search(s->ldap1.ldb, ntds_dn, LDB_SCOPE_BASE,
507                          "(objectClass=*)", guid_attrs, &r);
508         if (ret != LDB_SUCCESS) {
509                 return NT_STATUS_LDAP(ret);
510         } else if (r->count != 1) {
511                 talloc_free(r);
512                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
513         }
514
515         s->rid_manager_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
516
517         talloc_free(r);
518
519         return NT_STATUS_OK;
520 }
521
522 static NTSTATUS becomeDC_ldap1_site_object(struct libnet_BecomeDC_state *s)
523 {
524         int ret;
525         struct ldb_result *r;
526         struct ldb_dn *basedn;
527
528         basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Sites,%s",
529                                 s->dest_dsa.site_name,
530                                 s->forest.config_dn_str);
531         NT_STATUS_HAVE_NO_MEMORY(basedn);
532
533         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, 
534                          "(objectClass=*)", NULL, &r);
535         talloc_free(basedn);
536         if (ret != LDB_SUCCESS) {
537                 return NT_STATUS_LDAP(ret);
538         } else if (r->count != 1) {
539                 talloc_free(r);
540                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
541         }
542
543         s->dest_dsa.site_guid = samdb_result_guid(r->msgs[0], "objectGUID");
544
545         talloc_free(r);
546         return NT_STATUS_OK;
547 }
548
549 static NTSTATUS becomeDC_check_options(struct libnet_BecomeDC_state *s)
550 {
551         if (!s->callbacks.check_options) return NT_STATUS_OK;
552
553         s->_co.domain           = &s->domain;
554         s->_co.forest           = &s->forest;
555         s->_co.source_dsa       = &s->source_dsa;
556
557         return s->callbacks.check_options(s->callbacks.private_data, &s->_co);
558 }
559
560 static NTSTATUS becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state *s)
561 {
562         int ret;
563         struct ldb_result *r;
564         struct ldb_dn *basedn;
565         char *filter;
566         static const char *attrs[] = {
567                 "distinguishedName",
568                 "userAccountControl",
569                 NULL
570         };
571
572         basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
573         NT_STATUS_HAVE_NO_MEMORY(basedn);
574
575         filter = talloc_asprintf(basedn, "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))",
576                                  s->dest_dsa.netbios_name);
577         NT_STATUS_HAVE_NO_MEMORY(filter);
578
579         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_SUBTREE, 
580                          filter, attrs, &r);
581         talloc_free(basedn);
582         if (ret != LDB_SUCCESS) {
583                 return NT_STATUS_LDAP(ret);
584         } else if (r->count != 1) {
585                 talloc_free(r);
586                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
587         }
588
589         s->dest_dsa.computer_dn_str     = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
590         if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
591         talloc_steal(s, s->dest_dsa.computer_dn_str);
592
593         s->dest_dsa.user_account_control = samdb_result_uint(r->msgs[0], "userAccountControl", 0);
594
595         talloc_free(r);
596         return NT_STATUS_OK;
597 }
598
599 static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s)
600 {
601         int ret;
602         struct ldb_result *r;
603         struct ldb_dn *basedn;
604         const char *server_reference_dn_str;
605         struct ldb_dn *server_reference_dn;
606         struct ldb_dn *computer_dn;
607
608         basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
609                                 s->dest_dsa.netbios_name,
610                                 s->dest_dsa.site_name,
611                                 s->forest.config_dn_str);
612         NT_STATUS_HAVE_NO_MEMORY(basedn);
613
614         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, 
615                          "(objectClass=*)", NULL, &r);
616         talloc_free(basedn);
617         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
618                 /* if the object doesn't exist, we'll create it later */
619                 return NT_STATUS_OK;
620         } else if (ret != LDB_SUCCESS) {
621                 return NT_STATUS_LDAP(ret);
622         } else if (r->count != 1) {
623                 talloc_free(r);
624                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
625         }
626
627         server_reference_dn_str = samdb_result_string(r->msgs[0], "serverReference", NULL);
628         if (server_reference_dn_str) {
629                 server_reference_dn     = ldb_dn_new(r, s->ldap1.ldb, server_reference_dn_str);
630                 NT_STATUS_HAVE_NO_MEMORY(server_reference_dn);
631
632                 computer_dn             = ldb_dn_new(r, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
633                 NT_STATUS_HAVE_NO_MEMORY(computer_dn);
634
635                 /*
636                  * if the server object belongs to another DC in another domain in the forest,
637                  * we should not touch this object!
638                  */
639                 if (ldb_dn_compare(computer_dn, server_reference_dn) != 0) {
640                         talloc_free(r);
641                         return NT_STATUS_OBJECT_NAME_COLLISION;
642                 }
643         }
644
645         /* if the server object is already for the dest_dsa, then we don't need to create it */
646         s->dest_dsa.server_dn_str       = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
647         if (!s->dest_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
648         talloc_steal(s, s->dest_dsa.server_dn_str);
649
650         talloc_free(r);
651         return NT_STATUS_OK;
652 }
653
654 static NTSTATUS becomeDC_ldap1_server_object_2(struct libnet_BecomeDC_state *s)
655 {
656         int ret;
657         struct ldb_result *r;
658         struct ldb_dn *basedn;
659         const char *server_reference_bl_dn_str;
660         static const char *attrs[] = {
661                 "serverReferenceBL",
662                 NULL
663         };
664
665         /* if the server_dn_str has a valid value, we skip this lookup */
666         if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
667
668         basedn = ldb_dn_new(s, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
669         NT_STATUS_HAVE_NO_MEMORY(basedn);
670
671         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, 
672                          "(objectClass=*)", attrs, &r);
673         talloc_free(basedn);
674         if (ret != LDB_SUCCESS) {
675                 return NT_STATUS_LDAP(ret);
676         } else if (r->count != 1) {
677                 talloc_free(r);
678                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
679         }
680
681         server_reference_bl_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL);
682         if (!server_reference_bl_dn_str) {
683                 /* if no back link is present, we're done for this function */
684                 talloc_free(r);
685                 return NT_STATUS_OK;
686         }
687
688         /* if the server object is already for the dest_dsa, then we don't need to create it */
689         s->dest_dsa.server_dn_str       = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL);
690         if (s->dest_dsa.server_dn_str) {
691                 /* if a back link is present, we know that the server object is present */
692                 talloc_steal(s, s->dest_dsa.server_dn_str);
693         }
694
695         talloc_free(r);
696         return NT_STATUS_OK;
697 }
698
699 static NTSTATUS becomeDC_ldap1_server_object_add(struct libnet_BecomeDC_state *s)
700 {
701         int ret;
702         struct ldb_message *msg;
703         char *server_dn_str;
704
705         /* if the server_dn_str has a valid value, we skip this lookup */
706         if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
707
708         msg = ldb_msg_new(s);
709         NT_STATUS_HAVE_NO_MEMORY(msg);
710
711         msg->dn = ldb_dn_new_fmt(msg, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
712                                  s->dest_dsa.netbios_name,
713                                  s->dest_dsa.site_name,
714                                  s->forest.config_dn_str);
715         NT_STATUS_HAVE_NO_MEMORY(msg->dn);
716
717         ret = ldb_msg_add_string(msg, "objectClass", "server");
718         if (ret != 0) {
719                 talloc_free(msg);
720                 return NT_STATUS_NO_MEMORY;
721         }
722         ret = ldb_msg_add_string(msg, "systemFlags", "50000000");
723         if (ret != 0) {
724                 talloc_free(msg);
725                 return NT_STATUS_NO_MEMORY;
726         }
727         ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
728         if (ret != 0) {
729                 talloc_free(msg);
730                 return NT_STATUS_NO_MEMORY;
731         }
732
733         server_dn_str = ldb_dn_alloc_linearized(s, msg->dn);
734         NT_STATUS_HAVE_NO_MEMORY(server_dn_str);
735
736         ret = ldb_add(s->ldap1.ldb, msg);
737         talloc_free(msg);
738         if (ret != LDB_SUCCESS) {
739                 talloc_free(server_dn_str);
740                 return NT_STATUS_LDAP(ret);
741         }
742
743         s->dest_dsa.server_dn_str = server_dn_str;
744
745         return NT_STATUS_OK;
746 }
747
748 static NTSTATUS becomeDC_ldap1_server_object_modify(struct libnet_BecomeDC_state *s)
749 {
750         int ret;
751         struct ldb_message *msg;
752         uint32_t i;
753
754         /* make a 'modify' msg, and only for serverReference */
755         msg = ldb_msg_new(s);
756         NT_STATUS_HAVE_NO_MEMORY(msg);
757         msg->dn = ldb_dn_new(msg, s->ldap1.ldb, s->dest_dsa.server_dn_str);
758         NT_STATUS_HAVE_NO_MEMORY(msg->dn);
759
760         ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
761         if (ret != 0) {
762                 talloc_free(msg);
763                 return NT_STATUS_NO_MEMORY;
764         }
765
766         /* mark all the message elements (should be just one)
767            as LDB_FLAG_MOD_ADD */
768         for (i=0;i<msg->num_elements;i++) {
769                 msg->elements[i].flags = LDB_FLAG_MOD_ADD;
770         }
771
772         ret = ldb_modify(s->ldap1.ldb, msg);
773         if (ret == LDB_SUCCESS) {
774                 talloc_free(msg);
775                 return NT_STATUS_OK;
776         } else if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
777                 /* retry with LDB_FLAG_MOD_REPLACE */
778         } else {
779                 talloc_free(msg);
780                 return NT_STATUS_LDAP(ret);
781         }
782
783         /* mark all the message elements (should be just one)
784            as LDB_FLAG_MOD_REPLACE */
785         for (i=0;i<msg->num_elements;i++) {
786                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
787         }
788
789         ret = ldb_modify(s->ldap1.ldb, msg);
790         talloc_free(msg);
791         if (ret != LDB_SUCCESS) {
792                 return NT_STATUS_LDAP(ret);
793         }
794
795         return NT_STATUS_OK;
796 }
797
798 static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
799                                           struct becomeDC_drsuapi *drsuapi,
800                                           void (*recv_fn)(struct composite_context *req));
801 static void becomeDC_drsuapi1_connect_recv(struct composite_context *req);
802 static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s);
803
804 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s)
805 {
806         struct composite_context *c = s->creq;
807
808         c->status = becomeDC_ldap_connect(s, &s->ldap1);
809         if (!composite_is_ok(c)) return;
810
811         c->status = becomeDC_ldap1_rootdse(s);
812         if (!composite_is_ok(c)) return;
813
814         c->status = becomeDC_ldap1_crossref_behavior_version(s);
815         if (!composite_is_ok(c)) return;
816
817         c->status = becomeDC_ldap1_domain_behavior_version(s);
818         if (!composite_is_ok(c)) return;
819
820         c->status = becomeDC_ldap1_schema_object_version(s);
821         if (!composite_is_ok(c)) return;
822
823         c->status = becomeDC_ldap1_w2k3_update_revision(s);
824         if (!composite_is_ok(c)) return;
825
826         c->status = becomeDC_ldap1_infrastructure_fsmo(s);
827         if (!composite_is_ok(c)) return;
828
829         c->status = becomeDC_ldap1_rid_manager_fsmo(s);
830         if (!composite_is_ok(c)) return;
831
832         c->status = becomeDC_ldap1_site_object(s);
833         if (!composite_is_ok(c)) return;
834
835         c->status = becomeDC_check_options(s);
836         if (!composite_is_ok(c)) return;
837
838         c->status = becomeDC_ldap1_computer_object(s);
839         if (!composite_is_ok(c)) return;
840
841         c->status = becomeDC_ldap1_server_object_1(s);
842         if (!composite_is_ok(c)) return;
843
844         c->status = becomeDC_ldap1_server_object_2(s);
845         if (!composite_is_ok(c)) return;
846
847         c->status = becomeDC_ldap1_server_object_add(s);
848         if (!composite_is_ok(c)) return;
849
850         c->status = becomeDC_ldap1_server_object_modify(s);
851         if (!composite_is_ok(c)) return;
852
853         becomeDC_drsuapi_connect_send(s, &s->drsuapi1, becomeDC_drsuapi1_connect_recv);
854 }
855
856 static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
857                                           struct becomeDC_drsuapi *drsuapi,
858                                           void (*recv_fn)(struct composite_context *req))
859 {
860         struct composite_context *c = s->creq;
861         struct composite_context *creq;
862         char *binding_str;
863
864         drsuapi->s = s;
865
866         if (!drsuapi->binding) {
867                 binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[krb5,seal]", s->source_dsa.dns_name);
868                 if (composite_nomem(binding_str, c)) return;
869
870                 c->status = dcerpc_parse_binding(s, binding_str, &drsuapi->binding);
871                 talloc_free(binding_str);
872                 if (!composite_is_ok(c)) return;
873         }
874
875         creq = dcerpc_pipe_connect_b_send(s, drsuapi->binding, &dcerpc_table_drsuapi,
876                                           s->libnet->cred, s->libnet->event_ctx);
877         composite_continue(c, creq, recv_fn, s);
878 }
879
880 static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
881                                        struct becomeDC_drsuapi *drsuapi,
882                                        void (*recv_fn)(struct rpc_request *req));
883 static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req);
884
885 static void becomeDC_drsuapi1_connect_recv(struct composite_context *req)
886 {
887         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
888                                           struct libnet_BecomeDC_state);
889         struct composite_context *c = s->creq;
890
891         c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi1.pipe);
892         if (!composite_is_ok(c)) return;
893
894         becomeDC_drsuapi_bind_send(s, &s->drsuapi1, becomeDC_drsuapi1_bind_recv);
895 }
896
897 static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
898                                        struct becomeDC_drsuapi *drsuapi,
899                                        void (*recv_fn)(struct rpc_request *req))
900 {
901         struct composite_context *c = s->creq;
902         struct rpc_request *req;
903         struct drsuapi_DsBindInfo28 *bind_info28;
904
905         GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &drsuapi->bind_guid);
906
907         bind_info28                             = &drsuapi->local_info28;
908         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
909         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
910         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
911         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
912         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
913         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
914         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
915         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
916         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
917         if (s->domain.behavior_version == 2) {
918                 /* TODO: find out how this is really triggered! */
919                 bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
920         }
921         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
922         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
923         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
924         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
925         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
926         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
927         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
928         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
929         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
930         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_00100000;
931         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
932         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
933         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
934         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
935         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
936         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
937         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
938         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
939         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
940 #if 0 /* we don't support XPRESS compression yet */
941         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
942 #endif
943         bind_info28->site_guid                  = s->dest_dsa.site_guid;
944         if (s->domain.behavior_version == 2) {
945                 /* TODO: find out how this is really triggered! */
946                 bind_info28->u1                         = 528;
947         } else {
948                 bind_info28->u1                         = 516;
949         }
950         bind_info28->repl_epoch                 = 0;
951
952         drsuapi->bind_info_ctr.length           = 28;
953         drsuapi->bind_info_ctr.info.info28      = *bind_info28;
954
955         drsuapi->bind_r.in.bind_guid = &drsuapi->bind_guid;
956         drsuapi->bind_r.in.bind_info = &drsuapi->bind_info_ctr;
957         drsuapi->bind_r.out.bind_handle = &drsuapi->bind_handle;
958
959         req = dcerpc_drsuapi_DsBind_send(drsuapi->pipe, s, &drsuapi->bind_r);
960         composite_continue_rpc(c, req, recv_fn, s);
961 }
962
963 static WERROR becomeDC_drsuapi_bind_recv(struct libnet_BecomeDC_state *s,
964                                          struct becomeDC_drsuapi *drsuapi)
965 {
966         if (!W_ERROR_IS_OK(drsuapi->bind_r.out.result)) {
967                 return drsuapi->bind_r.out.result;
968         }
969
970         ZERO_STRUCT(drsuapi->remote_info28);
971         if (drsuapi->bind_r.out.bind_info) {
972                 switch (drsuapi->bind_r.out.bind_info->length) {
973                 case 24: {
974                         struct drsuapi_DsBindInfo24 *info24;
975                         info24 = &drsuapi->bind_r.out.bind_info->info.info24;
976                         drsuapi->remote_info28.supported_extensions     = info24->supported_extensions;
977                         drsuapi->remote_info28.site_guid                = info24->site_guid;
978                         drsuapi->remote_info28.u1                       = info24->u1;
979                         drsuapi->remote_info28.repl_epoch               = 0;
980                         break;
981                 }
982                 case 28:
983                         drsuapi->remote_info28 = drsuapi->bind_r.out.bind_info->info.info28;
984                         break;
985                 }
986         }
987
988         return WERR_OK;
989 }
990
991 static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s);
992
993 static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req)
994 {
995         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
996                                           struct libnet_BecomeDC_state);
997         struct composite_context *c = s->creq;
998         WERROR status;
999
1000         c->status = dcerpc_ndr_request_recv(req);
1001         if (!composite_is_ok(c)) return;
1002
1003         status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi1);
1004         if (!W_ERROR_IS_OK(status)) {
1005                 composite_error(c, werror_to_ntstatus(status));
1006                 return;
1007         }
1008
1009         becomeDC_drsuapi1_add_entry_send(s);
1010 }
1011
1012 static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req);
1013
1014 static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
1015 {
1016         struct composite_context *c = s->creq;
1017         struct rpc_request *req;
1018         struct drsuapi_DsAddEntry *r;
1019         struct drsuapi_DsReplicaObjectIdentifier *identifier;
1020         uint32_t num_attrs, i = 0;
1021         struct drsuapi_DsReplicaAttribute *attrs;
1022         bool w2k3;
1023
1024         /* choose a random invocationId */
1025         s->dest_dsa.invocation_id = GUID_random();
1026
1027         /*
1028          * if the schema version indicates w2k3, then
1029          * also send some w2k3 specific attributes
1030          */
1031         if (s->forest.schema_object_version >= 30) {
1032                 w2k3 = true;
1033         } else {
1034                 w2k3 = false;
1035         }
1036
1037         r = talloc_zero(s, struct drsuapi_DsAddEntry);
1038         if (composite_nomem(r, c)) return;
1039
1040         /* setup identifier */
1041         identifier              = talloc(r, struct drsuapi_DsReplicaObjectIdentifier);
1042         if (composite_nomem(identifier, c)) return;
1043         identifier->guid        = GUID_zero();
1044         identifier->sid         = s->zero_sid;
1045         identifier->dn          = talloc_asprintf(identifier, "CN=NTDS Settings,%s",
1046                                                   s->dest_dsa.server_dn_str);
1047         if (composite_nomem(identifier->dn, c)) return;
1048
1049         /* allocate attribute array */
1050         num_attrs       = 11;
1051         attrs           = talloc_array(r, struct drsuapi_DsReplicaAttribute, num_attrs);
1052         if (composite_nomem(attrs, c)) return;
1053
1054         /* ntSecurityDescriptor */
1055         {
1056                 struct drsuapi_DsAttributeValue *vs;
1057                 DATA_BLOB *vd;
1058                 struct security_descriptor *v;
1059                 struct dom_sid *domain_admins_sid;
1060                 const char *domain_admins_sid_str;
1061
1062                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1063                 if (composite_nomem(vs, c)) return;
1064
1065                 vd = talloc_array(vs, DATA_BLOB, 1);
1066                 if (composite_nomem(vd, c)) return;
1067
1068                 domain_admins_sid = dom_sid_add_rid(vs, s->domain.sid, DOMAIN_RID_ADMINS);
1069                 if (composite_nomem(domain_admins_sid, c)) return;
1070
1071                 domain_admins_sid_str = dom_sid_string(domain_admins_sid, domain_admins_sid);
1072                 if (composite_nomem(domain_admins_sid_str, c)) return;
1073
1074                 v = security_descriptor_create(vd,
1075                                                /* owner: domain admins */
1076                                                domain_admins_sid_str,
1077                                                /* owner group: domain admins */
1078                                                domain_admins_sid_str,
1079                                                /* authenticated users */
1080                                                SID_NT_AUTHENTICATED_USERS,
1081                                                SEC_ACE_TYPE_ACCESS_ALLOWED,
1082                                                SEC_STD_READ_CONTROL |
1083                                                SEC_ADS_LIST |
1084                                                SEC_ADS_READ_PROP |
1085                                                SEC_ADS_LIST_OBJECT,
1086                                                0,
1087                                                /* domain admins */
1088                                                domain_admins_sid_str,
1089                                                SEC_ACE_TYPE_ACCESS_ALLOWED,
1090                                                SEC_STD_REQUIRED |
1091                                                SEC_ADS_CREATE_CHILD |
1092                                                SEC_ADS_LIST |
1093                                                SEC_ADS_SELF_WRITE |
1094                                                SEC_ADS_READ_PROP |
1095                                                SEC_ADS_WRITE_PROP |
1096                                                SEC_ADS_DELETE_TREE |
1097                                                SEC_ADS_LIST_OBJECT |
1098                                                SEC_ADS_CONTROL_ACCESS,
1099                                                0,
1100                                                /* system */
1101                                                SID_NT_SYSTEM,
1102                                                SEC_ACE_TYPE_ACCESS_ALLOWED,
1103                                                SEC_STD_REQUIRED |
1104                                                SEC_ADS_CREATE_CHILD |
1105                                                SEC_ADS_DELETE_CHILD |
1106                                                SEC_ADS_LIST |
1107                                                SEC_ADS_SELF_WRITE |
1108                                                SEC_ADS_READ_PROP |
1109                                                SEC_ADS_WRITE_PROP |
1110                                                SEC_ADS_DELETE_TREE |
1111                                                SEC_ADS_LIST_OBJECT |
1112                                                SEC_ADS_CONTROL_ACCESS,
1113                                                0,
1114                                                /* end */
1115                                                NULL);
1116                 if (composite_nomem(v, c)) return;
1117
1118                 c->status = ndr_push_struct_blob(&vd[0], vd, v,(ndr_push_flags_fn_t)ndr_push_security_descriptor);
1119                 if (!composite_is_ok(c)) return;
1120
1121                 vs[0].blob              = &vd[0];
1122
1123                 attrs[i].attid                  = DRSUAPI_ATTRIBUTE_ntSecurityDescriptor;
1124                 attrs[i].value_ctr.num_values   = 1;
1125                 attrs[i].value_ctr.values       = vs;
1126
1127                 i++;
1128         }
1129
1130         /* objectClass: nTDSDSA */
1131         {
1132                 struct drsuapi_DsAttributeValue *vs;
1133                 DATA_BLOB *vd;
1134
1135                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1136                 if (composite_nomem(vs, c)) return;
1137
1138                 vd = talloc_array(vs, DATA_BLOB, 1);
1139                 if (composite_nomem(vd, c)) return;
1140
1141                 vd[0] = data_blob_talloc(vd, NULL, 4);
1142                 if (composite_nomem(vd[0].data, c)) return;
1143
1144                 /* value for nTDSDSA */
1145                 SIVAL(vd[0].data, 0, 0x0017002F);
1146
1147                 vs[0].blob              = &vd[0];
1148
1149                 attrs[i].attid                  = DRSUAPI_ATTRIBUTE_objectClass;
1150                 attrs[i].value_ctr.num_values   = 1;
1151                 attrs[i].value_ctr.values       = vs;
1152
1153                 i++;
1154         }
1155
1156         /* objectCategory: CN=NTDS-DSA,CN=Schema,... */
1157         {
1158                 struct drsuapi_DsAttributeValue *vs;
1159                 DATA_BLOB *vd;
1160                 struct drsuapi_DsReplicaObjectIdentifier3 v[1];
1161
1162                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1163                 if (composite_nomem(vs, c)) return;
1164
1165                 vd = talloc_array(vs, DATA_BLOB, 1);
1166                 if (composite_nomem(vd, c)) return;
1167
1168                 v[0].guid               = GUID_zero();
1169                 v[0].sid                = s->zero_sid;
1170                 v[0].dn                 = talloc_asprintf(vd, "CN=NTDS-DSA,%s",
1171                                                           s->forest.schema_dn_str);
1172                 if (composite_nomem(v->dn, c)) return;
1173
1174                 c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
1175                                                  (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1176                 if (!composite_is_ok(c)) return;
1177
1178                 vs[0].blob              = &vd[0];
1179
1180                 attrs[i].attid                  = DRSUAPI_ATTRIBUTE_objectCategory;
1181                 attrs[i].value_ctr.num_values   = 1;
1182                 attrs[i].value_ctr.values       = vs;
1183
1184                 i++;
1185         }
1186
1187         /* invocationId: random guid */
1188         {
1189                 struct drsuapi_DsAttributeValue *vs;
1190                 DATA_BLOB *vd;
1191                 const struct GUID *v;
1192
1193                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1194                 if (composite_nomem(vs, c)) return;
1195
1196                 vd = talloc_array(vs, DATA_BLOB, 1);
1197                 if (composite_nomem(vd, c)) return;
1198
1199                 v = &s->dest_dsa.invocation_id;
1200
1201                 c->status = ndr_push_struct_blob(&vd[0], vd, v, (ndr_push_flags_fn_t)ndr_push_GUID);
1202                 if (!composite_is_ok(c)) return;
1203
1204                 vs[0].blob              = &vd[0];
1205
1206                 attrs[i].attid                  = DRSUAPI_ATTRIBUTE_invocationId;
1207                 attrs[i].value_ctr.num_values   = 1;
1208                 attrs[i].value_ctr.values       = vs;
1209
1210                 i++;
1211         }
1212
1213         /* hasMasterNCs: ... */
1214         {
1215                 struct drsuapi_DsAttributeValue *vs;
1216                 DATA_BLOB *vd;
1217                 struct drsuapi_DsReplicaObjectIdentifier3 v[3];
1218
1219                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 3);
1220                 if (composite_nomem(vs, c)) return;
1221
1222                 vd = talloc_array(vs, DATA_BLOB, 3);
1223                 if (composite_nomem(vd, c)) return;
1224
1225                 v[0].guid               = GUID_zero();
1226                 v[0].sid                = s->zero_sid;
1227                 v[0].dn                 = s->forest.config_dn_str;
1228
1229                 v[1].guid               = GUID_zero();
1230                 v[1].sid                = s->zero_sid;
1231                 v[1].dn                 = s->domain.dn_str;
1232
1233                 v[2].guid               = GUID_zero();
1234                 v[2].sid                = s->zero_sid;
1235                 v[2].dn                 = s->forest.schema_dn_str;
1236
1237                 c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
1238                                                  (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1239                 if (!composite_is_ok(c)) return;
1240
1241                 c->status = ndr_push_struct_blob(&vd[1], vd, &v[1],
1242                                                  (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1243                 if (!composite_is_ok(c)) return;
1244
1245                 c->status = ndr_push_struct_blob(&vd[2], vd, &v[2],
1246                                                  (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1247                 if (!composite_is_ok(c)) return;
1248
1249                 vs[0].blob              = &vd[0];
1250                 vs[1].blob              = &vd[1];
1251                 vs[2].blob              = &vd[2];
1252
1253                 attrs[i].attid                  = DRSUAPI_ATTRIBUTE_hasMasterNCs;
1254                 attrs[i].value_ctr.num_values   = 3;
1255                 attrs[i].value_ctr.values       = vs;
1256
1257                 i++;
1258         }
1259
1260         /* msDS-hasMasterNCs: ... */
1261         if (w2k3) {
1262                 struct drsuapi_DsAttributeValue *vs;
1263                 DATA_BLOB *vd;
1264                 struct drsuapi_DsReplicaObjectIdentifier3 v[3];
1265
1266                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 3);
1267                 if (composite_nomem(vs, c)) return;
1268
1269                 vd = talloc_array(vs, DATA_BLOB, 3);
1270                 if (composite_nomem(vd, c)) return;
1271
1272                 v[0].guid               = GUID_zero();
1273                 v[0].sid                = s->zero_sid;
1274                 v[0].dn                 = s->forest.config_dn_str;
1275
1276                 v[1].guid               = GUID_zero();
1277                 v[1].sid                = s->zero_sid;
1278                 v[1].dn                 = s->domain.dn_str;
1279
1280                 v[2].guid               = GUID_zero();
1281                 v[2].sid                = s->zero_sid;
1282                 v[2].dn                 = s->forest.schema_dn_str;
1283
1284                 c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
1285                                                  (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1286                 if (!composite_is_ok(c)) return;
1287
1288                 c->status = ndr_push_struct_blob(&vd[1], vd, &v[1],
1289                                                  (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1290                 if (!composite_is_ok(c)) return;
1291
1292                 c->status = ndr_push_struct_blob(&vd[2], vd, &v[2],
1293                                                  (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1294                 if (!composite_is_ok(c)) return;
1295
1296                 vs[0].blob              = &vd[0];
1297                 vs[1].blob              = &vd[1];
1298                 vs[2].blob              = &vd[2];
1299
1300                 attrs[i].attid                  = DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs;
1301                 attrs[i].value_ctr.num_values   = 3;
1302                 attrs[i].value_ctr.values       = vs;
1303
1304                 i++;
1305         }
1306
1307         /* dMDLocation: CN=Schema,... */
1308         {
1309                 struct drsuapi_DsAttributeValue *vs;
1310                 DATA_BLOB *vd;
1311                 struct drsuapi_DsReplicaObjectIdentifier3 v[1];
1312
1313                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1314                 if (composite_nomem(vs, c)) return;
1315
1316                 vd = talloc_array(vs, DATA_BLOB, 1);
1317                 if (composite_nomem(vd, c)) return;
1318
1319                 v[0].guid               = GUID_zero();
1320                 v[0].sid                = s->zero_sid;
1321                 v[0].dn                 = s->forest.schema_dn_str;
1322
1323                 c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
1324                                                  (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1325                 if (!composite_is_ok(c)) return;
1326
1327                 vs[0].blob              = &vd[0];
1328
1329                 attrs[i].attid                  = DRSUAPI_ATTRIBUTE_dMDLocation;
1330                 attrs[i].value_ctr.num_values   = 1;
1331                 attrs[i].value_ctr.values       = vs;
1332
1333                 i++;
1334         }
1335
1336         /* msDS-HasDomainNCs: <domain_partition> */
1337         if (w2k3) {
1338                 struct drsuapi_DsAttributeValue *vs;
1339                 DATA_BLOB *vd;
1340                 struct drsuapi_DsReplicaObjectIdentifier3 v[1];
1341
1342                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1343                 if (composite_nomem(vs, c)) return;
1344
1345                 vd = talloc_array(vs, DATA_BLOB, 1);
1346                 if (composite_nomem(vd, c)) return;
1347
1348                 v[0].guid               = GUID_zero();
1349                 v[0].sid                = s->zero_sid;
1350                 v[0].dn                 = s->domain.dn_str;
1351
1352                 c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
1353                                                  (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1354                 if (!composite_is_ok(c)) return;
1355
1356                 vs[0].blob              = &vd[0];
1357
1358                 attrs[i].attid                  = DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs;
1359                 attrs[i].value_ctr.num_values   = 1;
1360                 attrs[i].value_ctr.values       = vs;
1361
1362                 i++;
1363         }
1364
1365         /* msDS-Behavior-Version */
1366         if (w2k3) {
1367                 struct drsuapi_DsAttributeValue *vs;
1368                 DATA_BLOB *vd;
1369
1370                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1371                 if (composite_nomem(vs, c)) return;
1372
1373                 vd = talloc_array(vs, DATA_BLOB, 1);
1374                 if (composite_nomem(vd, c)) return;
1375
1376                 vd[0] = data_blob_talloc(vd, NULL, 4);
1377                 if (composite_nomem(vd[0].data, c)) return;
1378
1379                 SIVAL(vd[0].data, 0, DS_BEHAVIOR_WIN2003);
1380
1381                 vs[0].blob              = &vd[0];
1382
1383                 attrs[i].attid                  = DRSUAPI_ATTRIBUTE_msDS_Behavior_Version;
1384                 attrs[i].value_ctr.num_values   = 1;
1385                 attrs[i].value_ctr.values       = vs;
1386
1387                 i++;
1388         }
1389
1390         /* systemFlags */
1391         {
1392                 struct drsuapi_DsAttributeValue *vs;
1393                 DATA_BLOB *vd;
1394
1395                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1396                 if (composite_nomem(vs, c)) return;
1397
1398                 vd = talloc_array(vs, DATA_BLOB, 1);
1399                 if (composite_nomem(vd, c)) return;
1400
1401                 vd[0] = data_blob_talloc(vd, NULL, 4);
1402                 if (composite_nomem(vd[0].data, c)) return;
1403
1404                 SIVAL(vd[0].data, 0, SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
1405
1406                 vs[0].blob              = &vd[0];
1407
1408                 attrs[i].attid                  = DRSUAPI_ATTRIBUTE_systemFlags;
1409                 attrs[i].value_ctr.num_values   = 1;
1410                 attrs[i].value_ctr.values       = vs;
1411
1412                 i++;
1413         }
1414
1415         /* serverReference: ... */
1416         {
1417                 struct drsuapi_DsAttributeValue *vs;
1418                 DATA_BLOB *vd;
1419                 struct drsuapi_DsReplicaObjectIdentifier3 v[1];
1420
1421                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1422                 if (composite_nomem(vs, c)) return;
1423
1424                 vd = talloc_array(vs, DATA_BLOB, 1);
1425                 if (composite_nomem(vd, c)) return;
1426
1427                 v[0].guid               = GUID_zero();
1428                 v[0].sid                = s->zero_sid;
1429                 v[0].dn                 = s->dest_dsa.computer_dn_str;
1430
1431                 c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
1432                                                  (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1433                 if (!composite_is_ok(c)) return;
1434
1435                 vs[0].blob              = &vd[0];
1436
1437                 attrs[i].attid                  = DRSUAPI_ATTRIBUTE_serverReference;
1438                 attrs[i].value_ctr.num_values   = 1;
1439                 attrs[i].value_ctr.values       = vs;
1440
1441                 i++;
1442         }
1443
1444         /* truncate the attribute list to the attribute count we have filled in */
1445         num_attrs = i;
1446
1447         /* setup request structure */
1448         r->in.bind_handle                                               = &s->drsuapi1.bind_handle;
1449         r->in.level                                                     = 2;
1450         r->in.req.req2.first_object.next_object                         = NULL;
1451         r->in.req.req2.first_object.object.identifier                   = identifier;
1452         r->in.req.req2.first_object.object.unknown1                     = 0x00000000;   
1453         r->in.req.req2.first_object.object.attribute_ctr.num_attributes = num_attrs;
1454         r->in.req.req2.first_object.object.attribute_ctr.attributes     = attrs;
1455
1456         req = dcerpc_drsuapi_DsAddEntry_send(s->drsuapi1.pipe, r, r);
1457         composite_continue_rpc(c, req, becomeDC_drsuapi1_add_entry_recv, s);
1458 }
1459
1460 static void becomeDC_drsuapi2_connect_recv(struct composite_context *req);
1461 static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s);
1462
1463 static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req)
1464 {
1465         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1466                                           struct libnet_BecomeDC_state);
1467         struct composite_context *c = s->creq;
1468         struct drsuapi_DsAddEntry *r = talloc_get_type(req->ndr.struct_ptr,
1469                                        struct drsuapi_DsAddEntry);
1470
1471         c->status = dcerpc_ndr_request_recv(req);
1472         if (!composite_is_ok(c)) return;
1473
1474         if (!W_ERROR_IS_OK(r->out.result)) {
1475                 composite_error(c, werror_to_ntstatus(r->out.result));
1476                 return;
1477         }
1478
1479         if (r->out.level == 3) {
1480                 if (r->out.ctr.ctr3.count != 1) {
1481                         WERROR status;
1482
1483                         if (r->out.ctr.ctr3.level != 1) {
1484                                 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
1485                                 return;
1486                         }
1487
1488                         if (!r->out.ctr.ctr3.error) {
1489                                 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
1490                                 return;
1491                         }
1492
1493                         status = r->out.ctr.ctr3.error->info1.status;
1494
1495                         if (!r->out.ctr.ctr3.error->info1.info) {
1496                                 composite_error(c, werror_to_ntstatus(status));
1497                                 return;
1498                         }
1499
1500                         /* see if we can get a more detailed error */
1501                         switch (r->out.ctr.ctr3.error->info1.level) {
1502                         case 1:
1503                                 status = r->out.ctr.ctr3.error->info1.info->error1.status;
1504                                 break;
1505                         case 4:
1506                         case 5:
1507                         case 6:
1508                         case 7:
1509                                 status = r->out.ctr.ctr3.error->info1.info->errorX.status;
1510                                 break;
1511                         }
1512
1513                         composite_error(c, werror_to_ntstatus(status));
1514                         return;
1515                 }
1516
1517                 s->dest_dsa.ntds_guid   = r->out.ctr.ctr3.objects[0].guid;
1518         } else if (r->out.level == 2) {
1519                 if (r->out.ctr.ctr2.count != 1) {
1520                         composite_error(c, werror_to_ntstatus(r->out.ctr.ctr2.error.status));
1521                         return;
1522                 }
1523
1524                 s->dest_dsa.ntds_guid   = r->out.ctr.ctr2.objects[0].guid;
1525         } else {
1526                 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
1527                 return;
1528         }
1529
1530         talloc_free(r);
1531
1532         s->dest_dsa.ntds_dn_str = talloc_asprintf(s, "CN=NTDS Settings,%s",
1533                                                   s->dest_dsa.server_dn_str);
1534         if (composite_nomem(s->dest_dsa.ntds_dn_str, c)) return;
1535
1536         c->status = becomeDC_prepare_db(s);
1537         if (!composite_is_ok(c)) return;
1538
1539         becomeDC_drsuapi_connect_send(s, &s->drsuapi2, becomeDC_drsuapi2_connect_recv);
1540 }
1541
1542 static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s)
1543 {
1544         if (!s->callbacks.prepare_db) return NT_STATUS_OK;
1545
1546         s->_pp.domain           = &s->domain;
1547         s->_pp.forest           = &s->forest;
1548         s->_pp.source_dsa       = &s->source_dsa;
1549         s->_pp.dest_dsa         = &s->dest_dsa;
1550
1551         return s->callbacks.prepare_db(s->callbacks.private_data, &s->_pp);
1552 }
1553
1554 static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req);
1555
1556 static void becomeDC_drsuapi2_connect_recv(struct composite_context *req)
1557 {
1558         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
1559                                           struct libnet_BecomeDC_state);
1560         struct composite_context *c = s->creq;
1561
1562         c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi2.pipe);
1563         if (!composite_is_ok(c)) return;
1564
1565         becomeDC_drsuapi_bind_send(s, &s->drsuapi2, becomeDC_drsuapi2_bind_recv);
1566 }
1567
1568 static void becomeDC_drsuapi3_connect_recv(struct composite_context *req);
1569
1570 static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req)
1571 {
1572         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1573                                           struct libnet_BecomeDC_state);
1574         struct composite_context *c = s->creq;
1575         char *binding_str;
1576         WERROR status;
1577
1578         c->status = dcerpc_ndr_request_recv(req);
1579         if (!composite_is_ok(c)) return;
1580
1581         status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi2);
1582         if (!W_ERROR_IS_OK(status)) {
1583                 composite_error(c, werror_to_ntstatus(status));
1584                 return;
1585         }
1586
1587         /* this avoids the epmapper lookup on the 2nd connection */
1588         binding_str = dcerpc_binding_string(s, s->drsuapi2.binding);
1589         if (composite_nomem(binding_str, c)) return;
1590
1591         c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi3.binding);
1592         talloc_free(binding_str);
1593         if (!composite_is_ok(c)) return;
1594
1595         becomeDC_drsuapi_connect_send(s, &s->drsuapi3, becomeDC_drsuapi3_connect_recv);
1596 }
1597
1598 static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s);
1599
1600 static void becomeDC_drsuapi3_connect_recv(struct composite_context *req)
1601 {
1602         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
1603                                           struct libnet_BecomeDC_state);
1604         struct composite_context *c = s->creq;
1605
1606         c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi3.pipe);
1607         if (!composite_is_ok(c)) return;
1608
1609         becomeDC_drsuapi3_pull_schema_send(s);
1610 }
1611
1612 static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s,
1613                                                  struct becomeDC_drsuapi *drsuapi_h,
1614                                                  struct becomeDC_drsuapi *drsuapi_p,
1615                                                  struct libnet_BecomeDC_Partition *partition,
1616                                                  void (*recv_fn)(struct rpc_request *req))
1617 {
1618         struct composite_context *c = s->creq;
1619         struct rpc_request *req;
1620         struct drsuapi_DsGetNCChanges *r;
1621
1622         r = talloc(s, struct drsuapi_DsGetNCChanges);
1623         if (composite_nomem(r, c)) return;
1624
1625         r->in.level = talloc(r, int32_t);
1626         if (composite_nomem(r->in.level, c)) return;
1627         r->out.level = talloc(r, int32_t);
1628         if (composite_nomem(r->out.level, c)) return;
1629
1630         r->in.bind_handle       = &drsuapi_h->bind_handle;
1631         if (drsuapi_h->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
1632                 *r->in.level                            = 8;
1633                 r->in.req.req8.destination_dsa_guid     = partition->destination_dsa_guid;
1634                 r->in.req.req8.source_dsa_invocation_id = partition->source_dsa_invocation_id;
1635                 r->in.req.req8.naming_context           = &partition->nc;
1636                 r->in.req.req8.highwatermark            = partition->highwatermark;
1637                 r->in.req.req8.uptodateness_vector      = NULL;
1638                 r->in.req.req8.replica_flags            = partition->replica_flags;
1639                 r->in.req.req8.max_object_count         = 133;
1640                 r->in.req.req8.max_ndr_size             = 1336811;
1641                 r->in.req.req8.unknown4                 = 0;
1642                 r->in.req.req8.h1                       = 0;
1643                 r->in.req.req8.unique_ptr1              = 0;
1644                 r->in.req.req8.unique_ptr2              = 0;
1645                 r->in.req.req8.mapping_ctr.num_mappings = 0;
1646                 r->in.req.req8.mapping_ctr.mappings     = NULL;
1647         } else {
1648                 *r->in.level                            = 5;
1649                 r->in.req.req5.destination_dsa_guid     = partition->destination_dsa_guid;
1650                 r->in.req.req5.source_dsa_invocation_id = partition->source_dsa_invocation_id;
1651                 r->in.req.req5.naming_context           = &partition->nc;
1652                 r->in.req.req5.highwatermark            = partition->highwatermark;
1653                 r->in.req.req5.uptodateness_vector      = NULL;
1654                 r->in.req.req5.replica_flags            = partition->replica_flags;
1655                 r->in.req.req5.max_object_count         = 133;
1656                 r->in.req.req5.max_ndr_size             = 1336770;
1657                 r->in.req.req5.unknown4                 = 0;
1658                 r->in.req.req5.h1                       = 0;
1659         }
1660
1661         /* 
1662          * we should try to use the drsuapi_p->pipe here, as w2k3 does
1663          * but it seems that some extra flags in the DCERPC Bind call
1664          * are needed for it. Or the same KRB5 TGS is needed on both
1665          * connections.
1666          */
1667         req = dcerpc_drsuapi_DsGetNCChanges_send(drsuapi_h->pipe, r, r);
1668         composite_continue_rpc(c, req, recv_fn, s);
1669 }
1670
1671 static WERROR becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state *s,
1672                                                    struct libnet_BecomeDC_Partition *partition,
1673                                                    struct drsuapi_DsGetNCChanges *r)
1674 {
1675         uint32_t ctr_level = 0;
1676         struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
1677         struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
1678         struct GUID *source_dsa_guid;
1679         struct GUID *source_dsa_invocation_id;
1680         struct drsuapi_DsReplicaHighWaterMark *new_highwatermark;
1681         NTSTATUS nt_status;
1682
1683         if (!W_ERROR_IS_OK(r->out.result)) {
1684                 return r->out.result;
1685         }
1686
1687         if (*r->out.level == 1) {
1688                 ctr_level = 1;
1689                 ctr1 = &r->out.ctr.ctr1;
1690         } else if (*r->out.level == 2) {
1691                 ctr_level = 1;
1692                 ctr1 = r->out.ctr.ctr2.ctr.mszip1.ctr1;
1693         } else if (*r->out.level == 6) {
1694                 ctr_level = 6;
1695                 ctr6 = &r->out.ctr.ctr6;
1696         } else if (*r->out.level == 7 &&
1697                    r->out.ctr.ctr7.level == 6 &&
1698                    r->out.ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP) {
1699                 ctr_level = 6;
1700                 ctr6 = r->out.ctr.ctr7.ctr.mszip6.ctr6;
1701         } else {
1702                 return WERR_BAD_NET_RESP;
1703         }
1704
1705         switch (ctr_level) {
1706         case 1:
1707                 source_dsa_guid                 = &ctr1->source_dsa_guid;
1708                 source_dsa_invocation_id        = &ctr1->source_dsa_invocation_id;
1709                 new_highwatermark               = &ctr1->new_highwatermark;
1710                 break;
1711         case 6:
1712                 source_dsa_guid                 = &ctr6->source_dsa_guid;
1713                 source_dsa_invocation_id        = &ctr6->source_dsa_invocation_id;
1714                 new_highwatermark               = &ctr6->new_highwatermark;
1715                 break;
1716         }
1717
1718         partition->highwatermark                = *new_highwatermark;
1719         partition->source_dsa_guid              = *source_dsa_guid;
1720         partition->source_dsa_invocation_id     = *source_dsa_invocation_id;
1721
1722         if (!partition->store_chunk) return WERR_OK;
1723
1724         s->_sc.domain           = &s->domain;
1725         s->_sc.forest           = &s->forest;
1726         s->_sc.source_dsa       = &s->source_dsa;
1727         s->_sc.dest_dsa         = &s->dest_dsa;
1728         s->_sc.partition        = partition;
1729         s->_sc.ctr_level        = ctr_level;
1730         s->_sc.ctr1             = ctr1;
1731         s->_sc.ctr6             = ctr6;
1732
1733         nt_status = partition->store_chunk(s->callbacks.private_data, &s->_sc);
1734         if (!NT_STATUS_IS_OK(nt_status)) {
1735                 return ntstatus_to_werror(nt_status);
1736         }
1737
1738         return WERR_OK;
1739 }
1740
1741 static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req);
1742
1743 static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s)
1744 {
1745         s->schema_part.nc.guid  = GUID_zero();
1746         s->schema_part.nc.sid   = s->zero_sid;
1747         s->schema_part.nc.dn    = s->forest.schema_dn_str;
1748
1749         s->schema_part.destination_dsa_guid     = s->drsuapi2.bind_guid;
1750
1751         s->schema_part.replica_flags    = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
1752                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
1753                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
1754                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
1755                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
1756                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
1757
1758         s->schema_part.store_chunk      = s->callbacks.schema_chunk;
1759
1760         becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part,
1761                                              becomeDC_drsuapi3_pull_schema_recv);
1762 }
1763
1764 static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s);
1765
1766 static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req)
1767 {
1768         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1769                                           struct libnet_BecomeDC_state);
1770         struct composite_context *c = s->creq;
1771         struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
1772                                            struct drsuapi_DsGetNCChanges);
1773         WERROR status;
1774
1775         c->status = dcerpc_ndr_request_recv(req);
1776         if (!composite_is_ok(c)) return;
1777
1778         status = becomeDC_drsuapi_pull_partition_recv(s, &s->schema_part, r);
1779         if (!W_ERROR_IS_OK(status)) {
1780                 composite_error(c, werror_to_ntstatus(status));
1781                 return;
1782         }
1783
1784         talloc_free(r);
1785
1786         if (s->schema_part.highwatermark.tmp_highest_usn > s->schema_part.highwatermark.highest_usn) {
1787                 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part,
1788                                                      becomeDC_drsuapi3_pull_schema_recv);
1789                 return;
1790         }
1791
1792         becomeDC_drsuapi3_pull_config_send(s);
1793 }
1794
1795 static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req);
1796
1797 static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s)
1798 {
1799         s->config_part.nc.guid  = GUID_zero();
1800         s->config_part.nc.sid   = s->zero_sid;
1801         s->config_part.nc.dn    = s->forest.config_dn_str;
1802
1803         s->config_part.destination_dsa_guid     = s->drsuapi2.bind_guid;
1804
1805         s->config_part.replica_flags    = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
1806                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
1807                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
1808                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
1809                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
1810                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
1811
1812         s->config_part.store_chunk      = s->callbacks.config_chunk;
1813
1814         becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part,
1815                                              becomeDC_drsuapi3_pull_config_recv);
1816 }
1817
1818 static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req)
1819 {
1820         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1821                                           struct libnet_BecomeDC_state);
1822         struct composite_context *c = s->creq;
1823         struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
1824                                            struct drsuapi_DsGetNCChanges);
1825         WERROR status;
1826
1827         c->status = dcerpc_ndr_request_recv(req);
1828         if (!composite_is_ok(c)) return;
1829
1830         status = becomeDC_drsuapi_pull_partition_recv(s, &s->config_part, r);
1831         if (!W_ERROR_IS_OK(status)) {
1832                 composite_error(c, werror_to_ntstatus(status));
1833                 return;
1834         }
1835
1836         talloc_free(r);
1837
1838         if (s->config_part.highwatermark.tmp_highest_usn > s->config_part.highwatermark.highest_usn) {
1839                 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part,
1840                                                      becomeDC_drsuapi3_pull_config_recv);
1841                 return;
1842         }
1843
1844         becomeDC_connect_ldap2(s);
1845 }
1846
1847 static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req);
1848
1849 static void becomeDC_drsuapi3_pull_domain_send(struct libnet_BecomeDC_state *s)
1850 {
1851         s->domain_part.nc.guid  = GUID_zero();
1852         s->domain_part.nc.sid   = s->zero_sid;
1853         s->domain_part.nc.dn    = s->domain.dn_str;
1854
1855         s->domain_part.destination_dsa_guid     = s->drsuapi2.bind_guid;
1856
1857         s->domain_part.replica_flags    = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
1858                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
1859                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
1860                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
1861                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
1862                                         | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
1863
1864         s->domain_part.store_chunk      = s->callbacks.domain_chunk;
1865
1866         becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part,
1867                                              becomeDC_drsuapi3_pull_domain_recv);
1868 }
1869
1870 static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s,
1871                                               struct becomeDC_drsuapi *drsuapi,
1872                                               struct libnet_BecomeDC_Partition *partition,
1873                                               void (*recv_fn)(struct rpc_request *req));
1874 static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req);
1875
1876 static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req)
1877 {
1878         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1879                                           struct libnet_BecomeDC_state);
1880         struct composite_context *c = s->creq;
1881         struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
1882                                            struct drsuapi_DsGetNCChanges);
1883         WERROR status;
1884
1885         c->status = dcerpc_ndr_request_recv(req);
1886         if (!composite_is_ok(c)) return;
1887
1888         status = becomeDC_drsuapi_pull_partition_recv(s, &s->domain_part, r);
1889         if (!W_ERROR_IS_OK(status)) {
1890                 composite_error(c, werror_to_ntstatus(status));
1891                 return;
1892         }
1893
1894         talloc_free(r);
1895
1896         if (s->domain_part.highwatermark.tmp_highest_usn > s->domain_part.highwatermark.highest_usn) {
1897                 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part,
1898                                                      becomeDC_drsuapi3_pull_domain_recv);
1899                 return;
1900         }
1901
1902         becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->schema_part,
1903                                           becomeDC_drsuapi2_update_refs_schema_recv);
1904 }
1905
1906 static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s,
1907                                               struct becomeDC_drsuapi *drsuapi,
1908                                               struct libnet_BecomeDC_Partition *partition,
1909                                               void (*recv_fn)(struct rpc_request *req))
1910 {
1911         struct composite_context *c = s->creq;
1912         struct rpc_request *req;
1913         struct drsuapi_DsReplicaUpdateRefs *r;
1914         const char *ntds_guid_str;
1915         const char *ntds_dns_name;
1916
1917         r = talloc(s, struct drsuapi_DsReplicaUpdateRefs);
1918         if (composite_nomem(r, c)) return;
1919
1920         ntds_guid_str = GUID_string(r, &s->dest_dsa.ntds_guid);
1921         if (composite_nomem(ntds_guid_str, c)) return;
1922
1923         ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
1924                                         ntds_guid_str,
1925                                         s->domain.dns_name);
1926         if (composite_nomem(ntds_dns_name, c)) return;
1927
1928         r->in.bind_handle               = &drsuapi->bind_handle;
1929         r->in.level                     = 1;
1930         r->in.req.req1.naming_context   = &partition->nc;
1931         r->in.req.req1.dest_dsa_dns_name= ntds_dns_name;
1932         r->in.req.req1.dest_dsa_guid    = s->dest_dsa.ntds_guid;
1933         r->in.req.req1.options          = DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE
1934                                         | DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE
1935                                         | DRSUAPI_DS_REPLICA_UPDATE_0x00000010;
1936
1937         req = dcerpc_drsuapi_DsReplicaUpdateRefs_send(drsuapi->pipe, r, r);
1938         composite_continue_rpc(c, req, recv_fn, s);
1939 }
1940
1941 static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req);
1942
1943 static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req)
1944 {
1945         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1946                                           struct libnet_BecomeDC_state);
1947         struct composite_context *c = s->creq;
1948         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
1949                                            struct drsuapi_DsReplicaUpdateRefs);
1950
1951         c->status = dcerpc_ndr_request_recv(req);
1952         if (!composite_is_ok(c)) return;
1953
1954         if (!W_ERROR_IS_OK(r->out.result)) {
1955                 composite_error(c, werror_to_ntstatus(r->out.result));
1956                 return;
1957         }
1958
1959         talloc_free(r);
1960
1961         becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->config_part,
1962                                           becomeDC_drsuapi2_update_refs_config_recv);
1963 }
1964
1965 static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req);
1966
1967 static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req)
1968 {
1969         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1970                                           struct libnet_BecomeDC_state);
1971         struct composite_context *c = s->creq;
1972         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
1973                                            struct drsuapi_DsReplicaUpdateRefs);
1974
1975         c->status = dcerpc_ndr_request_recv(req);
1976         if (!composite_is_ok(c)) return;
1977
1978         if (!W_ERROR_IS_OK(r->out.result)) {
1979                 composite_error(c, werror_to_ntstatus(r->out.result));
1980                 return;
1981         }
1982
1983         talloc_free(r);
1984
1985         becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->domain_part,
1986                                           becomeDC_drsuapi2_update_refs_domain_recv);
1987 }
1988
1989 static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req)
1990 {
1991         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1992                                           struct libnet_BecomeDC_state);
1993         struct composite_context *c = s->creq;
1994         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
1995                                            struct drsuapi_DsReplicaUpdateRefs);
1996
1997         c->status = dcerpc_ndr_request_recv(req);
1998         if (!composite_is_ok(c)) return;
1999
2000         if (!W_ERROR_IS_OK(r->out.result)) {
2001                 composite_error(c, werror_to_ntstatus(r->out.result));
2002                 return;
2003         }
2004
2005         talloc_free(r);
2006
2007         /* TODO: use DDNS updates and register dns names */
2008         composite_done(c);
2009 }
2010
2011 static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s)
2012 {
2013         int ret;
2014         struct ldb_message *msg;
2015         uint32_t i;
2016         uint32_t user_account_control = UF_SERVER_TRUST_ACCOUNT |
2017                                         UF_TRUSTED_FOR_DELEGATION;
2018
2019         /* as the value is already as we want it to be, we're done */
2020         if (s->dest_dsa.user_account_control == user_account_control) {
2021                 return NT_STATUS_OK;
2022         }
2023
2024         /* make a 'modify' msg, and only for serverReference */
2025         msg = ldb_msg_new(s);
2026         NT_STATUS_HAVE_NO_MEMORY(msg);
2027         msg->dn = ldb_dn_new(msg, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
2028         NT_STATUS_HAVE_NO_MEMORY(msg->dn);
2029
2030         ret = ldb_msg_add_fmt(msg, "userAccountControl", "%u", user_account_control);
2031         if (ret != 0) {
2032                 talloc_free(msg);
2033                 return NT_STATUS_NO_MEMORY;
2034         }
2035
2036         /* mark all the message elements (should be just one)
2037            as LDB_FLAG_MOD_REPLACE */
2038         for (i=0;i<msg->num_elements;i++) {
2039                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2040         }
2041
2042         ret = ldb_modify(s->ldap2.ldb, msg);
2043         talloc_free(msg);
2044         if (ret != LDB_SUCCESS) {
2045                 return NT_STATUS_LDAP(ret);
2046         }
2047
2048         s->dest_dsa.user_account_control = user_account_control;
2049
2050         return NT_STATUS_OK;
2051 }
2052
2053 static NTSTATUS becomeDC_ldap2_move_computer(struct libnet_BecomeDC_state *s)
2054 {
2055         int ret;
2056         struct ldb_result *r;
2057         struct ldb_dn *basedn;
2058         struct ldb_dn *old_dn;
2059         struct ldb_dn *new_dn;
2060         static const char *_1_1_attrs[] = {
2061                 "1.1",
2062                 NULL
2063         };
2064
2065         basedn = ldb_dn_new_fmt(s, s->ldap2.ldb, "<WKGUID=a361b2ffffd211d1aa4b00c04fd7d83a,%s>",
2066                                 s->domain.dn_str);
2067         NT_STATUS_HAVE_NO_MEMORY(basedn);
2068
2069         ret = ldb_search(s->ldap2.ldb, basedn, LDB_SCOPE_BASE,
2070                          "(objectClass=*)", _1_1_attrs, &r);
2071         talloc_free(basedn);
2072         if (ret != LDB_SUCCESS) {
2073                 return NT_STATUS_LDAP(ret);
2074         } else if (r->count != 1) {
2075                 talloc_free(r);
2076                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
2077         }
2078
2079         old_dn = ldb_dn_new(r, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
2080         NT_STATUS_HAVE_NO_MEMORY(old_dn);
2081
2082         new_dn = r->msgs[0]->dn;
2083
2084         if (!ldb_dn_add_child_fmt(new_dn, "CN=%s", s->dest_dsa.netbios_name)) {
2085                 talloc_free(r);
2086                 return NT_STATUS_NO_MEMORY;
2087         }
2088
2089         if (ldb_dn_compare(old_dn, new_dn) == 0) {
2090                 /* we don't need to rename if the old and new dn match */
2091                 talloc_free(r);
2092                 return NT_STATUS_OK;
2093         }
2094
2095         ret = ldb_rename(s->ldap2.ldb, old_dn, new_dn);
2096         if (ret != LDB_SUCCESS) {
2097                 talloc_free(r);
2098                 return NT_STATUS_LDAP(ret);
2099         }
2100
2101         s->dest_dsa.computer_dn_str = ldb_dn_alloc_linearized(s, new_dn);
2102         NT_STATUS_HAVE_NO_MEMORY(s->dest_dsa.computer_dn_str);
2103
2104         talloc_free(r);
2105
2106         return NT_STATUS_OK;
2107 }
2108
2109 static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s)
2110 {
2111         struct composite_context *c = s->creq;
2112
2113         c->status = becomeDC_ldap_connect(s, &s->ldap2);
2114         if (!composite_is_ok(c)) return;
2115
2116         c->status = becomeDC_ldap2_modify_computer(s);
2117         if (!composite_is_ok(c)) return;
2118
2119         c->status = becomeDC_ldap2_move_computer(s);
2120         if (!composite_is_ok(c)) return;
2121
2122         becomeDC_drsuapi3_pull_domain_send(s);
2123 }
2124
2125 struct composite_context *libnet_BecomeDC_send(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
2126 {
2127         struct composite_context *c;
2128         struct libnet_BecomeDC_state *s;
2129         char *tmp_name;
2130
2131         c = composite_create(mem_ctx, ctx->event_ctx);
2132         if (c == NULL) return NULL;
2133
2134         s = talloc_zero(c, struct libnet_BecomeDC_state);
2135         if (composite_nomem(s, c)) return c;
2136         c->private_data = s;
2137         s->creq         = c;
2138         s->libnet       = ctx;
2139
2140         /* Domain input */
2141         s->domain.dns_name      = talloc_strdup(s, r->in.domain_dns_name);
2142         if (composite_nomem(s->domain.dns_name, c)) return c;
2143         s->domain.netbios_name  = talloc_strdup(s, r->in.domain_netbios_name);
2144         if (composite_nomem(s->domain.netbios_name, c)) return c;
2145         s->domain.sid           = dom_sid_dup(s, r->in.domain_sid);
2146         if (composite_nomem(s->domain.sid, c)) return c;
2147
2148         /* Source DSA input */
2149         s->source_dsa.address   = talloc_strdup(s, r->in.source_dsa_address);
2150         if (composite_nomem(s->source_dsa.address, c)) return c;
2151
2152         /* Destination DSA input */
2153         s->dest_dsa.netbios_name= talloc_strdup(s, r->in.dest_dsa_netbios_name);
2154         if (composite_nomem(s->dest_dsa.netbios_name, c)) return c;
2155
2156         /* Destination DSA dns_name construction */
2157         tmp_name                = strlower_talloc(s, s->dest_dsa.netbios_name);
2158         if (composite_nomem(tmp_name, c)) return c;
2159         s->dest_dsa.dns_name    = talloc_asprintf(s, "%s.%s",
2160                                                   tmp_name,
2161                                                   s->domain.dns_name);
2162         talloc_free(tmp_name);
2163         if (composite_nomem(s->dest_dsa.dns_name, c)) return c;
2164         /* Callback function pointers */
2165         s->callbacks = r->in.callbacks;
2166
2167         becomeDC_send_cldap(s);
2168         return c;
2169 }
2170
2171 NTSTATUS libnet_BecomeDC_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
2172 {
2173         NTSTATUS status;
2174
2175         status = composite_wait(c);
2176
2177         ZERO_STRUCT(r->out);
2178
2179         talloc_free(c);
2180         return status;
2181 }
2182
2183 NTSTATUS libnet_BecomeDC(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
2184 {
2185         NTSTATUS status;
2186         struct composite_context *c;
2187         c = libnet_BecomeDC_send(ctx, mem_ctx, r);
2188         status = libnet_BecomeDC_recv(c, mem_ctx, r);
2189         return status;
2190 }