s4:libnet_become_dc - Fix some uninitialised variables
[ira/wip.git] / source4 / libnet / libnet_become_dc.c
index c4f9cabb1166411c0284a3a119c7c7e9fc78b9c4..c4e786c83384f8e95112eeae3b5cdbbc9b7c85db 100644 (file)
 #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"
 #include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
 #include "librpc/gen_ndr/ndr_drsuapi.h"
 #include "auth/gensec/gensec.h"
 #include "param/param.h"
@@ -687,7 +688,7 @@ struct libnet_BecomeDC_state {
        struct {
                struct cldap_socket *sock;
                struct cldap_netlogon io;
-               struct nbt_cldap_netlogon_5 netlogon5;
+               struct NETLOGON_SAM_LOGON_RESPONSE_EX netlogon;
        } cldap;
 
        struct becomeDC_ldap {
@@ -730,12 +731,12 @@ struct libnet_BecomeDC_state {
        struct libnet_BecomeDC_Callbacks callbacks;
 };
 
-static void becomeDC_recv_cldap(struct cldap_request *req);
+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);
@@ -745,42 +746,45 @@ static void becomeDC_send_cldap(struct libnet_BecomeDC_state *s)
        s->cldap.io.in.domain_guid      = NULL;
        s->cldap.io.in.domain_sid       = NULL;
        s->cldap.io.in.acct_control     = -1;
-       s->cldap.io.in.version          = 6;
+       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.netlogon5 = s->cldap.io.out.netlogon.logon5;
+       s->cldap.netlogon = s->cldap.io.out.netlogon.data.nt5_ex;
 
-       s->domain.dns_name              = s->cldap.netlogon5.dns_domain;
-       s->domain.netbios_name          = s->cldap.netlogon5.domain;
-       s->domain.guid                  = s->cldap.netlogon5.domain_uuid;
+       s->domain.dns_name              = s->cldap.netlogon.dns_domain;
+       s->domain.netbios_name          = s->cldap.netlogon.domain;
+       s->domain.guid                  = s->cldap.netlogon.domain_uuid;
 
-       s->forest.dns_name              = s->cldap.netlogon5.forest;
+       s->forest.dns_name              = s->cldap.netlogon.forest;
 
-       s->source_dsa.dns_name          = s->cldap.netlogon5.pdc_dns_name;
-       s->source_dsa.netbios_name      = s->cldap.netlogon5.pdc_name;
-       s->source_dsa.site_name         = s->cldap.netlogon5.server_site;
+       s->source_dsa.dns_name          = s->cldap.netlogon.pdc_dns_name;
+       s->source_dsa.netbios_name      = s->cldap.netlogon.pdc_name;
+       s->source_dsa.site_name         = s->cldap.netlogon.server_site;
 
-       s->dest_dsa.site_name           = s->cldap.netlogon5.client_site;
+       s->dest_dsa.site_name           = s->cldap.netlogon.client_site;
 
        becomeDC_connect_ldap1(s);
 }
@@ -793,7 +797,7 @@ static NTSTATUS becomeDC_ldap_connect(struct libnet_BecomeDC_state *s,
        url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
        NT_STATUS_HAVE_NO_MEMORY(url);
 
-       ldap->ldb = ldb_wrap_connect(s, s->libnet->lp_ctx, url,
+       ldap->ldb = ldb_wrap_connect(s, s->libnet->event_ctx, s->libnet->lp_ctx, url,
                                     NULL,
                                     s->libnet->cred,
                                     0, NULL);
@@ -818,8 +822,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);
@@ -827,7 +831,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];
 
@@ -862,8 +865,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);
@@ -891,8 +894,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);
@@ -920,8 +923,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);
@@ -950,8 +953,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 */
@@ -998,8 +1001,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);
@@ -1011,8 +1014,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);
@@ -1036,8 +1039,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) {
@@ -1051,8 +1054,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) {
@@ -1095,8 +1098,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);
@@ -1113,8 +1116,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);
@@ -1138,8 +1141,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) {
@@ -1153,8 +1156,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) {
@@ -1180,8 +1183,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);
@@ -1212,7 +1215,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",
@@ -1222,12 +1224,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);
@@ -1261,8 +1260,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 */
@@ -1318,8 +1317,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);
@@ -1514,13 +1513,30 @@ 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;
@@ -1600,12 +1616,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;
@@ -1634,10 +1645,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;
@@ -2081,7 +2101,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, DS_DC_FUNCTION_2008_R2);
 
                vs[0].blob              = &vd[0];
 
@@ -2155,11 +2175,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);
@@ -2194,37 +2218,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;
                        }
 
@@ -2232,14 +2256,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;
@@ -2374,40 +2398,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.unknown4                 = 0;
-               r->in.req.req8.h1                       = 0;
-               r->in.req.req8.unique_ptr1              = 0;
-               r->in.req.req8.unique_ptr2              = 0;
-               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.unknown4                 = 0;
-               r->in.req.req5.h1                       = 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;
        }
 
        /* 
@@ -2429,49 +2455,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;
 
@@ -2552,7 +2600,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;
@@ -2614,7 +2662,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;
@@ -2681,7 +2729,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;
@@ -2719,8 +2767,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);
@@ -2863,8 +2915,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);