2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2006
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.
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.
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.
22 #include "libnet/libnet.h"
23 #include "libcli/composite/composite.h"
24 #include "libcli/cldap/cldap.h"
25 #include "lib/ldb/include/ldb.h"
26 #include "lib/ldb/include/ldb_errors.h"
27 #include "lib/db_wrap.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "dsdb/common/flags.h"
30 #include "librpc/gen_ndr/ndr_drsuapi_c.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_misc.h"
33 #include "librpc/gen_ndr/ndr_security.h"
34 #include "librpc/gen_ndr/ndr_drsuapi.h"
36 struct libnet_BecomeDC_state {
37 struct composite_context *creq;
39 struct libnet_context *libnet;
41 struct dom_sid zero_sid;
44 struct cldap_socket *sock;
45 struct cldap_netlogon io;
46 struct nbt_cldap_netlogon_5 netlogon5;
49 struct becomeDC_ldap {
50 struct ldb_context *ldb;
51 const struct ldb_message *rootdse;
54 struct becomeDC_drsuapi {
55 struct libnet_BecomeDC_state *s;
56 struct dcerpc_binding *binding;
57 struct dcerpc_pipe *pipe;
58 struct drsuapi_DsBind bind_r;
59 struct GUID bind_guid;
60 struct drsuapi_DsBindInfoCtr bind_info_ctr;
61 struct drsuapi_DsBindInfo28 local_info28;
62 struct drsuapi_DsBindInfo28 remote_info28;
63 struct policy_handle bind_handle;
64 } drsuapi1, drsuapi2, drsuapi3;
66 struct libnet_BecomeDC_Domain domain;
67 struct libnet_BecomeDC_Forest forest;
68 struct libnet_BecomeDC_SourceDSA source_dsa;
69 struct libnet_BecomeDC_DestDSA dest_dsa;
71 struct libnet_BecomeDC_Partition schema_part, config_part, domain_part;
73 struct becomeDC_fsmo {
75 const char *server_dn_str;
76 const char *ntds_dn_str;
77 struct GUID ntds_guid;
78 } infrastructure_fsmo;
80 struct becomeDC_fsmo rid_manager_fsmo;
82 struct libnet_BecomeDC_CheckOptions _co;
83 struct libnet_BecomeDC_PrepareDB _pp;
84 struct libnet_BecomeDC_StoreChunk _sc;
85 struct libnet_BecomeDC_Callbacks callbacks;
88 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s);
90 static void becomeDC_recv_cldap(struct cldap_request *req)
92 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
93 struct libnet_BecomeDC_state);
94 struct composite_context *c = s->creq;
96 c->status = cldap_netlogon_recv(req, s, &s->cldap.io);
97 if (!composite_is_ok(c)) return;
99 s->cldap.netlogon5 = s->cldap.io.out.netlogon.logon5;
101 s->domain.dns_name = s->cldap.netlogon5.dns_domain;
102 s->domain.netbios_name = s->cldap.netlogon5.domain;
103 s->domain.guid = s->cldap.netlogon5.domain_uuid;
105 s->forest.dns_name = s->cldap.netlogon5.forest;
107 s->source_dsa.dns_name = s->cldap.netlogon5.pdc_dns_name;
108 s->source_dsa.netbios_name = s->cldap.netlogon5.pdc_name;
109 s->source_dsa.site_name = s->cldap.netlogon5.server_site;
111 s->dest_dsa.site_name = s->cldap.netlogon5.client_site;
113 becomeDC_connect_ldap1(s);
116 static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
118 struct composite_context *c = s->creq;
119 struct cldap_request *req;
121 s->cldap.io.in.dest_address = s->source_dsa.address;
122 s->cldap.io.in.realm = s->domain.dns_name;
123 s->cldap.io.in.host = s->dest_dsa.netbios_name;
124 s->cldap.io.in.user = NULL;
125 s->cldap.io.in.domain_guid = NULL;
126 s->cldap.io.in.domain_sid = NULL;
127 s->cldap.io.in.acct_control = -1;
128 s->cldap.io.in.version = 6;
130 s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx);
131 if (composite_nomem(s->cldap.sock, c)) return;
133 req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
134 if (composite_nomem(req, c)) return;
135 req->async.fn = becomeDC_recv_cldap;
136 req->async.private = s;
139 static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s, struct becomeDC_ldap *ldap)
143 url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
144 NT_STATUS_HAVE_NO_MEMORY(url);
146 ldap->ldb = ldb_wrap_connect(s, url,
151 if (ldap->ldb == NULL) {
152 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
158 static NTSTATUS becomeDC_ldap1_rootdse(struct libnet_BecomeDC_state *s)
161 struct ldb_result *r;
162 struct ldb_dn *basedn;
163 static const char *attrs[] = {
168 basedn = ldb_dn_new(s, s->ldap1.ldb, NULL);
169 NT_STATUS_HAVE_NO_MEMORY(basedn);
171 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
172 "(objectClass=*)", attrs, &r);
174 if (ret != LDB_SUCCESS) {
175 return NT_STATUS_LDAP(ret);
176 } else if (r->count != 1) {
178 return NT_STATUS_INVALID_NETWORK_RESPONSE;
182 s->ldap1.rootdse = r->msgs[0];
184 s->domain.dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "defaultNamingContext", NULL);
185 if (!s->domain.dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
187 s->forest.root_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "rootDomainNamingContext", NULL);
188 if (!s->forest.root_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
189 s->forest.config_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "configurationNamingContext", NULL);
190 if (!s->forest.config_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
191 s->forest.schema_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "schemaNamingContext", NULL);
192 if (!s->forest.schema_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
194 s->source_dsa.server_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "serverName", NULL);
195 if (!s->source_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
196 s->source_dsa.ntds_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "dsServiceName", NULL);
197 if (!s->source_dsa.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
202 static NTSTATUS becomeDC_ldap1_crossref_behavior_version(struct libnet_BecomeDC_state *s)
205 struct ldb_result *r;
206 struct ldb_dn *basedn;
207 static const char *attrs[] = {
208 "msDs-Behavior-Version",
212 basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.config_dn_str);
213 NT_STATUS_HAVE_NO_MEMORY(basedn);
215 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_ONELEVEL,
216 "(cn=Partitions)", attrs, &r);
218 if (ret != LDB_SUCCESS) {
219 return NT_STATUS_LDAP(ret);
220 } else if (r->count != 1) {
222 return NT_STATUS_INVALID_NETWORK_RESPONSE;
225 s->forest.crossref_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
231 static NTSTATUS becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_state *s)
234 struct ldb_result *r;
235 struct ldb_dn *basedn;
236 static const char *attrs[] = {
237 "msDs-Behavior-Version",
241 basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
242 NT_STATUS_HAVE_NO_MEMORY(basedn);
244 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
245 "(objectClass=*)", attrs, &r);
247 if (ret != LDB_SUCCESS) {
248 return NT_STATUS_LDAP(ret);
249 } else if (r->count != 1) {
251 return NT_STATUS_INVALID_NETWORK_RESPONSE;
254 s->domain.behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
260 static NTSTATUS becomeDC_ldap1_schema_object_version(struct libnet_BecomeDC_state *s)
263 struct ldb_result *r;
264 struct ldb_dn *basedn;
265 static const char *attrs[] = {
270 basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.schema_dn_str);
271 NT_STATUS_HAVE_NO_MEMORY(basedn);
273 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
274 "(objectClass=*)", attrs, &r);
276 if (ret != LDB_SUCCESS) {
277 return NT_STATUS_LDAP(ret);
278 } else if (r->count != 1) {
280 return NT_STATUS_INVALID_NETWORK_RESPONSE;
283 s->forest.schema_object_version = ldb_msg_find_attr_as_uint(r->msgs[0], "objectVersion", 0);
289 static NTSTATUS becomeDC_ldap1_w2k3_update_revision(struct libnet_BecomeDC_state *s)
292 struct ldb_result *r;
293 struct ldb_dn *basedn;
294 static const char *attrs[] = {
299 basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=Windows2003Update,CN=DomainUpdates,CN=System,%s",
301 NT_STATUS_HAVE_NO_MEMORY(basedn);
303 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
304 "(objectClass=*)", attrs, &r);
306 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
307 /* w2k doesn't have this object */
308 s->domain.w2k3_update_revision = 0;
310 } else if (ret != LDB_SUCCESS) {
311 return NT_STATUS_LDAP(ret);
312 } else if (r->count != 1) {
314 return NT_STATUS_INVALID_NETWORK_RESPONSE;
317 s->domain.w2k3_update_revision = ldb_msg_find_attr_as_uint(r->msgs[0], "revision", 0);
323 static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state *s)
326 struct ldb_result *r;
327 struct ldb_dn *basedn;
328 struct ldb_dn *ntds_dn;
329 struct ldb_dn *server_dn;
330 static const char *_1_1_attrs[] = {
334 static const char *fsmo_attrs[] = {
338 static const char *dns_attrs[] = {
342 static const char *guid_attrs[] = {
347 basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "<WKGUID=2fbac1870ade11d297c400c04fd8d5cd,%s>",
349 NT_STATUS_HAVE_NO_MEMORY(basedn);
351 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
352 "(objectClass=*)", _1_1_attrs, &r);
354 if (ret != LDB_SUCCESS) {
355 return NT_STATUS_LDAP(ret);
356 } else if (r->count != 1) {
358 return NT_STATUS_INVALID_NETWORK_RESPONSE;
361 basedn = talloc_steal(s, r->msgs[0]->dn);
364 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
365 "(objectClass=*)", fsmo_attrs, &r);
367 if (ret != LDB_SUCCESS) {
368 return NT_STATUS_LDAP(ret);
369 } else if (r->count != 1) {
371 return NT_STATUS_INVALID_NETWORK_RESPONSE;
374 s->infrastructure_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
375 if (!s->infrastructure_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
376 talloc_steal(s, s->infrastructure_fsmo.ntds_dn_str);
380 ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->infrastructure_fsmo.ntds_dn_str);
381 NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
383 server_dn = ldb_dn_get_parent(s, ntds_dn);
384 NT_STATUS_HAVE_NO_MEMORY(server_dn);
386 s->infrastructure_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
387 NT_STATUS_HAVE_NO_MEMORY(s->infrastructure_fsmo.server_dn_str);
389 ret = ldb_search(s->ldap1.ldb, server_dn, LDB_SCOPE_BASE,
390 "(objectClass=*)", dns_attrs, &r);
391 if (ret != LDB_SUCCESS) {
392 return NT_STATUS_LDAP(ret);
393 } else if (r->count != 1) {
395 return NT_STATUS_INVALID_NETWORK_RESPONSE;
398 s->infrastructure_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL);
399 if (!s->infrastructure_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
400 talloc_steal(s, s->infrastructure_fsmo.dns_name);
404 ret = ldb_search(s->ldap1.ldb, ntds_dn, LDB_SCOPE_BASE,
405 "(objectClass=*)", guid_attrs, &r);
406 if (ret != LDB_SUCCESS) {
407 return NT_STATUS_LDAP(ret);
408 } else if (r->count != 1) {
410 return NT_STATUS_INVALID_NETWORK_RESPONSE;
413 s->infrastructure_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
420 static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s)
423 struct ldb_result *r;
424 struct ldb_dn *basedn;
425 const char *reference_dn_str;
426 struct ldb_dn *ntds_dn;
427 struct ldb_dn *server_dn;
428 static const char *rid_attrs[] = {
429 "rIDManagerReference",
432 static const char *fsmo_attrs[] = {
436 static const char *dns_attrs[] = {
440 static const char *guid_attrs[] = {
445 basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
446 NT_STATUS_HAVE_NO_MEMORY(basedn);
448 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
449 "(objectClass=*)", rid_attrs, &r);
451 if (ret != LDB_SUCCESS) {
452 return NT_STATUS_LDAP(ret);
453 } else if (r->count != 1) {
455 return NT_STATUS_INVALID_NETWORK_RESPONSE;
458 reference_dn_str = samdb_result_string(r->msgs[0], "rIDManagerReference", NULL);
459 if (!reference_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
461 basedn = ldb_dn_new(s, s->ldap1.ldb, reference_dn_str);
462 NT_STATUS_HAVE_NO_MEMORY(basedn);
466 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
467 "(objectClass=*)", fsmo_attrs, &r);
469 if (ret != LDB_SUCCESS) {
470 return NT_STATUS_LDAP(ret);
471 } else if (r->count != 1) {
473 return NT_STATUS_INVALID_NETWORK_RESPONSE;
476 s->rid_manager_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
477 if (!s->rid_manager_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
478 talloc_steal(s, s->rid_manager_fsmo.ntds_dn_str);
482 ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->rid_manager_fsmo.ntds_dn_str);
483 NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
485 server_dn = ldb_dn_get_parent(s, ntds_dn);
486 NT_STATUS_HAVE_NO_MEMORY(server_dn);
488 s->rid_manager_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
489 NT_STATUS_HAVE_NO_MEMORY(s->rid_manager_fsmo.server_dn_str);
491 ret = ldb_search(s->ldap1.ldb, server_dn, LDB_SCOPE_BASE,
492 "(objectClass=*)", dns_attrs, &r);
493 if (ret != LDB_SUCCESS) {
494 return NT_STATUS_LDAP(ret);
495 } else if (r->count != 1) {
497 return NT_STATUS_INVALID_NETWORK_RESPONSE;
500 s->rid_manager_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL);
501 if (!s->rid_manager_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
502 talloc_steal(s, s->rid_manager_fsmo.dns_name);
506 ret = ldb_search(s->ldap1.ldb, ntds_dn, LDB_SCOPE_BASE,
507 "(objectClass=*)", guid_attrs, &r);
508 if (ret != LDB_SUCCESS) {
509 return NT_STATUS_LDAP(ret);
510 } else if (r->count != 1) {
512 return NT_STATUS_INVALID_NETWORK_RESPONSE;
515 s->rid_manager_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
522 static NTSTATUS becomeDC_ldap1_site_object(struct libnet_BecomeDC_state *s)
525 struct ldb_result *r;
526 struct ldb_dn *basedn;
528 basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Sites,%s",
529 s->dest_dsa.site_name,
530 s->forest.config_dn_str);
531 NT_STATUS_HAVE_NO_MEMORY(basedn);
533 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
534 "(objectClass=*)", NULL, &r);
536 if (ret != LDB_SUCCESS) {
537 return NT_STATUS_LDAP(ret);
538 } else if (r->count != 1) {
540 return NT_STATUS_INVALID_NETWORK_RESPONSE;
543 s->dest_dsa.site_guid = samdb_result_guid(r->msgs[0], "objectGUID");
549 static NTSTATUS becomeDC_check_options(struct libnet_BecomeDC_state *s)
551 if (!s->callbacks.check_options) return NT_STATUS_OK;
553 s->_co.domain = &s->domain;
554 s->_co.forest = &s->forest;
555 s->_co.source_dsa = &s->source_dsa;
557 return s->callbacks.check_options(s->callbacks.private_data, &s->_co);
560 static NTSTATUS becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state *s)
563 struct ldb_result *r;
564 struct ldb_dn *basedn;
566 static const char *attrs[] = {
568 "userAccountControl",
572 basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
573 NT_STATUS_HAVE_NO_MEMORY(basedn);
575 filter = talloc_asprintf(basedn, "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))",
576 s->dest_dsa.netbios_name);
577 NT_STATUS_HAVE_NO_MEMORY(filter);
579 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_SUBTREE,
582 if (ret != LDB_SUCCESS) {
583 return NT_STATUS_LDAP(ret);
584 } else if (r->count != 1) {
586 return NT_STATUS_INVALID_NETWORK_RESPONSE;
589 s->dest_dsa.computer_dn_str = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
590 if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
591 talloc_steal(s, s->dest_dsa.computer_dn_str);
593 s->dest_dsa.user_account_control = samdb_result_uint(r->msgs[0], "userAccountControl", 0);
599 static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s)
602 struct ldb_result *r;
603 struct ldb_dn *basedn;
604 const char *server_reference_dn_str;
605 struct ldb_dn *server_reference_dn;
606 struct ldb_dn *computer_dn;
608 basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
609 s->dest_dsa.netbios_name,
610 s->dest_dsa.site_name,
611 s->forest.config_dn_str);
612 NT_STATUS_HAVE_NO_MEMORY(basedn);
614 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
615 "(objectClass=*)", NULL, &r);
617 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
618 /* if the object doesn't exist, we'll create it later */
620 } else if (ret != LDB_SUCCESS) {
621 return NT_STATUS_LDAP(ret);
622 } else if (r->count != 1) {
624 return NT_STATUS_INVALID_NETWORK_RESPONSE;
627 server_reference_dn_str = samdb_result_string(r->msgs[0], "serverReference", NULL);
628 if (server_reference_dn_str) {
629 server_reference_dn = ldb_dn_new(r, s->ldap1.ldb, server_reference_dn_str);
630 NT_STATUS_HAVE_NO_MEMORY(server_reference_dn);
632 computer_dn = ldb_dn_new(r, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
633 NT_STATUS_HAVE_NO_MEMORY(computer_dn);
636 * if the server object belongs to another DC in another domain in the forest,
637 * we should not touch this object!
639 if (ldb_dn_compare(computer_dn, server_reference_dn) != 0) {
641 return NT_STATUS_OBJECT_NAME_COLLISION;
645 /* if the server object is already for the dest_dsa, then we don't need to create it */
646 s->dest_dsa.server_dn_str = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
647 if (!s->dest_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
648 talloc_steal(s, s->dest_dsa.server_dn_str);
654 static NTSTATUS becomeDC_ldap1_server_object_2(struct libnet_BecomeDC_state *s)
657 struct ldb_result *r;
658 struct ldb_dn *basedn;
659 const char *server_reference_bl_dn_str;
660 static const char *attrs[] = {
665 /* if the server_dn_str has a valid value, we skip this lookup */
666 if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
668 basedn = ldb_dn_new(s, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
669 NT_STATUS_HAVE_NO_MEMORY(basedn);
671 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
672 "(objectClass=*)", attrs, &r);
674 if (ret != LDB_SUCCESS) {
675 return NT_STATUS_LDAP(ret);
676 } else if (r->count != 1) {
678 return NT_STATUS_INVALID_NETWORK_RESPONSE;
681 server_reference_bl_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL);
682 if (!server_reference_bl_dn_str) {
683 /* if no back link is present, we're done for this function */
688 /* if the server object is already for the dest_dsa, then we don't need to create it */
689 s->dest_dsa.server_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL);
690 if (s->dest_dsa.server_dn_str) {
691 /* if a back link is present, we know that the server object is present */
692 talloc_steal(s, s->dest_dsa.server_dn_str);
699 static NTSTATUS becomeDC_ldap1_server_object_add(struct libnet_BecomeDC_state *s)
702 struct ldb_message *msg;
705 /* if the server_dn_str has a valid value, we skip this lookup */
706 if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
708 msg = ldb_msg_new(s);
709 NT_STATUS_HAVE_NO_MEMORY(msg);
711 msg->dn = ldb_dn_new_fmt(msg, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
712 s->dest_dsa.netbios_name,
713 s->dest_dsa.site_name,
714 s->forest.config_dn_str);
715 NT_STATUS_HAVE_NO_MEMORY(msg->dn);
717 ret = ldb_msg_add_string(msg, "objectClass", "server");
720 return NT_STATUS_NO_MEMORY;
722 ret = ldb_msg_add_string(msg, "systemFlags", "50000000");
725 return NT_STATUS_NO_MEMORY;
727 ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
730 return NT_STATUS_NO_MEMORY;
733 server_dn_str = ldb_dn_alloc_linearized(s, msg->dn);
734 NT_STATUS_HAVE_NO_MEMORY(server_dn_str);
736 ret = ldb_add(s->ldap1.ldb, msg);
738 if (ret != LDB_SUCCESS) {
739 talloc_free(server_dn_str);
740 return NT_STATUS_LDAP(ret);
743 s->dest_dsa.server_dn_str = server_dn_str;
748 static NTSTATUS becomeDC_ldap1_server_object_modify(struct libnet_BecomeDC_state *s)
751 struct ldb_message *msg;
754 /* make a 'modify' msg, and only for serverReference */
755 msg = ldb_msg_new(s);
756 NT_STATUS_HAVE_NO_MEMORY(msg);
757 msg->dn = ldb_dn_new(msg, s->ldap1.ldb, s->dest_dsa.server_dn_str);
758 NT_STATUS_HAVE_NO_MEMORY(msg->dn);
760 ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
763 return NT_STATUS_NO_MEMORY;
766 /* mark all the message elements (should be just one)
767 as LDB_FLAG_MOD_ADD */
768 for (i=0;i<msg->num_elements;i++) {
769 msg->elements[i].flags = LDB_FLAG_MOD_ADD;
772 ret = ldb_modify(s->ldap1.ldb, msg);
773 if (ret == LDB_SUCCESS) {
776 } else if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
777 /* retry with LDB_FLAG_MOD_REPLACE */
780 return NT_STATUS_LDAP(ret);
783 /* mark all the message elements (should be just one)
784 as LDB_FLAG_MOD_REPLACE */
785 for (i=0;i<msg->num_elements;i++) {
786 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
789 ret = ldb_modify(s->ldap1.ldb, msg);
791 if (ret != LDB_SUCCESS) {
792 return NT_STATUS_LDAP(ret);
798 static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
799 struct becomeDC_drsuapi *drsuapi,
800 void (*recv_fn)(struct composite_context *req));
801 static void becomeDC_drsuapi1_connect_recv(struct composite_context *req);
802 static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s);
804 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s)
806 struct composite_context *c = s->creq;
808 c->status = becomeDC_ldap_connect(s, &s->ldap1);
809 if (!composite_is_ok(c)) return;
811 c->status = becomeDC_ldap1_rootdse(s);
812 if (!composite_is_ok(c)) return;
814 c->status = becomeDC_ldap1_crossref_behavior_version(s);
815 if (!composite_is_ok(c)) return;
817 c->status = becomeDC_ldap1_domain_behavior_version(s);
818 if (!composite_is_ok(c)) return;
820 c->status = becomeDC_ldap1_schema_object_version(s);
821 if (!composite_is_ok(c)) return;
823 c->status = becomeDC_ldap1_w2k3_update_revision(s);
824 if (!composite_is_ok(c)) return;
826 c->status = becomeDC_ldap1_infrastructure_fsmo(s);
827 if (!composite_is_ok(c)) return;
829 c->status = becomeDC_ldap1_rid_manager_fsmo(s);
830 if (!composite_is_ok(c)) return;
832 c->status = becomeDC_ldap1_site_object(s);
833 if (!composite_is_ok(c)) return;
835 c->status = becomeDC_check_options(s);
836 if (!composite_is_ok(c)) return;
838 c->status = becomeDC_ldap1_computer_object(s);
839 if (!composite_is_ok(c)) return;
841 c->status = becomeDC_ldap1_server_object_1(s);
842 if (!composite_is_ok(c)) return;
844 c->status = becomeDC_ldap1_server_object_2(s);
845 if (!composite_is_ok(c)) return;
847 c->status = becomeDC_ldap1_server_object_add(s);
848 if (!composite_is_ok(c)) return;
850 c->status = becomeDC_ldap1_server_object_modify(s);
851 if (!composite_is_ok(c)) return;
853 becomeDC_drsuapi_connect_send(s, &s->drsuapi1, becomeDC_drsuapi1_connect_recv);
856 static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
857 struct becomeDC_drsuapi *drsuapi,
858 void (*recv_fn)(struct composite_context *req))
860 struct composite_context *c = s->creq;
861 struct composite_context *creq;
866 if (!drsuapi->binding) {
867 binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[krb5,seal]", s->source_dsa.dns_name);
868 if (composite_nomem(binding_str, c)) return;
870 c->status = dcerpc_parse_binding(s, binding_str, &drsuapi->binding);
871 talloc_free(binding_str);
872 if (!composite_is_ok(c)) return;
875 creq = dcerpc_pipe_connect_b_send(s, drsuapi->binding, &dcerpc_table_drsuapi,
876 s->libnet->cred, s->libnet->event_ctx);
877 composite_continue(c, creq, recv_fn, s);
880 static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
881 struct becomeDC_drsuapi *drsuapi,
882 void (*recv_fn)(struct rpc_request *req));
883 static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req);
885 static void becomeDC_drsuapi1_connect_recv(struct composite_context *req)
887 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
888 struct libnet_BecomeDC_state);
889 struct composite_context *c = s->creq;
891 c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi1.pipe);
892 if (!composite_is_ok(c)) return;
894 becomeDC_drsuapi_bind_send(s, &s->drsuapi1, becomeDC_drsuapi1_bind_recv);
897 static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
898 struct becomeDC_drsuapi *drsuapi,
899 void (*recv_fn)(struct rpc_request *req))
901 struct composite_context *c = s->creq;
902 struct rpc_request *req;
903 struct drsuapi_DsBindInfo28 *bind_info28;
905 GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &drsuapi->bind_guid);
907 bind_info28 = &drsuapi->local_info28;
908 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
909 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
910 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
911 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
912 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
913 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
914 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
915 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
916 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
917 if (s->domain.behavior_version == 2) {
918 /* TODO: find out how this is really triggered! */
919 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
921 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
922 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
923 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
924 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
925 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
926 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
927 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
928 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
929 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
930 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_00100000;
931 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
932 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
933 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
934 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
935 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
936 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
937 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
938 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
939 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
940 #if 0 /* we don't support XPRESS compression yet */
941 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
943 bind_info28->site_guid = s->dest_dsa.site_guid;
944 if (s->domain.behavior_version == 2) {
945 /* TODO: find out how this is really triggered! */
946 bind_info28->u1 = 528;
948 bind_info28->u1 = 516;
950 bind_info28->repl_epoch = 0;
952 drsuapi->bind_info_ctr.length = 28;
953 drsuapi->bind_info_ctr.info.info28 = *bind_info28;
955 drsuapi->bind_r.in.bind_guid = &drsuapi->bind_guid;
956 drsuapi->bind_r.in.bind_info = &drsuapi->bind_info_ctr;
957 drsuapi->bind_r.out.bind_handle = &drsuapi->bind_handle;
959 req = dcerpc_drsuapi_DsBind_send(drsuapi->pipe, s, &drsuapi->bind_r);
960 composite_continue_rpc(c, req, recv_fn, s);
963 static WERROR becomeDC_drsuapi_bind_recv(struct libnet_BecomeDC_state *s,
964 struct becomeDC_drsuapi *drsuapi)
966 if (!W_ERROR_IS_OK(drsuapi->bind_r.out.result)) {
967 return drsuapi->bind_r.out.result;
970 ZERO_STRUCT(drsuapi->remote_info28);
971 if (drsuapi->bind_r.out.bind_info) {
972 switch (drsuapi->bind_r.out.bind_info->length) {
974 struct drsuapi_DsBindInfo24 *info24;
975 info24 = &drsuapi->bind_r.out.bind_info->info.info24;
976 drsuapi->remote_info28.supported_extensions = info24->supported_extensions;
977 drsuapi->remote_info28.site_guid = info24->site_guid;
978 drsuapi->remote_info28.u1 = info24->u1;
979 drsuapi->remote_info28.repl_epoch = 0;
983 drsuapi->remote_info28 = drsuapi->bind_r.out.bind_info->info.info28;
991 static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s);
993 static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req)
995 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
996 struct libnet_BecomeDC_state);
997 struct composite_context *c = s->creq;
1000 c->status = dcerpc_ndr_request_recv(req);
1001 if (!composite_is_ok(c)) return;
1003 status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi1);
1004 if (!W_ERROR_IS_OK(status)) {
1005 composite_error(c, werror_to_ntstatus(status));
1009 becomeDC_drsuapi1_add_entry_send(s);
1012 static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req);
1014 static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
1016 struct composite_context *c = s->creq;
1017 struct rpc_request *req;
1018 struct drsuapi_DsAddEntry *r;
1019 struct drsuapi_DsReplicaObjectIdentifier *identifier;
1020 uint32_t num_attrs, i = 0;
1021 struct drsuapi_DsReplicaAttribute *attrs;
1024 /* choose a random invocationId */
1025 s->dest_dsa.invocation_id = GUID_random();
1028 * if the schema version indicates w2k3, then
1029 * also send some w2k3 specific attributes
1031 if (s->forest.schema_object_version >= 30) {
1037 r = talloc_zero(s, struct drsuapi_DsAddEntry);
1038 if (composite_nomem(r, c)) return;
1040 /* setup identifier */
1041 identifier = talloc(r, struct drsuapi_DsReplicaObjectIdentifier);
1042 if (composite_nomem(identifier, c)) return;
1043 identifier->guid = GUID_zero();
1044 identifier->sid = s->zero_sid;
1045 identifier->dn = talloc_asprintf(identifier, "CN=NTDS Settings,%s",
1046 s->dest_dsa.server_dn_str);
1047 if (composite_nomem(identifier->dn, c)) return;
1049 /* allocate attribute array */
1051 attrs = talloc_array(r, struct drsuapi_DsReplicaAttribute, num_attrs);
1052 if (composite_nomem(attrs, c)) return;
1054 /* ntSecurityDescriptor */
1056 struct drsuapi_DsAttributeValue *vs;
1058 struct security_descriptor *v;
1059 struct dom_sid *domain_admins_sid;
1060 const char *domain_admins_sid_str;
1062 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1063 if (composite_nomem(vs, c)) return;
1065 vd = talloc_array(vs, DATA_BLOB, 1);
1066 if (composite_nomem(vd, c)) return;
1068 domain_admins_sid = dom_sid_add_rid(vs, s->domain.sid, DOMAIN_RID_ADMINS);
1069 if (composite_nomem(domain_admins_sid, c)) return;
1071 domain_admins_sid_str = dom_sid_string(domain_admins_sid, domain_admins_sid);
1072 if (composite_nomem(domain_admins_sid_str, c)) return;
1074 v = security_descriptor_create(vd,
1075 /* owner: domain admins */
1076 domain_admins_sid_str,
1077 /* owner group: domain admins */
1078 domain_admins_sid_str,
1079 /* authenticated users */
1080 SID_NT_AUTHENTICATED_USERS,
1081 SEC_ACE_TYPE_ACCESS_ALLOWED,
1082 SEC_STD_READ_CONTROL |
1085 SEC_ADS_LIST_OBJECT,
1088 domain_admins_sid_str,
1089 SEC_ACE_TYPE_ACCESS_ALLOWED,
1091 SEC_ADS_CREATE_CHILD |
1093 SEC_ADS_SELF_WRITE |
1095 SEC_ADS_WRITE_PROP |
1096 SEC_ADS_DELETE_TREE |
1097 SEC_ADS_LIST_OBJECT |
1098 SEC_ADS_CONTROL_ACCESS,
1102 SEC_ACE_TYPE_ACCESS_ALLOWED,
1104 SEC_ADS_CREATE_CHILD |
1105 SEC_ADS_DELETE_CHILD |
1107 SEC_ADS_SELF_WRITE |
1109 SEC_ADS_WRITE_PROP |
1110 SEC_ADS_DELETE_TREE |
1111 SEC_ADS_LIST_OBJECT |
1112 SEC_ADS_CONTROL_ACCESS,
1116 if (composite_nomem(v, c)) return;
1118 c->status = ndr_push_struct_blob(&vd[0], vd, v,(ndr_push_flags_fn_t)ndr_push_security_descriptor);
1119 if (!composite_is_ok(c)) return;
1121 vs[0].blob = &vd[0];
1123 attrs[i].attid = DRSUAPI_ATTRIBUTE_ntSecurityDescriptor;
1124 attrs[i].value_ctr.num_values = 1;
1125 attrs[i].value_ctr.values = vs;
1130 /* objectClass: nTDSDSA */
1132 struct drsuapi_DsAttributeValue *vs;
1135 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1136 if (composite_nomem(vs, c)) return;
1138 vd = talloc_array(vs, DATA_BLOB, 1);
1139 if (composite_nomem(vd, c)) return;
1141 vd[0] = data_blob_talloc(vd, NULL, 4);
1142 if (composite_nomem(vd[0].data, c)) return;
1144 /* value for nTDSDSA */
1145 SIVAL(vd[0].data, 0, 0x0017002F);
1147 vs[0].blob = &vd[0];
1149 attrs[i].attid = DRSUAPI_ATTRIBUTE_objectClass;
1150 attrs[i].value_ctr.num_values = 1;
1151 attrs[i].value_ctr.values = vs;
1156 /* objectCategory: CN=NTDS-DSA,CN=Schema,... */
1158 struct drsuapi_DsAttributeValue *vs;
1160 struct drsuapi_DsReplicaObjectIdentifier3 v[1];
1162 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1163 if (composite_nomem(vs, c)) return;
1165 vd = talloc_array(vs, DATA_BLOB, 1);
1166 if (composite_nomem(vd, c)) return;
1168 v[0].guid = GUID_zero();
1169 v[0].sid = s->zero_sid;
1170 v[0].dn = talloc_asprintf(vd, "CN=NTDS-DSA,%s",
1171 s->forest.schema_dn_str);
1172 if (composite_nomem(v->dn, c)) return;
1174 c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
1175 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1176 if (!composite_is_ok(c)) return;
1178 vs[0].blob = &vd[0];
1180 attrs[i].attid = DRSUAPI_ATTRIBUTE_objectCategory;
1181 attrs[i].value_ctr.num_values = 1;
1182 attrs[i].value_ctr.values = vs;
1187 /* invocationId: random guid */
1189 struct drsuapi_DsAttributeValue *vs;
1191 const struct GUID *v;
1193 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1194 if (composite_nomem(vs, c)) return;
1196 vd = talloc_array(vs, DATA_BLOB, 1);
1197 if (composite_nomem(vd, c)) return;
1199 v = &s->dest_dsa.invocation_id;
1201 c->status = ndr_push_struct_blob(&vd[0], vd, v, (ndr_push_flags_fn_t)ndr_push_GUID);
1202 if (!composite_is_ok(c)) return;
1204 vs[0].blob = &vd[0];
1206 attrs[i].attid = DRSUAPI_ATTRIBUTE_invocationId;
1207 attrs[i].value_ctr.num_values = 1;
1208 attrs[i].value_ctr.values = vs;
1213 /* hasMasterNCs: ... */
1215 struct drsuapi_DsAttributeValue *vs;
1217 struct drsuapi_DsReplicaObjectIdentifier3 v[3];
1219 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 3);
1220 if (composite_nomem(vs, c)) return;
1222 vd = talloc_array(vs, DATA_BLOB, 3);
1223 if (composite_nomem(vd, c)) return;
1225 v[0].guid = GUID_zero();
1226 v[0].sid = s->zero_sid;
1227 v[0].dn = s->forest.config_dn_str;
1229 v[1].guid = GUID_zero();
1230 v[1].sid = s->zero_sid;
1231 v[1].dn = s->domain.dn_str;
1233 v[2].guid = GUID_zero();
1234 v[2].sid = s->zero_sid;
1235 v[2].dn = s->forest.schema_dn_str;
1237 c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
1238 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1239 if (!composite_is_ok(c)) return;
1241 c->status = ndr_push_struct_blob(&vd[1], vd, &v[1],
1242 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1243 if (!composite_is_ok(c)) return;
1245 c->status = ndr_push_struct_blob(&vd[2], vd, &v[2],
1246 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1247 if (!composite_is_ok(c)) return;
1249 vs[0].blob = &vd[0];
1250 vs[1].blob = &vd[1];
1251 vs[2].blob = &vd[2];
1253 attrs[i].attid = DRSUAPI_ATTRIBUTE_hasMasterNCs;
1254 attrs[i].value_ctr.num_values = 3;
1255 attrs[i].value_ctr.values = vs;
1260 /* msDS-hasMasterNCs: ... */
1262 struct drsuapi_DsAttributeValue *vs;
1264 struct drsuapi_DsReplicaObjectIdentifier3 v[3];
1266 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 3);
1267 if (composite_nomem(vs, c)) return;
1269 vd = talloc_array(vs, DATA_BLOB, 3);
1270 if (composite_nomem(vd, c)) return;
1272 v[0].guid = GUID_zero();
1273 v[0].sid = s->zero_sid;
1274 v[0].dn = s->forest.config_dn_str;
1276 v[1].guid = GUID_zero();
1277 v[1].sid = s->zero_sid;
1278 v[1].dn = s->domain.dn_str;
1280 v[2].guid = GUID_zero();
1281 v[2].sid = s->zero_sid;
1282 v[2].dn = s->forest.schema_dn_str;
1284 c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
1285 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1286 if (!composite_is_ok(c)) return;
1288 c->status = ndr_push_struct_blob(&vd[1], vd, &v[1],
1289 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1290 if (!composite_is_ok(c)) return;
1292 c->status = ndr_push_struct_blob(&vd[2], vd, &v[2],
1293 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1294 if (!composite_is_ok(c)) return;
1296 vs[0].blob = &vd[0];
1297 vs[1].blob = &vd[1];
1298 vs[2].blob = &vd[2];
1300 attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs;
1301 attrs[i].value_ctr.num_values = 3;
1302 attrs[i].value_ctr.values = vs;
1307 /* dMDLocation: CN=Schema,... */
1309 struct drsuapi_DsAttributeValue *vs;
1311 struct drsuapi_DsReplicaObjectIdentifier3 v[1];
1313 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1314 if (composite_nomem(vs, c)) return;
1316 vd = talloc_array(vs, DATA_BLOB, 1);
1317 if (composite_nomem(vd, c)) return;
1319 v[0].guid = GUID_zero();
1320 v[0].sid = s->zero_sid;
1321 v[0].dn = s->forest.schema_dn_str;
1323 c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
1324 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1325 if (!composite_is_ok(c)) return;
1327 vs[0].blob = &vd[0];
1329 attrs[i].attid = DRSUAPI_ATTRIBUTE_dMDLocation;
1330 attrs[i].value_ctr.num_values = 1;
1331 attrs[i].value_ctr.values = vs;
1336 /* msDS-HasDomainNCs: <domain_partition> */
1338 struct drsuapi_DsAttributeValue *vs;
1340 struct drsuapi_DsReplicaObjectIdentifier3 v[1];
1342 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1343 if (composite_nomem(vs, c)) return;
1345 vd = talloc_array(vs, DATA_BLOB, 1);
1346 if (composite_nomem(vd, c)) return;
1348 v[0].guid = GUID_zero();
1349 v[0].sid = s->zero_sid;
1350 v[0].dn = s->domain.dn_str;
1352 c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
1353 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1354 if (!composite_is_ok(c)) return;
1356 vs[0].blob = &vd[0];
1358 attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs;
1359 attrs[i].value_ctr.num_values = 1;
1360 attrs[i].value_ctr.values = vs;
1365 /* msDS-Behavior-Version */
1367 struct drsuapi_DsAttributeValue *vs;
1370 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1371 if (composite_nomem(vs, c)) return;
1373 vd = talloc_array(vs, DATA_BLOB, 1);
1374 if (composite_nomem(vd, c)) return;
1376 vd[0] = data_blob_talloc(vd, NULL, 4);
1377 if (composite_nomem(vd[0].data, c)) return;
1379 SIVAL(vd[0].data, 0, DS_BEHAVIOR_WIN2003);
1381 vs[0].blob = &vd[0];
1383 attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_Behavior_Version;
1384 attrs[i].value_ctr.num_values = 1;
1385 attrs[i].value_ctr.values = vs;
1392 struct drsuapi_DsAttributeValue *vs;
1395 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1396 if (composite_nomem(vs, c)) return;
1398 vd = talloc_array(vs, DATA_BLOB, 1);
1399 if (composite_nomem(vd, c)) return;
1401 vd[0] = data_blob_talloc(vd, NULL, 4);
1402 if (composite_nomem(vd[0].data, c)) return;
1404 SIVAL(vd[0].data, 0, SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
1406 vs[0].blob = &vd[0];
1408 attrs[i].attid = DRSUAPI_ATTRIBUTE_systemFlags;
1409 attrs[i].value_ctr.num_values = 1;
1410 attrs[i].value_ctr.values = vs;
1415 /* serverReference: ... */
1417 struct drsuapi_DsAttributeValue *vs;
1419 struct drsuapi_DsReplicaObjectIdentifier3 v[1];
1421 vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1);
1422 if (composite_nomem(vs, c)) return;
1424 vd = talloc_array(vs, DATA_BLOB, 1);
1425 if (composite_nomem(vd, c)) return;
1427 v[0].guid = GUID_zero();
1428 v[0].sid = s->zero_sid;
1429 v[0].dn = s->dest_dsa.computer_dn_str;
1431 c->status = ndr_push_struct_blob(&vd[0], vd, &v[0],
1432 (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
1433 if (!composite_is_ok(c)) return;
1435 vs[0].blob = &vd[0];
1437 attrs[i].attid = DRSUAPI_ATTRIBUTE_serverReference;
1438 attrs[i].value_ctr.num_values = 1;
1439 attrs[i].value_ctr.values = vs;
1444 /* truncate the attribute list to the attribute count we have filled in */
1447 /* setup request structure */
1448 r->in.bind_handle = &s->drsuapi1.bind_handle;
1450 r->in.req.req2.first_object.next_object = NULL;
1451 r->in.req.req2.first_object.object.identifier = identifier;
1452 r->in.req.req2.first_object.object.unknown1 = 0x00000000;
1453 r->in.req.req2.first_object.object.attribute_ctr.num_attributes = num_attrs;
1454 r->in.req.req2.first_object.object.attribute_ctr.attributes = attrs;
1456 req = dcerpc_drsuapi_DsAddEntry_send(s->drsuapi1.pipe, r, r);
1457 composite_continue_rpc(c, req, becomeDC_drsuapi1_add_entry_recv, s);
1460 static void becomeDC_drsuapi2_connect_recv(struct composite_context *req);
1461 static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s);
1463 static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req)
1465 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1466 struct libnet_BecomeDC_state);
1467 struct composite_context *c = s->creq;
1468 struct drsuapi_DsAddEntry *r = talloc_get_type(req->ndr.struct_ptr,
1469 struct drsuapi_DsAddEntry);
1471 c->status = dcerpc_ndr_request_recv(req);
1472 if (!composite_is_ok(c)) return;
1474 if (!W_ERROR_IS_OK(r->out.result)) {
1475 composite_error(c, werror_to_ntstatus(r->out.result));
1479 if (r->out.level == 3) {
1480 if (r->out.ctr.ctr3.count != 1) {
1483 if (r->out.ctr.ctr3.level != 1) {
1484 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
1488 if (!r->out.ctr.ctr3.error) {
1489 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
1493 status = r->out.ctr.ctr3.error->info1.status;
1495 if (!r->out.ctr.ctr3.error->info1.info) {
1496 composite_error(c, werror_to_ntstatus(status));
1500 /* see if we can get a more detailed error */
1501 switch (r->out.ctr.ctr3.error->info1.level) {
1503 status = r->out.ctr.ctr3.error->info1.info->error1.status;
1509 status = r->out.ctr.ctr3.error->info1.info->errorX.status;
1513 composite_error(c, werror_to_ntstatus(status));
1517 s->dest_dsa.ntds_guid = r->out.ctr.ctr3.objects[0].guid;
1518 } else if (r->out.level == 2) {
1519 if (r->out.ctr.ctr2.count != 1) {
1520 composite_error(c, werror_to_ntstatus(r->out.ctr.ctr2.error.status));
1524 s->dest_dsa.ntds_guid = r->out.ctr.ctr2.objects[0].guid;
1526 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
1532 s->dest_dsa.ntds_dn_str = talloc_asprintf(s, "CN=NTDS Settings,%s",
1533 s->dest_dsa.server_dn_str);
1534 if (composite_nomem(s->dest_dsa.ntds_dn_str, c)) return;
1536 c->status = becomeDC_prepare_db(s);
1537 if (!composite_is_ok(c)) return;
1539 becomeDC_drsuapi_connect_send(s, &s->drsuapi2, becomeDC_drsuapi2_connect_recv);
1542 static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s)
1544 if (!s->callbacks.prepare_db) return NT_STATUS_OK;
1546 s->_pp.domain = &s->domain;
1547 s->_pp.forest = &s->forest;
1548 s->_pp.source_dsa = &s->source_dsa;
1549 s->_pp.dest_dsa = &s->dest_dsa;
1551 return s->callbacks.prepare_db(s->callbacks.private_data, &s->_pp);
1554 static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req);
1556 static void becomeDC_drsuapi2_connect_recv(struct composite_context *req)
1558 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
1559 struct libnet_BecomeDC_state);
1560 struct composite_context *c = s->creq;
1562 c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi2.pipe);
1563 if (!composite_is_ok(c)) return;
1565 becomeDC_drsuapi_bind_send(s, &s->drsuapi2, becomeDC_drsuapi2_bind_recv);
1568 static void becomeDC_drsuapi3_connect_recv(struct composite_context *req);
1570 static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req)
1572 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1573 struct libnet_BecomeDC_state);
1574 struct composite_context *c = s->creq;
1578 c->status = dcerpc_ndr_request_recv(req);
1579 if (!composite_is_ok(c)) return;
1581 status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi2);
1582 if (!W_ERROR_IS_OK(status)) {
1583 composite_error(c, werror_to_ntstatus(status));
1587 /* this avoids the epmapper lookup on the 2nd connection */
1588 binding_str = dcerpc_binding_string(s, s->drsuapi2.binding);
1589 if (composite_nomem(binding_str, c)) return;
1591 c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi3.binding);
1592 talloc_free(binding_str);
1593 if (!composite_is_ok(c)) return;
1595 becomeDC_drsuapi_connect_send(s, &s->drsuapi3, becomeDC_drsuapi3_connect_recv);
1598 static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s);
1600 static void becomeDC_drsuapi3_connect_recv(struct composite_context *req)
1602 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
1603 struct libnet_BecomeDC_state);
1604 struct composite_context *c = s->creq;
1606 c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi3.pipe);
1607 if (!composite_is_ok(c)) return;
1609 becomeDC_drsuapi3_pull_schema_send(s);
1612 static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s,
1613 struct becomeDC_drsuapi *drsuapi_h,
1614 struct becomeDC_drsuapi *drsuapi_p,
1615 struct libnet_BecomeDC_Partition *partition,
1616 void (*recv_fn)(struct rpc_request *req))
1618 struct composite_context *c = s->creq;
1619 struct rpc_request *req;
1620 struct drsuapi_DsGetNCChanges *r;
1622 r = talloc(s, struct drsuapi_DsGetNCChanges);
1623 if (composite_nomem(r, c)) return;
1625 r->in.level = talloc(r, int32_t);
1626 if (composite_nomem(r->in.level, c)) return;
1627 r->out.level = talloc(r, int32_t);
1628 if (composite_nomem(r->out.level, c)) return;
1630 r->in.bind_handle = &drsuapi_h->bind_handle;
1631 if (drsuapi_h->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
1633 r->in.req.req8.destination_dsa_guid = partition->destination_dsa_guid;
1634 r->in.req.req8.source_dsa_invocation_id = partition->source_dsa_invocation_id;
1635 r->in.req.req8.naming_context = &partition->nc;
1636 r->in.req.req8.highwatermark = partition->highwatermark;
1637 r->in.req.req8.uptodateness_vector = NULL;
1638 r->in.req.req8.replica_flags = partition->replica_flags;
1639 r->in.req.req8.max_object_count = 133;
1640 r->in.req.req8.max_ndr_size = 1336811;
1641 r->in.req.req8.unknown4 = 0;
1642 r->in.req.req8.h1 = 0;
1643 r->in.req.req8.unique_ptr1 = 0;
1644 r->in.req.req8.unique_ptr2 = 0;
1645 r->in.req.req8.mapping_ctr.num_mappings = 0;
1646 r->in.req.req8.mapping_ctr.mappings = NULL;
1649 r->in.req.req5.destination_dsa_guid = partition->destination_dsa_guid;
1650 r->in.req.req5.source_dsa_invocation_id = partition->source_dsa_invocation_id;
1651 r->in.req.req5.naming_context = &partition->nc;
1652 r->in.req.req5.highwatermark = partition->highwatermark;
1653 r->in.req.req5.uptodateness_vector = NULL;
1654 r->in.req.req5.replica_flags = partition->replica_flags;
1655 r->in.req.req5.max_object_count = 133;
1656 r->in.req.req5.max_ndr_size = 1336770;
1657 r->in.req.req5.unknown4 = 0;
1658 r->in.req.req5.h1 = 0;
1662 * we should try to use the drsuapi_p->pipe here, as w2k3 does
1663 * but it seems that some extra flags in the DCERPC Bind call
1664 * are needed for it. Or the same KRB5 TGS is needed on both
1667 req = dcerpc_drsuapi_DsGetNCChanges_send(drsuapi_h->pipe, r, r);
1668 composite_continue_rpc(c, req, recv_fn, s);
1671 static WERROR becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state *s,
1672 struct libnet_BecomeDC_Partition *partition,
1673 struct drsuapi_DsGetNCChanges *r)
1675 uint32_t ctr_level = 0;
1676 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
1677 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
1678 struct GUID *source_dsa_guid;
1679 struct GUID *source_dsa_invocation_id;
1680 struct drsuapi_DsReplicaHighWaterMark *new_highwatermark;
1683 if (!W_ERROR_IS_OK(r->out.result)) {
1684 return r->out.result;
1687 if (*r->out.level == 1) {
1689 ctr1 = &r->out.ctr.ctr1;
1690 } else if (*r->out.level == 2) {
1692 ctr1 = r->out.ctr.ctr2.ctr.mszip1.ctr1;
1693 } else if (*r->out.level == 6) {
1695 ctr6 = &r->out.ctr.ctr6;
1696 } else if (*r->out.level == 7 &&
1697 r->out.ctr.ctr7.level == 6 &&
1698 r->out.ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP) {
1700 ctr6 = r->out.ctr.ctr7.ctr.mszip6.ctr6;
1702 return WERR_BAD_NET_RESP;
1705 switch (ctr_level) {
1707 source_dsa_guid = &ctr1->source_dsa_guid;
1708 source_dsa_invocation_id = &ctr1->source_dsa_invocation_id;
1709 new_highwatermark = &ctr1->new_highwatermark;
1712 source_dsa_guid = &ctr6->source_dsa_guid;
1713 source_dsa_invocation_id = &ctr6->source_dsa_invocation_id;
1714 new_highwatermark = &ctr6->new_highwatermark;
1718 partition->highwatermark = *new_highwatermark;
1719 partition->source_dsa_guid = *source_dsa_guid;
1720 partition->source_dsa_invocation_id = *source_dsa_invocation_id;
1722 if (!partition->store_chunk) return WERR_OK;
1724 s->_sc.domain = &s->domain;
1725 s->_sc.forest = &s->forest;
1726 s->_sc.source_dsa = &s->source_dsa;
1727 s->_sc.dest_dsa = &s->dest_dsa;
1728 s->_sc.partition = partition;
1729 s->_sc.ctr_level = ctr_level;
1733 nt_status = partition->store_chunk(s->callbacks.private_data, &s->_sc);
1734 if (!NT_STATUS_IS_OK(nt_status)) {
1735 return ntstatus_to_werror(nt_status);
1741 static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req);
1743 static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s)
1745 s->schema_part.nc.guid = GUID_zero();
1746 s->schema_part.nc.sid = s->zero_sid;
1747 s->schema_part.nc.dn = s->forest.schema_dn_str;
1749 s->schema_part.destination_dsa_guid = s->drsuapi2.bind_guid;
1751 s->schema_part.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
1752 | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
1753 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
1754 | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
1755 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
1756 | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
1758 s->schema_part.store_chunk = s->callbacks.schema_chunk;
1760 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part,
1761 becomeDC_drsuapi3_pull_schema_recv);
1764 static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s);
1766 static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req)
1768 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1769 struct libnet_BecomeDC_state);
1770 struct composite_context *c = s->creq;
1771 struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
1772 struct drsuapi_DsGetNCChanges);
1775 c->status = dcerpc_ndr_request_recv(req);
1776 if (!composite_is_ok(c)) return;
1778 status = becomeDC_drsuapi_pull_partition_recv(s, &s->schema_part, r);
1779 if (!W_ERROR_IS_OK(status)) {
1780 composite_error(c, werror_to_ntstatus(status));
1786 if (s->schema_part.highwatermark.tmp_highest_usn > s->schema_part.highwatermark.highest_usn) {
1787 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part,
1788 becomeDC_drsuapi3_pull_schema_recv);
1792 becomeDC_drsuapi3_pull_config_send(s);
1795 static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req);
1797 static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s)
1799 s->config_part.nc.guid = GUID_zero();
1800 s->config_part.nc.sid = s->zero_sid;
1801 s->config_part.nc.dn = s->forest.config_dn_str;
1803 s->config_part.destination_dsa_guid = s->drsuapi2.bind_guid;
1805 s->config_part.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
1806 | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
1807 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
1808 | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
1809 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
1810 | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
1812 s->config_part.store_chunk = s->callbacks.config_chunk;
1814 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part,
1815 becomeDC_drsuapi3_pull_config_recv);
1818 static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req)
1820 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1821 struct libnet_BecomeDC_state);
1822 struct composite_context *c = s->creq;
1823 struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
1824 struct drsuapi_DsGetNCChanges);
1827 c->status = dcerpc_ndr_request_recv(req);
1828 if (!composite_is_ok(c)) return;
1830 status = becomeDC_drsuapi_pull_partition_recv(s, &s->config_part, r);
1831 if (!W_ERROR_IS_OK(status)) {
1832 composite_error(c, werror_to_ntstatus(status));
1838 if (s->config_part.highwatermark.tmp_highest_usn > s->config_part.highwatermark.highest_usn) {
1839 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part,
1840 becomeDC_drsuapi3_pull_config_recv);
1844 becomeDC_connect_ldap2(s);
1847 static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req);
1849 static void becomeDC_drsuapi3_pull_domain_send(struct libnet_BecomeDC_state *s)
1851 s->domain_part.nc.guid = GUID_zero();
1852 s->domain_part.nc.sid = s->zero_sid;
1853 s->domain_part.nc.dn = s->domain.dn_str;
1855 s->domain_part.destination_dsa_guid = s->drsuapi2.bind_guid;
1857 s->domain_part.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
1858 | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
1859 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
1860 | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
1861 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
1862 | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
1864 s->domain_part.store_chunk = s->callbacks.domain_chunk;
1866 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part,
1867 becomeDC_drsuapi3_pull_domain_recv);
1870 static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s,
1871 struct becomeDC_drsuapi *drsuapi,
1872 struct libnet_BecomeDC_Partition *partition,
1873 void (*recv_fn)(struct rpc_request *req));
1874 static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req);
1876 static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req)
1878 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1879 struct libnet_BecomeDC_state);
1880 struct composite_context *c = s->creq;
1881 struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
1882 struct drsuapi_DsGetNCChanges);
1885 c->status = dcerpc_ndr_request_recv(req);
1886 if (!composite_is_ok(c)) return;
1888 status = becomeDC_drsuapi_pull_partition_recv(s, &s->domain_part, r);
1889 if (!W_ERROR_IS_OK(status)) {
1890 composite_error(c, werror_to_ntstatus(status));
1896 if (s->domain_part.highwatermark.tmp_highest_usn > s->domain_part.highwatermark.highest_usn) {
1897 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part,
1898 becomeDC_drsuapi3_pull_domain_recv);
1902 becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->schema_part,
1903 becomeDC_drsuapi2_update_refs_schema_recv);
1906 static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s,
1907 struct becomeDC_drsuapi *drsuapi,
1908 struct libnet_BecomeDC_Partition *partition,
1909 void (*recv_fn)(struct rpc_request *req))
1911 struct composite_context *c = s->creq;
1912 struct rpc_request *req;
1913 struct drsuapi_DsReplicaUpdateRefs *r;
1914 const char *ntds_guid_str;
1915 const char *ntds_dns_name;
1917 r = talloc(s, struct drsuapi_DsReplicaUpdateRefs);
1918 if (composite_nomem(r, c)) return;
1920 ntds_guid_str = GUID_string(r, &s->dest_dsa.ntds_guid);
1921 if (composite_nomem(ntds_guid_str, c)) return;
1923 ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
1925 s->domain.dns_name);
1926 if (composite_nomem(ntds_dns_name, c)) return;
1928 r->in.bind_handle = &drsuapi->bind_handle;
1930 r->in.req.req1.naming_context = &partition->nc;
1931 r->in.req.req1.dest_dsa_dns_name= ntds_dns_name;
1932 r->in.req.req1.dest_dsa_guid = s->dest_dsa.ntds_guid;
1933 r->in.req.req1.options = DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE
1934 | DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE
1935 | DRSUAPI_DS_REPLICA_UPDATE_0x00000010;
1937 req = dcerpc_drsuapi_DsReplicaUpdateRefs_send(drsuapi->pipe, r, r);
1938 composite_continue_rpc(c, req, recv_fn, s);
1941 static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req);
1943 static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req)
1945 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1946 struct libnet_BecomeDC_state);
1947 struct composite_context *c = s->creq;
1948 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
1949 struct drsuapi_DsReplicaUpdateRefs);
1951 c->status = dcerpc_ndr_request_recv(req);
1952 if (!composite_is_ok(c)) return;
1954 if (!W_ERROR_IS_OK(r->out.result)) {
1955 composite_error(c, werror_to_ntstatus(r->out.result));
1961 becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->config_part,
1962 becomeDC_drsuapi2_update_refs_config_recv);
1965 static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req);
1967 static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req)
1969 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1970 struct libnet_BecomeDC_state);
1971 struct composite_context *c = s->creq;
1972 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
1973 struct drsuapi_DsReplicaUpdateRefs);
1975 c->status = dcerpc_ndr_request_recv(req);
1976 if (!composite_is_ok(c)) return;
1978 if (!W_ERROR_IS_OK(r->out.result)) {
1979 composite_error(c, werror_to_ntstatus(r->out.result));
1985 becomeDC_drsuapi_update_refs_send(s, &s->drsuapi2, &s->domain_part,
1986 becomeDC_drsuapi2_update_refs_domain_recv);
1989 static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req)
1991 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1992 struct libnet_BecomeDC_state);
1993 struct composite_context *c = s->creq;
1994 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
1995 struct drsuapi_DsReplicaUpdateRefs);
1997 c->status = dcerpc_ndr_request_recv(req);
1998 if (!composite_is_ok(c)) return;
2000 if (!W_ERROR_IS_OK(r->out.result)) {
2001 composite_error(c, werror_to_ntstatus(r->out.result));
2007 /* TODO: use DDNS updates and register dns names */
2011 static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s)
2014 struct ldb_message *msg;
2016 uint32_t user_account_control = UF_SERVER_TRUST_ACCOUNT |
2017 UF_TRUSTED_FOR_DELEGATION;
2019 /* as the value is already as we want it to be, we're done */
2020 if (s->dest_dsa.user_account_control == user_account_control) {
2021 return NT_STATUS_OK;
2024 /* make a 'modify' msg, and only for serverReference */
2025 msg = ldb_msg_new(s);
2026 NT_STATUS_HAVE_NO_MEMORY(msg);
2027 msg->dn = ldb_dn_new(msg, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
2028 NT_STATUS_HAVE_NO_MEMORY(msg->dn);
2030 ret = ldb_msg_add_fmt(msg, "userAccountControl", "%u", user_account_control);
2033 return NT_STATUS_NO_MEMORY;
2036 /* mark all the message elements (should be just one)
2037 as LDB_FLAG_MOD_REPLACE */
2038 for (i=0;i<msg->num_elements;i++) {
2039 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2042 ret = ldb_modify(s->ldap2.ldb, msg);
2044 if (ret != LDB_SUCCESS) {
2045 return NT_STATUS_LDAP(ret);
2048 s->dest_dsa.user_account_control = user_account_control;
2050 return NT_STATUS_OK;
2053 static NTSTATUS becomeDC_ldap2_move_computer(struct libnet_BecomeDC_state *s)
2056 struct ldb_result *r;
2057 struct ldb_dn *basedn;
2058 struct ldb_dn *old_dn;
2059 struct ldb_dn *new_dn;
2060 static const char *_1_1_attrs[] = {
2065 basedn = ldb_dn_new_fmt(s, s->ldap2.ldb, "<WKGUID=a361b2ffffd211d1aa4b00c04fd7d83a,%s>",
2067 NT_STATUS_HAVE_NO_MEMORY(basedn);
2069 ret = ldb_search(s->ldap2.ldb, basedn, LDB_SCOPE_BASE,
2070 "(objectClass=*)", _1_1_attrs, &r);
2071 talloc_free(basedn);
2072 if (ret != LDB_SUCCESS) {
2073 return NT_STATUS_LDAP(ret);
2074 } else if (r->count != 1) {
2076 return NT_STATUS_INVALID_NETWORK_RESPONSE;
2079 old_dn = ldb_dn_new(r, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
2080 NT_STATUS_HAVE_NO_MEMORY(old_dn);
2082 new_dn = r->msgs[0]->dn;
2084 if (!ldb_dn_add_child_fmt(new_dn, "CN=%s", s->dest_dsa.netbios_name)) {
2086 return NT_STATUS_NO_MEMORY;
2089 if (ldb_dn_compare(old_dn, new_dn) == 0) {
2090 /* we don't need to rename if the old and new dn match */
2092 return NT_STATUS_OK;
2095 ret = ldb_rename(s->ldap2.ldb, old_dn, new_dn);
2096 if (ret != LDB_SUCCESS) {
2098 return NT_STATUS_LDAP(ret);
2101 s->dest_dsa.computer_dn_str = ldb_dn_alloc_linearized(s, new_dn);
2102 NT_STATUS_HAVE_NO_MEMORY(s->dest_dsa.computer_dn_str);
2106 return NT_STATUS_OK;
2109 static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s)
2111 struct composite_context *c = s->creq;
2113 c->status = becomeDC_ldap_connect(s, &s->ldap2);
2114 if (!composite_is_ok(c)) return;
2116 c->status = becomeDC_ldap2_modify_computer(s);
2117 if (!composite_is_ok(c)) return;
2119 c->status = becomeDC_ldap2_move_computer(s);
2120 if (!composite_is_ok(c)) return;
2122 becomeDC_drsuapi3_pull_domain_send(s);
2125 struct composite_context *libnet_BecomeDC_send(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
2127 struct composite_context *c;
2128 struct libnet_BecomeDC_state *s;
2131 c = composite_create(mem_ctx, ctx->event_ctx);
2132 if (c == NULL) return NULL;
2134 s = talloc_zero(c, struct libnet_BecomeDC_state);
2135 if (composite_nomem(s, c)) return c;
2136 c->private_data = s;
2141 s->domain.dns_name = talloc_strdup(s, r->in.domain_dns_name);
2142 if (composite_nomem(s->domain.dns_name, c)) return c;
2143 s->domain.netbios_name = talloc_strdup(s, r->in.domain_netbios_name);
2144 if (composite_nomem(s->domain.netbios_name, c)) return c;
2145 s->domain.sid = dom_sid_dup(s, r->in.domain_sid);
2146 if (composite_nomem(s->domain.sid, c)) return c;
2148 /* Source DSA input */
2149 s->source_dsa.address = talloc_strdup(s, r->in.source_dsa_address);
2150 if (composite_nomem(s->source_dsa.address, c)) return c;
2152 /* Destination DSA input */
2153 s->dest_dsa.netbios_name= talloc_strdup(s, r->in.dest_dsa_netbios_name);
2154 if (composite_nomem(s->dest_dsa.netbios_name, c)) return c;
2156 /* Destination DSA dns_name construction */
2157 tmp_name = strlower_talloc(s, s->dest_dsa.netbios_name);
2158 if (composite_nomem(tmp_name, c)) return c;
2159 s->dest_dsa.dns_name = talloc_asprintf(s, "%s.%s",
2161 s->domain.dns_name);
2162 talloc_free(tmp_name);
2163 if (composite_nomem(s->dest_dsa.dns_name, c)) return c;
2164 /* Callback function pointers */
2165 s->callbacks = r->in.callbacks;
2167 becomeDC_send_cldap(s);
2171 NTSTATUS libnet_BecomeDC_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
2175 status = composite_wait(c);
2177 ZERO_STRUCT(r->out);
2183 NTSTATUS libnet_BecomeDC(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
2186 struct composite_context *c;
2187 c = libnet_BecomeDC_send(ctx, mem_ctx, r);
2188 status = libnet_BecomeDC_recv(c, mem_ctx, r);