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"
33 struct libnet_BecomeDC_state {
34 struct composite_context *creq;
36 struct libnet_context *libnet;
38 struct dom_sid zero_sid;
41 struct cldap_socket *sock;
42 struct cldap_netlogon io;
43 struct nbt_cldap_netlogon_5 netlogon5;
46 struct becomeDC_ldap {
47 struct ldb_context *ldb;
48 const struct ldb_message *rootdse;
51 struct becomeDC_drsuapi {
52 struct libnet_BecomeDC_state *s;
53 struct dcerpc_binding *binding;
54 struct dcerpc_pipe *pipe;
55 struct drsuapi_DsBind bind_r;
56 struct GUID bind_guid;
57 struct drsuapi_DsBindInfoCtr bind_info_ctr;
58 struct drsuapi_DsBindInfo28 local_info28;
59 struct drsuapi_DsBindInfo28 remote_info28;
60 struct policy_handle bind_handle;
61 } drsuapi1, drsuapi2, drsuapi3;
66 const char *netbios_name;
67 const struct dom_sid *sid;
77 const char *root_dn_str;
78 const char *config_dn_str;
79 const char *schema_dn_str;
88 const char *netbios_name;
89 const char *site_name;
90 const char *server_dn_str;
91 const char *ntds_dn_str;
96 const char *netbios_name;
100 const char *site_name;
101 struct GUID site_guid;
102 const char *computer_dn_str;
103 const char *server_dn_str;
104 const char *ntds_dn_str;
105 struct GUID ntds_guid;
106 struct GUID invocation_id;
107 uint32_t user_account_control;
111 uint32_t domain_behavior_version;
112 uint32_t config_behavior_version;
113 uint32_t schema_object_version;
114 uint32_t w2k3_update_revision;
117 struct becomeDC_partition {
118 struct drsuapi_DsReplicaObjectIdentifier nc;
119 struct GUID destination_dsa_guid;
120 struct GUID source_dsa_guid;
121 struct GUID source_dsa_invocation_id;
122 struct drsuapi_DsReplicaHighWaterMark highwatermark;
123 struct drsuapi_DsReplicaCoursorCtrEx *uptodateness_vector;
124 uint32_t replica_flags;
127 struct becomeDC_fsmo {
128 const char *dns_name;
129 const char *server_dn_str;
130 const char *ntds_dn_str;
131 struct GUID ntds_guid;
132 } infrastructure_fsmo;
134 struct becomeDC_fsmo rid_manager_fsmo;
137 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s);
139 static void becomeDC_recv_cldap(struct cldap_request *req)
141 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
142 struct libnet_BecomeDC_state);
143 struct composite_context *c = s->creq;
145 c->status = cldap_netlogon_recv(req, s, &s->cldap.io);
146 if (!composite_is_ok(c)) return;
148 s->cldap.netlogon5 = s->cldap.io.out.netlogon.logon5;
150 s->domain.dns_name = s->cldap.netlogon5.dns_domain;
151 s->domain.netbios_name = s->cldap.netlogon5.domain;
152 s->domain.guid = s->cldap.netlogon5.domain_uuid;
154 s->forest.dns_name = s->cldap.netlogon5.forest;
156 s->source_dsa.dns_name = s->cldap.netlogon5.pdc_dns_name;
157 s->source_dsa.netbios_name = s->cldap.netlogon5.pdc_name;
158 s->source_dsa.site_name = s->cldap.netlogon5.server_site;
160 s->dest_dsa.site_name = s->cldap.netlogon5.client_site;
162 becomeDC_connect_ldap1(s);
165 static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
167 struct composite_context *c = s->creq;
168 struct cldap_request *req;
170 s->cldap.io.in.dest_address = s->source_dsa.address;
171 s->cldap.io.in.realm = s->domain.dns_name;
172 s->cldap.io.in.host = s->dest_dsa.netbios_name;
173 s->cldap.io.in.user = NULL;
174 s->cldap.io.in.domain_guid = NULL;
175 s->cldap.io.in.domain_sid = NULL;
176 s->cldap.io.in.acct_control = -1;
177 s->cldap.io.in.version = 6;
179 s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx);
180 if (composite_nomem(s->cldap.sock, c)) return;
182 req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
183 if (composite_nomem(req, c)) return;
184 req->async.fn = becomeDC_recv_cldap;
185 req->async.private = s;
188 static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s, struct becomeDC_ldap *ldap)
192 url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
193 NT_STATUS_HAVE_NO_MEMORY(url);
195 ldap->ldb = ldb_wrap_connect(s, url,
200 if (ldap->ldb == NULL) {
201 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
207 static NTSTATUS becomeDC_ldap1_rootdse(struct libnet_BecomeDC_state *s)
210 struct ldb_result *r;
211 struct ldb_dn *basedn;
212 static const char *attrs[] = {
217 basedn = ldb_dn_new(s, s->ldap1.ldb, NULL);
218 NT_STATUS_HAVE_NO_MEMORY(basedn);
220 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
221 "(objectClass=*)", attrs, &r);
223 if (ret != LDB_SUCCESS) {
224 return NT_STATUS_LDAP(ret);
225 } else if (r->count != 1) {
227 return NT_STATUS_INVALID_NETWORK_RESPONSE;
231 s->ldap1.rootdse = r->msgs[0];
233 s->domain.dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "defaultNamingContext", NULL);
234 if (!s->domain.dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
236 s->forest.root_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "rootDomainNamingContext", NULL);
237 if (!s->forest.root_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
238 s->forest.config_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "configurationNamingContext", NULL);
239 if (!s->forest.config_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
240 s->forest.schema_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "schemaNamingContext", NULL);
241 if (!s->forest.schema_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
243 s->source_dsa.server_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "serverName", NULL);
244 if (!s->source_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
245 s->source_dsa.ntds_dn_str = ldb_msg_find_attr_as_string(s->ldap1.rootdse, "dsServiceName", NULL);
246 if (!s->source_dsa.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
251 static NTSTATUS becomeDC_ldap1_config_behavior_version(struct libnet_BecomeDC_state *s)
254 struct ldb_result *r;
255 struct ldb_dn *basedn;
256 static const char *attrs[] = {
257 "msDs-Behavior-Version",
261 basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.config_dn_str);
262 NT_STATUS_HAVE_NO_MEMORY(basedn);
264 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_ONELEVEL,
265 "(cn=Partitions)", attrs, &r);
267 if (ret != LDB_SUCCESS) {
268 return NT_STATUS_LDAP(ret);
269 } else if (r->count != 1) {
271 return NT_STATUS_INVALID_NETWORK_RESPONSE;
274 s->ads_options.config_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
280 static NTSTATUS becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_state *s)
283 struct ldb_result *r;
284 struct ldb_dn *basedn;
285 static const char *attrs[] = {
286 "msDs-Behavior-Version",
290 basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
291 NT_STATUS_HAVE_NO_MEMORY(basedn);
293 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
294 "(objectClass=*)", attrs, &r);
296 if (ret != LDB_SUCCESS) {
297 return NT_STATUS_LDAP(ret);
298 } else if (r->count != 1) {
300 return NT_STATUS_INVALID_NETWORK_RESPONSE;
303 s->ads_options.domain_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0);
309 static NTSTATUS becomeDC_ldap1_schema_object_version(struct libnet_BecomeDC_state *s)
312 struct ldb_result *r;
313 struct ldb_dn *basedn;
314 static const char *attrs[] = {
319 basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.schema_dn_str);
320 NT_STATUS_HAVE_NO_MEMORY(basedn);
322 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
323 "(objectClass=*)", attrs, &r);
325 if (ret != LDB_SUCCESS) {
326 return NT_STATUS_LDAP(ret);
327 } else if (r->count != 1) {
329 return NT_STATUS_INVALID_NETWORK_RESPONSE;
332 s->ads_options.schema_object_version = ldb_msg_find_attr_as_uint(r->msgs[0], "objectVersion", 0);
338 static NTSTATUS becomeDC_ldap1_w2k3_update_revision(struct libnet_BecomeDC_state *s)
341 struct ldb_result *r;
342 struct ldb_dn *basedn;
343 static const char *attrs[] = {
348 basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=Windows2003Update,CN=DomainUpdates,CN=System,%s",
350 NT_STATUS_HAVE_NO_MEMORY(basedn);
352 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
353 "(objectClass=*)", attrs, &r);
355 if (ret != LDB_SUCCESS) {
356 return NT_STATUS_LDAP(ret);
357 } else if (r->count != 1) {
359 return NT_STATUS_INVALID_NETWORK_RESPONSE;
362 s->ads_options.w2k3_update_revision = ldb_msg_find_attr_as_uint(r->msgs[0], "revision", 0);
368 static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state *s)
371 struct ldb_result *r;
372 struct ldb_dn *basedn;
373 struct ldb_dn *ntds_dn;
374 struct ldb_dn *server_dn;
375 static const char *_1_1_attrs[] = {
379 static const char *fsmo_attrs[] = {
383 static const char *dns_attrs[] = {
387 static const char *guid_attrs[] = {
392 basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "<WKGUID=2fbac1870ade11d297c400c04fd8d5cd,%s>",
394 NT_STATUS_HAVE_NO_MEMORY(basedn);
396 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
397 "(objectClass=*)", _1_1_attrs, &r);
399 if (ret != LDB_SUCCESS) {
400 return NT_STATUS_LDAP(ret);
401 } else if (r->count != 1) {
403 return NT_STATUS_INVALID_NETWORK_RESPONSE;
406 basedn = talloc_steal(s, r->msgs[0]->dn);
409 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
410 "(objectClass=*)", fsmo_attrs, &r);
412 if (ret != LDB_SUCCESS) {
413 return NT_STATUS_LDAP(ret);
414 } else if (r->count != 1) {
416 return NT_STATUS_INVALID_NETWORK_RESPONSE;
419 s->infrastructure_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
420 if (!s->infrastructure_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
421 talloc_steal(s, s->infrastructure_fsmo.ntds_dn_str);
425 ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->infrastructure_fsmo.ntds_dn_str);
426 NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
428 server_dn = ldb_dn_get_parent(s, ntds_dn);
429 NT_STATUS_HAVE_NO_MEMORY(server_dn);
431 s->infrastructure_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
432 NT_STATUS_HAVE_NO_MEMORY(s->infrastructure_fsmo.server_dn_str);
434 ret = ldb_search(s->ldap1.ldb, server_dn, LDB_SCOPE_BASE,
435 "(objectClass=*)", dns_attrs, &r);
436 if (ret != LDB_SUCCESS) {
437 return NT_STATUS_LDAP(ret);
438 } else if (r->count != 1) {
440 return NT_STATUS_INVALID_NETWORK_RESPONSE;
443 s->infrastructure_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL);
444 if (!s->infrastructure_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
445 talloc_steal(s, s->infrastructure_fsmo.dns_name);
449 ret = ldb_search(s->ldap1.ldb, ntds_dn, LDB_SCOPE_BASE,
450 "(objectClass=*)", guid_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 s->infrastructure_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
465 static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s)
468 struct ldb_result *r;
469 struct ldb_dn *basedn;
470 const char *reference_dn_str;
471 struct ldb_dn *ntds_dn;
472 struct ldb_dn *server_dn;
473 static const char *rid_attrs[] = {
474 "rIDManagerReference",
477 static const char *fsmo_attrs[] = {
481 static const char *dns_attrs[] = {
485 static const char *guid_attrs[] = {
490 basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
491 NT_STATUS_HAVE_NO_MEMORY(basedn);
493 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
494 "(objectClass=*)", rid_attrs, &r);
496 if (ret != LDB_SUCCESS) {
497 return NT_STATUS_LDAP(ret);
498 } else if (r->count != 1) {
500 return NT_STATUS_INVALID_NETWORK_RESPONSE;
503 reference_dn_str = samdb_result_string(r->msgs[0], "rIDManagerReference", NULL);
504 if (!reference_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
506 basedn = ldb_dn_new(s, s->ldap1.ldb, reference_dn_str);
507 NT_STATUS_HAVE_NO_MEMORY(basedn);
511 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
512 "(objectClass=*)", fsmo_attrs, &r);
514 if (ret != LDB_SUCCESS) {
515 return NT_STATUS_LDAP(ret);
516 } else if (r->count != 1) {
518 return NT_STATUS_INVALID_NETWORK_RESPONSE;
521 s->rid_manager_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL);
522 if (!s->rid_manager_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
523 talloc_steal(s, s->rid_manager_fsmo.ntds_dn_str);
527 ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->rid_manager_fsmo.ntds_dn_str);
528 NT_STATUS_HAVE_NO_MEMORY(ntds_dn);
530 server_dn = ldb_dn_get_parent(s, ntds_dn);
531 NT_STATUS_HAVE_NO_MEMORY(server_dn);
533 s->rid_manager_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn);
534 NT_STATUS_HAVE_NO_MEMORY(s->rid_manager_fsmo.server_dn_str);
536 ret = ldb_search(s->ldap1.ldb, server_dn, LDB_SCOPE_BASE,
537 "(objectClass=*)", dns_attrs, &r);
538 if (ret != LDB_SUCCESS) {
539 return NT_STATUS_LDAP(ret);
540 } else if (r->count != 1) {
542 return NT_STATUS_INVALID_NETWORK_RESPONSE;
545 s->rid_manager_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL);
546 if (!s->rid_manager_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE;
547 talloc_steal(s, s->rid_manager_fsmo.dns_name);
551 ret = ldb_search(s->ldap1.ldb, ntds_dn, LDB_SCOPE_BASE,
552 "(objectClass=*)", guid_attrs, &r);
553 if (ret != LDB_SUCCESS) {
554 return NT_STATUS_LDAP(ret);
555 } else if (r->count != 1) {
557 return NT_STATUS_INVALID_NETWORK_RESPONSE;
560 s->rid_manager_fsmo.ntds_guid = samdb_result_guid(r->msgs[0], "objectGUID");
567 static NTSTATUS becomeDC_ldap1_site_object(struct libnet_BecomeDC_state *s)
570 struct ldb_result *r;
571 struct ldb_dn *basedn;
573 basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Sites,%s",
574 s->dest_dsa.site_name,
575 s->forest.config_dn_str);
576 NT_STATUS_HAVE_NO_MEMORY(basedn);
578 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
579 "(objectClass=*)", NULL, &r);
581 if (ret != LDB_SUCCESS) {
582 return NT_STATUS_LDAP(ret);
583 } else if (r->count != 1) {
585 return NT_STATUS_INVALID_NETWORK_RESPONSE;
588 s->dest_dsa.site_guid = samdb_result_guid(r->msgs[0], "objectGUID");
594 static NTSTATUS becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state *s)
597 struct ldb_result *r;
598 struct ldb_dn *basedn;
600 static const char *attrs[] = {
602 "userAccountControl",
606 basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str);
607 NT_STATUS_HAVE_NO_MEMORY(basedn);
609 filter = talloc_asprintf(basedn, "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))",
610 s->dest_dsa.netbios_name);
611 NT_STATUS_HAVE_NO_MEMORY(filter);
613 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_SUBTREE,
616 if (ret != LDB_SUCCESS) {
617 return NT_STATUS_LDAP(ret);
618 } else if (r->count != 1) {
620 return NT_STATUS_INVALID_NETWORK_RESPONSE;
623 s->dest_dsa.computer_dn_str = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
624 if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
625 talloc_steal(s, s->dest_dsa.computer_dn_str);
627 s->dest_dsa.user_account_control = samdb_result_uint(r->msgs[0], "userAccountControl", 0);
633 static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s)
636 struct ldb_result *r;
637 struct ldb_dn *basedn;
638 const char *server_reference_dn_str;
639 struct ldb_dn *server_reference_dn;
640 struct ldb_dn *computer_dn;
642 basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
643 s->dest_dsa.netbios_name,
644 s->dest_dsa.site_name,
645 s->forest.config_dn_str);
646 NT_STATUS_HAVE_NO_MEMORY(basedn);
648 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
649 "(objectClass=*)", NULL, &r);
651 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
652 /* if the object doesn't exist, we'll create it later */
654 } else if (ret != LDB_SUCCESS) {
655 return NT_STATUS_LDAP(ret);
656 } else if (r->count != 1) {
658 return NT_STATUS_INVALID_NETWORK_RESPONSE;
661 server_reference_dn_str = samdb_result_string(r->msgs[0], "serverReference", NULL);
662 if (server_reference_dn_str) {
663 server_reference_dn = ldb_dn_new(r, s->ldap1.ldb, server_reference_dn_str);
664 NT_STATUS_HAVE_NO_MEMORY(server_reference_dn);
666 computer_dn = ldb_dn_new(r, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
667 NT_STATUS_HAVE_NO_MEMORY(computer_dn);
670 * if the server object belongs to another DC in another domain in the forest,
671 * we should not touch this object!
673 if (ldb_dn_compare(computer_dn, server_reference_dn) != 0) {
675 return NT_STATUS_OBJECT_NAME_COLLISION;
679 /* if the server object is already for the dest_dsa, then we don't need to create it */
680 s->dest_dsa.server_dn_str = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
681 if (!s->dest_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
682 talloc_steal(s, s->dest_dsa.server_dn_str);
688 static NTSTATUS becomeDC_ldap1_server_object_2(struct libnet_BecomeDC_state *s)
691 struct ldb_result *r;
692 struct ldb_dn *basedn;
693 const char *server_reference_bl_dn_str;
694 static const char *attrs[] = {
699 /* if the server_dn_str has a valid value, we skip this lookup */
700 if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
702 basedn = ldb_dn_new(s, s->ldap1.ldb, s->dest_dsa.computer_dn_str);
703 NT_STATUS_HAVE_NO_MEMORY(basedn);
705 ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE,
706 "(objectClass=*)", attrs, &r);
708 if (ret != LDB_SUCCESS) {
709 return NT_STATUS_LDAP(ret);
710 } else if (r->count != 1) {
712 return NT_STATUS_INVALID_NETWORK_RESPONSE;
715 server_reference_bl_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL);
716 if (!server_reference_bl_dn_str) {
717 /* if no back link is present, we're done for this function */
722 /* if the server object is already for the dest_dsa, then we don't need to create it */
723 s->dest_dsa.server_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL);
724 if (s->dest_dsa.server_dn_str) {
725 /* if a back link is present, we know that the server object is present */
726 talloc_steal(s, s->dest_dsa.server_dn_str);
733 static NTSTATUS becomeDC_ldap1_server_object_add(struct libnet_BecomeDC_state *s)
736 struct ldb_message *msg;
739 /* if the server_dn_str has a valid value, we skip this lookup */
740 if (s->dest_dsa.server_dn_str) return NT_STATUS_OK;
742 msg = ldb_msg_new(s);
743 NT_STATUS_HAVE_NO_MEMORY(msg);
745 msg->dn = ldb_dn_new_fmt(msg, s->ldap1.ldb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
746 s->dest_dsa.netbios_name,
747 s->dest_dsa.site_name,
748 s->forest.config_dn_str);
749 NT_STATUS_HAVE_NO_MEMORY(msg->dn);
751 ret = ldb_msg_add_string(msg, "objectClass", "server");
754 return NT_STATUS_NO_MEMORY;
756 ret = ldb_msg_add_string(msg, "systemFlags", "50000000");
759 return NT_STATUS_NO_MEMORY;
761 ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
764 return NT_STATUS_NO_MEMORY;
767 server_dn_str = ldb_dn_alloc_linearized(s, msg->dn);
768 NT_STATUS_HAVE_NO_MEMORY(server_dn_str);
770 ret = ldb_add(s->ldap1.ldb, msg);
772 if (ret != LDB_SUCCESS) {
773 talloc_free(server_dn_str);
774 return NT_STATUS_LDAP(ret);
777 s->dest_dsa.server_dn_str = server_dn_str;
782 static NTSTATUS becomeDC_ldap1_server_object_modify(struct libnet_BecomeDC_state *s)
785 struct ldb_message *msg;
788 /* make a 'modify' msg, and only for serverReference */
789 msg = ldb_msg_new(s);
790 NT_STATUS_HAVE_NO_MEMORY(msg);
791 msg->dn = ldb_dn_new(msg, s->ldap1.ldb, s->dest_dsa.server_dn_str);
792 NT_STATUS_HAVE_NO_MEMORY(msg->dn);
794 ret = ldb_msg_add_string(msg, "serverReference", s->dest_dsa.computer_dn_str);
797 return NT_STATUS_NO_MEMORY;
800 /* mark all the message elements (should be just one)
801 as LDB_FLAG_MOD_ADD */
802 for (i=0;i<msg->num_elements;i++) {
803 msg->elements[i].flags = LDB_FLAG_MOD_ADD;
806 ret = ldb_modify(s->ldap1.ldb, msg);
807 if (ret == LDB_SUCCESS) {
810 } else if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
811 /* retry with LDB_FLAG_MOD_REPLACE */
814 return NT_STATUS_LDAP(ret);
817 /* mark all the message elements (should be just one)
818 as LDB_FLAG_MOD_REPLACE */
819 for (i=0;i<msg->num_elements;i++) {
820 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
823 ret = ldb_modify(s->ldap1.ldb, msg);
825 if (ret != LDB_SUCCESS) {
826 return NT_STATUS_LDAP(ret);
832 static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
833 struct becomeDC_drsuapi *drsuapi,
834 void (*recv_fn)(struct composite_context *req));
835 static void becomeDC_drsuapi1_connect_recv(struct composite_context *req);
836 static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s);
838 static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s)
840 struct composite_context *c = s->creq;
842 c->status = becomeDC_ldap_connect(s, &s->ldap1);
843 if (!composite_is_ok(c)) return;
845 c->status = becomeDC_ldap1_rootdse(s);
846 if (!composite_is_ok(c)) return;
848 c->status = becomeDC_ldap1_config_behavior_version(s);
849 if (!composite_is_ok(c)) return;
851 c->status = becomeDC_ldap1_domain_behavior_version(s);
852 if (!composite_is_ok(c)) return;
854 c->status = becomeDC_ldap1_schema_object_version(s);
855 if (!composite_is_ok(c)) return;
857 c->status = becomeDC_ldap1_w2k3_update_revision(s);
858 if (!composite_is_ok(c)) return;
860 c->status = becomeDC_ldap1_infrastructure_fsmo(s);
861 if (!composite_is_ok(c)) return;
863 c->status = becomeDC_ldap1_rid_manager_fsmo(s);
864 if (!composite_is_ok(c)) return;
866 c->status = becomeDC_ldap1_site_object(s);
867 if (!composite_is_ok(c)) return;
869 c->status = becomeDC_ldap1_computer_object(s);
870 if (!composite_is_ok(c)) return;
872 c->status = becomeDC_ldap1_server_object_1(s);
873 if (!composite_is_ok(c)) return;
875 c->status = becomeDC_ldap1_server_object_2(s);
876 if (!composite_is_ok(c)) return;
878 c->status = becomeDC_ldap1_server_object_add(s);
879 if (!composite_is_ok(c)) return;
881 c->status = becomeDC_ldap1_server_object_modify(s);
882 if (!composite_is_ok(c)) return;
884 becomeDC_drsuapi_connect_send(s, &s->drsuapi1, becomeDC_drsuapi1_connect_recv);
887 static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s,
888 struct becomeDC_drsuapi *drsuapi,
889 void (*recv_fn)(struct composite_context *req))
891 struct composite_context *c = s->creq;
892 struct composite_context *creq;
897 if (!drsuapi->binding) {
898 binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[krb5,seal]", s->source_dsa.dns_name);
899 if (composite_nomem(binding_str, c)) return;
901 c->status = dcerpc_parse_binding(s, binding_str, &drsuapi->binding);
902 talloc_free(binding_str);
903 if (!composite_is_ok(c)) return;
906 creq = dcerpc_pipe_connect_b_send(s, drsuapi->binding, &dcerpc_table_drsuapi,
907 s->libnet->cred, s->libnet->event_ctx);
908 composite_continue(c, creq, recv_fn, s);
911 static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
912 struct becomeDC_drsuapi *drsuapi,
913 void (*recv_fn)(struct rpc_request *req));
914 static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req);
916 static void becomeDC_drsuapi1_connect_recv(struct composite_context *req)
918 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
919 struct libnet_BecomeDC_state);
920 struct composite_context *c = s->creq;
922 c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi1.pipe);
923 if (!composite_is_ok(c)) return;
925 becomeDC_drsuapi_bind_send(s, &s->drsuapi1, becomeDC_drsuapi1_bind_recv);
928 static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s,
929 struct becomeDC_drsuapi *drsuapi,
930 void (*recv_fn)(struct rpc_request *req))
932 struct composite_context *c = s->creq;
933 struct rpc_request *req;
934 struct drsuapi_DsBindInfo28 *bind_info28;
936 GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &drsuapi->bind_guid);
938 bind_info28 = &drsuapi->local_info28;
939 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
940 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
941 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
942 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
943 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
944 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
945 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
946 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
947 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
948 if (s->ads_options.domain_behavior_version == 2) {
949 /* TODO: find out how this is really triggered! */
950 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
952 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
953 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
954 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
955 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
956 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
957 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
958 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
959 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
960 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
961 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_00100000;
962 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
963 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
964 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
965 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
966 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
967 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
968 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
969 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
970 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
971 #if 0 /* we don't support XPRESS compression yet */
972 bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
974 bind_info28->site_guid = s->dest_dsa.site_guid;
975 if (s->ads_options.domain_behavior_version == 2) {
976 /* TODO: find out how this is really triggered! */
977 bind_info28->u1 = 528;
979 bind_info28->u1 = 516;
981 bind_info28->repl_epoch = 0;
983 drsuapi->bind_info_ctr.length = 28;
984 drsuapi->bind_info_ctr.info.info28 = *bind_info28;
986 drsuapi->bind_r.in.bind_guid = &drsuapi->bind_guid;
987 drsuapi->bind_r.in.bind_info = &drsuapi->bind_info_ctr;
988 drsuapi->bind_r.out.bind_handle = &drsuapi->bind_handle;
990 req = dcerpc_drsuapi_DsBind_send(drsuapi->pipe, s, &drsuapi->bind_r);
991 composite_continue_rpc(c, req, recv_fn, s);
994 static WERROR becomeDC_drsuapi_bind_recv(struct libnet_BecomeDC_state *s,
995 struct becomeDC_drsuapi *drsuapi)
997 if (!W_ERROR_IS_OK(drsuapi->bind_r.out.result)) {
998 return drsuapi->bind_r.out.result;
1001 ZERO_STRUCT(drsuapi->remote_info28);
1002 if (drsuapi->bind_r.out.bind_info) {
1003 switch (drsuapi->bind_r.out.bind_info->length) {
1005 struct drsuapi_DsBindInfo24 *info24;
1006 info24 = &drsuapi->bind_r.out.bind_info->info.info24;
1007 drsuapi->remote_info28.supported_extensions = info24->supported_extensions;
1008 drsuapi->remote_info28.site_guid = info24->site_guid;
1009 drsuapi->remote_info28.u1 = info24->u1;
1010 drsuapi->remote_info28.repl_epoch = 0;
1014 drsuapi->remote_info28 = drsuapi->bind_r.out.bind_info->info.info28;
1022 static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s);
1024 static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req)
1026 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1027 struct libnet_BecomeDC_state);
1028 struct composite_context *c = s->creq;
1031 c->status = dcerpc_ndr_request_recv(req);
1032 if (!composite_is_ok(c)) return;
1034 status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi1);
1035 if (!W_ERROR_IS_OK(status)) {
1036 composite_error(c, werror_to_ntstatus(status));
1040 becomeDC_drsuapi1_add_entry_send(s);
1043 static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req);
1045 static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s)
1047 struct composite_context *c = s->creq;
1048 struct rpc_request *req;
1049 struct drsuapi_DsAddEntry *r;
1050 struct drsuapi_DsReplicaObjectIdentifier *identifier;
1051 uint32_t num_attrs, i = 0;
1052 struct drsuapi_DsReplicaAttribute *attrs;
1054 /* choose a random invocationId */
1055 s->dest_dsa.invocation_id = GUID_random();
1057 r = talloc_zero(s, struct drsuapi_DsAddEntry);
1058 if (composite_nomem(r, c)) return;
1060 /* setup identifier */
1061 identifier = talloc(r, struct drsuapi_DsReplicaObjectIdentifier);
1062 if (composite_nomem(identifier, c)) return;
1063 identifier->guid = GUID_zero();
1064 identifier->sid = s->zero_sid;
1065 identifier->dn = talloc_asprintf(identifier, "CN=NTDS Settings,%s",
1066 s->dest_dsa.server_dn_str);
1067 if (composite_nomem(identifier->dn, c)) return;
1069 /* allocate attribute array */
1071 attrs = talloc_array(r, struct drsuapi_DsReplicaAttribute, num_attrs);
1072 if (composite_nomem(attrs, c)) return;
1074 /* ntSecurityDescriptor */
1076 struct drsuapi_DsAttributeValueSecurityDescriptor *vs;
1077 struct security_descriptor *v;
1078 struct dom_sid *domain_admins_sid;
1079 const char *domain_admins_sid_str;
1081 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueSecurityDescriptor, 1);
1082 if (composite_nomem(vs, c)) return;
1084 domain_admins_sid = dom_sid_add_rid(vs, s->domain.sid, DOMAIN_RID_ADMINS);
1085 if (composite_nomem(domain_admins_sid, c)) return;
1087 domain_admins_sid_str = dom_sid_string(domain_admins_sid, domain_admins_sid);
1088 if (composite_nomem(domain_admins_sid_str, c)) return;
1090 v = security_descriptor_create(vs,
1091 /* owner: domain admins */
1092 domain_admins_sid_str,
1093 /* owner group: domain admins */
1094 domain_admins_sid_str,
1095 /* authenticated users */
1096 SID_NT_AUTHENTICATED_USERS,
1097 SEC_ACE_TYPE_ACCESS_ALLOWED,
1098 SEC_STD_READ_CONTROL |
1101 SEC_ADS_LIST_OBJECT,
1104 domain_admins_sid_str,
1105 SEC_ACE_TYPE_ACCESS_ALLOWED,
1107 SEC_ADS_CREATE_CHILD |
1109 SEC_ADS_SELF_WRITE |
1111 SEC_ADS_WRITE_PROP |
1112 SEC_ADS_DELETE_TREE |
1113 SEC_ADS_LIST_OBJECT |
1114 SEC_ADS_CONTROL_ACCESS,
1118 SEC_ACE_TYPE_ACCESS_ALLOWED,
1120 SEC_ADS_CREATE_CHILD |
1121 SEC_ADS_DELETE_CHILD |
1123 SEC_ADS_SELF_WRITE |
1125 SEC_ADS_WRITE_PROP |
1126 SEC_ADS_DELETE_TREE |
1127 SEC_ADS_LIST_OBJECT |
1128 SEC_ADS_CONTROL_ACCESS,
1132 if (composite_nomem(v, c)) return;
1136 attrs[i].attid = DRSUAPI_ATTRIBUTE_ntSecurityDescriptor;
1137 attrs[i].value_ctr.security_descriptor.num_values = 1;
1138 attrs[i].value_ctr.security_descriptor.values = vs;
1143 /* objectClass: nTDSDSA */
1145 struct drsuapi_DsAttributeValueObjectClassId *vs;
1146 enum drsuapi_DsObjectClassId *v;
1148 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueObjectClassId, 1);
1149 if (composite_nomem(vs, c)) return;
1151 v = talloc_array(vs, enum drsuapi_DsObjectClassId, 1);
1152 if (composite_nomem(v, c)) return;
1154 /* value for nTDSDSA */
1157 vs[0].objectClassId = &v[0];
1159 attrs[i].attid = DRSUAPI_ATTRIBUTE_objectClass;
1160 attrs[i].value_ctr.object_class_id.num_values = 1;
1161 attrs[i].value_ctr.object_class_id.values = vs;
1166 /* objectCategory: CN=NTDS-DSA,CN=Schema,... */
1168 struct drsuapi_DsAttributeValueDNString *vs;
1169 struct drsuapi_DsReplicaObjectIdentifier3 *v;
1171 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 1);
1172 if (composite_nomem(vs, c)) return;
1174 v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 1);
1175 if (composite_nomem(v, c)) return;
1177 /* value for nTDSDSA */
1178 v[0].guid = GUID_zero();
1179 v[0].sid = s->zero_sid;
1180 v[0].dn = talloc_asprintf(v, "CN=NTDS-DSA,%s",
1181 s->forest.schema_dn_str);
1182 if (composite_nomem(v->dn, c)) return;
1184 vs[0].object = &v[0];
1186 attrs[i].attid = DRSUAPI_ATTRIBUTE_objectCategory;
1187 attrs[i].value_ctr.dn_string.num_values = 1;
1188 attrs[i].value_ctr.dn_string.values = vs;
1193 /* invocationId: random guid */
1195 struct drsuapi_DsAttributeValueGUID *vs;
1198 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueGUID, 1);
1199 if (composite_nomem(vs, c)) return;
1201 v = talloc_array(vs, struct GUID, 1);
1202 if (composite_nomem(v, c)) return;
1204 /* value for nTDSDSA */
1205 v[0] = s->dest_dsa.invocation_id;
1209 attrs[i].attid = DRSUAPI_ATTRIBUTE_invocationId;
1210 attrs[i].value_ctr.guid.num_values = 1;
1211 attrs[i].value_ctr.guid.values = vs;
1216 /* hasMasterNCs: ... */
1218 struct drsuapi_DsAttributeValueDNString *vs;
1219 struct drsuapi_DsReplicaObjectIdentifier3 *v;
1221 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 3);
1222 if (composite_nomem(vs, c)) return;
1224 v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 3);
1225 if (composite_nomem(v, c)) return;
1227 v[0].guid = GUID_zero();
1228 v[0].sid = s->zero_sid;
1229 v[0].dn = s->forest.config_dn_str;
1231 v[1].guid = GUID_zero();
1232 v[1].sid = s->zero_sid;
1233 v[1].dn = s->domain.dn_str;
1235 v[2].guid = GUID_zero();
1236 v[2].sid = s->zero_sid;
1237 v[2].dn = s->forest.schema_dn_str;
1239 vs[0].object = &v[0];
1240 vs[1].object = &v[1];
1241 vs[2].object = &v[2];
1243 attrs[i].attid = DRSUAPI_ATTRIBUTE_hasMasterNCs;
1244 attrs[i].value_ctr.dn_string.num_values = 3;
1245 attrs[i].value_ctr.dn_string.values = vs;
1250 /* msDS-hasMasterNCs: ... */
1252 struct drsuapi_DsAttributeValueDNString *vs;
1253 struct drsuapi_DsReplicaObjectIdentifier3 *v;
1255 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 3);
1256 if (composite_nomem(vs, c)) return;
1258 v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 3);
1259 if (composite_nomem(v, c)) return;
1261 v[0].guid = GUID_zero();
1262 v[0].sid = s->zero_sid;
1263 v[0].dn = s->forest.config_dn_str;
1265 v[1].guid = GUID_zero();
1266 v[1].sid = s->zero_sid;
1267 v[1].dn = s->domain.dn_str;
1269 v[2].guid = GUID_zero();
1270 v[2].sid = s->zero_sid;
1271 v[2].dn = s->forest.schema_dn_str;
1273 vs[0].object = &v[0];
1274 vs[1].object = &v[1];
1275 vs[2].object = &v[2];
1277 attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs;
1278 attrs[i].value_ctr.dn_string.num_values = 3;
1279 attrs[i].value_ctr.dn_string.values = vs;
1284 /* dMDLocation: CN=Schema,... */
1286 struct drsuapi_DsAttributeValueDNString *vs;
1287 struct drsuapi_DsReplicaObjectIdentifier3 *v;
1289 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 1);
1290 if (composite_nomem(vs, c)) return;
1292 v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 1);
1293 if (composite_nomem(v, c)) return;
1295 v[0].guid = GUID_zero();
1296 v[0].sid = s->zero_sid;
1297 v[0].dn = s->forest.schema_dn_str;
1299 vs[0].object = &v[0];
1301 attrs[i].attid = DRSUAPI_ATTRIBUTE_dMDLocation;
1302 attrs[i].value_ctr.dn_string.num_values = 1;
1303 attrs[i].value_ctr.dn_string.values = vs;
1308 /* msDS-HasDomainNCs: <domain_partition> */
1310 struct drsuapi_DsAttributeValueDNString *vs;
1311 struct drsuapi_DsReplicaObjectIdentifier3 *v;
1313 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 1);
1314 if (composite_nomem(vs, c)) return;
1316 v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 1);
1317 if (composite_nomem(v, c)) return;
1319 v[0].guid = GUID_zero();
1320 v[0].sid = s->zero_sid;
1321 v[0].dn = s->domain.dn_str;
1323 vs[0].object = &v[0];
1325 attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs;
1326 attrs[i].value_ctr.dn_string.num_values = 1;
1327 attrs[i].value_ctr.dn_string.values = vs;
1332 /* msDS-Behavior-Version */
1334 struct drsuapi_DsAttributeValueUINT32 *vs;
1337 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueUINT32, 1);
1338 if (composite_nomem(vs, c)) return;
1340 v = talloc_array(vs, uint32_t, 1);
1341 if (composite_nomem(v, c)) return;
1345 vs[0].value = &v[0];
1347 attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_Behavior_Version;
1348 attrs[i].value_ctr.uint32.num_values = 1;
1349 attrs[i].value_ctr.uint32.values = vs;
1356 struct drsuapi_DsAttributeValueUINT32 *vs;
1359 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueUINT32, 1);
1360 if (composite_nomem(vs, c)) return;
1362 v = talloc_array(vs, uint32_t, 1);
1363 if (composite_nomem(v, c)) return;
1365 v[0] = SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE;
1367 vs[0].value = &v[0];
1369 attrs[i].attid = DRSUAPI_ATTRIBUTE_systemFlags;
1370 attrs[i].value_ctr.uint32.num_values = 1;
1371 attrs[i].value_ctr.uint32.values = vs;
1376 /* serverReference: ... */
1378 struct drsuapi_DsAttributeValueDNString *vs;
1379 struct drsuapi_DsReplicaObjectIdentifier3 *v;
1381 vs = talloc_array(attrs, struct drsuapi_DsAttributeValueDNString, 1);
1382 if (composite_nomem(vs, c)) return;
1384 v = talloc_array(vs, struct drsuapi_DsReplicaObjectIdentifier3, 1);
1385 if (composite_nomem(v, c)) return;
1387 v[0].guid = GUID_zero();
1388 v[0].sid = s->zero_sid;
1389 v[0].dn = s->dest_dsa.computer_dn_str;
1391 vs[0].object = &v[0];
1393 attrs[i].attid = DRSUAPI_ATTRIBUTE_serverReference;
1394 attrs[i].value_ctr.dn_string.num_values = 1;
1395 attrs[i].value_ctr.dn_string.values = vs;
1400 /* truncate the attribute list to the attribute count we have filled in */
1403 /* setup request structure */
1404 r->in.bind_handle = &s->drsuapi1.bind_handle;
1406 r->in.req.req2.first_object.next_object = NULL;
1407 r->in.req.req2.first_object.object.identifier = identifier;
1408 r->in.req.req2.first_object.object.unknown1 = 0x00000000;
1409 r->in.req.req2.first_object.object.attribute_ctr.num_attributes = num_attrs;
1410 r->in.req.req2.first_object.object.attribute_ctr.attributes = attrs;
1412 req = dcerpc_drsuapi_DsAddEntry_send(s->drsuapi1.pipe, r, r);
1413 composite_continue_rpc(c, req, becomeDC_drsuapi1_add_entry_recv, s);
1416 static void becomeDC_drsuapi2_connect_recv(struct composite_context *req);
1418 static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req)
1420 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1421 struct libnet_BecomeDC_state);
1422 struct composite_context *c = s->creq;
1423 struct drsuapi_DsAddEntry *r = talloc_get_type(req->ndr.struct_ptr,
1424 struct drsuapi_DsAddEntry);
1426 c->status = dcerpc_ndr_request_recv(req);
1427 if (!composite_is_ok(c)) return;
1429 if (!W_ERROR_IS_OK(r->out.result)) {
1430 composite_error(c, werror_to_ntstatus(r->out.result));
1434 if (r->out.level == 3) {
1435 if (r->out.ctr.ctr3.count != 1) {
1438 if (r->out.ctr.ctr3.level != 1) {
1439 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
1443 if (!r->out.ctr.ctr3.error) {
1444 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
1448 status = r->out.ctr.ctr3.error->info1.status;
1450 if (!r->out.ctr.ctr3.error->info1.info) {
1451 composite_error(c, werror_to_ntstatus(status));
1455 /* see if we can get a more detailed error */
1456 switch (r->out.ctr.ctr3.error->info1.level) {
1458 status = r->out.ctr.ctr3.error->info1.info->error1.status;
1464 status = r->out.ctr.ctr3.error->info1.info->errorX.status;
1468 composite_error(c, werror_to_ntstatus(status));
1472 s->dest_dsa.ntds_guid = r->out.ctr.ctr3.objects[0].guid;
1473 } else if (r->out.level == 2) {
1474 if (r->out.ctr.ctr2.count != 1) {
1475 composite_error(c, werror_to_ntstatus(r->out.ctr.ctr2.error.status));
1479 s->dest_dsa.ntds_guid = r->out.ctr.ctr2.objects[0].guid;
1481 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
1487 becomeDC_drsuapi_connect_send(s, &s->drsuapi2, becomeDC_drsuapi2_connect_recv);
1490 static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req);
1492 static void becomeDC_drsuapi2_connect_recv(struct composite_context *req)
1494 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
1495 struct libnet_BecomeDC_state);
1496 struct composite_context *c = s->creq;
1498 c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi2.pipe);
1499 if (!composite_is_ok(c)) return;
1501 becomeDC_drsuapi_bind_send(s, &s->drsuapi2, becomeDC_drsuapi2_bind_recv);
1504 static void becomeDC_drsuapi3_connect_recv(struct composite_context *req);
1506 static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req)
1508 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1509 struct libnet_BecomeDC_state);
1510 struct composite_context *c = s->creq;
1513 c->status = dcerpc_ndr_request_recv(req);
1514 if (!composite_is_ok(c)) return;
1516 status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi2);
1517 if (!W_ERROR_IS_OK(status)) {
1518 composite_error(c, werror_to_ntstatus(status));
1522 /* this avoids the epmapper lookup on the 2nd connection */
1523 s->drsuapi3.binding = s->drsuapi2.binding;
1525 becomeDC_drsuapi_connect_send(s, &s->drsuapi3, becomeDC_drsuapi3_connect_recv);
1528 static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s);
1530 static void becomeDC_drsuapi3_connect_recv(struct composite_context *req)
1532 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data,
1533 struct libnet_BecomeDC_state);
1534 struct composite_context *c = s->creq;
1536 c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi3.pipe);
1537 if (!composite_is_ok(c)) return;
1539 becomeDC_drsuapi3_pull_schema_send(s);
1542 static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s,
1543 struct becomeDC_drsuapi *drsuapi_h,
1544 struct becomeDC_drsuapi *drsuapi_p,
1545 struct becomeDC_partition *partition,
1546 void (*recv_fn)(struct rpc_request *req))
1548 struct composite_context *c = s->creq;
1549 struct rpc_request *req;
1550 struct drsuapi_DsGetNCChanges *r;
1552 r = talloc(s, struct drsuapi_DsGetNCChanges);
1553 if (composite_nomem(r, c)) return;
1555 r->in.bind_handle = &drsuapi_h->bind_handle;
1556 if (drsuapi_h->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
1558 r->in.req.req8.destination_dsa_guid = partition->destination_dsa_guid;
1559 r->in.req.req8.source_dsa_invocation_id = partition->source_dsa_invocation_id;
1560 r->in.req.req8.naming_context = &partition->nc;
1561 r->in.req.req8.highwatermark = partition->highwatermark;
1562 r->in.req.req8.uptodateness_vector = partition->uptodateness_vector;
1563 r->in.req.req8.replica_flags = partition->replica_flags;
1564 r->in.req.req8.max_object_count = 133;
1565 r->in.req.req8.max_ndr_size = 1336811;
1566 r->in.req.req8.unknown4 = 0;
1567 r->in.req.req8.h1 = 0;
1568 r->in.req.req8.unique_ptr1 = 0;
1569 r->in.req.req8.unique_ptr2 = 0;
1570 r->in.req.req8.ctr12.count = 0;
1571 r->in.req.req8.ctr12.array = NULL;
1574 r->in.req.req5.destination_dsa_guid = partition->destination_dsa_guid;
1575 r->in.req.req5.source_dsa_invocation_id = partition->source_dsa_invocation_id;
1576 r->in.req.req5.naming_context = &partition->nc;
1577 r->in.req.req5.highwatermark = partition->highwatermark;
1578 r->in.req.req5.uptodateness_vector = partition->uptodateness_vector;
1579 r->in.req.req5.replica_flags = partition->replica_flags;
1580 r->in.req.req5.max_object_count = 133;
1581 r->in.req.req5.max_ndr_size = 1336770;
1582 r->in.req.req5.unknown4 = 0;
1583 r->in.req.req5.h1 = 0;
1587 * we should try to use the drsuapi_p->pipe here, as w2k3 does
1588 * but it seems that some extra flags in the DCERPC Bind call
1589 * are needed for it. Or the same KRB5 TGS is needed on both
1592 req = dcerpc_drsuapi_DsGetNCChanges_send(drsuapi_h->pipe, r, r);
1593 composite_continue_rpc(c, req, recv_fn, s);
1596 static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req);
1598 static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s)
1600 s->schema.nc.guid = GUID_zero();
1601 s->schema.nc.sid = s->zero_sid;
1602 s->schema.nc.dn = s->forest.schema_dn_str;
1604 s->schema.destination_dsa_guid = s->drsuapi2.bind_guid;
1606 s->schema.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
1607 | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
1608 | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS
1609 | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS
1610 | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED
1611 | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES;
1613 becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema,
1614 becomeDC_drsuapi3_pull_schema_recv);
1617 static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req)
1619 struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private,
1620 struct libnet_BecomeDC_state);
1621 struct composite_context *c = s->creq;
1622 struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
1623 struct drsuapi_DsGetNCChanges);
1625 c->status = dcerpc_ndr_request_recv(req);
1626 if (!composite_is_ok(c)) return;
1628 if (!W_ERROR_IS_OK(r->out.result)) {
1629 composite_error(c, werror_to_ntstatus(r->out.result));
1635 becomeDC_connect_ldap2(s);
1638 static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s)
1641 struct ldb_message *msg;
1643 uint32_t user_account_control = UF_SERVER_TRUST_ACCOUNT |
1644 UF_TRUSTED_FOR_DELEGATION;
1646 /* as the value is already as we want it to be, we're done */
1647 if (s->dest_dsa.user_account_control == user_account_control) {
1648 return NT_STATUS_OK;
1651 /* make a 'modify' msg, and only for serverReference */
1652 msg = ldb_msg_new(s);
1653 NT_STATUS_HAVE_NO_MEMORY(msg);
1654 msg->dn = ldb_dn_new(msg, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
1655 NT_STATUS_HAVE_NO_MEMORY(msg->dn);
1657 ret = ldb_msg_add_fmt(msg, "userAccountControl", "%u", user_account_control);
1660 return NT_STATUS_NO_MEMORY;
1663 /* mark all the message elements (should be just one)
1664 as LDB_FLAG_MOD_REPLACE */
1665 for (i=0;i<msg->num_elements;i++) {
1666 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1669 ret = ldb_modify(s->ldap2.ldb, msg);
1671 if (ret != LDB_SUCCESS) {
1672 return NT_STATUS_LDAP(ret);
1675 s->dest_dsa.user_account_control = user_account_control;
1677 return NT_STATUS_OK;
1680 static NTSTATUS becomeDC_ldap2_move_computer(struct libnet_BecomeDC_state *s)
1683 struct ldb_result *r;
1684 struct ldb_dn *basedn;
1685 struct ldb_dn *old_dn;
1686 struct ldb_dn *new_dn;
1687 static const char *_1_1_attrs[] = {
1692 basedn = ldb_dn_new_fmt(s, s->ldap2.ldb, "<WKGUID=a361b2ffffd211d1aa4b00c04fd7d83a,%s>",
1694 NT_STATUS_HAVE_NO_MEMORY(basedn);
1696 ret = ldb_search(s->ldap2.ldb, basedn, LDB_SCOPE_BASE,
1697 "(objectClass=*)", _1_1_attrs, &r);
1698 talloc_free(basedn);
1699 if (ret != LDB_SUCCESS) {
1700 return NT_STATUS_LDAP(ret);
1701 } else if (r->count != 1) {
1703 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1706 old_dn = ldb_dn_new(r, s->ldap2.ldb, s->dest_dsa.computer_dn_str);
1707 NT_STATUS_HAVE_NO_MEMORY(old_dn);
1709 new_dn = r->msgs[0]->dn;
1711 if (!ldb_dn_add_child_fmt(new_dn, "CN=%s", s->dest_dsa.netbios_name)) {
1713 return NT_STATUS_NO_MEMORY;
1716 if (ldb_dn_compare(old_dn, new_dn) == 0) {
1717 /* we don't need to rename if the old and new dn match */
1719 return NT_STATUS_OK;
1722 ret = ldb_rename(s->ldap2.ldb, old_dn, new_dn);
1723 if (ret != LDB_SUCCESS) {
1725 return NT_STATUS_LDAP(ret);
1728 s->dest_dsa.computer_dn_str = ldb_dn_alloc_linearized(s, new_dn);
1729 NT_STATUS_HAVE_NO_MEMORY(s->dest_dsa.computer_dn_str);
1733 return NT_STATUS_OK;
1736 static void becomeDC_connect_ldap2(struct libnet_BecomeDC_state *s)
1738 struct composite_context *c = s->creq;
1740 c->status = becomeDC_ldap_connect(s, &s->ldap2);
1741 if (!composite_is_ok(c)) return;
1743 c->status = becomeDC_ldap2_modify_computer(s);
1744 if (!composite_is_ok(c)) return;
1746 c->status = becomeDC_ldap2_move_computer(s);
1747 if (!composite_is_ok(c)) return;
1749 composite_error(c, NT_STATUS_NOT_IMPLEMENTED);
1752 struct composite_context *libnet_BecomeDC_send(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
1754 struct composite_context *c;
1755 struct libnet_BecomeDC_state *s;
1758 c = composite_create(mem_ctx, ctx->event_ctx);
1759 if (c == NULL) return NULL;
1761 s = talloc_zero(c, struct libnet_BecomeDC_state);
1762 if (composite_nomem(s, c)) return c;
1763 c->private_data = s;
1768 s->domain.dns_name = talloc_strdup(s, r->in.domain_dns_name);
1769 if (composite_nomem(s->domain.dns_name, c)) return c;
1770 s->domain.netbios_name = talloc_strdup(s, r->in.domain_netbios_name);
1771 if (composite_nomem(s->domain.netbios_name, c)) return c;
1772 s->domain.sid = dom_sid_dup(s, r->in.domain_sid);
1773 if (composite_nomem(s->domain.sid, c)) return c;
1775 /* Source DSA input */
1776 s->source_dsa.address = talloc_strdup(s, r->in.source_dsa_address);
1777 if (composite_nomem(s->source_dsa.address, c)) return c;
1779 /* Destination DSA input */
1780 s->dest_dsa.netbios_name= talloc_strdup(s, r->in.dest_dsa_netbios_name);
1781 if (composite_nomem(s->dest_dsa.netbios_name, c)) return c;
1783 /* Destination DSA dns_name construction */
1784 tmp_name = strlower_talloc(s, s->dest_dsa.netbios_name);
1785 if (composite_nomem(tmp_name, c)) return c;
1786 s->dest_dsa.dns_name = talloc_asprintf_append(tmp_name, ".%s",
1787 s->domain.dns_name);
1788 if (composite_nomem(s->dest_dsa.dns_name, c)) return c;
1790 becomeDC_send_cldap(s);
1794 NTSTATUS libnet_BecomeDC_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
1798 status = composite_wait(c);
1800 ZERO_STRUCT(r->out);
1806 NTSTATUS libnet_BecomeDC(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_BecomeDC *r)
1809 struct composite_context *c;
1810 c = libnet_BecomeDC_send(ctx, mem_ctx, r);
1811 status = libnet_BecomeDC_recv(c, mem_ctx, r);