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