r20067: use a global zero_sid
[jelmer/samba4-debian.git] / source / libnet / libnet_become_dc.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher      2006
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "libnet/libnet.h"
23 #include "libcli/composite/composite.h"
24 #include "libcli/cldap/cldap.h"
25 #include "lib/ldb/include/ldb.h"
26 #include "lib/ldb/include/ldb_errors.h"
27 #include "lib/db_wrap.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "dsdb/common/flags.h"
30 #include "librpc/gen_ndr/ndr_drsuapi_c.h"
31 #include "libcli/security/security.h"
32
33 struct libnet_BecomeDC_state {
34         struct composite_context *creq;
35
36         struct libnet_context *libnet;
37
38         struct dom_sid zero_sid;
39
40         struct {
41                 struct cldap_socket *sock;
42                 struct cldap_netlogon io;
43                 struct nbt_cldap_netlogon_5 netlogon5;
44         } cldap;
45
46         struct becomeDC_ldap {
47                 struct ldb_context *ldb;
48                 const struct ldb_message *rootdse;
49         } ldap1, ldap2;
50
51         struct becomeDC_drsuapi {
52                 struct libnet_BecomeDC_state *s;
53                 struct dcerpc_binding *binding;
54                 struct dcerpc_pipe *pipe;
55                 struct drsuapi_DsBind bind_r;
56                 struct GUID bind_guid;
57                 struct drsuapi_DsBindInfoCtr bind_info_ctr;
58                 struct drsuapi_DsBindInfo28 local_info28;
59                 struct drsuapi_DsBindInfo28 remote_info28;
60                 struct policy_handle bind_handle;
61         } drsuapi1;
62
63         struct {
64                 /* input */
65                 const char *dns_name;
66                 const char *netbios_name;
67                 const struct dom_sid *sid;
68
69                 /* constructed */
70                 struct GUID guid;
71                 const char *dn_str;
72         } domain;
73
74         struct {
75                 /* constructed */
76                 const char *dns_name;
77                 const char *root_dn_str;
78                 const char *config_dn_str;
79                 const char *schema_dn_str;
80         } forest;
81
82         struct {
83                 /* input */
84                 const char *address;
85
86                 /* constructed */
87                 const char *dns_name;
88                 const char *netbios_name;
89                 const char *site_name;
90                 const char *server_dn_str;
91                 const char *ntds_dn_str;
92         } source_dsa;
93
94         struct {
95                 /* input */
96                 const char *netbios_name;
97
98                 /* constructed */
99                 const char *dns_name;
100                 const char *site_name;
101                 struct GUID site_guid;
102                 const char *computer_dn_str;
103                 const char *server_dn_str;
104                 const char *ntds_dn_str;
105                 struct GUID invocation_id;
106                 uint32_t user_account_control;
107         } dest_dsa;
108
109         struct {
110                 uint32_t domain_behavior_version;
111                 uint32_t config_behavior_version;
112                 uint32_t schema_object_version;
113                 uint32_t w2k3_update_revision;
114         } ads_options;
115
116         struct becomeDC_fsmo {
117                 const char *dns_name;
118                 const char *server_dn_str;
119                 const char *ntds_dn_str;
120                 struct GUID ntds_guid;
121         } infrastructure_fsmo;
122
123         struct becomeDC_fsmo rid_manager_fsmo;
124 };
125
126 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s);
127
128 static void becomeDC_recv_cldap(struct cldap_request *req)
129 {
130         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
131                                           struct libnet_BecomeDC_state);
132         struct composite_context *c = s->creq;
133
134         c->status = cldap_netlogon_recv(req, s, &s->cldap.io);
135         if (!composite_is_ok(c)) return;
136
137         s->cldap.netlogon5 = s->cldap.io.out.netlogon.logon5;
138
139         s->domain.dns_name              = s->cldap.netlogon5.dns_domain;
140         s->domain.netbios_name          = s->cldap.netlogon5.domain;
141         s->domain.guid                  = s->cldap.netlogon5.domain_uuid;
142
143         s->forest.dns_name              = s->cldap.netlogon5.forest;
144
145         s->source_dsa.dns_name          = s->cldap.netlogon5.pdc_dns_name;
146         s->source_dsa.netbios_name      = s->cldap.netlogon5.pdc_name;
147         s->source_dsa.site_name         = s->cldap.netlogon5.server_site;
148
149         s->dest_dsa.site_name           = s->cldap.netlogon5.client_site;
150
151         becomeDC_connect_ldap1(s);
152 }
153
154 static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
155 {
156         struct composite_context *c = s->creq;
157         struct cldap_request *req;
158
159         s->cldap.io.in.dest_address     = s->source_dsa.address;
160         s->cldap.io.in.realm            = s->domain.dns_name;
161         s->cldap.io.in.host             = s->dest_dsa.netbios_name;
162         s->cldap.io.in.user             = NULL;
163         s->cldap.io.in.domain_guid      = NULL;
164         s->cldap.io.in.domain_sid       = NULL;
165         s->cldap.io.in.acct_control     = -1;
166         s->cldap.io.in.version          = 6;
167
168         s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx);
169         if (composite_nomem(s->cldap.sock, c)) return;
170
171         req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
172         if (composite_nomem(req, c)) return;
173         req->async.fn           = becomeDC_recv_cldap;
174         req->async.private      = s;
175 }
176
177 static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s, struct becomeDC_ldap *ldap)
178 {
179         char *url;
180
181         url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
182         NT_STATUS_HAVE_NO_MEMORY(url);
183
184         ldap->ldb = ldb_wrap_connect(s, url,
185                                      NULL,
186                                      s->libnet->cred,
187                                      0, NULL);
188         talloc_free(url);
189         if (ldap->ldb == NULL) {
190                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
191         }
192
193         return NT_STATUS_OK;
194 }
195
196 static NTSTATUS becomeDC_ldap1_rootdse(struct libnet_BecomeDC_state *s)
197 {
198         int ret;
199         struct ldb_result *r;
200         struct ldb_dn *basedn;
201         static const char *attrs[] = {
202                 "*",
203                 NULL
204         };
205
206         basedn = ldb_dn_new(s, s->ldap1.ldb, NULL);
207         NT_STATUS_HAVE_NO_MEMORY(basedn);
208
209         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, 
210                          "(objectClass=*)", attrs, &r);
211         talloc_free(basedn);
212         if (ret != LDB_SUCCESS) {
213                 return NT_STATUS_LDAP(ret);
214         } else if (r->count != 1) {
215                 talloc_free(r);
216                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
217         }
218         talloc_steal(s, r);
219
220         s->ldap1.rootdse = r->msgs[0];
221
222         s->domain.dn_str        = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "defaultNamingContext", NULL);
223         if (!s->domain.dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
224
225         s->forest.root_dn_str   = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "rootDomainNamingContext", NULL);
226         if (!s->forest.root_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
227         s->forest.config_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "configurationNamingContext", NULL);
228         if (!s->forest.config_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
229         s->forest.schema_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "schemaNamingContext", NULL);
230         if (!s->forest.schema_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
231
232         s->source_dsa.server_dn_str     = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "serverName", NULL);
233         if (!s->source_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
234         s->source_dsa.ntds_dn_str       = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "dsServiceName", NULL);
235         if (!s->source_dsa.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
236
237         return NT_STATUS_OK;
238 }
239
240 static NTSTATUS becomeDC_ldap1_config_behavior_version(struct libnet_BecomeDC_state *s)
241 {
242         int ret;
243         struct ldb_result *r;
244         struct ldb_dn *basedn;
245         static const char *attrs[] = {
246                 "msDs-Behavior-Version",
247                 NULL
248         };
249
250         basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.config_dn_str);
251         NT_STATUS_HAVE_NO_MEMORY(basedn);
252
253         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_ONELEVEL,
254                          "(cn=Partitions)", attrs, &r);
255         talloc_free(basedn);
256         if (ret != LDB_SUCCESS) {
257                 return NT_STATUS_LDAP(ret);
258         } else if (r->count != 1) {
259                 talloc_free(r);
260                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
261         }
262
263         s->ads_options.config_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
264
265         talloc_free(r);
266         return NT_STATUS_OK;
267 }
268
269 static NTSTATUS becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_state *s)
270 {
271         int ret;
272         struct ldb_result *r;
273         struct ldb_dn *basedn;
274         static const char *attrs[] = {
275                 "msDs-Behavior-Version",
276                 NULL
277         };
278
279         basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
280         NT_STATUS_HAVE_NO_MEMORY(basedn);
281
282         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
283                          "(objectClass=*)", attrs, &r);
284         talloc_free(basedn);
285         if (ret != LDB_SUCCESS) {
286                 return NT_STATUS_LDAP(ret);
287         } else if (r->count != 1) {
288                 talloc_free(r);
289                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
290         }
291
292         s->ads_options.domain_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
293
294         talloc_free(r);
295         return NT_STATUS_OK;
296 }
297
298 static NTSTATUS becomeDC_ldap1_schema_object_version(struct libnet_BecomeDC_state *s)
299 {
300         int ret;
301         struct ldb_result *r;
302         struct ldb_dn *basedn;
303         static const char *attrs[] = {
304                 "objectVersion",
305                 NULL
306         };
307
308         basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.schema_dn_str);
309         NT_STATUS_HAVE_NO_MEMORY(basedn);
310
311         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
312                          "(objectClass=*)", attrs, &r);
313         talloc_free(basedn);
314         if (ret != LDB_SUCCESS) {
315                 return NT_STATUS_LDAP(ret);
316         } else if (r->count != 1) {
317                 talloc_free(r);
318                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
319         }
320
321         s->ads_options.schema_object_version = ldb_msg_find_attr_as_uint(r->msgs[0], "objectVersion", 0);
322
323         talloc_free(r);
324         return NT_STATUS_OK;
325 }
326
327 static NTSTATUS becomeDC_ldap1_w2k3_update_revision(struct libnet_BecomeDC_state *s)
328 {
329         int ret;
330         struct ldb_result *r;
331         struct ldb_dn *basedn;
332         static const char *attrs[] = {
333                 "revision",
334                 NULL
335         };
336
337         basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=Windows2003Update,CN=DomainUpdates,CN=System,%s",
338                                 s->domain.dn_str);
339         NT_STATUS_HAVE_NO_MEMORY(basedn);
340
341         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
342                          "(objectClass=*)", attrs, &r);
343         talloc_free(basedn);
344         if (ret != LDB_SUCCESS) {
345                 return NT_STATUS_LDAP(ret);
346         } else if (r->count != 1) {
347                 talloc_free(r);
348                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
349         }
350
351         s->ads_options.w2k3_update_revision = ldb_msg_find_attr_as_uint(r->msgs[0], "revision", 0);
352
353         talloc_free(r);
354         return NT_STATUS_OK;
355 }
356
357 static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state *s)
358 {
359         int ret;
360         struct ldb_result *r;
361         struct ldb_dn *basedn;
362         struct ldb_dn *ntds_dn;
363         struct ldb_dn *server_dn;
364         static const char *_1_1_attrs[] = {
365                 "1.1",
366                 NULL
367         };
368         static const char *fsmo_attrs[] = {
369                 "fSMORoleOwner",
370                 NULL
371         };
372         static const char *dns_attrs[] = {
373                 "dnsHostName",
374                 NULL
375         };
376         static const char *guid_attrs[] = {
377                 "objectGUID",
378                 NULL
379         };
380
381         basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "<WKGUID=2fbac1870ade11d297c400c04fd8d5cd,%s>",
382                                 s->domain.dn_str);
383         NT_STATUS_HAVE_NO_MEMORY(basedn);
384
385         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
386                          "(objectClass=*)", _1_1_attrs, &r);
387         talloc_free(basedn);
388         if (ret != LDB_SUCCESS) {
389                 return NT_STATUS_LDAP(ret);
390         } else if (r->count != 1) {
391                 talloc_free(r);
392                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
393         }
394
395         basedn = talloc_steal(s, r->msgs[0]->dn);
396         talloc_free(r);
397
398         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
399                          "(objectClass=*)", fsmo_attrs, &r);
400         talloc_free(basedn);
401         if (ret != LDB_SUCCESS) {
402                 return NT_STATUS_LDAP(ret);
403         } else if (r->count != 1) {
404                 talloc_free(r);
405                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
406         }
407
408         s->infrastructure_fsmo.ntds_dn_str      = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
409         if (!s->infrastructure_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
410         talloc_steal(s, s->infrastructure_fsmo.ntds_dn_str);
411
412         talloc_free(r);
413
414         ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->infrastructure_fsmo.ntds_dn_str);
415         NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
416
417         server_dn = ldb_dn_get_parent(s, ntds_dn);
418         NT_STATUS_HAVE_NO_MEMORY(server_dn);
419
420         s->infrastructure_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
421         NT_STATUS_HAVE_NO_MEMORY(s->infrastructure_fsmo.server_dn_str);
422
423         ret = ldb_search(s->ldap1.ldb, server_dn, LDB_SCOPE_BASE,
424                          "(objectClass=*)", dns_attrs, &r);
425         if (ret != LDB_SUCCESS) {
426                 return NT_STATUS_LDAP(ret);
427         } else if (r->count != 1) {
428                 talloc_free(r);
429                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
430         }
431
432         s->infrastructure_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL);
433         if (!s->infrastructure_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
434         talloc_steal(s, s->infrastructure_fsmo.dns_name);
435
436         talloc_free(r);
437
438         ret = ldb_search(s->ldap1.ldb, ntds_dn, LDB_SCOPE_BASE,
439                          "(objectClass=*)", guid_attrs, &r);
440         if (ret != LDB_SUCCESS) {
441                 return NT_STATUS_LDAP(ret);
442         } else if (r->count != 1) {
443                 talloc_free(r);
444                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
445         }
446
447         s->infrastructure_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
448
449         talloc_free(r);
450
451         return NT_STATUS_OK;
452 }
453
454 static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s)
455 {
456         int ret;
457         struct ldb_result *r;
458         struct ldb_dn *basedn;
459         const char *reference_dn_str;
460         struct ldb_dn *ntds_dn;
461         struct ldb_dn *server_dn;
462         static const char *rid_attrs[] = {
463                 "rIDManagerReference",
464                 NULL
465         };
466         static const char *fsmo_attrs[] = {
467                 "fSMORoleOwner",
468                 NULL
469         };
470         static const char *dns_attrs[] = {
471                 "dnsHostName",
472                 NULL
473         };
474         static const char *guid_attrs[] = {
475                 "objectGUID",
476                 NULL
477         };
478
479         basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
480         NT_STATUS_HAVE_NO_MEMORY(basedn);
481
482         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
483                          "(objectClass=*)", rid_attrs, &r);
484         talloc_free(basedn);
485         if (ret != LDB_SUCCESS) {
486                 return NT_STATUS_LDAP(ret);
487         } else if (r->count != 1) {
488                 talloc_free(r);
489                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
490         }
491
492         reference_dn_str        = samdb_result_string(r->msgs[0], "rIDManagerReference", NULL);
493         if (!reference_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
494
495         basedn = ldb_dn_new(s, s->ldap1.ldb, reference_dn_str);
496         NT_STATUS_HAVE_NO_MEMORY(basedn);
497
498         talloc_free(r);
499
500         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
501                          "(objectClass=*)", fsmo_attrs, &r);
502         talloc_free(basedn);
503         if (ret != LDB_SUCCESS) {
504                 return NT_STATUS_LDAP(ret);
505         } else if (r->count != 1) {
506                 talloc_free(r);
507                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
508         }
509
510         s->rid_manager_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
511         if (!s->rid_manager_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
512         talloc_steal(s, s->rid_manager_fsmo.ntds_dn_str);
513
514         talloc_free(r);
515
516         ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->rid_manager_fsmo.ntds_dn_str);
517         NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
518
519         server_dn = ldb_dn_get_parent(s, ntds_dn);
520         NT_STATUS_HAVE_NO_MEMORY(server_dn);
521
522         s->rid_manager_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
523         NT_STATUS_HAVE_NO_MEMORY(s->rid_manager_fsmo.server_dn_str);
524
525         ret = ldb_search(s->ldap1.ldb, server_dn, LDB_SCOPE_BASE,
526                          "(objectClass=*)", dns_attrs, &r);
527         if (ret != LDB_SUCCESS) {
528                 return NT_STATUS_LDAP(ret);
529         } else if (r->count != 1) {
530                 talloc_free(r);
531                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
532         }
533
534         s->rid_manager_fsmo.dns_name    = samdb_result_string(r->msgs[0], "dnsHostName", NULL);
535         if (!s->rid_manager_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
536         talloc_steal(s, s->rid_manager_fsmo.dns_name);
537
538         talloc_free(r);
539
540         ret = ldb_search(s->ldap1.ldb, ntds_dn, LDB_SCOPE_BASE,
541                          "(objectClass=*)", guid_attrs, &r);
542         if (ret != LDB_SUCCESS) {
543                 return NT_STATUS_LDAP(ret);
544         } else if (r->count != 1) {
545                 talloc_free(r);
546                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
547         }
548
549         s->rid_manager_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
550
551         talloc_free(r);
552
553         return NT_STATUS_OK;
554 }
555
556 static NTSTATUS becomeDC_ldap1_site_object(struct libnet_BecomeDC_state *s)
557 {
558         int ret;
559         struct ldb_result *r;
560         struct ldb_dn *basedn;
561
562         basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Sites,%s",
563                                 s->dest_dsa.site_name,
564                                 s->forest.config_dn_str);
565         NT_STATUS_HAVE_NO_MEMORY(basedn);
566
567         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, 
568                          "(objectClass=*)", NULL, &r);
569         talloc_free(basedn);
570         if (ret != LDB_SUCCESS) {
571                 return NT_STATUS_LDAP(ret);
572         } else if (r->count != 1) {
573                 talloc_free(r);
574                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
575         }
576
577         s->dest_dsa.site_guid = samdb_result_guid(r->msgs[0], "objectGUID");
578
579         talloc_free(r);
580         return NT_STATUS_OK;
581 }
582
583 static NTSTATUS becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state *s)
584 {
585         int ret;
586         struct ldb_result *r;
587         struct ldb_dn *basedn;
588         char *filter;
589         static const char *attrs[] = {
590                 "distinguishedName",
591                 "userAccountControl",
592                 NULL
593         };
594
595         basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
596         NT_STATUS_HAVE_NO_MEMORY(basedn);
597
598         filter = talloc_asprintf(basedn, "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))",
599                                  s->dest_dsa.netbios_name);
600         NT_STATUS_HAVE_NO_MEMORY(filter);
601
602         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_SUBTREE, 
603                          filter, attrs, &r);
604         talloc_free(basedn);
605         if (ret != LDB_SUCCESS) {
606                 return NT_STATUS_LDAP(ret);
607         } else if (r->count != 1) {
608                 talloc_free(r);
609                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
610         }
611
612         s->dest_dsa.computer_dn_str     = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
613         if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
614         talloc_steal(s, s->dest_dsa.computer_dn_str);
615
616         s->dest_dsa.user_account_control = samdb_result_uint(r->msgs[0], "userAccountControl", 0);
617
618         talloc_free(r);
619         return NT_STATUS_OK;
620 }
621
622 static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s)
623 {
624         int ret;
625         struct ldb_result *r;
626         struct ldb_dn *basedn;
627         const char *server_reference_dn_str;
628         struct ldb_dn *server_reference_dn;
629         struct ldb_dn *computer_dn;
630
631         basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
632                                 s->dest_dsa.netbios_name,
633                                 s->dest_dsa.site_name,
634                                 s->forest.config_dn_str);
635         NT_STATUS_HAVE_NO_MEMORY(basedn);
636
637         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, 
638                          "(objectClass=*)", NULL, &r);
639         talloc_free(basedn);
640         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
641                 /* if the object doesn't exist, we'll create it later */
642                 return NT_STATUS_OK;
643         } else if (ret != LDB_SUCCESS) {
644                 return NT_STATUS_LDAP(ret);
645         } else if (r->count != 1) {
646                 talloc_free(r);
647                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
648         }
649
650         server_reference_dn_str = samdb_result_string(r->msgs[0], "serverReference", NULL);
651         if (server_reference_dn_str) {
652                 server_reference_dn     = ldb_dn_new(r, s->ldap1.ldb, server_reference_dn_str);
653                 NT_STATUS_HAVE_NO_MEMORY(server_reference_dn);
654
655                 computer_dn             = ldb_dn_new(r, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
656                 NT_STATUS_HAVE_NO_MEMORY(computer_dn);
657
658                 /*
659                  * if the server object belongs to another DC in another domain in the forest,
660                  * we should not touch this object!
661                  */
662                 if (ldb_dn_compare(computer_dn, server_reference_dn) != 0) {
663                         talloc_free(r);
664                         return NT_STATUS_OBJECT_NAME_COLLISION;
665                 }
666         }
667
668         /* if the server object is already for the dest_dsa, then we don't need to create it */
669         s->dest_dsa.server_dn_str       = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
670         if (!s->dest_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
671         talloc_steal(s, s->dest_dsa.server_dn_str);
672
673         talloc_free(r);
674         return NT_STATUS_OK;
675 }
676
677 static NTSTATUS becomeDC_ldap1_server_object_2(struct libnet_BecomeDC_state *s)
678 {
679         int ret;
680         struct ldb_result *r;
681         struct ldb_dn *basedn;
682         const char *server_reference_bl_dn_str;
683         static const char *attrs[] = {
684                 "serverReferenceBL",
685                 NULL
686         };
687
688         /* if the server_dn_str has a valid value, we skip this lookup */
689         if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
690
691         basedn = ldb_dn_new(s, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
692         NT_STATUS_HAVE_NO_MEMORY(basedn);
693
694         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, 
695                          "(objectClass=*)", attrs, &r);
696         talloc_free(basedn);
697         if (ret != LDB_SUCCESS) {
698                 return NT_STATUS_LDAP(ret);
699         } else if (r->count != 1) {
700                 talloc_free(r);
701                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
702         }
703
704         server_reference_bl_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL);
705         if (!server_reference_bl_dn_str) {
706                 /* if no back link is present, we're done for this function */
707                 talloc_free(r);
708                 return NT_STATUS_OK;
709         }
710
711         /* if the server object is already for the dest_dsa, then we don't need to create it */
712         s->dest_dsa.server_dn_str       = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL);
713         if (s->dest_dsa.server_dn_str) {
714                 /* if a back link is present, we know that the server object is present */
715                 talloc_steal(s, s->dest_dsa.server_dn_str);
716         }
717
718         talloc_free(r);
719         return NT_STATUS_OK;
720 }
721
722 static NTSTATUS becomeDC_ldap1_server_object_add(struct libnet_BecomeDC_state *s)
723 {
724         int ret;
725         struct ldb_message *msg;
726         char *server_dn_str;
727
728         /* if the server_dn_str has a valid value, we skip this lookup */
729         if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
730
731         msg = ldb_msg_new(s);
732         NT_STATUS_HAVE_NO_MEMORY(msg);
733
734         msg->dn = ldb_dn_new_fmt(msg, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
735                                  s->dest_dsa.netbios_name,
736                                  s->dest_dsa.site_name,
737                                  s->forest.config_dn_str);
738         NT_STATUS_HAVE_NO_MEMORY(msg->dn);
739
740         ret = ldb_msg_add_string(msg, "objectClass", "server");
741         if (ret != 0) {
742                 talloc_free(msg);
743                 return NT_STATUS_NO_MEMORY;
744         }
745         ret = ldb_msg_add_string(msg, "systemFlags", "50000000");
746         if (ret != 0) {
747                 talloc_free(msg);
748                 return NT_STATUS_NO_MEMORY;
749         }
750         ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
751         if (ret != 0) {
752                 talloc_free(msg);
753                 return NT_STATUS_NO_MEMORY;
754         }
755
756         server_dn_str = ldb_dn_alloc_linearized(s, msg->dn);
757         NT_STATUS_HAVE_NO_MEMORY(server_dn_str);
758
759         ret = ldb_add(s->ldap1.ldb, msg);
760         talloc_free(msg);
761         if (ret != LDB_SUCCESS) {
762                 talloc_free(server_dn_str);
763                 return NT_STATUS_LDAP(ret);
764         }
765
766         s->dest_dsa.server_dn_str = server_dn_str;
767
768         return NT_STATUS_OK;
769 }
770
771 static NTSTATUS becomeDC_ldap1_server_object_modify(struct libnet_BecomeDC_state *s)
772 {
773         int ret;
774         struct ldb_message *msg;
775         uint32_t i;
776
777         /* make a 'modify' msg, and only for serverReference */
778         msg = ldb_msg_new(s);
779         NT_STATUS_HAVE_NO_MEMORY(msg);
780         msg->dn = ldb_dn_new(msg, s->ldap1.ldb, s->dest_dsa.server_dn_str);
781         NT_STATUS_HAVE_NO_MEMORY(msg->dn);
782
783         ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
784         if (ret != 0) {
785                 talloc_free(msg);
786                 return NT_STATUS_NO_MEMORY;
787         }
788
789         /* mark all the message elements (should be just one)
790            as LDB_FLAG_MOD_ADD */
791         for (i=0;i<msg->num_elements;i++) {
792                 msg->elements[i].flags = LDB_FLAG_MOD_ADD;
793         }
794
795         ret = ldb_modify(s->ldap1.ldb, msg);
796         if (ret == LDB_SUCCESS) {
797                 talloc_free(msg);
798                 return NT_STATUS_OK;
799         } else if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
800                 /* retry with LDB_FLAG_MOD_REPLACE */
801         } else {
802                 talloc_free(msg);
803                 return NT_STATUS_LDAP(ret);
804         }
805
806         /* mark all the message elements (should be just one)
807            as LDB_FLAG_MOD_REPLACE */
808         for (i=0;i<msg->num_elements;i++) {
809                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
810         }
811
812         ret = ldb_modify(s->ldap1.ldb, msg);
813         talloc_free(msg);
814         if (ret != LDB_SUCCESS) {
815                 return NT_STATUS_LDAP(ret);
816         }
817
818         return NT_STATUS_OK;
819 }
820
821 static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
822                                           struct becomeDC_drsuapi *drsuapi,
823                                           void (*recv_fn)(struct composite_context *req));
824 static void becomeDC_drsuapi1_connect_recv(struct composite_context *req);
825 static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s);
826
827 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s)
828 {
829         struct composite_context *c = s->creq;
830
831         c->status = becomeDC_ldap_connect(s, &s->ldap1);
832         if (!composite_is_ok(c)) return;
833
834         c->status = becomeDC_ldap1_rootdse(s);
835         if (!composite_is_ok(c)) return;
836
837         c->status = becomeDC_ldap1_config_behavior_version(s);
838         if (!composite_is_ok(c)) return;
839
840         c->status = becomeDC_ldap1_domain_behavior_version(s);
841         if (!composite_is_ok(c)) return;
842
843         c->status = becomeDC_ldap1_schema_object_version(s);
844         if (!composite_is_ok(c)) return;
845
846         c->status = becomeDC_ldap1_w2k3_update_revision(s);
847         if (!composite_is_ok(c)) return;
848
849         c->status = becomeDC_ldap1_infrastructure_fsmo(s);
850         if (!composite_is_ok(c)) return;
851
852         c->status = becomeDC_ldap1_rid_manager_fsmo(s);
853         if (!composite_is_ok(c)) return;
854
855         c->status = becomeDC_ldap1_site_object(s);
856         if (!composite_is_ok(c)) return;
857
858         c->status = becomeDC_ldap1_computer_object(s);
859         if (!composite_is_ok(c)) return;
860
861         c->status = becomeDC_ldap1_server_object_1(s);
862         if (!composite_is_ok(c)) return;
863
864         c->status = becomeDC_ldap1_server_object_2(s);
865         if (!composite_is_ok(c)) return;
866
867         c->status = becomeDC_ldap1_server_object_add(s);
868         if (!composite_is_ok(c)) return;
869
870         c->status = becomeDC_ldap1_server_object_modify(s);
871         if (!composite_is_ok(c)) return;
872
873         becomeDC_drsuapi_connect_send(s, &s->drsuapi1, becomeDC_drsuapi1_connect_recv);
874 }
875
876 static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
877                                           struct becomeDC_drsuapi *drsuapi,
878                                           void (*recv_fn)(struct composite_context *req))
879 {
880         struct composite_context *c = s->creq;
881         struct composite_context *creq;
882         char *binding_str;
883
884         drsuapi->s = s;
885
886         binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[krb5,seal]", s->source_dsa.dns_name);
887         if (composite_nomem(binding_str, c)) return;
888
889         c->status = dcerpc_parse_binding(s, binding_str, &drsuapi->binding);
890         talloc_free(binding_str);
891         if (!composite_is_ok(c)) return;
892
893         creq = dcerpc_pipe_connect_b_send(s, drsuapi->binding, &dcerpc_table_drsuapi,
894                                           s->libnet->cred, s->libnet->event_ctx);
895         composite_continue(c, creq, recv_fn, s);
896 }
897
898 static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
899                                        struct becomeDC_drsuapi *drsuapi,
900                                        void (*recv_fn)(struct rpc_request *req));
901 static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req);
902
903 static void becomeDC_drsuapi1_connect_recv(struct composite_context *req)
904 {
905         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
906                                           struct libnet_BecomeDC_state);
907         struct composite_context *c = s->creq;
908
909         c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi1.pipe);
910         if (!composite_is_ok(c)) return;
911
912         becomeDC_drsuapi_bind_send(s, &s->drsuapi1, becomeDC_drsuapi1_bind_recv);
913 }
914
915 static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
916                                        struct becomeDC_drsuapi *drsuapi,
917                                        void (*recv_fn)(struct rpc_request *req))
918 {
919         struct composite_context *c = s->creq;
920         struct rpc_request *req;
921         struct drsuapi_DsBindInfo28 *bind_info28;
922
923         GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &drsuapi->bind_guid);
924
925         bind_info28                             = &drsuapi->local_info28;
926         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
927         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
928         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
929         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
930         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
931         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
932         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
933         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
934         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
935         if (s->ads_options.domain_behavior_version == 2) {
936                 /* TODO: find out how this is really triggered! */
937                 bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
938         }
939         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
940         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
941         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
942         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
943         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
944         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
945         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
946         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
947         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
948         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_00100000;
949         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
950         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
951         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
952         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
953         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
954         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
955         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
956         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
957         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
958 #if 0 /* we don't support XPRESS compression yet */
959         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
960 #endif
961         bind_info28->site_guid                  = s->dest_dsa.site_guid;
962         if (s->ads_options.domain_behavior_version == 2) {
963                 /* TODO: find out how this is really triggered! */
964                 bind_info28->u1                         = 528;
965         } else {
966                 bind_info28->u1                         = 516;
967         }
968         bind_info28->repl_epoch                 = 0;
969
970         drsuapi->bind_info_ctr.length           = 28;
971         drsuapi->bind_info_ctr.info.info28      = *bind_info28;
972
973         drsuapi->bind_r.in.bind_guid = &drsuapi->bind_guid;
974         drsuapi->bind_r.in.bind_info = &drsuapi->bind_info_ctr;
975         drsuapi->bind_r.out.bind_handle = &drsuapi->bind_handle;
976
977         req = dcerpc_drsuapi_DsBind_send(drsuapi->pipe, s, &drsuapi->bind_r);
978         composite_continue_rpc(c, req, recv_fn, s);
979 }
980
981 static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s);
982
983 static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req)
984 {
985         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
986                                           struct libnet_BecomeDC_state);
987         struct composite_context *c = s->creq;
988
989         c->status = dcerpc_ndr_request_recv(req);
990         if (!composite_is_ok(c)) return;
991
992         if (!W_ERROR_IS_OK(s->drsuapi1.bind_r.out.result)) {
993                 composite_error(c, werror_to_ntstatus(s->drsuapi1.bind_r.out.result));
994                 return;
995         }
996
997         ZERO_STRUCT(s->drsuapi1.remote_info28);
998         if (s->drsuapi1.bind_r.out.bind_info) {
999                 switch (s->drsuapi1.bind_r.out.bind_info->length) {
1000                 case 24: {
1001                         struct drsuapi_DsBindInfo24 *info24;
1002                         info24 = &s->drsuapi1.bind_r.out.bind_info->info.info24;
1003                         s->drsuapi1.remote_info28.supported_extensions  = info24->supported_extensions;
1004                         s->drsuapi1.remote_info28.site_guid             = info24->site_guid;
1005                         s->drsuapi1.remote_info28.u1                    = info24->u1;
1006                         s->drsuapi1.remote_info28.repl_epoch            = 0;
1007                         break;
1008                 }
1009                 case 28:
1010                         s->drsuapi1.remote_info28 = s->drsuapi1.bind_r.out.bind_info->info.info28;
1011                         break;
1012                 }
1013         }
1014
1015         becomeDC_drsuapi1_add_entry_send(s);
1016 }
1017
1018 static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req);
1019
1020 static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
1021 {
1022         struct composite_context *c = s->creq;
1023         struct rpc_request *req;
1024         struct drsuapi_DsAddEntry *r;
1025         struct drsuapi_DsReplicaObjectIdentifier *identifier;
1026         uint32_t num_attrs, i = 0;
1027         struct drsuapi_DsReplicaAttribute *attrs;
1028
1029         /* choose a random invocationId */
1030         s->dest_dsa.invocation_id = GUID_random();
1031
1032         r = talloc_zero(s, struct drsuapi_DsAddEntry);
1033         if (composite_nomem(r, c)) return;
1034
1035         /* setup identifier */
1036         identifier              = talloc(r, struct drsuapi_DsReplicaObjectIdentifier);
1037         if (composite_nomem(identifier, c)) return;
1038         identifier->guid        = GUID_zero();
1039         identifier->sid         = s->zero_sid;
1040         identifier->dn          = talloc_asprintf(identifier, "CN=NTDS Settings,%s",
1041                                                   s->dest_dsa.server_dn_str);
1042         if (composite_nomem(identifier->dn, c)) return;
1043
1044         /* allocate attribute array */
1045         num_attrs       = 11;
1046         attrs           = talloc_array(r, struct drsuapi_DsReplicaAttribute, num_attrs);
1047         if (composite_nomem(attrs, c)) return;
1048
1049         /* ntSecurityDescriptor */
1050         {
1051                 struct drsuapi_DsAttributeValueSecurityDescriptor *vs;
1052                 struct security_descriptor *v;
1053                 struct dom_sid *domain_admins_sid;
1054                 const char *domain_admins_sid_str;
1055
1056                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueSecurityDescriptor, 1);
1057                 if (composite_nomem(vs, c)) return;
1058
1059                 domain_admins_sid = dom_sid_add_rid(vs, s->domain.sid, DOMAIN_RID_ADMINS);
1060                 if (composite_nomem(domain_admins_sid, c)) return;
1061
1062                 domain_admins_sid_str = dom_sid_string(domain_admins_sid, domain_admins_sid);
1063                 if (composite_nomem(domain_admins_sid_str, c)) return;
1064
1065                 v = security_descriptor_create(vs,
1066                                                /* owner: domain admins */
1067                                                domain_admins_sid_str,
1068                                                /* owner group: domain admins */
1069                                                domain_admins_sid_str,
1070                                                /* authenticated users */
1071                                                SID_NT_AUTHENTICATED_USERS,
1072                                                SEC_ACE_TYPE_ACCESS_ALLOWED,
1073                                                SEC_STD_READ_CONTROL |
1074                                                SEC_ADS_LIST |
1075                                                SEC_ADS_READ_PROP |
1076                                                SEC_ADS_LIST_OBJECT,
1077                                                0,
1078                                                /* domain admins */
1079                                                domain_admins_sid_str,
1080                                                SEC_ACE_TYPE_ACCESS_ALLOWED,
1081                                                SEC_STD_REQUIRED |
1082                                                SEC_ADS_CREATE_CHILD |
1083                                                SEC_ADS_LIST |
1084                                                SEC_ADS_SELF_WRITE |
1085                                                SEC_ADS_READ_PROP |
1086                                                SEC_ADS_WRITE_PROP |
1087                                                SEC_ADS_DELETE_TREE |
1088                                                SEC_ADS_LIST_OBJECT |
1089                                                SEC_ADS_CONTROL_ACCESS,
1090                                                0,
1091                                                /* system */
1092                                                SID_NT_SYSTEM,
1093                                                SEC_ACE_TYPE_ACCESS_ALLOWED,
1094                                                SEC_STD_REQUIRED |
1095                                                SEC_ADS_CREATE_CHILD |
1096                                                SEC_ADS_DELETE_CHILD |
1097                                                SEC_ADS_LIST |
1098                                                SEC_ADS_SELF_WRITE |
1099                                                SEC_ADS_READ_PROP |
1100                                                SEC_ADS_WRITE_PROP |
1101                                                SEC_ADS_DELETE_TREE |
1102                                                SEC_ADS_LIST_OBJECT |
1103                                                SEC_ADS_CONTROL_ACCESS,
1104                                                0,
1105                                                /* end */
1106                                                NULL);
1107                 if (composite_nomem(v, c)) return;
1108
1109                 vs[0].sd                = v;
1110
1111                 attrs[i].attid                                          = DRSUAPI_ATTRIBUTE_ntSecurityDescriptor;
1112                 attrs[i].value_ctr.security_descriptor.num_values       = 1;
1113                 attrs[i].value_ctr.security_descriptor.values           = vs;
1114
1115                 i++;
1116         }
1117
1118         /* objectClass: nTDSDSA */
1119         {
1120                 struct drsuapi_DsAttributeValueObjectClassId *vs;
1121                 enum drsuapi_DsObjectClassId *v;
1122
1123                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueObjectClassId, 1);
1124                 if (composite_nomem(vs, c)) return;
1125
1126                 v = talloc_array(vs, enum drsuapi_DsObjectClassId, 1);
1127                 if (composite_nomem(v, c)) return;
1128
1129                 /* value for nTDSDSA */
1130                 v[0]                    = 0x0017002F;
1131
1132                 vs[0].objectClassId     = &v[0];
1133
1134                 attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_objectClass;
1135                 attrs[i].value_ctr.object_class_id.num_values   = 1;
1136                 attrs[i].value_ctr.object_class_id.values       = vs;
1137
1138                 i++;
1139         }
1140
1141         /* objectCategory: CN=NTDS-DSA,CN=Schema,... */
1142         {
1143                 struct drsuapi_DsAttributeValueDNString *vs;
1144                 struct drsuapi_DsReplicaObjectIdentifier3 *v;
1145
1146                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 1);
1147                 if (composite_nomem(vs, c)) return;
1148
1149                 v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 1);
1150                 if (composite_nomem(v, c)) return;
1151
1152                 /* value for nTDSDSA */
1153                 v[0].guid               = GUID_zero();
1154                 v[0].sid                = s->zero_sid;
1155                 v[0].dn                 = talloc_asprintf(v, "CN=NTDS-DSA,%s",
1156                                                           s->forest.schema_dn_str);
1157                 if (composite_nomem(v->dn, c)) return;
1158
1159                 vs[0].object            = &v[0];
1160
1161                 attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_objectCategory;
1162                 attrs[i].value_ctr.dn_string.num_values         = 1;
1163                 attrs[i].value_ctr.dn_string.values             = vs;
1164
1165                 i++;
1166         }
1167
1168         /* invocationId: random guid */
1169         {
1170                 struct drsuapi_DsAttributeValueGUID *vs;
1171                 struct GUID *v;
1172
1173                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueGUID, 1);
1174                 if (composite_nomem(vs, c)) return;
1175
1176                 v = talloc_array(vs, struct GUID, 1);
1177                 if (composite_nomem(v, c)) return;
1178
1179                 /* value for nTDSDSA */
1180                 v[0]                    = s->dest_dsa.invocation_id;
1181
1182                 vs[0].guid              = &v[0];
1183
1184                 attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_invocationId;
1185                 attrs[i].value_ctr.guid.num_values              = 1;
1186                 attrs[i].value_ctr.guid.values                  = vs;
1187
1188                 i++;
1189         }
1190
1191         /* hasMasterNCs: ... */
1192         {
1193                 struct drsuapi_DsAttributeValueDNString *vs;
1194                 struct drsuapi_DsReplicaObjectIdentifier3 *v;
1195
1196                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 3);
1197                 if (composite_nomem(vs, c)) return;
1198
1199                 v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 3);
1200                 if (composite_nomem(v, c)) return;
1201
1202                 v[0].guid               = GUID_zero();
1203                 v[0].sid                = s->zero_sid;
1204                 v[0].dn                 = s->forest.config_dn_str;
1205
1206                 v[1].guid               = GUID_zero();
1207                 v[1].sid                = s->zero_sid;
1208                 v[1].dn                 = s->domain.dn_str;
1209
1210                 v[2].guid               = GUID_zero();
1211                 v[2].sid                = s->zero_sid;
1212                 v[2].dn                 = s->forest.schema_dn_str;
1213
1214                 vs[0].object            = &v[0];
1215                 vs[1].object            = &v[1];
1216                 vs[2].object            = &v[2];
1217
1218                 attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_hasMasterNCs;
1219                 attrs[i].value_ctr.dn_string.num_values         = 3;
1220                 attrs[i].value_ctr.dn_string.values             = vs;
1221
1222                 i++;
1223         }
1224
1225         /* msDS-hasMasterNCs: ... */
1226         {
1227                 struct drsuapi_DsAttributeValueDNString *vs;
1228                 struct drsuapi_DsReplicaObjectIdentifier3 *v;
1229
1230                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 3);
1231                 if (composite_nomem(vs, c)) return;
1232
1233                 v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 3);
1234                 if (composite_nomem(v, c)) return;
1235
1236                 v[0].guid               = GUID_zero();
1237                 v[0].sid                = s->zero_sid;
1238                 v[0].dn                 = s->forest.config_dn_str;
1239
1240                 v[1].guid               = GUID_zero();
1241                 v[1].sid                = s->zero_sid;
1242                 v[1].dn                 = s->domain.dn_str;
1243
1244                 v[2].guid               = GUID_zero();
1245                 v[2].sid                = s->zero_sid;
1246                 v[2].dn                 = s->forest.schema_dn_str;
1247
1248                 vs[0].object            = &v[0];
1249                 vs[1].object            = &v[1];
1250                 vs[2].object            = &v[2];
1251
1252                 attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs;
1253                 attrs[i].value_ctr.dn_string.num_values         = 3;
1254                 attrs[i].value_ctr.dn_string.values             = vs;
1255
1256                 i++;
1257         }
1258
1259         /* dMDLocation: CN=Schema,... */
1260         {
1261                 struct drsuapi_DsAttributeValueDNString *vs;
1262                 struct drsuapi_DsReplicaObjectIdentifier3 *v;
1263
1264                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 1);
1265                 if (composite_nomem(vs, c)) return;
1266
1267                 v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 1);
1268                 if (composite_nomem(v, c)) return;
1269
1270                 v[0].guid               = GUID_zero();
1271                 v[0].sid                = s->zero_sid;
1272                 v[0].dn                 = s->forest.schema_dn_str;
1273
1274                 vs[0].object            = &v[0];
1275
1276                 attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_dMDLocation;
1277                 attrs[i].value_ctr.dn_string.num_values         = 1;
1278                 attrs[i].value_ctr.dn_string.values             = vs;
1279
1280                 i++;
1281         }
1282
1283         /* msDS-HasDomainNCs: <domain_partition> */
1284         {
1285                 struct drsuapi_DsAttributeValueDNString *vs;
1286                 struct drsuapi_DsReplicaObjectIdentifier3 *v;
1287
1288                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 1);
1289                 if (composite_nomem(vs, c)) return;
1290
1291                 v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 1);
1292                 if (composite_nomem(v, c)) return;
1293
1294                 v[0].guid               = GUID_zero();
1295                 v[0].sid                = s->zero_sid;
1296                 v[0].dn                 = s->domain.dn_str;
1297
1298                 vs[0].object            = &v[0];
1299
1300                 attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs;
1301                 attrs[i].value_ctr.dn_string.num_values         = 1;
1302                 attrs[i].value_ctr.dn_string.values             = vs;
1303
1304                 i++;
1305         }
1306
1307         /* msDS-Behavior-Version */
1308         {
1309                 struct drsuapi_DsAttributeValueUINT32 *vs;
1310                 uint32_t *v;
1311
1312                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueUINT32, 1);
1313                 if (composite_nomem(vs, c)) return;
1314
1315                 v = talloc_array(vs, uint32_t, 1);
1316                 if (composite_nomem(v, c)) return;
1317
1318                 v[0]                    = 0x00000002;
1319
1320                 vs[0].value             = &v[0];
1321
1322                 attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_msDS_Behavior_Version;
1323                 attrs[i].value_ctr.uint32.num_values            = 1;
1324                 attrs[i].value_ctr.uint32.values                = vs;
1325
1326                 i++;
1327         }
1328
1329         /* systemFlags */
1330         {
1331                 struct drsuapi_DsAttributeValueUINT32 *vs;
1332                 uint32_t *v;
1333
1334                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueUINT32, 1);
1335                 if (composite_nomem(vs, c)) return;
1336
1337                 v = talloc_array(vs, uint32_t, 1);
1338                 if (composite_nomem(v, c)) return;
1339
1340                 v[0]                    = SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE;
1341
1342                 vs[0].value             = &v[0];
1343
1344                 attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_systemFlags;
1345                 attrs[i].value_ctr.uint32.num_values            = 1;
1346                 attrs[i].value_ctr.uint32.values                = vs;
1347
1348                 i++;
1349         }
1350
1351         /* serverReference: ... */
1352         {
1353                 struct drsuapi_DsAttributeValueDNString *vs;
1354                 struct drsuapi_DsReplicaObjectIdentifier3 *v;
1355
1356                 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 1);
1357                 if (composite_nomem(vs, c)) return;
1358
1359                 v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 1);
1360                 if (composite_nomem(v, c)) return;
1361
1362                 v[0].guid               = GUID_zero();
1363                 v[0].sid                = s->zero_sid;
1364                 v[0].dn                 = s->dest_dsa.computer_dn_str;
1365
1366                 vs[0].object            = &v[0];
1367
1368                 attrs[i].attid                                  = DRSUAPI_ATTRIBUTE_serverReference;
1369                 attrs[i].value_ctr.dn_string.num_values         = 1;
1370                 attrs[i].value_ctr.dn_string.values             = vs;
1371
1372                 i++;
1373         }
1374
1375         /* truncate the attribute list to the attribute count we have filled in */
1376         num_attrs = i;
1377
1378         /* setup request structure */
1379         r->in.bind_handle                                               = &s->drsuapi1.bind_handle;
1380         r->in.level                                                     = 2;
1381         r->in.req.req2.first_object.next_object                         = NULL;
1382         r->in.req.req2.first_object.object.identifier                   = identifier;
1383         r->in.req.req2.first_object.object.unknown1                     = 0x00000000;   
1384         r->in.req.req2.first_object.object.attribute_ctr.num_attributes = num_attrs;
1385         r->in.req.req2.first_object.object.attribute_ctr.attributes     = attrs;
1386
1387         req = dcerpc_drsuapi_DsAddEntry_send(s->drsuapi1.pipe, r, r);
1388         composite_continue_rpc(c, req, becomeDC_drsuapi1_add_entry_recv, s);
1389 }
1390
1391 static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req)
1392 {
1393         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1394                                           struct libnet_BecomeDC_state);
1395         struct composite_context *c = s->creq;
1396         struct drsuapi_DsAddEntry *r = talloc_get_type(req->ndr.struct_ptr,
1397                                        struct drsuapi_DsAddEntry);
1398
1399         c->status = dcerpc_ndr_request_recv(req);
1400         if (!composite_is_ok(c)) return;
1401
1402         if (!W_ERROR_IS_OK(r->out.result)) {
1403                 composite_error(c, werror_to_ntstatus(r->out.result));
1404                 return;
1405         }
1406
1407         becomeDC_connect_ldap2(s);
1408 }
1409
1410 static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s)
1411 {
1412         int ret;
1413         struct ldb_message *msg;
1414         uint32_t i;
1415         uint32_t user_account_control = UF_SERVER_TRUST_ACCOUNT |
1416                                         UF_TRUSTED_FOR_DELEGATION;
1417
1418         /* as the value is already as we want it to be, we're done */
1419         if (s->dest_dsa.user_account_control == user_account_control) {
1420                 return NT_STATUS_OK;
1421         }
1422
1423         /* make a 'modify' msg, and only for serverReference */
1424         msg = ldb_msg_new(s);
1425         NT_STATUS_HAVE_NO_MEMORY(msg);
1426         msg->dn = ldb_dn_new(msg, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
1427         NT_STATUS_HAVE_NO_MEMORY(msg->dn);
1428
1429         ret = ldb_msg_add_fmt(msg, "userAccountControl", "%u", user_account_control);
1430         if (ret != 0) {
1431                 talloc_free(msg);
1432                 return NT_STATUS_NO_MEMORY;
1433         }
1434
1435         /* mark all the message elements (should be just one)
1436            as LDB_FLAG_MOD_REPLACE */
1437         for (i=0;i<msg->num_elements;i++) {
1438                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1439         }
1440
1441         ret = ldb_modify(s->ldap2.ldb, msg);
1442         talloc_free(msg);
1443         if (ret != LDB_SUCCESS) {
1444                 return NT_STATUS_LDAP(ret);
1445         }
1446
1447         s->dest_dsa.user_account_control = user_account_control;
1448
1449         return NT_STATUS_OK;
1450 }
1451
1452 static NTSTATUS becomeDC_ldap2_move_computer(struct libnet_BecomeDC_state *s)
1453 {
1454         int ret;
1455         struct ldb_result *r;
1456         struct ldb_dn *basedn;
1457         struct ldb_dn *old_dn;
1458         struct ldb_dn *new_dn;
1459         static const char *_1_1_attrs[] = {
1460                 "1.1",
1461                 NULL
1462         };
1463
1464         basedn = ldb_dn_new_fmt(s, s->ldap2.ldb, "<WKGUID=a361b2ffffd211d1aa4b00c04fd7d83a,%s>",
1465                                 s->domain.dn_str);
1466         NT_STATUS_HAVE_NO_MEMORY(basedn);
1467
1468         ret = ldb_search(s->ldap2.ldb, basedn, LDB_SCOPE_BASE,
1469                          "(objectClass=*)", _1_1_attrs, &r);
1470         talloc_free(basedn);
1471         if (ret != LDB_SUCCESS) {
1472                 return NT_STATUS_LDAP(ret);
1473         } else if (r->count != 1) {
1474                 talloc_free(r);
1475                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1476         }
1477
1478         old_dn = ldb_dn_new(r, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
1479         NT_STATUS_HAVE_NO_MEMORY(old_dn);
1480
1481         new_dn = r->msgs[0]->dn;
1482
1483         if (!ldb_dn_add_child_fmt(new_dn, "CN=%s", s->dest_dsa.netbios_name)) {
1484                 talloc_free(r);
1485                 return NT_STATUS_NO_MEMORY;
1486         }
1487
1488         if (ldb_dn_compare(old_dn, new_dn) == 0) {
1489                 /* we don't need to rename if the old and new dn match */
1490                 talloc_free(r);
1491                 return NT_STATUS_OK;
1492         }
1493
1494         ret = ldb_rename(s->ldap2.ldb, old_dn, new_dn);
1495         talloc_free(r);
1496         if (ret != LDB_SUCCESS) {
1497                 return NT_STATUS_LDAP(ret);
1498         }
1499
1500         return NT_STATUS_OK;
1501 }
1502
1503 static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s)
1504 {
1505         struct composite_context *c = s->creq;
1506
1507         c->status = becomeDC_ldap_connect(s, &s->ldap2);
1508         if (!composite_is_ok(c)) return;
1509
1510         c->status = becomeDC_ldap2_modify_computer(s);
1511         if (!composite_is_ok(c)) return;
1512
1513         c->status = becomeDC_ldap2_move_computer(s);
1514         if (!composite_is_ok(c)) return;
1515
1516         composite_error(c, NT_STATUS_NOT_IMPLEMENTED);
1517 }
1518
1519 struct composite_context *libnet_BecomeDC_send(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
1520 {
1521         struct composite_context *c;
1522         struct libnet_BecomeDC_state *s;
1523         char *tmp_name;
1524
1525         c = composite_create(mem_ctx, ctx->event_ctx);
1526         if (c == NULL) return NULL;
1527
1528         s = talloc_zero(c, struct libnet_BecomeDC_state);
1529         if (composite_nomem(s, c)) return c;
1530         c->private_data = s;
1531         s->creq         = c;
1532         s->libnet       = ctx;
1533
1534         /* Domain input */
1535         s->domain.dns_name      = talloc_strdup(s, r->in.domain_dns_name);
1536         if (composite_nomem(s->domain.dns_name, c)) return c;
1537         s->domain.netbios_name  = talloc_strdup(s, r->in.domain_netbios_name);
1538         if (composite_nomem(s->domain.netbios_name, c)) return c;
1539         s->domain.sid           = dom_sid_dup(s, r->in.domain_sid);
1540         if (composite_nomem(s->domain.sid, c)) return c;
1541
1542         /* Source DSA input */
1543         s->source_dsa.address   = talloc_strdup(s, r->in.source_dsa_address);
1544         if (composite_nomem(s->source_dsa.address, c)) return c;
1545
1546         /* Destination DSA input */
1547         s->dest_dsa.netbios_name= talloc_strdup(s, r->in.dest_dsa_netbios_name);
1548         if (composite_nomem(s->dest_dsa.netbios_name, c)) return c;
1549
1550         /* Destination DSA dns_name construction */
1551         tmp_name                = strlower_talloc(s, s->dest_dsa.netbios_name);
1552         if (composite_nomem(tmp_name, c)) return c;
1553         s->dest_dsa.dns_name    = talloc_asprintf_append(tmp_name, ".%s",
1554                                                          s->domain.dns_name);
1555         if (composite_nomem(s->dest_dsa.dns_name, c)) return c;
1556
1557         becomeDC_send_cldap(s);
1558         return c;
1559 }
1560
1561 NTSTATUS libnet_BecomeDC_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
1562 {
1563         NTSTATUS status;
1564
1565         status = composite_wait(c);
1566
1567         ZERO_STRUCT(r->out);
1568
1569         talloc_free(c);
1570         return status;
1571 }
1572
1573 NTSTATUS libnet_BecomeDC(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
1574 {
1575         NTSTATUS status;
1576         struct composite_context *c;
1577         c = libnet_BecomeDC_send(ctx, mem_ctx, r);
1578         status = libnet_BecomeDC_recv(c, mem_ctx, r);
1579         return status;
1580 }