X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source4%2Flibnet%2Flibnet_become_dc.c;h=3fb308dcd7065788f0a7594d8fa9f0769c042876;hb=89ba043c7d9d95a02723efe18c415fd47a02b26d;hp=d3eeebe2147f99eb3fed35a6cc656456cc4c6587;hpb=8974bf92a84091ce4b6cd42525648a71a4ca20b4;p=samba.git diff --git a/source4/libnet/libnet_become_dc.c b/source4/libnet/libnet_become_dc.c index d3eeebe2147..3fb308dcd70 100644 --- a/source4/libnet/libnet_become_dc.c +++ b/source4/libnet/libnet_become_dc.c @@ -25,7 +25,7 @@ #include "lib/ldb/include/ldb_errors.h" #include "lib/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" @@ -731,12 +731,26 @@ struct libnet_BecomeDC_state { struct libnet_BecomeDC_Callbacks callbacks; }; -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 compatible */ + return lp_parm_int(lp_ctx, NULL, "ads", "dc function level", + DS_DC_FUNCTION_2008); +} + +static int32_t get_min_function_level(struct loadparm_context *lp_ctx) +{ + /* per default it is (Windows) 2003 Native compatible */ + return lp_parm_int(lp_ctx, NULL, "ads", "min function level", + DS_DOMAIN_FUNCTION_2003); +} + +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; s->cldap.io.in.dest_address = s->source_dsa.address; s->cldap.io.in.dest_port = lp_cldap_port(s->libnet->lp_ctx); @@ -749,28 +763,30 @@ 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; + c->status = cldap_socket_init(s, s->libnet->event_ctx, + NULL, NULL, &s->cldap.sock);//TODO + 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); + c->status = cldap_netlogon_recv(req, + lp_iconv_convenience(s->libnet->lp_ctx), + s, &s->cldap.io); + talloc_free(req); if (!composite_is_ok(c)) return; - s->cldap.netlogon = s->cldap.io.out.netlogon.nt5_ex; + 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; @@ -820,8 +836,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 +845,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 +879,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 +890,22 @@ 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_min_function_level(s->libnet->lp_ctx)) { + talloc_free(r); + DEBUG(0,("The servers function level %u is below 'ads:min function level' of %u\n", + s->forest.crossref_behavior_version, + get_min_function_level(s->libnet->lp_ctx))); + return NT_STATUS_NOT_SUPPORTED; + } + 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 +924,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 +935,22 @@ 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_min_function_level(s->libnet->lp_ctx)) { + talloc_free(r); + DEBUG(0,("The servers function level %u is below 'ads:min function level' of %u\n", + s->forest.crossref_behavior_version, + get_min_function_level(s->libnet->lp_ctx))); + return NT_STATUS_NOT_SUPPORTED; + } + 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 +969,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 +999,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 */ @@ -1000,8 +1047,8 @@ static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(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=*)", _1_1_attrs, &r); + ret = ldb_search(s->ldap1.ldb, s, &r, basedn, LDB_SCOPE_BASE, + _1_1_attrs, "(objectClass=*)"); talloc_free(basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); @@ -1013,8 +1060,8 @@ static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state 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); + 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); @@ -1038,8 +1085,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) { @@ -1053,8 +1100,8 @@ static NTSTATUS becomeDC_ldap1_infrastructure_fsmo(struct libnet_BecomeDC_state 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 +1144,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); @@ -1115,8 +1162,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); @@ -1140,8 +1187,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) { @@ -1155,8 +1202,8 @@ static NTSTATUS becomeDC_ldap1_rid_manager_fsmo(struct libnet_BecomeDC_state *s) 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 +1229,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 +1261,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 +1270,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); @@ -1263,8 +1306,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 */ @@ -1285,8 +1328,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); @@ -1320,8 +1363,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); @@ -1516,13 +1559,31 @@ static void becomeDC_drsuapi_connect_send(struct libnet_BecomeDC_state *s, drsuapi->s = s; if (!drsuapi->binding) { - if (lp_parm_bool(s->libnet->lp_ctx, NULL, "become_dc", "print", false)) { - binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[print,seal]", s->source_dsa.dns_name); - if (composite_nomem(binding_str, c)) return; - } else { - binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[seal]", s->source_dsa.dns_name); - if (composite_nomem(binding_str, c)) return; + 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 (lp_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", + "print", false)) + { + print_str = "print,"; } + binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[%s%sseal]", + s->source_dsa.dns_name, + krb5_str, print_str); + if (composite_nomem(binding_str, c)) return; c->status = dcerpc_parse_binding(s, binding_str, &drsuapi->binding); talloc_free(binding_str); if (!composite_is_ok(c)) return; @@ -1575,7 +1636,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; } @@ -1602,12 +1663,7 @@ static void becomeDC_drsuapi_bind_send(struct libnet_BecomeDC_state *s, bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS; #endif bind_info28->site_guid = s->dest_dsa.site_guid; - if (s->domain.behavior_version == 2) { - /* TODO: find out how this is really triggered! */ - bind_info28->u1 = 528; - } else { - bind_info28->u1 = 516; - } + bind_info28->pid = 0; bind_info28->repl_epoch = 0; drsuapi->bind_info_ctr.length = 28; @@ -1636,10 +1692,19 @@ static WERROR becomeDC_drsuapi_bind_recv(struct libnet_BecomeDC_state *s, info24 = &drsuapi->bind_r.out.bind_info->info.info24; drsuapi->remote_info28.supported_extensions = info24->supported_extensions; drsuapi->remote_info28.site_guid = info24->site_guid; - drsuapi->remote_info28.u1 = info24->u1; + drsuapi->remote_info28.pid = info24->pid; drsuapi->remote_info28.repl_epoch = 0; break; } + case 48: { + struct drsuapi_DsBindInfo48 *info48; + info48 = &drsuapi->bind_r.out.bind_info->info.info48; + drsuapi->remote_info28.supported_extensions = info48->supported_extensions; + drsuapi->remote_info28.site_guid = info48->site_guid; + drsuapi->remote_info28.pid = info48->pid; + drsuapi->remote_info28.repl_epoch = info48->repl_epoch; + break; + } case 28: drsuapi->remote_info28 = drsuapi->bind_r.out.bind_info->info.info28; break; @@ -1698,8 +1763,8 @@ static void becomeDC_drsuapi1_add_entry_send(struct libnet_BecomeDC_state *s) 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; @@ -2083,7 +2148,7 @@ 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_WIN2003); + SIVAL(vd[0].data, 0, get_dc_function_level(s->libnet->lp_ctx)); vs[0].blob = &vd[0]; @@ -2157,11 +2222,15 @@ 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.unknown1 = 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->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, int32_t); + r->out.ctr = talloc(s, union drsuapi_DsAddEntryCtr); req = dcerpc_drsuapi_DsAddEntry_send(s->drsuapi1.pipe, r, r); composite_continue_rpc(c, req, becomeDC_drsuapi1_add_entry_recv, s); @@ -2196,37 +2265,37 @@ static void becomeDC_drsuapi1_add_entry_recv(struct rpc_request *req) return; } - if (r->out.level == 3) { - if (r->out.ctr.ctr3.count != 1) { + if (*r->out.level_out == 3) { + if (r->out.ctr->ctr3.count != 1) { WERROR status; - if (r->out.ctr.ctr3.level != 1) { + if (r->out.ctr->ctr3.level != 1) { composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } - if (!r->out.ctr.ctr3.error) { + if (!r->out.ctr->ctr3.error) { composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } - status = r->out.ctr.ctr3.error->info1.status; + status = r->out.ctr->ctr3.error->info1.status; - if (!r->out.ctr.ctr3.error->info1.info) { + if (!r->out.ctr->ctr3.error->info1.info) { 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) { + switch (r->out.ctr->ctr3.error->info1.level) { case 1: - status = r->out.ctr.ctr3.error->info1.info->error1.status; + status = r->out.ctr->ctr3.error->info1.info->error1.status; break; case 4: case 5: case 6: case 7: - status = r->out.ctr.ctr3.error->info1.info->errorX.status; + status = r->out.ctr->ctr3.error->info1.info->errorX.status; break; } @@ -2234,14 +2303,14 @@ 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)); + s->dest_dsa.ntds_guid = r->out.ctr->ctr3.objects[0].guid; + } else if (*r->out.level_out == 2) { + if (r->out.ctr->ctr2.count != 1) { + composite_error(c, werror_to_ntstatus(r->out.ctr->ctr2.error.status)); return; } - s->dest_dsa.ntds_guid = r->out.ctr.ctr2.objects[0].guid; + s->dest_dsa.ntds_guid = r->out.ctr->ctr2.objects[0].guid; } else { composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); return; @@ -2376,40 +2445,42 @@ static void becomeDC_drsuapi_pull_partition_send(struct libnet_BecomeDC_state *s 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, int32_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; } /* @@ -2431,49 +2502,71 @@ 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; if (!W_ERROR_IS_OK(r->out.result)) { 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.ctr.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_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.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->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.mszip6.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; + } + } + switch (ctr_level) { case 1: source_dsa_guid = &ctr1->source_dsa_guid; source_dsa_invocation_id = &ctr1->source_dsa_invocation_id; new_highwatermark = &ctr1->new_highwatermark; + more_data = ctr1->more_data; break; case 6: source_dsa_guid = &ctr6->source_dsa_guid; source_dsa_invocation_id = &ctr6->source_dsa_invocation_id; new_highwatermark = &ctr6->new_highwatermark; + more_data = ctr6->more_data; break; } partition->highwatermark = *new_highwatermark; partition->source_dsa_guid = *source_dsa_guid; partition->source_dsa_invocation_id = *source_dsa_invocation_id; + partition->more_data = more_data; if (!partition->store_chunk) return WERR_OK; @@ -2554,7 +2647,7 @@ static void becomeDC_drsuapi3_pull_schema_recv(struct rpc_request *req) talloc_free(r); - if (s->schema_part.highwatermark.tmp_highest_usn > s->schema_part.highwatermark.highest_usn) { + if (s->schema_part.more_data) { becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->schema_part, becomeDC_drsuapi3_pull_schema_recv); return; @@ -2616,7 +2709,7 @@ static void becomeDC_drsuapi3_pull_config_recv(struct rpc_request *req) talloc_free(r); - if (s->config_part.highwatermark.tmp_highest_usn > s->config_part.highwatermark.highest_usn) { + if (s->config_part.more_data) { becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->config_part, becomeDC_drsuapi3_pull_config_recv); return; @@ -2683,7 +2776,7 @@ static void becomeDC_drsuapi3_pull_domain_recv(struct rpc_request *req) talloc_free(r); - if (s->domain_part.highwatermark.tmp_highest_usn > s->domain_part.highwatermark.highest_usn) { + if (s->domain_part.more_data) { becomeDC_drsuapi_pull_partition_send(s, &s->drsuapi2, &s->drsuapi3, &s->domain_part, becomeDC_drsuapi3_pull_domain_recv); return; @@ -2721,8 +2814,12 @@ static void becomeDC_drsuapi_update_refs_send(struct libnet_BecomeDC_state *s, 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; + | DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE; + + /* I think this is how we mark ourselves as a RODC */ + if (!lp_parm_bool(s->libnet->lp_ctx, NULL, "repl", "RODC", false)) { + r->in.req.req1.options |= DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE; + } req = dcerpc_drsuapi_DsReplicaUpdateRefs_send(drsuapi->pipe, r, r); composite_continue_rpc(c, req, recv_fn, s); @@ -2865,8 +2962,8 @@ static NTSTATUS becomeDC_ldap2_move_computer(struct libnet_BecomeDC_state *s) 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); + ret = ldb_search(s->ldap2.ldb, s, &r, basedn, LDB_SCOPE_BASE, + _1_1_attrs, "(objectClass=*)"); talloc_free(basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret);