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