r20045: implement the drsuapi_DsRemoveDSServer() call
[jra/samba/.git] / source4 / libnet / libnet_become_dc.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher      2006
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "libnet/libnet.h"
23 #include "libcli/composite/composite.h"
24 #include "libcli/cldap/cldap.h"
25 #include "lib/ldb/include/ldb.h"
26 #include "lib/ldb/include/ldb_errors.h"
27 #include "lib/db_wrap.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "dsdb/common/flags.h"
30
31 struct libnet_BecomeDC_state {
32         struct composite_context *creq;
33
34         struct libnet_context *libnet;
35
36         struct {
37                 struct cldap_socket *sock;
38                 struct cldap_netlogon io;
39                 struct nbt_cldap_netlogon_5 netlogon5;
40         } cldap;
41
42         struct becomeDC_ldap {
43                 struct ldb_context *ldb;
44                 const struct ldb_message *rootdse;
45         } ldap1, ldap2;
46
47         struct {
48                 /* input */
49                 const char *dns_name;
50                 const char *netbios_name;
51
52                 /* constructed */
53                 struct GUID guid;
54                 const char *dn_str;
55         } domain;
56
57         struct {
58                 /* constructed */
59                 const char *dns_name;
60                 const char *root_dn_str;
61                 const char *config_dn_str;
62                 const char *schema_dn_str;
63         } forest;
64
65         struct {
66                 /* input */
67                 const char *address;
68
69                 /* constructed */
70                 const char *dns_name;
71                 const char *netbios_name;
72                 const char *site_name;
73                 const char *server_dn_str;
74                 const char *ntds_dn_str;
75         } source_dsa;
76
77         struct {
78                 /* input */
79                 const char *netbios_name;
80
81                 /* constructed */
82                 const char *dns_name;
83                 const char *site_name;
84                 struct GUID site_guid;
85                 const char *computer_dn_str;
86                 const char *server_dn_str;
87                 const char *ntds_dn_str;
88                 uint32_t user_account_control;
89         } dest_dsa;
90
91         struct {
92                 uint32_t domain_behavior_version;
93                 uint32_t config_behavior_version;
94                 uint32_t schema_object_version;
95                 uint32_t w2k3_update_revision;
96         } ads_options;
97
98         struct becomeDC_fsmo {
99                 const char *dns_name;
100                 const char *server_dn_str;
101                 const char *ntds_dn_str;
102                 struct GUID ntds_guid;
103         } infrastructure_fsmo;
104
105         struct becomeDC_fsmo rid_manager_fsmo;
106 };
107
108 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s);
109
110 static void becomeDC_recv_cldap(struct cldap_request *req)
111 {
112         struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
113                                           struct libnet_BecomeDC_state);
114         struct composite_context *c = s->creq;
115
116         c->status = cldap_netlogon_recv(req, s, &s->cldap.io);
117         if (!composite_is_ok(c)) return;
118
119         s->cldap.netlogon5 = s->cldap.io.out.netlogon.logon5;
120
121         s->domain.dns_name              = s->cldap.netlogon5.dns_domain;
122         s->domain.netbios_name          = s->cldap.netlogon5.domain;
123         s->domain.guid                  = s->cldap.netlogon5.domain_uuid;
124
125         s->forest.dns_name              = s->cldap.netlogon5.forest;
126
127         s->source_dsa.dns_name          = s->cldap.netlogon5.pdc_dns_name;
128         s->source_dsa.netbios_name      = s->cldap.netlogon5.pdc_name;
129         s->source_dsa.site_name         = s->cldap.netlogon5.server_site;
130
131         s->dest_dsa.site_name           = s->cldap.netlogon5.client_site;
132
133         becomeDC_connect_ldap1(s);
134 }
135
136 static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
137 {
138         struct composite_context *c = s->creq;
139         struct cldap_request *req;
140
141         s->cldap.io.in.dest_address     = s->source_dsa.address;
142         s->cldap.io.in.realm            = s->domain.dns_name;
143         s->cldap.io.in.host             = s->dest_dsa.netbios_name;
144         s->cldap.io.in.user             = NULL;
145         s->cldap.io.in.domain_guid      = NULL;
146         s->cldap.io.in.domain_sid       = NULL;
147         s->cldap.io.in.acct_control     = -1;
148         s->cldap.io.in.version          = 6;
149
150         s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx);
151         if (composite_nomem(s->cldap.sock, c)) return;
152
153         req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
154         if (composite_nomem(req, c)) return;
155         req->async.fn           = becomeDC_recv_cldap;
156         req->async.private      = s;
157 }
158
159 static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s, struct becomeDC_ldap *ldap)
160 {
161         char *url;
162
163         url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
164         NT_STATUS_HAVE_NO_MEMORY(url);
165
166         ldap->ldb = ldb_wrap_connect(s, url,
167                                      NULL,
168                                      s->libnet->cred,
169                                      0, NULL);
170         talloc_free(url);
171         if (ldap->ldb == NULL) {
172                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
173         }
174
175         return NT_STATUS_OK;
176 }
177
178 static NTSTATUS becomeDC_ldap1_rootdse(struct libnet_BecomeDC_state *s)
179 {
180         int ret;
181         struct ldb_result *r;
182         struct ldb_dn *basedn;
183         static const char *attrs[] = {
184                 "*",
185                 NULL
186         };
187
188         basedn = ldb_dn_new(s, s->ldap1.ldb, NULL);
189         NT_STATUS_HAVE_NO_MEMORY(basedn);
190
191         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, 
192                          "(objectClass=*)", attrs, &r);
193         talloc_free(basedn);
194         if (ret != LDB_SUCCESS) {
195                 return NT_STATUS_LDAP(ret);
196         } else if (r->count != 1) {
197                 talloc_free(r);
198                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
199         }
200         talloc_steal(s, r);
201
202         s->ldap1.rootdse = r->msgs[0];
203
204         s->domain.dn_str        = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "defaultNamingContext", NULL);
205         if (!s->domain.dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
206
207         s->forest.root_dn_str   = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "rootDomainNamingContext", NULL);
208         if (!s->forest.root_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
209         s->forest.config_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "configurationNamingContext", NULL);
210         if (!s->forest.config_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
211         s->forest.schema_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "schemaNamingContext", NULL);
212         if (!s->forest.schema_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
213
214         s->source_dsa.server_dn_str     = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "serverName", NULL);
215         if (!s->source_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
216         s->source_dsa.ntds_dn_str       = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "dsServiceName", NULL);
217         if (!s->source_dsa.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
218
219         return NT_STATUS_OK;
220 }
221
222 static NTSTATUS becomeDC_ldap1_config_behavior_version(struct libnet_BecomeDC_state *s)
223 {
224         int ret;
225         struct ldb_result *r;
226         struct ldb_dn *basedn;
227         static const char *attrs[] = {
228                 "msDs-Behavior-Version",
229                 NULL
230         };
231
232         basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.config_dn_str);
233         NT_STATUS_HAVE_NO_MEMORY(basedn);
234
235         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_ONELEVEL,
236                          "(cn=Partitions)", attrs, &r);
237         talloc_free(basedn);
238         if (ret != LDB_SUCCESS) {
239                 return NT_STATUS_LDAP(ret);
240         } else if (r->count != 1) {
241                 talloc_free(r);
242                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
243         }
244
245         s->ads_options.config_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
246
247         talloc_free(r);
248         return NT_STATUS_OK;
249 }
250
251 static NTSTATUS becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_state *s)
252 {
253         int ret;
254         struct ldb_result *r;
255         struct ldb_dn *basedn;
256         static const char *attrs[] = {
257                 "msDs-Behavior-Version",
258                 NULL
259         };
260
261         basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
262         NT_STATUS_HAVE_NO_MEMORY(basedn);
263
264         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
265                          "(objectClass=*)", attrs, &r);
266         talloc_free(basedn);
267         if (ret != LDB_SUCCESS) {
268                 return NT_STATUS_LDAP(ret);
269         } else if (r->count != 1) {
270                 talloc_free(r);
271                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
272         }
273
274         s->ads_options.domain_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
275
276         talloc_free(r);
277         return NT_STATUS_OK;
278 }
279
280 static NTSTATUS becomeDC_ldap1_schema_object_version(struct libnet_BecomeDC_state *s)
281 {
282         int ret;
283         struct ldb_result *r;
284         struct ldb_dn *basedn;
285         static const char *attrs[] = {
286                 "objectVersion",
287                 NULL
288         };
289
290         basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.schema_dn_str);
291         NT_STATUS_HAVE_NO_MEMORY(basedn);
292
293         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
294                          "(objectClass=*)", attrs, &r);
295         talloc_free(basedn);
296         if (ret != LDB_SUCCESS) {
297                 return NT_STATUS_LDAP(ret);
298         } else if (r->count != 1) {
299                 talloc_free(r);
300                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
301         }
302
303         s->ads_options.schema_object_version = ldb_msg_find_attr_as_uint(r->msgs[0], "objectVersion", 0);
304
305         talloc_free(r);
306         return NT_STATUS_OK;
307 }
308
309 static NTSTATUS becomeDC_ldap1_w2k3_update_revision(struct libnet_BecomeDC_state *s)
310 {
311         int ret;
312         struct ldb_result *r;
313         struct ldb_dn *basedn;
314         static const char *attrs[] = {
315                 "revision",
316                 NULL
317         };
318
319         basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=Windows2003Update,CN=DomainUpdates,CN=System,%s",
320                                 s->domain.dn_str);
321         NT_STATUS_HAVE_NO_MEMORY(basedn);
322
323         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
324                          "(objectClass=*)", attrs, &r);
325         talloc_free(basedn);
326         if (ret != LDB_SUCCESS) {
327                 return NT_STATUS_LDAP(ret);
328         } else if (r->count != 1) {
329                 talloc_free(r);
330                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
331         }
332
333         s->ads_options.w2k3_update_revision = ldb_msg_find_attr_as_uint(r->msgs[0], "revision", 0);
334
335         talloc_free(r);
336         return NT_STATUS_OK;
337 }
338
339 static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state *s)
340 {
341         int ret;
342         struct ldb_result *r;
343         struct ldb_dn *basedn;
344         struct ldb_dn *ntds_dn;
345         struct ldb_dn *server_dn;
346         static const char *_1_1_attrs[] = {
347                 "1.1",
348                 NULL
349         };
350         static const char *fsmo_attrs[] = {
351                 "fSMORoleOwner",
352                 NULL
353         };
354         static const char *dns_attrs[] = {
355                 "dnsHostName",
356                 NULL
357         };
358         static const char *guid_attrs[] = {
359                 "objectGUID",
360                 NULL
361         };
362
363         basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "<WKGUID=2fbac1870ade11d297c400c04fd8d5cd,%s>",
364                                 s->domain.dn_str);
365         NT_STATUS_HAVE_NO_MEMORY(basedn);
366
367         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
368                          "(objectClass=*)", _1_1_attrs, &r);
369         talloc_free(basedn);
370         if (ret != LDB_SUCCESS) {
371                 return NT_STATUS_LDAP(ret);
372         } else if (r->count != 1) {
373                 talloc_free(r);
374                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
375         }
376
377         basedn = talloc_steal(s, r->msgs[0]->dn);
378         talloc_free(r);
379
380         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
381                          "(objectClass=*)", fsmo_attrs, &r);
382         talloc_free(basedn);
383         if (ret != LDB_SUCCESS) {
384                 return NT_STATUS_LDAP(ret);
385         } else if (r->count != 1) {
386                 talloc_free(r);
387                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
388         }
389
390         s->infrastructure_fsmo.ntds_dn_str      = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
391         if (!s->infrastructure_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
392         talloc_steal(s, s->infrastructure_fsmo.ntds_dn_str);
393
394         talloc_free(r);
395
396         ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->infrastructure_fsmo.ntds_dn_str);
397         NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
398
399         server_dn = ldb_dn_get_parent(s, ntds_dn);
400         NT_STATUS_HAVE_NO_MEMORY(server_dn);
401
402         s->infrastructure_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
403         NT_STATUS_HAVE_NO_MEMORY(s->infrastructure_fsmo.server_dn_str);
404
405         ret = ldb_search(s->ldap1.ldb, server_dn, LDB_SCOPE_BASE,
406                          "(objectClass=*)", dns_attrs, &r);
407         if (ret != LDB_SUCCESS) {
408                 return NT_STATUS_LDAP(ret);
409         } else if (r->count != 1) {
410                 talloc_free(r);
411                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
412         }
413
414         s->infrastructure_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL);
415         if (!s->infrastructure_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
416         talloc_steal(s, s->infrastructure_fsmo.dns_name);
417
418         talloc_free(r);
419
420         ret = ldb_search(s->ldap1.ldb, ntds_dn, LDB_SCOPE_BASE,
421                          "(objectClass=*)", guid_attrs, &r);
422         if (ret != LDB_SUCCESS) {
423                 return NT_STATUS_LDAP(ret);
424         } else if (r->count != 1) {
425                 talloc_free(r);
426                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
427         }
428
429         s->infrastructure_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
430
431         talloc_free(r);
432
433         return NT_STATUS_OK;
434 }
435
436 static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s)
437 {
438         int ret;
439         struct ldb_result *r;
440         struct ldb_dn *basedn;
441         const char *reference_dn_str;
442         struct ldb_dn *ntds_dn;
443         struct ldb_dn *server_dn;
444         static const char *rid_attrs[] = {
445                 "rIDManagerReference",
446                 NULL
447         };
448         static const char *fsmo_attrs[] = {
449                 "fSMORoleOwner",
450                 NULL
451         };
452         static const char *dns_attrs[] = {
453                 "dnsHostName",
454                 NULL
455         };
456         static const char *guid_attrs[] = {
457                 "objectGUID",
458                 NULL
459         };
460
461         basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
462         NT_STATUS_HAVE_NO_MEMORY(basedn);
463
464         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
465                          "(objectClass=*)", rid_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         reference_dn_str        = samdb_result_string(r->msgs[0], "rIDManagerReference", NULL);
475         if (!reference_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
476
477         basedn = ldb_dn_new(s, s->ldap1.ldb, reference_dn_str);
478         NT_STATUS_HAVE_NO_MEMORY(basedn);
479
480         talloc_free(r);
481
482         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
483                          "(objectClass=*)", fsmo_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         s->rid_manager_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
493         if (!s->rid_manager_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
494         talloc_steal(s, s->rid_manager_fsmo.ntds_dn_str);
495
496         talloc_free(r);
497
498         ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->rid_manager_fsmo.ntds_dn_str);
499         NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
500
501         server_dn = ldb_dn_get_parent(s, ntds_dn);
502         NT_STATUS_HAVE_NO_MEMORY(server_dn);
503
504         s->rid_manager_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
505         NT_STATUS_HAVE_NO_MEMORY(s->rid_manager_fsmo.server_dn_str);
506
507         ret = ldb_search(s->ldap1.ldb, server_dn, LDB_SCOPE_BASE,
508                          "(objectClass=*)", dns_attrs, &r);
509         if (ret != LDB_SUCCESS) {
510                 return NT_STATUS_LDAP(ret);
511         } else if (r->count != 1) {
512                 talloc_free(r);
513                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
514         }
515
516         s->rid_manager_fsmo.dns_name    = samdb_result_string(r->msgs[0], "dnsHostName", NULL);
517         if (!s->rid_manager_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
518         talloc_steal(s, s->rid_manager_fsmo.dns_name);
519
520         talloc_free(r);
521
522         ret = ldb_search(s->ldap1.ldb, ntds_dn, LDB_SCOPE_BASE,
523                          "(objectClass=*)", guid_attrs, &r);
524         if (ret != LDB_SUCCESS) {
525                 return NT_STATUS_LDAP(ret);
526         } else if (r->count != 1) {
527                 talloc_free(r);
528                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
529         }
530
531         s->rid_manager_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
532
533         talloc_free(r);
534
535         return NT_STATUS_OK;
536 }
537
538 static NTSTATUS becomeDC_ldap1_site_object(struct libnet_BecomeDC_state *s)
539 {
540         int ret;
541         struct ldb_result *r;
542         struct ldb_dn *basedn;
543
544         basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Sites,%s",
545                                 s->dest_dsa.site_name,
546                                 s->forest.config_dn_str);
547         NT_STATUS_HAVE_NO_MEMORY(basedn);
548
549         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, 
550                          "(objectClass=*)", NULL, &r);
551         talloc_free(basedn);
552         if (ret != LDB_SUCCESS) {
553                 return NT_STATUS_LDAP(ret);
554         } else if (r->count != 1) {
555                 talloc_free(r);
556                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
557         }
558
559         s->dest_dsa.site_guid = samdb_result_guid(r->msgs[0], "objectGUID");
560
561         talloc_free(r);
562         return NT_STATUS_OK;
563 }
564
565 static NTSTATUS becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state *s)
566 {
567         int ret;
568         struct ldb_result *r;
569         struct ldb_dn *basedn;
570         char *filter;
571         static const char *attrs[] = {
572                 "distinguishedName",
573                 "userAccountControl",
574                 NULL
575         };
576
577         basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
578         NT_STATUS_HAVE_NO_MEMORY(basedn);
579
580         filter = talloc_asprintf(basedn, "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))",
581                                  s->dest_dsa.netbios_name);
582         NT_STATUS_HAVE_NO_MEMORY(filter);
583
584         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_SUBTREE, 
585                          filter, attrs, &r);
586         talloc_free(basedn);
587         if (ret != LDB_SUCCESS) {
588                 return NT_STATUS_LDAP(ret);
589         } else if (r->count != 1) {
590                 talloc_free(r);
591                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
592         }
593
594         s->dest_dsa.computer_dn_str     = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
595         if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
596         talloc_steal(s, s->dest_dsa.computer_dn_str);
597
598         s->dest_dsa.user_account_control = samdb_result_uint(r->msgs[0], "userAccountControl", 0);
599
600         talloc_free(r);
601         return NT_STATUS_OK;
602 }
603
604 static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s)
605 {
606         int ret;
607         struct ldb_result *r;
608         struct ldb_dn *basedn;
609         const char *server_reference_dn_str;
610         struct ldb_dn *server_reference_dn;
611         struct ldb_dn *computer_dn;
612
613         basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
614                                 s->dest_dsa.netbios_name,
615                                 s->dest_dsa.site_name,
616                                 s->forest.config_dn_str);
617         NT_STATUS_HAVE_NO_MEMORY(basedn);
618
619         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, 
620                          "(objectClass=*)", NULL, &r);
621         talloc_free(basedn);
622         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
623                 /* if the object doesn't exist, we'll create it later */
624                 return NT_STATUS_OK;
625         } else if (ret != LDB_SUCCESS) {
626                 return NT_STATUS_LDAP(ret);
627         } else if (r->count != 1) {
628                 talloc_free(r);
629                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
630         }
631
632         server_reference_dn_str         = samdb_result_string(r->msgs[0], "serverReference", NULL);
633         if (!server_reference_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
634         server_reference_dn             = ldb_dn_new(r, s->ldap1.ldb, server_reference_dn_str);
635         NT_STATUS_HAVE_NO_MEMORY(server_reference_dn);
636
637         computer_dn                     = ldb_dn_new(r, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
638         NT_STATUS_HAVE_NO_MEMORY(computer_dn);
639
640         /*
641          * if the server object belongs to another DC in another domain in the forest,
642          * we should not touch this object!
643          */
644         if (ldb_dn_compare(computer_dn, server_reference_dn) != 0) {
645                 talloc_free(r);
646                 return NT_STATUS_OBJECT_NAME_COLLISION;
647         }
648
649         /* if the server object is already for the dest_dsa, then we don't need to create it */
650         s->dest_dsa.server_dn_str       = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
651         if (!s->dest_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
652         talloc_steal(s, s->dest_dsa.server_dn_str);
653
654         talloc_free(r);
655         return NT_STATUS_OK;
656 }
657
658 static NTSTATUS becomeDC_ldap1_server_object_2(struct libnet_BecomeDC_state *s)
659 {
660         int ret;
661         struct ldb_result *r;
662         struct ldb_dn *basedn;
663         const char *server_reference_bl_dn_str;
664         static const char *attrs[] = {
665                 "serverReferenceBL",
666                 NULL
667         };
668
669         /* if the server_dn_str has a valid value, we skip this lookup */
670         if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
671
672         basedn = ldb_dn_new(s, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
673         NT_STATUS_HAVE_NO_MEMORY(basedn);
674
675         ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, 
676                          "(objectClass=*)", attrs, &r);
677         talloc_free(basedn);
678         if (ret != LDB_SUCCESS) {
679                 return NT_STATUS_LDAP(ret);
680         } else if (r->count != 1) {
681                 talloc_free(r);
682                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
683         }
684
685         server_reference_bl_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL);
686         if (!server_reference_bl_dn_str) {
687                 /* if no back link is present, we're done for this function */
688                 talloc_free(r);
689                 return NT_STATUS_OK;
690         }
691
692         /* if the server object is already for the dest_dsa, then we don't need to create it */
693         s->dest_dsa.server_dn_str       = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL);
694         if (s->dest_dsa.server_dn_str) {
695                 /* if a back link is present, we know that the server object is present */
696                 talloc_steal(s, s->dest_dsa.server_dn_str);
697         }
698
699         talloc_free(r);
700         return NT_STATUS_OK;
701 }
702
703 static NTSTATUS becomeDC_ldap1_server_object_add(struct libnet_BecomeDC_state *s)
704 {
705         int ret;
706         struct ldb_message *msg;
707         char *server_dn_str;
708
709         /* if the server_dn_str has a valid value, we skip this lookup */
710         if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
711
712         msg = ldb_msg_new(s);
713         NT_STATUS_HAVE_NO_MEMORY(msg);
714
715         msg->dn = ldb_dn_new_fmt(msg, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
716                                  s->dest_dsa.netbios_name,
717                                  s->dest_dsa.site_name,
718                                  s->forest.config_dn_str);
719         NT_STATUS_HAVE_NO_MEMORY(msg->dn);
720
721         ret = ldb_msg_add_string(msg, "objectClass", "server");
722         if (ret != 0) {
723                 talloc_free(msg);
724                 return NT_STATUS_NO_MEMORY;
725         }
726         ret = ldb_msg_add_string(msg, "systemFlags", "50000000");
727         if (ret != 0) {
728                 talloc_free(msg);
729                 return NT_STATUS_NO_MEMORY;
730         }
731         ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
732         if (ret != 0) {
733                 talloc_free(msg);
734                 return NT_STATUS_NO_MEMORY;
735         }
736
737         server_dn_str = ldb_dn_alloc_linearized(s, msg->dn);
738         NT_STATUS_HAVE_NO_MEMORY(server_dn_str);
739
740         ret = ldb_add(s->ldap1.ldb, msg);
741         talloc_free(msg);
742         if (ret != LDB_SUCCESS) {
743                 talloc_free(server_dn_str);
744                 return NT_STATUS_LDAP(ret);
745         }
746
747         s->dest_dsa.server_dn_str = server_dn_str;
748
749         return NT_STATUS_OK;
750 }
751
752 static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s);
753
754 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s)
755 {
756         struct composite_context *c = s->creq;
757
758         c->status = becomeDC_ldap_connect(s, &s->ldap1);
759         if (!composite_is_ok(c)) return;
760
761         c->status = becomeDC_ldap1_rootdse(s);
762         if (!composite_is_ok(c)) return;
763
764         c->status = becomeDC_ldap1_config_behavior_version(s);
765         if (!composite_is_ok(c)) return;
766
767         c->status = becomeDC_ldap1_domain_behavior_version(s);
768         if (!composite_is_ok(c)) return;
769
770         c->status = becomeDC_ldap1_schema_object_version(s);
771         if (!composite_is_ok(c)) return;
772
773         c->status = becomeDC_ldap1_w2k3_update_revision(s);
774         if (!composite_is_ok(c)) return;
775
776         c->status = becomeDC_ldap1_infrastructure_fsmo(s);
777         if (!composite_is_ok(c)) return;
778
779         c->status = becomeDC_ldap1_rid_manager_fsmo(s);
780         if (!composite_is_ok(c)) return;
781
782         c->status = becomeDC_ldap1_site_object(s);
783         if (!composite_is_ok(c)) return;
784
785         c->status = becomeDC_ldap1_computer_object(s);
786         if (!composite_is_ok(c)) return;
787
788         c->status = becomeDC_ldap1_server_object_1(s);
789         if (!composite_is_ok(c)) return;
790
791         c->status = becomeDC_ldap1_server_object_2(s);
792         if (!composite_is_ok(c)) return;
793
794         c->status = becomeDC_ldap1_server_object_add(s);
795         if (!composite_is_ok(c)) return;
796
797         becomeDC_connect_ldap2(s);
798 }
799
800 static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s)
801 {
802         int ret;
803         struct ldb_message *msg;
804         uint32_t i;
805         uint32_t user_account_control = UF_SERVER_TRUST_ACCOUNT |
806                                         UF_TRUSTED_FOR_DELEGATION;
807
808         /* as the value is already as we want it to be, we're done */
809         if (s->dest_dsa.user_account_control == user_account_control) {
810                 return NT_STATUS_OK;
811         }
812
813         /* make a 'modify' msg, and only for serverReference */
814         msg = ldb_msg_new(s);
815         NT_STATUS_HAVE_NO_MEMORY(msg);
816         msg->dn = ldb_dn_new(msg, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
817         NT_STATUS_HAVE_NO_MEMORY(msg->dn);
818
819         ret = ldb_msg_add_fmt(msg, "userAccountControl", "%u", user_account_control);
820         if (ret != 0) {
821                 talloc_free(msg);
822                 return NT_STATUS_NO_MEMORY;
823         }
824
825         /* mark all the message elements (should be just one)
826            as LDB_FLAG_MOD_REPLACE */
827         for (i=0;i<msg->num_elements;i++) {
828                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
829         }
830
831         ret = ldb_modify(s->ldap2.ldb, msg);
832         talloc_free(msg);
833         if (ret != LDB_SUCCESS) {
834                 return NT_STATUS_LDAP(ret);
835         }
836
837         s->dest_dsa.user_account_control = user_account_control;
838
839         return NT_STATUS_OK;
840 }
841
842 static NTSTATUS becomeDC_ldap2_move_computer(struct libnet_BecomeDC_state *s)
843 {
844         int ret;
845         struct ldb_result *r;
846         struct ldb_dn *basedn;
847         struct ldb_dn *old_dn;
848         struct ldb_dn *new_dn;
849         static const char *_1_1_attrs[] = {
850                 "1.1",
851                 NULL
852         };
853
854         basedn = ldb_dn_new_fmt(s, s->ldap2.ldb, "<WKGUID=a361b2ffffd211d1aa4b00c04fd7d83a,%s>",
855                                 s->domain.dn_str);
856         NT_STATUS_HAVE_NO_MEMORY(basedn);
857
858         ret = ldb_search(s->ldap2.ldb, basedn, LDB_SCOPE_BASE,
859                          "(objectClass=*)", _1_1_attrs, &r);
860         talloc_free(basedn);
861         if (ret != LDB_SUCCESS) {
862                 return NT_STATUS_LDAP(ret);
863         } else if (r->count != 1) {
864                 talloc_free(r);
865                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
866         }
867
868         old_dn = ldb_dn_new(r, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
869         NT_STATUS_HAVE_NO_MEMORY(old_dn);
870
871         new_dn = r->msgs[0]->dn;
872
873         if (!ldb_dn_add_child_fmt(new_dn, "CN=%s", s->dest_dsa.netbios_name)) {
874                 talloc_free(r);
875                 return NT_STATUS_NO_MEMORY;
876         }
877
878         if (ldb_dn_compare(old_dn, new_dn) == 0) {
879                 /* we don't need to rename if the old and new dn match */
880                 talloc_free(r);
881                 return NT_STATUS_OK;
882         }
883
884         ret = ldb_rename(s->ldap2.ldb, old_dn, new_dn);
885         talloc_free(r);
886         if (ret != LDB_SUCCESS) {
887                 return NT_STATUS_LDAP(ret);
888         }
889
890         return NT_STATUS_OK;
891 }
892
893 static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s)
894 {
895         struct composite_context *c = s->creq;
896
897         c->status = becomeDC_ldap_connect(s, &s->ldap2);
898         if (!composite_is_ok(c)) return;
899
900         c->status = becomeDC_ldap2_modify_computer(s);
901         if (!composite_is_ok(c)) return;
902
903         c->status = becomeDC_ldap2_move_computer(s);
904         if (!composite_is_ok(c)) return;
905
906         composite_error(c, NT_STATUS_NOT_IMPLEMENTED);
907 }
908
909 struct composite_context *libnet_BecomeDC_send(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
910 {
911         struct composite_context *c;
912         struct libnet_BecomeDC_state *s;
913         char *tmp_name;
914
915         c = composite_create(mem_ctx, ctx->event_ctx);
916         if (c == NULL) return NULL;
917
918         s = talloc_zero(c, struct libnet_BecomeDC_state);
919         if (composite_nomem(s, c)) return c;
920         c->private_data = s;
921         s->creq         = c;
922         s->libnet       = ctx;
923
924         /* Domain input */
925         s->domain.dns_name      = talloc_strdup(s, r->in.domain_dns_name);
926         if (composite_nomem(s->domain.dns_name, c)) return c;
927         s->domain.netbios_name  = talloc_strdup(s, r->in.domain_netbios_name);
928         if (composite_nomem(s->domain.netbios_name, c)) return c;
929
930         /* Source DSA input */
931         s->source_dsa.address   = talloc_strdup(s, r->in.source_dsa_address);
932         if (composite_nomem(s->source_dsa.address, c)) return c;
933
934         /* Destination DSA input */
935         s->dest_dsa.netbios_name= talloc_strdup(s, r->in.dest_dsa_netbios_name);
936         if (composite_nomem(s->dest_dsa.netbios_name, c)) return c;
937
938         /* Destination DSA dns_name construction */
939         tmp_name                = strlower_talloc(s, s->dest_dsa.netbios_name);
940         if (composite_nomem(tmp_name, c)) return c;
941         s->dest_dsa.dns_name    = talloc_asprintf_append(tmp_name, ".%s",
942                                                          s->domain.dns_name);
943         if (composite_nomem(s->dest_dsa.dns_name, c)) return c;
944
945         becomeDC_send_cldap(s);
946         return c;
947 }
948
949 NTSTATUS libnet_BecomeDC_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
950 {
951         NTSTATUS status;
952
953         status = composite_wait(c);
954
955         ZERO_STRUCT(r->out);
956
957         talloc_free(c);
958         return status;
959 }
960
961 NTSTATUS libnet_BecomeDC(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
962 {
963         NTSTATUS status;
964         struct composite_context *c;
965         c = libnet_BecomeDC_send(ctx, mem_ctx, r);
966         status = libnet_BecomeDC_recv(c, mem_ctx, r);
967         return status;
968 }