Order switch statements
[samba.git] / source4 / dsdb / repl / drepl_out_helpers.c
index 60dccffb2378644cba8e2038ae291ad0814fb93b..305432395791963d18a30b0f12a3c9657d2a755e 100644 (file)
@@ -24,9 +24,8 @@
 #include "auth/auth.h"
 #include "smbd/service.h"
 #include "lib/events/events.h"
-#include "lib/messaging/irpc.h"
 #include "dsdb/repl/drepl_service.h"
-#include "lib/ldb/include/ldb_errors.h"
+#include <ldb_errors.h>
 #include "../lib/util/dlinklist.h"
 #include "librpc/gen_ndr/ndr_misc.h"
 #include "librpc/gen_ndr/ndr_drsuapi.h"
@@ -35,6 +34,7 @@
 #include "auth/gensec/gensec.h"
 #include "param/param.h"
 #include "../lib/util/tevent_ntstatus.h"
+#include "libcli/security/security.h"
 
 struct dreplsrv_out_drsuapi_state {
        struct tevent_context *ev;
@@ -67,14 +67,17 @@ struct tevent_req *dreplsrv_out_drsuapi_send(TALLOC_CTX *mem_ctx,
        state->conn     = conn;
        state->drsuapi  = conn->drsuapi;
 
-       if (state->drsuapi && !state->drsuapi->pipe->conn->dead) {
-               tevent_req_done(req);
-               return tevent_req_post(req, ev);
-       }
+       if (state->drsuapi != NULL) {
+               struct dcerpc_binding_handle *b =
+                       state->drsuapi->pipe->binding_handle;
+               bool is_connected = dcerpc_binding_handle_is_connected(b);
+
+               if (is_connected) {
+                       tevent_req_done(req);
+                       return tevent_req_post(req, ev);
+               }
 
-       if (state->drsuapi && state->drsuapi->pipe->conn->dead) {
-               talloc_free(state->drsuapi);
-               conn->drsuapi = NULL;
+               TALLOC_FREE(conn->drsuapi);
        }
 
        state->drsuapi = talloc_zero(state, struct dreplsrv_drsuapi_connection);
@@ -114,6 +117,7 @@ static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq)
        state->drsuapi->drsuapi_handle = state->drsuapi->pipe->binding_handle;
 
        status = gensec_session_key(state->drsuapi->pipe->conn->security_state.generic_state,
+                                   state->drsuapi,
                                    &state->drsuapi->gensec_skey);
        if (tevent_req_nterror(req, status)) {
                return;
@@ -172,6 +176,20 @@ static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
                        info28->repl_epoch              = 0;
                        break;
                }
+               case 28: {
+                       *info28 = state->bind_r.out.bind_info->info.info28;
+                       break;
+               }
+               case 32: {
+                       struct drsuapi_DsBindInfo32 *info32;
+                       info32 = &state->bind_r.out.bind_info->info.info32;
+
+                       info28->supported_extensions    = info32->supported_extensions;
+                       info28->site_guid               = info32->site_guid;
+                       info28->pid                     = info32->pid;
+                       info28->repl_epoch              = info32->repl_epoch;
+                       break;
+               }
                case 48: {
                        struct drsuapi_DsBindInfo48 *info48;
                        info48 = &state->bind_r.out.bind_info->info.info48;
@@ -182,8 +200,19 @@ static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
                        info28->repl_epoch              = info48->repl_epoch;
                        break;
                }
-               case 28:
-                       *info28 = state->bind_r.out.bind_info->info.info28;
+               case 52: {
+                       struct drsuapi_DsBindInfo52 *info52;
+                       info52 = &state->bind_r.out.bind_info->info.info52;
+
+                       info28->supported_extensions    = info52->supported_extensions;
+                       info28->site_guid               = info52->site_guid;
+                       info28->pid                     = info52->pid;
+                       info28->repl_epoch              = info52->repl_epoch;
+                       break;
+               }
+               default:
+                       DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
+                               state->bind_r.out.bind_info->length));
                        break;
                }
        }
@@ -260,6 +289,121 @@ static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
 
 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
 
+/*
+  get a RODC partial attribute set for a replication call
+ */
+static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
+                                                       TALLOC_CTX *mem_ctx,
+                                                       struct drsuapi_DsPartialAttributeSet **_pas,
+                                                       bool for_schema)
+{
+       struct drsuapi_DsPartialAttributeSet *pas;
+       struct dsdb_schema *schema;
+       uint32_t i;
+
+       pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
+       NT_STATUS_HAVE_NO_MEMORY(pas);
+
+       schema = dsdb_get_schema(service->samdb, NULL);
+
+       pas->version = 1;
+       pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
+       if (pas->attids == NULL) {
+               TALLOC_FREE(pas);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       for (i=0; i<schema->num_attributes; i++) {
+               struct dsdb_attribute *a;
+               a = schema->attributes_by_attributeID_id[i];
+                if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
+                       continue;
+               }
+               if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
+                       continue;
+               }
+               pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
+               pas->num_attids++;
+       }
+
+       pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
+       if (pas->attids == NULL) {
+               TALLOC_FREE(pas);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       *_pas = pas;
+       return NT_STATUS_OK;
+}
+
+
+/*
+  get a GC partial attribute set for a replication call
+ */
+static NTSTATUS dreplsrv_get_gc_partial_attribute_set(struct dreplsrv_service *service,
+                                                     TALLOC_CTX *mem_ctx,
+                                                     struct drsuapi_DsPartialAttributeSet **_pas)
+{
+       struct drsuapi_DsPartialAttributeSet *pas;
+       struct dsdb_schema *schema;
+       uint32_t i;
+
+       pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
+       NT_STATUS_HAVE_NO_MEMORY(pas);
+
+       schema = dsdb_get_schema(service->samdb, NULL);
+
+       pas->version = 1;
+       pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
+       if (pas->attids == NULL) {
+               TALLOC_FREE(pas);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       for (i=0; i<schema->num_attributes; i++) {
+               struct dsdb_attribute *a;
+               a = schema->attributes_by_attributeID_id[i];
+                if (a->isMemberOfPartialAttributeSet) {
+                       pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, false);
+                       pas->num_attids++;
+               }
+       }
+
+       pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
+       if (pas->attids == NULL) {
+               TALLOC_FREE(pas);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       *_pas = pas;
+       return NT_STATUS_OK;
+}
+
+/*
+  convert from one udv format to the other
+ */
+static WERROR udv_convert(TALLOC_CTX *mem_ctx,
+                         const struct replUpToDateVectorCtr2 *udv,
+                         struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
+{
+       uint32_t i;
+
+       udv_ex->version = 2;
+       udv_ex->reserved1 = 0;
+       udv_ex->reserved2 = 0;
+       udv_ex->count = udv->count;
+       udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
+       W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
+
+       for (i=0; i<udv->count; i++) {
+               udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
+               udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
+       }
+
+       return WERR_OK;
+}
+
+
 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
 {
        struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
@@ -271,10 +415,11 @@ static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
        struct drsuapi_DsGetNCChanges *r;
        struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
        struct tevent_req *subreq;
-
-       if ((rf1->replica_flags & DRSUAPI_DRS_WRIT_REP) == 0) {
-               return;
-       }
+       struct drsuapi_DsPartialAttributeSet *pas = NULL;
+       NTSTATUS status;
+       uint32_t replica_flags;
+       struct drsuapi_DsReplicaHighWaterMark highwatermark;
+       struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
 
        r = talloc(state, struct drsuapi_DsGetNCChanges);
        if (tevent_req_nomem(r, req)) {
@@ -294,26 +439,82 @@ static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
                return;
        }
 
+       if (partition->uptodatevector.count != 0 &&
+           partition->uptodatevector_ex.count == 0) {
+               WERROR werr;
+               werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
+               if (!W_ERROR_IS_OK(werr)) {
+                       DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
+                                ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
+               }
+       }
+
        if (partition->uptodatevector_ex.count == 0) {
                uptodateness_vector = NULL;
        } else {
                uptodateness_vector = &partition->uptodatevector_ex;
        }
 
+       replica_flags = rf1->replica_flags;
+       highwatermark = rf1->highwatermark;
+
+       if (partition->partial_replica) {
+               status = dreplsrv_get_gc_partial_attribute_set(service, r, &pas);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0,(__location__ ": Failed to construct GC partial attribute set : %s\n", nt_errstr(status)));
+                       return;
+               }
+               replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
+       } else if (partition->rodc_replica) {
+               bool for_schema = false;
+               if (ldb_dn_compare_base(schema_dn, partition->dn) == 0) {
+                       for_schema = true;
+               }
+
+               status = dreplsrv_get_rodc_partial_attribute_set(service, r, &pas, for_schema);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0,(__location__ ": Failed to construct RODC partial attribute set : %s\n", nt_errstr(status)));
+                       return;
+               }
+               if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
+                       replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
+               }
+       }
+       if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
+               /*
+                * If it's an exop never set the ADD_REF even if it's in
+                * repsFrom flags.
+                */
+               replica_flags &= ~DRSUAPI_DRS_ADD_REF;
+       }
+
+       /* is this a full resync of all objects? */
+       if (state->op->options & DRSUAPI_DRS_FULL_SYNC_NOW) {
+               ZERO_STRUCT(highwatermark);
+               /* clear the FULL_SYNC_NOW option for subsequent
+                  stages of the replication cycle */
+               state->op->options &= ~DRSUAPI_DRS_FULL_SYNC_NOW;
+               state->op->options |= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS;
+               replica_flags |= DRSUAPI_DRS_NEVER_SYNCED;
+       }
+       if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
+               uptodateness_vector = NULL;
+       }
+
        r->in.bind_handle       = &drsuapi->bind_handle;
        if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
                r->in.level                             = 8;
                r->in.req->req8.destination_dsa_guid    = service->ntds_guid;
                r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
                r->in.req->req8.naming_context          = &partition->nc;
-               r->in.req->req8.highwatermark           = rf1->highwatermark;
+               r->in.req->req8.highwatermark           = highwatermark;
                r->in.req->req8.uptodateness_vector     = uptodateness_vector;
-               r->in.req->req8.replica_flags           = rf1->replica_flags;
+               r->in.req->req8.replica_flags           = replica_flags;
                r->in.req->req8.max_object_count        = 133;
                r->in.req->req8.max_ndr_size            = 1336811;
                r->in.req->req8.extended_op             = state->op->extended_op;
                r->in.req->req8.fsmo_info               = state->op->fsmo_info;
-               r->in.req->req8.partial_attribute_set   = NULL;
+               r->in.req->req8.partial_attribute_set   = pas;
                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;
@@ -322,9 +523,9 @@ static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
                r->in.req->req5.destination_dsa_guid    = service->ntds_guid;
                r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
                r->in.req->req5.naming_context          = &partition->nc;
-               r->in.req->req5.highwatermark           = rf1->highwatermark;
+               r->in.req->req5.highwatermark           = highwatermark;
                r->in.req->req5.uptodateness_vector     = uptodateness_vector;
-               r->in.req->req5.replica_flags           = rf1->replica_flags;
+               r->in.req->req5.replica_flags           = replica_flags;
                r->in.req->req5.max_object_count        = 133;
                r->in.req->req5.max_ndr_size            = 1336770;
                r->in.req->req5.extended_op             = state->op->extended_op;
@@ -364,7 +565,7 @@ static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
        uint32_t ctr_level = 0;
        struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
        struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
-
+       enum drsuapi_DsExtendedError extended_ret;
        state->ndr_struct_ptr = NULL;
 
        status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
@@ -419,6 +620,21 @@ static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
                        tevent_req_nterror(req, status);
                        return;
                }
+               extended_ret = ctr6->extended_ret;
+       }
+
+       if (ctr_level == 1) {
+               extended_ret = ctr1->extended_ret;
+       }
+
+       if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
+               state->op->extended_ret = extended_ret;
+
+               if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       tevent_req_nterror(req, status);
+                       return;
+               }
        }
 
        dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
@@ -438,6 +654,9 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
        struct dreplsrv_service *service = state->op->service;
        struct dreplsrv_partition *partition = state->op->source_dsa->partition;
        struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
+       struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
+       struct dsdb_schema *schema;
+       struct dsdb_schema *working_schema = NULL;
        const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
        uint32_t object_count;
        struct drsuapi_DsReplicaObjectListItemEx *first_object;
@@ -448,6 +667,7 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
        bool more_data = false;
        WERROR status;
        NTSTATUS nt_status;
+       uint32_t dsdb_repl_flags = 0;
 
        switch (ctr_level) {
        case 1:
@@ -456,6 +676,8 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
                first_object                    = ctr1->first_object;
                linked_attributes_count         = 0;
                linked_attributes               = NULL;
+               rf1.source_dsa_obj_guid         = ctr1->source_dsa_guid;
+               rf1.source_dsa_invocation_id    = ctr1->source_dsa_invocation_id;
                rf1.highwatermark               = ctr1->new_highwatermark;
                uptodateness_vector             = NULL; /* TODO: map it */
                more_data                       = ctr1->more_data;
@@ -466,6 +688,8 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
                first_object                    = ctr6->first_object;
                linked_attributes_count         = ctr6->linked_attributes_count;
                linked_attributes               = ctr6->linked_attributes;
+               rf1.source_dsa_obj_guid         = ctr6->source_dsa_guid;
+               rf1.source_dsa_invocation_id    = ctr6->source_dsa_invocation_id;
                rf1.highwatermark               = ctr6->new_highwatermark;
                uptodateness_vector             = ctr6->uptodateness_vector;
                more_data                       = ctr6->more_data;
@@ -476,17 +700,57 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
                return;
        }
 
-       status = dsdb_extended_replicated_objects_convert(service->samdb,
-                                                         partition->nc.dn,
-                                                         mapping_ctr,
-                                                         object_count,
-                                                         first_object,
-                                                         linked_attributes_count,
-                                                         linked_attributes,
-                                                         &rf1,
-                                                         uptodateness_vector,
-                                                         &drsuapi->gensec_skey,
-                                                         state, &objects);
+       schema = dsdb_get_schema(service->samdb, NULL);
+       if (!schema) {
+               DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
+               tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+               return;
+       }
+
+       /*
+        * Decide what working schema to use for object conversion.
+        * We won't need a working schema for empty replicas sent.
+        */
+       if (first_object) {
+               bool is_schema = ldb_dn_compare(partition->dn, schema_dn) == 0;
+               if (is_schema) {
+                       /* create working schema to convert objects with */
+                       status = dsdb_repl_make_working_schema(service->samdb,
+                                                              schema,
+                                                              mapping_ctr,
+                                                              object_count,
+                                                              first_object,
+                                                              &drsuapi->gensec_skey,
+                                                              state, &working_schema);
+                       if (!W_ERROR_IS_OK(status)) {
+                               DEBUG(0,("Failed to create working schema: %s\n",
+                                        win_errstr(status)));
+                               tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+                               return;
+                       }
+               }
+       }
+
+       if (partition->partial_replica || partition->rodc_replica) {
+               dsdb_repl_flags |= DSDB_REPL_FLAG_PARTIAL_REPLICA;
+       }
+       if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
+               dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
+       }
+
+       status = dsdb_replicated_objects_convert(service->samdb,
+                                                working_schema ? working_schema : schema,
+                                                partition->nc.dn,
+                                                mapping_ctr,
+                                                object_count,
+                                                first_object,
+                                                linked_attributes_count,
+                                                linked_attributes,
+                                                &rf1,
+                                                uptodateness_vector,
+                                                &drsuapi->gensec_skey,
+                                                dsdb_repl_flags,
+                                                state, &objects);
        if (!W_ERROR_IS_OK(status)) {
                nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
                DEBUG(0,("Failed to convert objects: %s/%s\n",
@@ -495,9 +759,10 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
                return;
        }
 
-       status = dsdb_extended_replicated_objects_commit(service->samdb,
-                                                        objects, 
-                                                        &state->op->source_dsa->notify_uSN);
+       status = dsdb_replicated_objects_commit(service->samdb,
+                                               working_schema,
+                                               objects,
+                                               &state->op->source_dsa->notify_uSN);
        talloc_free(objects);
        if (!W_ERROR_IS_OK(status)) {
                nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
@@ -507,12 +772,10 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
                return;
        }
 
-       /* if it applied fine, we need to update the highwatermark */
-       *state->op->source_dsa->repsFrom1 = rf1;
-
-       /*
-        * TODO: update our uptodatevector!
-        */
+       if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
+               /* if it applied fine, we need to update the highwatermark */
+               *state->op->source_dsa->repsFrom1 = rf1;
+       }
 
        /* we don't need this maybe very large structure anymore */
        TALLOC_FREE(r);
@@ -522,6 +785,16 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
                return;
        }
 
+       if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
+           state->op->service->am_rodc) {
+               /*
+                 we don't do the UpdateRefs for extended ops or if we
+                 are a RODC
+                */
+               tevent_req_done(req);
+               return;
+       }
+
        /* now we need to update the repsTo record for this partition
           on the server. These records are initially established when
           we join the domain, but they quickly expire.  We do it here
@@ -543,26 +816,17 @@ static void dreplsrv_update_refs_trigger(struct tevent_req *req)
        struct dreplsrv_partition *partition = state->op->source_dsa->partition;
        struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
        struct drsuapi_DsReplicaUpdateRefs *r;
-       char *ntds_guid_str;
        char *ntds_dns_name;
        struct tevent_req *subreq;
-       bool am_rodc;
-       int ret;
 
        r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
        if (tevent_req_nomem(r, req)) {
                return;
        }
 
-       ntds_guid_str = GUID_string(r, &service->ntds_guid);
-       if (tevent_req_nomem(ntds_guid_str, req)) {
-               return;
-       }
-
-       ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
-                                       ntds_guid_str,
-                                       lp_dnsdomain(service->task->lp_ctx));
+       ntds_dns_name = samdb_ntds_msdcs_dns_name(service->samdb, r, &service->ntds_guid);
        if (tevent_req_nomem(ntds_dns_name, req)) {
+               talloc_free(r);
                return;
        }
 
@@ -572,8 +836,7 @@ static void dreplsrv_update_refs_trigger(struct tevent_req *req)
        r->in.req.req1.dest_dsa_dns_name  = ntds_dns_name;
        r->in.req.req1.dest_dsa_guid      = service->ntds_guid;
        r->in.req.req1.options            = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
-       ret = samdb_rodc(service->samdb, &am_rodc);
-       if (ret == LDB_SUCCESS && !am_rodc) {
+       if (!service->am_rodc) {
                r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
        }
 
@@ -583,6 +846,7 @@ static void dreplsrv_update_refs_trigger(struct tevent_req *req)
                                                           drsuapi->drsuapi_handle,
                                                           r);
        if (tevent_req_nomem(subreq, req)) {
+               talloc_free(r);
                return;
        }
        tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
@@ -619,8 +883,28 @@ static void dreplsrv_update_refs_done(struct tevent_req *subreq)
                         nt_errstr(status),
                         r->in.req.req1.dest_dsa_dns_name,
                         r->in.req.req1.naming_context->dn));
-               tevent_req_nterror(req, status);
-               return;
+               /*
+                * TODO we are currently not sending the
+                * DsReplicaUpdateRefs at the correct moment,
+                * we do it just after a GetNcChanges which is
+                * not always correct.
+                * Especially when another DC is trying to demote
+                * it will sends us a DsReplicaSync that will trigger a getNcChanges
+                * this call will succeed but the DsRecplicaUpdateRefs that we send
+                * just after will not because the DC is in a demote state and
+                * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
+                * answer to the DsReplicaSync with a non OK status, the other DC
+                * will stop the demote due to this error.
+                * In order to cope with this we will for the moment concider
+                * a DS_DRA_BUSY not as an error.
+                * It's not ideal but it should not have a too huge impact for
+                * running production as this error otherwise never happen and
+                * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
+                */
+               if (!W_ERROR_EQUAL(r->out.result, WERR_DS_DRA_BUSY)) {
+                       tevent_req_nterror(req, status);
+                       return;
+               }
        }
 
        DEBUG(4,("UpdateRefs OK for %s %s\n",