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