X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source4%2Flibnet%2Flibnet_become_dc.c;h=a68f4c5ea05f4dbe645e511bb453174d7dc5e38c;hb=1e9f2bdb2f7f9e809dd3044dc94018e0b5b6e8d3;hp=19391e798338d02d888b22166dd6fb3e69a30473;hpb=7177df5df95c9fc0d2bc36340b948697980f00d3;p=samba.git diff --git a/source4/libnet/libnet_become_dc.c b/source4/libnet/libnet_become_dc.c index 19391e79833..a68f4c5ea05 100644 --- a/source4/libnet/libnet_become_dc.c +++ b/source4/libnet/libnet_become_dc.c @@ -21,11 +21,11 @@ #include "libnet/libnet.h" #include "libcli/composite/composite.h" #include "libcli/cldap/cldap.h" -#include "lib/ldb/include/ldb.h" -#include "lib/ldb/include/ldb_errors.h" -#include "lib/ldb_wrap.h" +#include +#include +#include "ldb_wrap.h" #include "dsdb/samdb/samdb.h" -#include "dsdb/common/flags.h" +#include "../libds/common/flags.h" #include "librpc/gen_ndr/ndr_drsuapi_c.h" #include "libcli/security/security.h" #include "librpc/gen_ndr/ndr_misc.h" @@ -34,6 +34,7 @@ #include "librpc/gen_ndr/ndr_drsuapi.h" #include "auth/gensec/gensec.h" #include "param/param.h" +#include "lib/tsocket/tsocket.h" /***************************************************************************** * Windows 2003 (w2k3) does the following steps when changing the server role @@ -336,7 +337,7 @@ * name: * objectGUID: * systemFlags: 1107296256 <0x42000000> - * objectCategory: CN=Site,C=Schema,CN=Configuration, + * objectCategory: CN=Site,CN=Schema,CN=Configuration, */ /*************************************************************** @@ -700,6 +701,7 @@ struct libnet_BecomeDC_state { struct libnet_BecomeDC_state *s; struct dcerpc_binding *binding; struct dcerpc_pipe *pipe; + struct dcerpc_binding_handle *drsuapi_handle; DATA_BLOB gensec_skey; struct drsuapi_DsBind bind_r; struct GUID bind_guid; @@ -709,6 +711,8 @@ struct libnet_BecomeDC_state { struct policy_handle bind_handle; } drsuapi1, drsuapi2, drsuapi3; + void *ndr_struct_ptr; + struct libnet_BecomeDC_Domain domain; struct libnet_BecomeDC_Forest forest; struct libnet_BecomeDC_SourceDSA source_dsa; @@ -729,17 +733,28 @@ struct libnet_BecomeDC_state { struct libnet_BecomeDC_PrepareDB _pp; struct libnet_BecomeDC_StoreChunk _sc; struct libnet_BecomeDC_Callbacks callbacks; + + bool rodc_join; }; -static void becomeDC_recv_cldap(struct cldap_request *req); +static int32_t get_dc_function_level(struct loadparm_context *lp_ctx) +{ + /* per default we are (Windows) 2008 R2 compatible */ + return lpcfg_parm_int(lp_ctx, NULL, "ads", "dc function level", + DS_DOMAIN_FUNCTION_2008_R2); +} + +static void becomeDC_recv_cldap(struct tevent_req *req); static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s) { struct composite_context *c = s->creq; - struct cldap_request *req; + struct tevent_req *req; + struct tsocket_address *dest_address; + int ret; - s->cldap.io.in.dest_address = s->source_dsa.address; - s->cldap.io.in.dest_port = lp_cldap_port(s->libnet->lp_ctx); + s->cldap.io.in.dest_address = NULL; + s->cldap.io.in.dest_port = 0; s->cldap.io.in.realm = s->domain.dns_name; s->cldap.io.in.host = s->dest_dsa.netbios_name; s->cldap.io.in.user = NULL; @@ -749,31 +764,45 @@ static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s) s->cldap.io.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; s->cldap.io.in.map_response = true; - s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx, - lp_iconv_convenience(s->libnet->lp_ctx)); - if (composite_nomem(s->cldap.sock, c)) return; + ret = tsocket_address_inet_from_strings(s, "ip", + s->source_dsa.address, + lpcfg_cldap_port(s->libnet->lp_ctx), + &dest_address); + if (ret != 0) { + c->status = map_nt_error_from_unix(errno); + if (!composite_is_ok(c)) return; + } + + c->status = cldap_socket_init(s, s->libnet->event_ctx, + NULL, dest_address, &s->cldap.sock); + if (!composite_is_ok(c)) return; - req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io); + req = cldap_netlogon_send(s, s->cldap.sock, &s->cldap.io); if (composite_nomem(req, c)) return; - req->async.fn = becomeDC_recv_cldap; - req->async.private = s; + tevent_req_set_callback(req, becomeDC_recv_cldap, s); } static void becomeDC_connect_ldap1(struct libnet_BecomeDC_state *s); -static void becomeDC_recv_cldap(struct cldap_request *req) +static void becomeDC_recv_cldap(struct tevent_req *req) { - struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private, + struct libnet_BecomeDC_state *s = tevent_req_callback_data(req, struct libnet_BecomeDC_state); struct composite_context *c = s->creq; c->status = cldap_netlogon_recv(req, s, &s->cldap.io); - if (!composite_is_ok(c)) return; - - s->cldap.netlogon = s->cldap.io.out.netlogon.nt5_ex; + talloc_free(req); + if (!composite_is_ok(c)) { + DEBUG(0,("Failed to send, receive or parse CLDAP reply from server %s for our host %s: %s\n", + s->cldap.io.in.dest_address, + s->cldap.io.in.host, + nt_errstr(c->status))); + return; + } + s->cldap.netlogon = s->cldap.io.out.netlogon.data.nt5_ex; s->domain.dns_name = s->cldap.netlogon.dns_domain; - s->domain.netbios_name = s->cldap.netlogon.domain; + s->domain.netbios_name = s->cldap.netlogon.domain_name; s->domain.guid = s->cldap.netlogon.domain_uuid; s->forest.dns_name = s->cldap.netlogon.forest; @@ -784,6 +813,15 @@ static void becomeDC_recv_cldap(struct cldap_request *req) s->dest_dsa.site_name = s->cldap.netlogon.client_site; + DEBUG(0,("CLDAP response: forest=%s dns=%s netbios=%s server_site=%s client_site=%s\n", + s->forest.dns_name, s->domain.dns_name, s->domain.netbios_name, + s->source_dsa.site_name, s->dest_dsa.site_name)); + if (!s->dest_dsa.site_name || strcmp(s->dest_dsa.site_name, "") == 0) { + DEBUG(0,("Got empty client site - using server site name %s\n", + s->source_dsa.site_name)); + s->dest_dsa.site_name = s->source_dsa.site_name; + } + becomeDC_connect_ldap1(s); } @@ -798,7 +836,7 @@ static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s, ldap->ldb = ldb_wrap_connect(s, s->libnet->event_ctx, s->libnet->lp_ctx, url, NULL, s->libnet->cred, - 0, NULL); + 0); talloc_free(url); if (ldap->ldb == NULL) { return NT_STATUS_UNEXPECTED_NETWORK_ERROR; @@ -820,8 +858,8 @@ static NTSTATUS becomeDC_ldap1_rootdse(struct libnet_BecomeDC_state *s) basedn = ldb_dn_new(s, s->ldap1.ldb, NULL); NT_STATUS_HAVE_NO_MEMORY(basedn); - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, - "(objectClass=*)", attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs, + "(objectClass=*)"); talloc_free(basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); @@ -829,7 +867,6 @@ static NTSTATUS becomeDC_ldap1_rootdse(struct libnet_BecomeDC_state *s) talloc_free(r); return NT_STATUS_INVALID_NETWORK_RESPONSE; } - talloc_steal(s, r); s->ldap1.rootdse = r->msgs[0]; @@ -864,8 +901,8 @@ static NTSTATUS becomeDC_ldap1_crossref_behavior_version(struct libnet_BecomeDC_ basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.config_dn_str); NT_STATUS_HAVE_NO_MEMORY(basedn); - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_ONELEVEL, - "(cn=Partitions)", attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_ONELEVEL, attrs, + "(cn=Partitions)"); talloc_free(basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); @@ -875,6 +912,14 @@ static NTSTATUS becomeDC_ldap1_crossref_behavior_version(struct libnet_BecomeDC_ } s->forest.crossref_behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0); + if (s->forest.crossref_behavior_version > + get_dc_function_level(s->libnet->lp_ctx)) { + talloc_free(r); + DEBUG(0,("The servers function level %u is above 'ads:dc function level' of %u\n", + s->forest.crossref_behavior_version, + get_dc_function_level(s->libnet->lp_ctx))); + return NT_STATUS_NOT_SUPPORTED; + } talloc_free(r); return NT_STATUS_OK; @@ -893,8 +938,8 @@ static NTSTATUS becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_st basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str); NT_STATUS_HAVE_NO_MEMORY(basedn); - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, - "(objectClass=*)", attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs, + "(objectClass=*)"); talloc_free(basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); @@ -904,6 +949,14 @@ static NTSTATUS becomeDC_ldap1_domain_behavior_version(struct libnet_BecomeDC_st } s->domain.behavior_version = ldb_msg_find_attr_as_uint(r->msgs[0], "msDs-Behavior-Version", 0); + if (s->domain.behavior_version > + get_dc_function_level(s->libnet->lp_ctx)) { + talloc_free(r); + DEBUG(0,("The servers function level %u is above 'ads:dc function level' of %u\n", + s->forest.crossref_behavior_version, + get_dc_function_level(s->libnet->lp_ctx))); + return NT_STATUS_NOT_SUPPORTED; + } talloc_free(r); return NT_STATUS_OK; @@ -922,8 +975,8 @@ static NTSTATUS becomeDC_ldap1_schema_object_version(struct libnet_BecomeDC_stat basedn = ldb_dn_new(s, s->ldap1.ldb, s->forest.schema_dn_str); NT_STATUS_HAVE_NO_MEMORY(basedn); - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, - "(objectClass=*)", attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs, + "(objectClass=*)"); talloc_free(basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); @@ -952,8 +1005,8 @@ static NTSTATUS becomeDC_ldap1_w2k3_update_revision(struct libnet_BecomeDC_state s->domain.dn_str); NT_STATUS_HAVE_NO_MEMORY(basedn); - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, - "(objectClass=*)", attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs, + "(objectClass=*)"); talloc_free(basedn); if (ret == LDB_ERR_NO_SUCH_OBJECT) { /* w2k doesn't have this object */ @@ -979,14 +1032,6 @@ static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state struct ldb_dn *basedn; struct ldb_dn *ntds_dn; struct ldb_dn *server_dn; - static const char *_1_1_attrs[] = { - "1.1", - NULL - }; - static const char *fsmo_attrs[] = { - "fSMORoleOwner", - NULL - }; static const char *dns_attrs[] = { "dnsHostName", NULL @@ -996,41 +1041,22 @@ static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state NULL }; - basedn = ldb_dn_new_fmt(s, s->ldap1.ldb, "", - s->domain.dn_str); - NT_STATUS_HAVE_NO_MEMORY(basedn); - - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, - "(objectClass=*)", _1_1_attrs, &r); - talloc_free(basedn); + ret = dsdb_wellknown_dn(s->ldap1.ldb, s, + ldb_get_default_basedn(s->ldap1.ldb), + DS_GUID_INFRASTRUCTURE_CONTAINER, + &basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); - } else if (r->count != 1) { - talloc_free(r); - return NT_STATUS_INVALID_NETWORK_RESPONSE; } - basedn = talloc_steal(s, r->msgs[0]->dn); - talloc_free(r); - - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, - "(objectClass=*)", fsmo_attrs, &r); - talloc_free(basedn); + ret = samdb_reference_dn(s->ldap1.ldb, s, basedn, "fSMORoleOwner", &ntds_dn); if (ret != LDB_SUCCESS) { + talloc_free(basedn); return NT_STATUS_LDAP(ret); - } else if (r->count != 1) { - talloc_free(r); - return NT_STATUS_INVALID_NETWORK_RESPONSE; } - s->infrastructure_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL); - if (!s->infrastructure_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; - talloc_steal(s, s->infrastructure_fsmo.ntds_dn_str); - - talloc_free(r); - - ntds_dn = ldb_dn_new(s, s->ldap1.ldb, s->infrastructure_fsmo.ntds_dn_str); - NT_STATUS_HAVE_NO_MEMORY(ntds_dn); + s->infrastructure_fsmo.ntds_dn_str = ldb_dn_get_linearized(ntds_dn); + NT_STATUS_HAVE_NO_MEMORY(s->infrastructure_fsmo.ntds_dn_str); server_dn = ldb_dn_get_parent(s, ntds_dn); NT_STATUS_HAVE_NO_MEMORY(server_dn); @@ -1038,8 +1064,8 @@ static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state s->infrastructure_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn); NT_STATUS_HAVE_NO_MEMORY(s->infrastructure_fsmo.server_dn_str); - ret = ldb_search(s->ldap1.ldb, server_dn, LDB_SCOPE_BASE, - "(objectClass=*)", dns_attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, server_dn, LDB_SCOPE_BASE, + dns_attrs, "(objectClass=*)"); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); } else if (r->count != 1) { @@ -1047,14 +1073,14 @@ static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state return NT_STATUS_INVALID_NETWORK_RESPONSE; } - s->infrastructure_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL); + s->infrastructure_fsmo.dns_name = ldb_msg_find_attr_as_string(r->msgs[0], "dnsHostName", NULL); if (!s->infrastructure_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE; talloc_steal(s, s->infrastructure_fsmo.dns_name); talloc_free(r); - ret = ldb_search(s->ldap1.ldb, ntds_dn, LDB_SCOPE_BASE, - "(objectClass=*)", guid_attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, ntds_dn, LDB_SCOPE_BASE, + guid_attrs, "(objectClass=*)"); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); } else if (r->count != 1) { @@ -1097,8 +1123,8 @@ static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s) basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str); NT_STATUS_HAVE_NO_MEMORY(basedn); - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, - "(objectClass=*)", rid_attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, + rid_attrs, "(objectClass=*)"); talloc_free(basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); @@ -1107,7 +1133,7 @@ static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s) return NT_STATUS_INVALID_NETWORK_RESPONSE; } - reference_dn_str = samdb_result_string(r->msgs[0], "rIDManagerReference", NULL); + reference_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "rIDManagerReference", NULL); if (!reference_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; basedn = ldb_dn_new(s, s->ldap1.ldb, reference_dn_str); @@ -1115,8 +1141,8 @@ static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s) talloc_free(r); - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, - "(objectClass=*)", fsmo_attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, + fsmo_attrs, "(objectClass=*)"); talloc_free(basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); @@ -1125,7 +1151,7 @@ static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s) return NT_STATUS_INVALID_NETWORK_RESPONSE; } - s->rid_manager_fsmo.ntds_dn_str = samdb_result_string(r->msgs[0], "fSMORoleOwner", NULL); + s->rid_manager_fsmo.ntds_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "fSMORoleOwner", NULL); if (!s->rid_manager_fsmo.ntds_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; talloc_steal(s, s->rid_manager_fsmo.ntds_dn_str); @@ -1140,8 +1166,8 @@ static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s) s->rid_manager_fsmo.server_dn_str = ldb_dn_alloc_linearized(s, server_dn); NT_STATUS_HAVE_NO_MEMORY(s->rid_manager_fsmo.server_dn_str); - ret = ldb_search(s->ldap1.ldb, server_dn, LDB_SCOPE_BASE, - "(objectClass=*)", dns_attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, server_dn, LDB_SCOPE_BASE, + dns_attrs, "(objectClass=*)"); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); } else if (r->count != 1) { @@ -1149,14 +1175,14 @@ static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s) return NT_STATUS_INVALID_NETWORK_RESPONSE; } - s->rid_manager_fsmo.dns_name = samdb_result_string(r->msgs[0], "dnsHostName", NULL); + s->rid_manager_fsmo.dns_name = ldb_msg_find_attr_as_string(r->msgs[0], "dnsHostName", NULL); if (!s->rid_manager_fsmo.dns_name) return NT_STATUS_INVALID_NETWORK_RESPONSE; talloc_steal(s, s->rid_manager_fsmo.dns_name); talloc_free(r); - ret = ldb_search(s->ldap1.ldb, ntds_dn, LDB_SCOPE_BASE, - "(objectClass=*)", guid_attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, ntds_dn, LDB_SCOPE_BASE, + guid_attrs, "(objectClass=*)"); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); } else if (r->count != 1) { @@ -1182,8 +1208,8 @@ static NTSTATUS becomeDC_ldap1_site_object(struct libnet_BecomeDC_state *s) s->forest.config_dn_str); NT_STATUS_HAVE_NO_MEMORY(basedn); - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, - "(objectClass=*)", NULL, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, + NULL, "(objectClass=*)"); talloc_free(basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); @@ -1214,7 +1240,6 @@ static NTSTATUS becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state *s) int ret; struct ldb_result *r; struct ldb_dn *basedn; - char *filter; static const char *attrs[] = { "distinguishedName", "userAccountControl", @@ -1224,12 +1249,9 @@ static NTSTATUS becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state *s) basedn = ldb_dn_new(s, s->ldap1.ldb, s->domain.dn_str); NT_STATUS_HAVE_NO_MEMORY(basedn); - filter = talloc_asprintf(basedn, "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))", - s->dest_dsa.netbios_name); - NT_STATUS_HAVE_NO_MEMORY(filter); - - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_SUBTREE, - filter, attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_SUBTREE, attrs, + "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))", + s->dest_dsa.netbios_name); talloc_free(basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); @@ -1238,11 +1260,11 @@ static NTSTATUS becomeDC_ldap1_computer_object(struct libnet_BecomeDC_state *s) return NT_STATUS_INVALID_NETWORK_RESPONSE; } - s->dest_dsa.computer_dn_str = samdb_result_string(r->msgs[0], "distinguishedName", NULL); + s->dest_dsa.computer_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "distinguishedName", NULL); if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; talloc_steal(s, s->dest_dsa.computer_dn_str); - s->dest_dsa.user_account_control = samdb_result_uint(r->msgs[0], "userAccountControl", 0); + s->dest_dsa.user_account_control = ldb_msg_find_attr_as_uint(r->msgs[0], "userAccountControl", 0); talloc_free(r); return NT_STATUS_OK; @@ -1263,8 +1285,8 @@ static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s) s->forest.config_dn_str); NT_STATUS_HAVE_NO_MEMORY(basedn); - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, - "(objectClass=*)", NULL, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, + NULL, "(objectClass=*)"); talloc_free(basedn); if (ret == LDB_ERR_NO_SUCH_OBJECT) { /* if the object doesn't exist, we'll create it later */ @@ -1276,7 +1298,7 @@ static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s) return NT_STATUS_INVALID_NETWORK_RESPONSE; } - server_reference_dn_str = samdb_result_string(r->msgs[0], "serverReference", NULL); + server_reference_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "serverReference", NULL); if (server_reference_dn_str) { server_reference_dn = ldb_dn_new(r, s->ldap1.ldb, server_reference_dn_str); NT_STATUS_HAVE_NO_MEMORY(server_reference_dn); @@ -1285,8 +1307,8 @@ static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s) NT_STATUS_HAVE_NO_MEMORY(computer_dn); /* - * if the server object belongs to another DC in another domain in the forest, - * we should not touch this object! + * if the server object belongs to another DC in another domain + * in the forest, we should not touch this object! */ if (ldb_dn_compare(computer_dn, server_reference_dn) != 0) { talloc_free(r); @@ -1295,7 +1317,7 @@ static NTSTATUS becomeDC_ldap1_server_object_1(struct libnet_BecomeDC_state *s) } /* if the server object is already for the dest_dsa, then we don't need to create it */ - s->dest_dsa.server_dn_str = samdb_result_string(r->msgs[0], "distinguishedName", NULL); + s->dest_dsa.server_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "distinguishedName", NULL); if (!s->dest_dsa.server_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; talloc_steal(s, s->dest_dsa.server_dn_str); @@ -1320,8 +1342,8 @@ static NTSTATUS becomeDC_ldap1_server_object_2(struct libnet_BecomeDC_state *s) basedn = ldb_dn_new(s, s->ldap1.ldb, s->dest_dsa.computer_dn_str); NT_STATUS_HAVE_NO_MEMORY(basedn); - ret = ldb_search(s->ldap1.ldb, basedn, LDB_SCOPE_BASE, - "(objectClass=*)", attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, + attrs, "(objectClass=*)"); talloc_free(basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); @@ -1330,7 +1352,7 @@ static NTSTATUS becomeDC_ldap1_server_object_2(struct libnet_BecomeDC_state *s) return NT_STATUS_INVALID_NETWORK_RESPONSE; } - server_reference_bl_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL); + server_reference_bl_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "serverReferenceBL", NULL); if (!server_reference_bl_dn_str) { /* if no back link is present, we're done for this function */ talloc_free(r); @@ -1338,7 +1360,7 @@ static NTSTATUS becomeDC_ldap1_server_object_2(struct libnet_BecomeDC_state *s) } /* if the server object is already for the dest_dsa, then we don't need to create it */ - s->dest_dsa.server_dn_str = samdb_result_string(r->msgs[0], "serverReferenceBL", NULL); + s->dest_dsa.server_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "serverReferenceBL", NULL); if (s->dest_dsa.server_dn_str) { /* if a back link is present, we know that the server object is present */ talloc_steal(s, s->dest_dsa.server_dn_str); @@ -1401,7 +1423,7 @@ static NTSTATUS becomeDC_ldap1_server_object_modify(struct libnet_BecomeDC_state { int ret; struct ldb_message *msg; - uint32_t i; + unsigned int i; /* make a 'modify' msg, and only for serverReference */ msg = ldb_msg_new(s); @@ -1516,22 +1538,23 @@ static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s, drsuapi->s = s; if (!drsuapi->binding) { - char *krb5_str = ""; - char *print_str = ""; + const char *krb5_str = ""; + const char *print_str = ""; /* * Note: Replication only works with Windows 2000 when 'krb5' is * passed as auth_type here. If NTLMSSP is used, Windows * 2000 returns garbage in the DsGetNCChanges() response - * if encrypted password attributes would be in the response. - * That means the replication of the schema and configuration - * partition works fine, but it fails for the domain partition. + * if encrypted password attributes would be in the + * response. That means the replication of the schema and + * configuration partition works fine, but it fails for + * the domain partition. */ - if (lp_parm_bool(s->libnet->lp_ctx, NULL, "become_dc", + if (lpcfg_parm_bool(s->libnet->lp_ctx, NULL, "become_dc", "force krb5", true)) { krb5_str = "krb5,"; } - if (lp_parm_bool(s->libnet->lp_ctx, NULL, "become_dc", + if (lpcfg_parm_bool(s->libnet->lp_ctx, NULL, "become_dc", "print", false)) { print_str = "print,"; @@ -1545,6 +1568,10 @@ static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s, if (!composite_is_ok(c)) return; } + if (DEBUGLEVEL >= 10) { + drsuapi->binding->flags |= DCERPC_DEBUG_PRINT_BOTH; + } + creq = dcerpc_pipe_connect_b_send(s, drsuapi->binding, &ndr_table_drsuapi, s->libnet->cred, s->libnet->event_ctx, s->libnet->lp_ctx); @@ -1553,8 +1580,8 @@ static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s, static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s, struct becomeDC_drsuapi *drsuapi, - void (*recv_fn)(struct rpc_request *req)); -static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req); + void (*recv_fn)(struct tevent_req *subreq)); +static void becomeDC_drsuapi1_bind_recv(struct tevent_req *subreq); static void becomeDC_drsuapi1_connect_recv(struct composite_context *req) { @@ -1565,6 +1592,8 @@ static void becomeDC_drsuapi1_connect_recv(struct composite_context *req) c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi1.pipe); if (!composite_is_ok(c)) return; + s->drsuapi1.drsuapi_handle = s->drsuapi1.pipe->binding_handle; + c->status = gensec_session_key(s->drsuapi1.pipe->conn->security_state.generic_state, &s->drsuapi1.gensec_skey); if (!composite_is_ok(c)) return; @@ -1574,11 +1603,11 @@ static void becomeDC_drsuapi1_connect_recv(struct composite_context *req) static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s, struct becomeDC_drsuapi *drsuapi, - void (*recv_fn)(struct rpc_request *req)) + void (*recv_fn)(struct tevent_req *subreq)) { struct composite_context *c = s->creq; - struct rpc_request *req; struct drsuapi_DsBindInfo28 *bind_info28; + struct tevent_req *subreq; GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &drsuapi->bind_guid); @@ -1592,7 +1621,7 @@ static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s, bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION; bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE; bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2; - if (s->domain.behavior_version == 2) { + if (s->domain.behavior_version >= DS_DOMAIN_FUNCTION_2003) { /* TODO: find out how this is really triggered! */ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION; } @@ -1605,7 +1634,7 @@ static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s, bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP; bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY; bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3; - bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_00100000; + bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V5; bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2; bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6; bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS; @@ -1629,8 +1658,11 @@ static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s, drsuapi->bind_r.in.bind_info = &drsuapi->bind_info_ctr; drsuapi->bind_r.out.bind_handle = &drsuapi->bind_handle; - req = dcerpc_drsuapi_DsBind_send(drsuapi->pipe, s, &drsuapi->bind_r); - composite_continue_rpc(c, req, recv_fn, s); + subreq = dcerpc_drsuapi_DsBind_r_send(s, c->event_ctx, + drsuapi->drsuapi_handle, + &drsuapi->bind_r); + if (composite_nomem(subreq, c)) return; + tevent_req_set_callback(subreq, recv_fn, s); } static WERROR becomeDC_drsuapi_bind_recv(struct libnet_BecomeDC_state *s, @@ -1672,26 +1704,17 @@ static WERROR becomeDC_drsuapi_bind_recv(struct libnet_BecomeDC_state *s, static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s); -static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req) +static void becomeDC_drsuapi1_bind_recv(struct tevent_req *subreq) { - struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, + struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq, struct libnet_BecomeDC_state); struct composite_context *c = s->creq; WERROR status; - bool print = false; - - if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { - print = true; - } - - c->status = dcerpc_ndr_request_recv(req); + c->status = dcerpc_drsuapi_DsBind_r_recv(subreq, s); + TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; - if (print) { - NDR_PRINT_OUT_DEBUG(drsuapi_DsBind, &s->drsuapi1.bind_r); - } - status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi1); if (!W_ERROR_IS_OK(status)) { composite_error(c, werror_to_ntstatus(status)); @@ -1701,26 +1724,25 @@ static void becomeDC_drsuapi1_bind_recv(struct rpc_request *req) becomeDC_drsuapi1_add_entry_send(s); } -static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req); +static void becomeDC_drsuapi1_add_entry_recv(struct tevent_req *subreq); static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) { struct composite_context *c = s->creq; - struct rpc_request *req; struct drsuapi_DsAddEntry *r; struct drsuapi_DsReplicaObjectIdentifier *identifier; uint32_t num_attrs, i = 0; struct drsuapi_DsReplicaAttribute *attrs; - struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(s->libnet->lp_ctx); enum ndr_err_code ndr_err; bool w2k3; + struct tevent_req *subreq; /* choose a random invocationId */ s->dest_dsa.invocation_id = GUID_random(); /* - * if the schema version indicates w2k3, then - * also send some w2k3 specific attributes + * if the schema version indicates w2k3, then also send some w2k3 + * specific attributes. */ if (s->forest.schema_object_version >= 30) { w2k3 = true; @@ -1741,7 +1763,7 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) if (composite_nomem(identifier->dn, c)) return; /* allocate attribute array */ - num_attrs = 11; + num_attrs = 12; attrs = talloc_array(r, struct drsuapi_DsReplicaAttribute, num_attrs); if (composite_nomem(attrs, c)) return; @@ -1810,7 +1832,8 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) NULL); if (composite_nomem(v, c)) return; - ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, v,(ndr_push_flags_fn_t)ndr_push_security_descriptor); + ndr_err = ndr_push_struct_blob(&vd[0], vd, v, + (ndr_push_flags_fn_t)ndr_push_security_descriptor); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { c->status = ndr_map_error2ntstatus(ndr_err); if (!composite_is_ok(c)) return; @@ -1818,7 +1841,7 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) vs[0].blob = &vd[0]; - attrs[i].attid = DRSUAPI_ATTRIBUTE_ntSecurityDescriptor; + attrs[i].attid = DRSUAPI_ATTID_ntSecurityDescriptor; attrs[i].value_ctr.num_values = 1; attrs[i].value_ctr.values = vs; @@ -1844,14 +1867,14 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) vs[0].blob = &vd[0]; - attrs[i].attid = DRSUAPI_ATTRIBUTE_objectClass; + attrs[i].attid = DRSUAPI_ATTID_objectClass; attrs[i].value_ctr.num_values = 1; attrs[i].value_ctr.values = vs; i++; } - /* objectCategory: CN=NTDS-DSA,CN=Schema,... */ + /* objectCategory: CN=NTDS-DSA,CN=Schema,... or CN=NTDS-DSA-RO,CN=Schema,... */ { struct drsuapi_DsAttributeValue *vs; DATA_BLOB *vd; @@ -1865,12 +1888,18 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) v[0].guid = GUID_zero(); v[0].sid = s->zero_sid; - v[0].dn = talloc_asprintf(vd, "CN=NTDS-DSA,%s", + + if (s->rodc_join) { + v[0].dn = talloc_asprintf(vd, "CN=NTDS-DSA-RO,%s", + s->forest.schema_dn_str); + } else { + v[0].dn = talloc_asprintf(vd, "CN=NTDS-DSA,%s", s->forest.schema_dn_str); + } if (composite_nomem(v[0].dn, c)) return; - ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], - (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); + ndr_err = ndr_push_struct_blob(&vd[0], vd, &v[0], + (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { c->status = ndr_map_error2ntstatus(ndr_err); if (!composite_is_ok(c)) return; @@ -1878,7 +1907,7 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) vs[0].blob = &vd[0]; - attrs[i].attid = DRSUAPI_ATTRIBUTE_objectCategory; + attrs[i].attid = DRSUAPI_ATTID_objectCategory; attrs[i].value_ctr.num_values = 1; attrs[i].value_ctr.values = vs; @@ -1899,15 +1928,12 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) v = &s->dest_dsa.invocation_id; - ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, v, (ndr_push_flags_fn_t)ndr_push_GUID); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - c->status = ndr_map_error2ntstatus(ndr_err); - if (!composite_is_ok(c)) return; - } + c->status = GUID_to_ndr_blob(v, vd, &vd[0]); + if (!composite_is_ok(c)) return; vs[0].blob = &vd[0]; - attrs[i].attid = DRSUAPI_ATTRIBUTE_invocationId; + attrs[i].attid = DRSUAPI_ATTID_invocationId; attrs[i].value_ctr.num_values = 1; attrs[i].value_ctr.values = vs; @@ -1938,22 +1964,22 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) v[2].sid = s->zero_sid; v[2].dn = s->forest.schema_dn_str; - ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], - (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); + ndr_err = ndr_push_struct_blob(&vd[0], vd, &v[0], + (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { c->status = ndr_map_error2ntstatus(ndr_err); if (!composite_is_ok(c)) return; } - ndr_err = ndr_push_struct_blob(&vd[1], vd, iconv_convenience, &v[1], - (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); + ndr_err = ndr_push_struct_blob(&vd[1], vd, &v[1], + (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { c->status = ndr_map_error2ntstatus(ndr_err); if (!composite_is_ok(c)) return; } - ndr_err = ndr_push_struct_blob(&vd[2], vd, iconv_convenience, &v[2], - (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); + ndr_err = ndr_push_struct_blob(&vd[2], vd, &v[2], + (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { c->status = ndr_map_error2ntstatus(ndr_err); if (!composite_is_ok(c)) return; @@ -1963,7 +1989,7 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) vs[1].blob = &vd[1]; vs[2].blob = &vd[2]; - attrs[i].attid = DRSUAPI_ATTRIBUTE_hasMasterNCs; + attrs[i].attid = DRSUAPI_ATTID_hasMasterNCs; attrs[i].value_ctr.num_values = 3; attrs[i].value_ctr.values = vs; @@ -1994,22 +2020,22 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) v[2].sid = s->zero_sid; v[2].dn = s->forest.schema_dn_str; - ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], - (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); + ndr_err = ndr_push_struct_blob(&vd[0], vd, &v[0], + (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { c->status = ndr_map_error2ntstatus(ndr_err); if (!composite_is_ok(c)) return; } - ndr_err = ndr_push_struct_blob(&vd[1], vd, iconv_convenience, &v[1], - (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); + ndr_err = ndr_push_struct_blob(&vd[1], vd, &v[1], + (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { c->status = ndr_map_error2ntstatus(ndr_err); if (!composite_is_ok(c)) return; } - ndr_err = ndr_push_struct_blob(&vd[2], vd, iconv_convenience, &v[2], - (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); + ndr_err = ndr_push_struct_blob(&vd[2], vd, &v[2], + (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { c->status = ndr_map_error2ntstatus(ndr_err); if (!composite_is_ok(c)) return; @@ -2019,7 +2045,7 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) vs[1].blob = &vd[1]; vs[2].blob = &vd[2]; - attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_hasMasterNCs; + attrs[i].attid = DRSUAPI_ATTID_msDS_hasMasterNCs; attrs[i].value_ctr.num_values = 3; attrs[i].value_ctr.values = vs; @@ -2042,8 +2068,8 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) v[0].sid = s->zero_sid; v[0].dn = s->forest.schema_dn_str; - ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], - (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); + ndr_err = ndr_push_struct_blob(&vd[0], vd, &v[0], + (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { c->status = ndr_map_error2ntstatus(ndr_err); if (!composite_is_ok(c)) return; @@ -2051,7 +2077,7 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) vs[0].blob = &vd[0]; - attrs[i].attid = DRSUAPI_ATTRIBUTE_dMDLocation; + attrs[i].attid = DRSUAPI_ATTID_dMDLocation; attrs[i].value_ctr.num_values = 1; attrs[i].value_ctr.values = vs; @@ -2074,8 +2100,8 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) v[0].sid = s->zero_sid; v[0].dn = s->domain.dn_str; - ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], - (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); + ndr_err = ndr_push_struct_blob(&vd[0], vd, &v[0], + (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { c->status = ndr_map_error2ntstatus(ndr_err); if (!composite_is_ok(c)) return; @@ -2083,7 +2109,7 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) vs[0].blob = &vd[0]; - attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_HasDomainNCs; + attrs[i].attid = DRSUAPI_ATTID_msDS_HasDomainNCs; attrs[i].value_ctr.num_values = 1; attrs[i].value_ctr.values = vs; @@ -2104,11 +2130,11 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) vd[0] = data_blob_talloc(vd, NULL, 4); if (composite_nomem(vd[0].data, c)) return; - SIVAL(vd[0].data, 0, DS_BEHAVIOR_WIN2008); + SIVAL(vd[0].data, 0, get_dc_function_level(s->libnet->lp_ctx)); vs[0].blob = &vd[0]; - attrs[i].attid = DRSUAPI_ATTRIBUTE_msDS_Behavior_Version; + attrs[i].attid = DRSUAPI_ATTID_msDS_Behavior_Version; attrs[i].value_ctr.num_values = 1; attrs[i].value_ctr.values = vs; @@ -2129,11 +2155,15 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) vd[0] = data_blob_talloc(vd, NULL, 4); if (composite_nomem(vd[0].data, c)) return; - SIVAL(vd[0].data, 0, SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE); + if (s->rodc_join) { + SIVAL(vd[0].data, 0, SYSTEM_FLAG_CONFIG_ALLOW_RENAME); + } else { + SIVAL(vd[0].data, 0, SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE); + } vs[0].blob = &vd[0]; - attrs[i].attid = DRSUAPI_ATTRIBUTE_systemFlags; + attrs[i].attid = DRSUAPI_ATTID_systemFlags; attrs[i].value_ctr.num_values = 1; attrs[i].value_ctr.values = vs; @@ -2156,8 +2186,8 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) v[0].sid = s->zero_sid; v[0].dn = s->dest_dsa.computer_dn_str; - ndr_err = ndr_push_struct_blob(&vd[0], vd, iconv_convenience, &v[0], - (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); + ndr_err = ndr_push_struct_blob(&vd[0], vd, &v[0], + (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { c->status = ndr_map_error2ntstatus(ndr_err); if (!composite_is_ok(c)) return; @@ -2165,7 +2195,32 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) vs[0].blob = &vd[0]; - attrs[i].attid = DRSUAPI_ATTRIBUTE_serverReference; + attrs[i].attid = DRSUAPI_ATTID_serverReference; + attrs[i].value_ctr.num_values = 1; + attrs[i].value_ctr.values = vs; + + i++; + } + + /* options:... */ + if (s->rodc_join) { + struct drsuapi_DsAttributeValue *vs; + DATA_BLOB *vd; + + vs = talloc_array(attrs, struct drsuapi_DsAttributeValue, 1); + if (composite_nomem(vs, c)) return; + + vd = talloc_array(vs, DATA_BLOB, 1); + if (composite_nomem(vd, c)) return; + + vd[0] = data_blob_talloc(vd, NULL, 4); + if (composite_nomem(vd[0].data, c)) return; + + SIVAL(vd[0].data, 0, DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL); + + vs[0].blob = &vd[0]; + + attrs[i].attid = DRSUAPI_ATTID_options; attrs[i].value_ctr.num_values = 1; attrs[i].value_ctr.values = vs; @@ -2178,76 +2233,154 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) /* setup request structure */ r->in.bind_handle = &s->drsuapi1.bind_handle; r->in.level = 2; - r->in.req.req2.first_object.next_object = NULL; - r->in.req.req2.first_object.object.identifier = identifier; - r->in.req.req2.first_object.object.flags = 0x00000000; - r->in.req.req2.first_object.object.attribute_ctr.num_attributes = num_attrs; - r->in.req.req2.first_object.object.attribute_ctr.attributes = attrs; - - req = dcerpc_drsuapi_DsAddEntry_send(s->drsuapi1.pipe, r, r); - composite_continue_rpc(c, req, becomeDC_drsuapi1_add_entry_recv, s); + r->in.req = talloc(s, union drsuapi_DsAddEntryRequest); + r->in.req->req2.first_object.next_object = NULL; + r->in.req->req2.first_object.object.identifier = identifier; + r->in.req->req2.first_object.object.flags = 0x00000000; + r->in.req->req2.first_object.object.attribute_ctr.num_attributes= num_attrs; + r->in.req->req2.first_object.object.attribute_ctr.attributes = attrs; + + r->out.level_out = talloc(s, uint32_t); + r->out.ctr = talloc(s, union drsuapi_DsAddEntryCtr); + + s->ndr_struct_ptr = r; + subreq = dcerpc_drsuapi_DsAddEntry_r_send(s, c->event_ctx, + s->drsuapi1.drsuapi_handle, r); + if (composite_nomem(subreq, c)) return; + tevent_req_set_callback(subreq, becomeDC_drsuapi1_add_entry_recv, s); } static void becomeDC_drsuapi2_connect_recv(struct composite_context *req); static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s); -static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req) +static void becomeDC_drsuapi1_add_entry_recv(struct tevent_req *subreq) { - struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, + struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq, struct libnet_BecomeDC_state); struct composite_context *c = s->creq; - struct drsuapi_DsAddEntry *r = talloc_get_type(req->ndr.struct_ptr, + struct drsuapi_DsAddEntry *r = talloc_get_type_abort(s->ndr_struct_ptr, struct drsuapi_DsAddEntry); char *binding_str; - bool print = false; - if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { - print = true; - } + s->ndr_struct_ptr = NULL; - c->status = dcerpc_ndr_request_recv(req); + c->status = dcerpc_drsuapi_DsAddEntry_r_recv(subreq, r); + TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; - if (print) { - NDR_PRINT_OUT_DEBUG(drsuapi_DsAddEntry, r); - } - if (!W_ERROR_IS_OK(r->out.result)) { composite_error(c, werror_to_ntstatus(r->out.result)); return; } - if (r->out.level == 3) { - if (r->out.ctr.ctr3.count != 1) { - WERROR status; + if (*r->out.level_out == 3) { + WERROR status; + union drsuapi_DsAddEntry_ErrData *err_data = r->out.ctr->ctr3.err_data; - if (r->out.ctr.ctr3.level != 1) { - composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } + /* check for errors */ + status = err_data ? err_data->v1.status : WERR_OK; + if (!W_ERROR_IS_OK(status)) { + struct drsuapi_DsAddEntryErrorInfo_Attr_V1 *attr_err; + struct drsuapi_DsAddEntry_AttrErrListItem_V1 *attr_err_li; + struct drsuapi_DsAddEntryErrorInfo_Name_V1 *name_err; + struct drsuapi_DsAddEntryErrorInfo_Referr_V1 *ref_err; + struct drsuapi_DsAddEntry_RefErrListItem_V1 *ref_li; - if (!r->out.ctr.ctr3.error) { + if (r->out.ctr->ctr3.err_ver != 1) { composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } - status = r->out.ctr.ctr3.error->info1.status; + DEBUG(0,("DsAddEntry (R3) of '%s' failed: " + "Errors: dir_err = %d, status = %s;\n", + r->in.req->req3.first_object.object.identifier->dn, + err_data->v1.dir_err, + win_errstr(err_data->v1.status))); - if (!r->out.ctr.ctr3.error->info1.info) { + if (!err_data->v1.info) { + DEBUG(0, ("DsAddEntry (R3): no error info returned!\n")); composite_error(c, werror_to_ntstatus(status)); return; } - /* see if we can get a more detailed error */ - switch (r->out.ctr.ctr3.error->info1.level) { - case 1: - status = r->out.ctr.ctr3.error->info1.info->error1.status; + /* dump more detailed error */ + switch (err_data->v1.dir_err) { + case DRSUAPI_DIRERR_ATTRIBUTE: + /* Dump attribute errors */ + attr_err = &err_data->v1.info->attr_err; + DEBUGADD(0,(" Attribute Error: object = %s, count = %d;\n", + attr_err->id->dn, + attr_err->count)); + attr_err_li = &attr_err->first; + for (; attr_err_li; attr_err_li = attr_err_li->next) { + struct drsuapi_DsAddEntry_AttrErr_V1 *err = &attr_err_li->err_data; + DEBUGADD(0,(" Error: err = %s, problem = 0x%08X, attid = 0x%08X;\n", + win_errstr(err->extended_err), + err->problem, + err->attid)); + /* TODO: should we print attribute value here? */ + } + break; + case DRSUAPI_DIRERR_NAME: + /* Dump Name resolution error */ + name_err = &err_data->v1.info->name_err; + DEBUGADD(0,(" Name Error: err = %s, problem = 0x%08X, id_matched = %s;\n", + win_errstr(name_err->extended_err), + name_err->problem, + name_err->id_matched->dn)); + break; + case DRSUAPI_DIRERR_REFERRAL: + /* Dump Referral errors */ + ref_err = &err_data->v1.info->referral_err; + DEBUGADD(0,(" Referral Error: extended_err = %s\n", + win_errstr(ref_err->extended_err))); + ref_li = &ref_err->refer; + for (; ref_li; ref_li = ref_li->next) { + struct drsuapi_DsaAddressListItem_V1 *addr; + DEBUGADD(0,(" Referral: id_target = %s, ref_type = 0x%04X,", + ref_li->id_target->dn, + ref_li->ref_type)); + if (ref_li->is_choice_set) { + DEBUGADD(0,(" choice = 0x%02X, ", + ref_li->choice)); + } + DEBUGADD(0,(" add_list (")); + for (addr = ref_li->addr_list; addr; addr = addr->next) { + DEBUGADD(0,("%s", addr->address->string)); + if (addr->next) { + DEBUGADD(0,(", ")); + } + } + DEBUGADD(0,(");\n")); + } + break; + case DRSUAPI_DIRERR_SECURITY: + /* Dump Security error. */ + DEBUGADD(0,(" Security Error: extended_err = %s, problem = 0x%08X\n", + win_errstr(err_data->v1.info->security_err.extended_err), + err_data->v1.info->security_err.problem)); + break; + case DRSUAPI_DIRERR_SERVICE: + /* Dump Service error. */ + DEBUGADD(0,(" Service Error: extended_err = %s, problem = 0x%08X\n", + win_errstr(err_data->v1.info->service_err.extended_err), + err_data->v1.info->service_err.problem)); break; - case 4: - case 5: - case 6: - case 7: - status = r->out.ctr.ctr3.error->info1.info->errorX.status; + case DRSUAPI_DIRERR_UPDATE: + /* Dump Update error. */ + DEBUGADD(0,(" Update Error: extended_err = %s, problem = 0x%08X\n", + win_errstr(err_data->v1.info->update_err.extended_err), + err_data->v1.info->update_err.problem)); + break; + case DRSUAPI_DIRERR_SYSTEM: + /* System error. */ + DEBUGADD(0,(" System Error: extended_err = %s, problem = 0x%08X\n", + win_errstr(err_data->v1.info->system_err.extended_err), + err_data->v1.info->system_err.problem)); + break; + case DRSUAPI_DIRERR_OK: /* mute compiler warnings */ + default: + DEBUGADD(0,(" Unknown DIRERR error class returned!\n")); break; } @@ -2255,14 +2388,35 @@ static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req) return; } - s->dest_dsa.ntds_guid = r->out.ctr.ctr3.objects[0].guid; - } else if (r->out.level == 2) { - if (r->out.ctr.ctr2.count != 1) { - composite_error(c, werror_to_ntstatus(r->out.ctr.ctr2.error.status)); + if (1 != r->out.ctr->ctr3.count) { + DEBUG(0,("DsAddEntry - Ctr3: something very wrong had happened - " + "method succeeded but objects returned are %d (expected 1).\n", + r->out.ctr->ctr3.count)); + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); + } + + s->dest_dsa.ntds_guid = r->out.ctr->ctr3.objects[0].guid; + + } else if (*r->out.level_out == 2) { + if (DRSUAPI_DIRERR_OK != r->out.ctr->ctr2.dir_err) { + DEBUG(0,("DsAddEntry failed with: dir_err = %d, extended_err = %s\n", + r->out.ctr->ctr2.dir_err, + win_errstr(r->out.ctr->ctr2.extended_err))); + composite_error(c, werror_to_ntstatus(r->out.ctr->ctr2.extended_err)); return; } - s->dest_dsa.ntds_guid = r->out.ctr.ctr2.objects[0].guid; + if (1 != r->out.ctr->ctr2.count) { + DEBUG(0,("DsAddEntry: something very wrong had happened - " + "method succeeded but objects returned are %d (expected 1). " + "Errors: dir_err = %d, extended_err = %s\n", + r->out.ctr->ctr2.count, + r->out.ctr->ctr2.dir_err, + win_errstr(r->out.ctr->ctr2.extended_err))); + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); + } + + s->dest_dsa.ntds_guid = r->out.ctr->ctr2.objects[0].guid; } else { composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); return; @@ -2285,6 +2439,10 @@ static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req) talloc_free(binding_str); if (!composite_is_ok(c)) return; + if (DEBUGLEVEL >= 10) { + s->drsuapi2.binding->flags |= DCERPC_DEBUG_PRINT_BOTH; + } + /* w2k3 uses the same assoc_group_id as on the first connection, so we do */ s->drsuapi2.binding->assoc_group_id = s->drsuapi1.pipe->assoc_group_id; @@ -2303,7 +2461,7 @@ static NTSTATUS becomeDC_prepare_db(struct libnet_BecomeDC_state *s) return s->callbacks.prepare_db(s->callbacks.private_data, &s->_pp); } -static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req); +static void becomeDC_drsuapi2_bind_recv(struct tevent_req *subreq); static void becomeDC_drsuapi2_connect_recv(struct composite_context *req) { @@ -2314,6 +2472,8 @@ static void becomeDC_drsuapi2_connect_recv(struct composite_context *req) c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi2.pipe); if (!composite_is_ok(c)) return; + s->drsuapi2.drsuapi_handle = s->drsuapi2.pipe->binding_handle; + c->status = gensec_session_key(s->drsuapi2.pipe->conn->security_state.generic_state, &s->drsuapi2.gensec_skey); if (!composite_is_ok(c)) return; @@ -2323,27 +2483,18 @@ static void becomeDC_drsuapi2_connect_recv(struct composite_context *req) static void becomeDC_drsuapi3_connect_recv(struct composite_context *req); -static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req) +static void becomeDC_drsuapi2_bind_recv(struct tevent_req *subreq) { - struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, + struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq, struct libnet_BecomeDC_state); struct composite_context *c = s->creq; char *binding_str; WERROR status; - bool print = false; - - if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { - print = true; - } - - c->status = dcerpc_ndr_request_recv(req); + c->status = dcerpc_drsuapi_DsBind_r_recv(subreq, s); + TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; - if (print) { - NDR_PRINT_OUT_DEBUG(drsuapi_DsBind, &s->drsuapi2.bind_r); - } - status = becomeDC_drsuapi_bind_recv(s, &s->drsuapi2); if (!W_ERROR_IS_OK(status)) { composite_error(c, werror_to_ntstatus(status)); @@ -2358,6 +2509,10 @@ static void becomeDC_drsuapi2_bind_recv(struct rpc_request *req) talloc_free(binding_str); if (!composite_is_ok(c)) return; + if (DEBUGLEVEL >= 10) { + s->drsuapi3.binding->flags |= DCERPC_DEBUG_PRINT_BOTH; + } + /* w2k3 uses the same assoc_group_id as on the first connection, so we do */ s->drsuapi3.binding->assoc_group_id = s->drsuapi1.pipe->assoc_group_id; /* w2k3 uses the concurrent multiplex feature on the 3rd connection, so we do */ @@ -2377,6 +2532,8 @@ static void becomeDC_drsuapi3_connect_recv(struct composite_context *req) c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi3.pipe); if (!composite_is_ok(c)) return; + s->drsuapi3.drsuapi_handle = s->drsuapi3.pipe->binding_handle; + c->status = gensec_session_key(s->drsuapi3.pipe->conn->security_state.generic_state, &s->drsuapi3.gensec_skey); if (!composite_is_ok(c)) return; @@ -2388,49 +2545,51 @@ static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s struct becomeDC_drsuapi *drsuapi_h, struct becomeDC_drsuapi *drsuapi_p, struct libnet_BecomeDC_Partition *partition, - void (*recv_fn)(struct rpc_request *req)) + void (*recv_fn)(struct tevent_req *subreq)) { struct composite_context *c = s->creq; - struct rpc_request *req; struct drsuapi_DsGetNCChanges *r; + struct tevent_req *subreq; r = talloc(s, struct drsuapi_DsGetNCChanges); if (composite_nomem(r, c)) return; - r->in.level = talloc(r, int32_t); - if (composite_nomem(r->in.level, c)) return; - r->out.level = talloc(r, int32_t); - if (composite_nomem(r->out.level, c)) return; + r->out.level_out = talloc(r, uint32_t); + if (composite_nomem(r->out.level_out, c)) return; + r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest); + if (composite_nomem(r->in.req, c)) return; + r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr); + if (composite_nomem(r->out.ctr, c)) return; r->in.bind_handle = &drsuapi_h->bind_handle; if (drsuapi_h->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) { - *r->in.level = 8; - r->in.req.req8.destination_dsa_guid = partition->destination_dsa_guid; - r->in.req.req8.source_dsa_invocation_id = partition->source_dsa_invocation_id; - r->in.req.req8.naming_context = &partition->nc; - r->in.req.req8.highwatermark = partition->highwatermark; - r->in.req.req8.uptodateness_vector = NULL; - r->in.req.req8.replica_flags = partition->replica_flags; - r->in.req.req8.max_object_count = 133; - r->in.req.req8.max_ndr_size = 1336811; - r->in.req.req8.extended_op = DRSUAPI_EXOP_NONE; - r->in.req.req8.fsmo_info = 0; - r->in.req.req8.partial_attribute_set = NULL; - r->in.req.req8.partial_attribute_set_ex = NULL; - r->in.req.req8.mapping_ctr.num_mappings = 0; - r->in.req.req8.mapping_ctr.mappings = NULL; + r->in.level = 8; + r->in.req->req8.destination_dsa_guid = partition->destination_dsa_guid; + r->in.req->req8.source_dsa_invocation_id= partition->source_dsa_invocation_id; + r->in.req->req8.naming_context = &partition->nc; + r->in.req->req8.highwatermark = partition->highwatermark; + r->in.req->req8.uptodateness_vector = NULL; + r->in.req->req8.replica_flags = partition->replica_flags; + r->in.req->req8.max_object_count = 133; + r->in.req->req8.max_ndr_size = 1336811; + r->in.req->req8.extended_op = DRSUAPI_EXOP_NONE; + r->in.req->req8.fsmo_info = 0; + r->in.req->req8.partial_attribute_set = NULL; + r->in.req->req8.partial_attribute_set_ex= NULL; + r->in.req->req8.mapping_ctr.num_mappings= 0; + r->in.req->req8.mapping_ctr.mappings = NULL; } else { - *r->in.level = 5; - r->in.req.req5.destination_dsa_guid = partition->destination_dsa_guid; - r->in.req.req5.source_dsa_invocation_id = partition->source_dsa_invocation_id; - r->in.req.req5.naming_context = &partition->nc; - r->in.req.req5.highwatermark = partition->highwatermark; - r->in.req.req5.uptodateness_vector = NULL; - r->in.req.req5.replica_flags = partition->replica_flags; - r->in.req.req5.max_object_count = 133; - r->in.req.req5.max_ndr_size = 1336770; - r->in.req.req5.extended_op = DRSUAPI_EXOP_NONE; - r->in.req.req5.fsmo_info = 0; + r->in.level = 5; + r->in.req->req5.destination_dsa_guid = partition->destination_dsa_guid; + r->in.req->req5.source_dsa_invocation_id= partition->source_dsa_invocation_id; + r->in.req->req5.naming_context = &partition->nc; + r->in.req->req5.highwatermark = partition->highwatermark; + r->in.req->req5.uptodateness_vector = NULL; + r->in.req->req5.replica_flags = partition->replica_flags; + r->in.req->req5.max_object_count = 133; + r->in.req->req5.max_ndr_size = 1336770; + r->in.req->req5.extended_op = DRSUAPI_EXOP_NONE; + r->in.req->req5.fsmo_info = 0; } /* @@ -2439,8 +2598,12 @@ static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s * are needed for it. Or the same KRB5 TGS is needed on both * connections. */ - req = dcerpc_drsuapi_DsGetNCChanges_send(drsuapi_p->pipe, r, r); - composite_continue_rpc(c, req, recv_fn, s); + s->ndr_struct_ptr = r; + subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(s, c->event_ctx, + drsuapi_p->drsuapi_handle, + r); + if (composite_nomem(subreq, c)) return; + tevent_req_set_callback(subreq, recv_fn, s); } static WERROR becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state *s, @@ -2452,9 +2615,9 @@ static WERROR becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state uint32_t ctr_level = 0; struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL; struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL; - struct GUID *source_dsa_guid; - struct GUID *source_dsa_invocation_id; - struct drsuapi_DsReplicaHighWaterMark *new_highwatermark; + struct GUID *source_dsa_guid = NULL; + struct GUID *source_dsa_invocation_id = NULL; + struct drsuapi_DsReplicaHighWaterMark *new_highwatermark = NULL; bool more_data = false; NTSTATUS nt_status; @@ -2462,29 +2625,36 @@ static WERROR becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state return r->out.result; } - if (*r->out.level == 1) { + if (*r->out.level_out == 1) { ctr_level = 1; - ctr1 = &r->out.ctr.ctr1; - } else if (*r->out.level == 2) { + ctr1 = &r->out.ctr->ctr1; + } else if (*r->out.level_out == 2 && + r->out.ctr->ctr2.mszip1.ts) { ctr_level = 1; - ctr1 = r->out.ctr.ctr2.mszip1.ctr1; - } else if (*r->out.level == 6) { + ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1; + } else if (*r->out.level_out == 6) { ctr_level = 6; - ctr6 = &r->out.ctr.ctr6; - } else if (*r->out.level == 7 && - r->out.ctr.ctr7.level == 6 && - r->out.ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP) { + ctr6 = &r->out.ctr->ctr6; + } else if (*r->out.level_out == 7 && + r->out.ctr->ctr7.level == 6 && + r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP && + r->out.ctr->ctr7.ctr.mszip6.ts) { ctr_level = 6; - ctr6 = r->out.ctr.ctr7.ctr.mszip6.ctr6; - } else if (*r->out.level == 7 && - r->out.ctr.ctr7.level == 6 && - r->out.ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS) { + ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6; + } else if (*r->out.level_out == 7 && + r->out.ctr->ctr7.level == 6 && + r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS && + r->out.ctr->ctr7.ctr.xpress6.ts) { ctr_level = 6; - ctr6 = r->out.ctr.ctr7.ctr.xpress6.ctr6; + ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6; } else { return WERR_BAD_NET_RESP; } + if (!ctr1 && ! ctr6) { + return WERR_BAD_NET_RESP; + } + if (ctr_level == 6) { if (!W_ERROR_IS_OK(ctr6->drs_error)) { return ctr6->drs_error; @@ -2535,7 +2705,7 @@ static WERROR becomeDC_drsuapi_pull_partition_recv(struct libnet_BecomeDC_state return WERR_OK; } -static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req); +static void becomeDC_drsuapi3_pull_schema_recv(struct tevent_req *subreq); static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s) { @@ -2545,12 +2715,15 @@ static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s) s->schema_part.destination_dsa_guid = s->drsuapi2.bind_guid; - s->schema_part.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE - | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP - | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS - | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS - | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED - | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES; + s->schema_part.replica_flags = DRSUAPI_DRS_WRIT_REP + | DRSUAPI_DRS_INIT_SYNC + | DRSUAPI_DRS_PER_SYNC + | DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS + | DRSUAPI_DRS_NEVER_SYNCED + | DRSUAPI_DRS_USE_COMPRESSION; + if (s->rodc_join) { + s->schema_part.replica_flags &= ~DRSUAPI_DRS_WRIT_REP; + } s->schema_part.store_chunk = s->callbacks.schema_chunk; @@ -2560,28 +2733,21 @@ static void becomeDC_drsuapi3_pull_schema_send(struct libnet_BecomeDC_state *s) static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s); -static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req) +static void becomeDC_drsuapi3_pull_schema_recv(struct tevent_req *subreq) { - struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, + struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq, struct libnet_BecomeDC_state); struct composite_context *c = s->creq; - struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr, + struct drsuapi_DsGetNCChanges *r = talloc_get_type_abort(s->ndr_struct_ptr, struct drsuapi_DsGetNCChanges); WERROR status; - bool print = false; - - if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { - print = true; - } + s->ndr_struct_ptr = NULL; - c->status = dcerpc_ndr_request_recv(req); + c->status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r); + TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; - if (print) { - NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r); - } - status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part, r); if (!W_ERROR_IS_OK(status)) { composite_error(c, werror_to_ntstatus(status)); @@ -2599,7 +2765,7 @@ static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req) becomeDC_drsuapi3_pull_config_send(s); } -static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req); +static void becomeDC_drsuapi3_pull_config_recv(struct tevent_req *subreq); static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s) { @@ -2609,12 +2775,15 @@ static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s) s->config_part.destination_dsa_guid = s->drsuapi2.bind_guid; - s->config_part.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE - | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP - | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS - | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS - | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED - | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES; + s->config_part.replica_flags = DRSUAPI_DRS_WRIT_REP + | DRSUAPI_DRS_INIT_SYNC + | DRSUAPI_DRS_PER_SYNC + | DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS + | DRSUAPI_DRS_NEVER_SYNCED + | DRSUAPI_DRS_USE_COMPRESSION; + if (s->rodc_join) { + s->schema_part.replica_flags &= ~DRSUAPI_DRS_WRIT_REP; + } s->config_part.store_chunk = s->callbacks.config_chunk; @@ -2622,28 +2791,21 @@ static void becomeDC_drsuapi3_pull_config_send(struct libnet_BecomeDC_state *s) becomeDC_drsuapi3_pull_config_recv); } -static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req) +static void becomeDC_drsuapi3_pull_config_recv(struct tevent_req *subreq) { - struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, + struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq, struct libnet_BecomeDC_state); struct composite_context *c = s->creq; - struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr, + struct drsuapi_DsGetNCChanges *r = talloc_get_type_abort(s->ndr_struct_ptr, struct drsuapi_DsGetNCChanges); WERROR status; - bool print = false; + s->ndr_struct_ptr = NULL; - if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { - print = true; - } - - c->status = dcerpc_ndr_request_recv(req); + c->status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r); + TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; - if (print) { - NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r); - } - status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->config_part, r); if (!W_ERROR_IS_OK(status)) { composite_error(c, werror_to_ntstatus(status)); @@ -2661,7 +2823,7 @@ static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req) becomeDC_connect_ldap2(s); } -static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req); +static void becomeDC_drsuapi3_pull_domain_recv(struct tevent_req *subreq); static void becomeDC_drsuapi3_pull_domain_send(struct libnet_BecomeDC_state *s) { @@ -2671,12 +2833,15 @@ static void becomeDC_drsuapi3_pull_domain_send(struct libnet_BecomeDC_state *s) s->domain_part.destination_dsa_guid = s->drsuapi2.bind_guid; - s->domain_part.replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE - | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP - | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS - | DRSUAPI_DS_REPLICA_NEIGHBOUR_FULL_IN_PROGRESS - | DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED - | DRSUAPI_DS_REPLICA_NEIGHBOUR_COMPRESS_CHANGES; + s->domain_part.replica_flags = DRSUAPI_DRS_WRIT_REP + | DRSUAPI_DRS_INIT_SYNC + | DRSUAPI_DRS_PER_SYNC + | DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS + | DRSUAPI_DRS_NEVER_SYNCED + | DRSUAPI_DRS_USE_COMPRESSION; + if (s->rodc_join) { + s->schema_part.replica_flags &= ~DRSUAPI_DRS_WRIT_REP; + } s->domain_part.store_chunk = s->callbacks.domain_chunk; @@ -2687,30 +2852,24 @@ static void becomeDC_drsuapi3_pull_domain_send(struct libnet_BecomeDC_state *s) static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s, struct becomeDC_drsuapi *drsuapi, struct libnet_BecomeDC_Partition *partition, - void (*recv_fn)(struct rpc_request *req)); -static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req); + void (*recv_fn)(struct tevent_req *subreq)); +static void becomeDC_drsuapi2_update_refs_schema_recv(struct tevent_req *subreq); -static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req) +static void becomeDC_drsuapi3_pull_domain_recv(struct tevent_req *subreq) { - struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, + struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq, struct libnet_BecomeDC_state); struct composite_context *c = s->creq; - struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr, + struct drsuapi_DsGetNCChanges *r = talloc_get_type_abort(s->ndr_struct_ptr, struct drsuapi_DsGetNCChanges); WERROR status; - bool print = false; - if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { - print = true; - } + s->ndr_struct_ptr = NULL; - c->status = dcerpc_ndr_request_recv(req); + c->status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r); + TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; - if (print) { - NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r); - } - status = becomeDC_drsuapi_pull_partition_recv(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part, r); if (!W_ERROR_IS_OK(status)) { composite_error(c, werror_to_ntstatus(status)); @@ -2732,13 +2891,13 @@ static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req) static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s, struct becomeDC_drsuapi *drsuapi, struct libnet_BecomeDC_Partition *partition, - void (*recv_fn)(struct rpc_request *req)) + void (*recv_fn)(struct tevent_req *subreq)) { struct composite_context *c = s->creq; - struct rpc_request *req; struct drsuapi_DsReplicaUpdateRefs *r; const char *ntds_guid_str; const char *ntds_dns_name; + struct tevent_req *subreq; r = talloc(s, struct drsuapi_DsReplicaUpdateRefs); if (composite_nomem(r, c)) return; @@ -2756,36 +2915,37 @@ static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s, r->in.req.req1.naming_context = &partition->nc; r->in.req.req1.dest_dsa_dns_name= ntds_dns_name; r->in.req.req1.dest_dsa_guid = s->dest_dsa.ntds_guid; - r->in.req.req1.options = DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE - | DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE - | DRSUAPI_DS_REPLICA_UPDATE_0x00000010; + r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF; - req = dcerpc_drsuapi_DsReplicaUpdateRefs_send(drsuapi->pipe, r, r); - composite_continue_rpc(c, req, recv_fn, s); + /* I think this is how we mark ourselves as a RODC */ + if (!lpcfg_parm_bool(s->libnet->lp_ctx, NULL, "repl", "RODC", false)) { + r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP; + } + + s->ndr_struct_ptr = r; + subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(s, c->event_ctx, + drsuapi->drsuapi_handle, + r); + if (composite_nomem(subreq, c)) return; + tevent_req_set_callback(subreq, recv_fn, s); } -static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req); +static void becomeDC_drsuapi2_update_refs_config_recv(struct tevent_req *subreq); -static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req) +static void becomeDC_drsuapi2_update_refs_schema_recv(struct tevent_req *subreq) { - struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, + struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq, struct libnet_BecomeDC_state); struct composite_context *c = s->creq; - struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr, + struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type_abort(s->ndr_struct_ptr, struct drsuapi_DsReplicaUpdateRefs); - bool print = false; - if (req->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) { - print = true; - } + s->ndr_struct_ptr = NULL; - c->status = dcerpc_ndr_request_recv(req); + c->status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r); + TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; - if (print) { - NDR_PRINT_OUT_DEBUG(drsuapi_DsReplicaUpdateRefs, r); - } - if (!W_ERROR_IS_OK(r->out.result)) { composite_error(c, werror_to_ntstatus(r->out.result)); return; @@ -2797,17 +2957,20 @@ static void becomeDC_drsuapi2_update_refs_schema_recv(struct rpc_request *req) becomeDC_drsuapi2_update_refs_config_recv); } -static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req); +static void becomeDC_drsuapi2_update_refs_domain_recv(struct tevent_req *subreq); -static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req) +static void becomeDC_drsuapi2_update_refs_config_recv(struct tevent_req *subreq) { - struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, + struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq, struct libnet_BecomeDC_state); struct composite_context *c = s->creq; - struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr, + struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(s->ndr_struct_ptr, struct drsuapi_DsReplicaUpdateRefs); - c->status = dcerpc_ndr_request_recv(req); + s->ndr_struct_ptr = NULL; + + c->status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r); + TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; if (!W_ERROR_IS_OK(r->out.result)) { @@ -2821,15 +2984,18 @@ static void becomeDC_drsuapi2_update_refs_config_recv(struct rpc_request *req) becomeDC_drsuapi2_update_refs_domain_recv); } -static void becomeDC_drsuapi2_update_refs_domain_recv(struct rpc_request *req) +static void becomeDC_drsuapi2_update_refs_domain_recv(struct tevent_req *subreq) { - struct libnet_BecomeDC_state *s = talloc_get_type(req->async.private_data, + struct libnet_BecomeDC_state *s = tevent_req_callback_data(subreq, struct libnet_BecomeDC_state); struct composite_context *c = s->creq; - struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr, + struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(s->ndr_struct_ptr, struct drsuapi_DsReplicaUpdateRefs); - c->status = dcerpc_ndr_request_recv(req); + s->ndr_struct_ptr = NULL; + + c->status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r); + TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; if (!W_ERROR_IS_OK(r->out.result)) { @@ -2847,7 +3013,7 @@ static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s) { int ret; struct ldb_message *msg; - uint32_t i; + unsigned int i; uint32_t user_account_control = UF_SERVER_TRUST_ACCOUNT | UF_TRUSTED_FOR_DELEGATION; @@ -2862,8 +3028,9 @@ static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s) msg->dn = ldb_dn_new(msg, s->ldap2.ldb, s->dest_dsa.computer_dn_str); NT_STATUS_HAVE_NO_MEMORY(msg->dn); - ret = ldb_msg_add_fmt(msg, "userAccountControl", "%u", user_account_control); - if (ret != 0) { + ret = samdb_msg_add_uint(s->ldap2.ldb, msg, msg, "userAccountControl", + user_account_control); + if (ret != LDB_SUCCESS) { talloc_free(msg); return NT_STATUS_NO_MEMORY; } @@ -2888,55 +3055,41 @@ static NTSTATUS becomeDC_ldap2_modify_computer(struct libnet_BecomeDC_state *s) static NTSTATUS becomeDC_ldap2_move_computer(struct libnet_BecomeDC_state *s) { int ret; - struct ldb_result *r; - struct ldb_dn *basedn; struct ldb_dn *old_dn; struct ldb_dn *new_dn; - static const char *_1_1_attrs[] = { - "1.1", - NULL - }; - - basedn = ldb_dn_new_fmt(s, s->ldap2.ldb, "", - s->domain.dn_str); - NT_STATUS_HAVE_NO_MEMORY(basedn); - ret = ldb_search(s->ldap2.ldb, basedn, LDB_SCOPE_BASE, - "(objectClass=*)", _1_1_attrs, &r); - talloc_free(basedn); + ret = dsdb_wellknown_dn(s->ldap2.ldb, s, + ldb_get_default_basedn(s->ldap2.ldb), + DS_GUID_DOMAIN_CONTROLLERS_CONTAINER, + &new_dn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); - } else if (r->count != 1) { - talloc_free(r); - return NT_STATUS_INVALID_NETWORK_RESPONSE; } - old_dn = ldb_dn_new(r, s->ldap2.ldb, s->dest_dsa.computer_dn_str); - NT_STATUS_HAVE_NO_MEMORY(old_dn); - - new_dn = r->msgs[0]->dn; - if (!ldb_dn_add_child_fmt(new_dn, "CN=%s", s->dest_dsa.netbios_name)) { - talloc_free(r); + talloc_free(new_dn); return NT_STATUS_NO_MEMORY; } + old_dn = ldb_dn_new(new_dn, s->ldap2.ldb, s->dest_dsa.computer_dn_str); + NT_STATUS_HAVE_NO_MEMORY(old_dn); + if (ldb_dn_compare(old_dn, new_dn) == 0) { /* we don't need to rename if the old and new dn match */ - talloc_free(r); + talloc_free(new_dn); return NT_STATUS_OK; } ret = ldb_rename(s->ldap2.ldb, old_dn, new_dn); if (ret != LDB_SUCCESS) { - talloc_free(r); + talloc_free(new_dn); return NT_STATUS_LDAP(ret); } s->dest_dsa.computer_dn_str = ldb_dn_alloc_linearized(s, new_dn); NT_STATUS_HAVE_NO_MEMORY(s->dest_dsa.computer_dn_str); - talloc_free(r); + talloc_free(new_dn); return NT_STATUS_OK; } @@ -2998,6 +3151,9 @@ struct composite_context *libnet_BecomeDC_send(struct libnet_context *ctx, TALLO /* Callback function pointers */ s->callbacks = r->in.callbacks; + /* RODC join*/ + s->rodc_join = r->in.rodc_join; + becomeDC_send_cldap(s); return c; }