Revert "s4-dsdb: Remove strcasecmp() fallback in replmd_ldb_message_element_attid_sort"
[obnox/samba/samba-obnox.git] / source4 / dsdb / samdb / ldb_modules / repl_meta_data.c
index a1a0b87e45af066ccce3420118b91f7a9898524a..24dcc6f04dce79583fa5e78efeb904bcb51280df 100644 (file)
@@ -94,6 +94,8 @@ struct replmd_replicated_request {
        bool is_urgent;
 };
 
+static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
+
 enum urgent_situation {
        REPL_URGENT_ON_CREATE = 1,
        REPL_URGENT_ON_UPDATE = 2,
@@ -2313,12 +2315,28 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
        bool is_urgent = false, rodc = false;
        unsigned int functional_level;
        const DATA_BLOB *guid_blob;
+       struct ldb_control *sd_propagation_control;
 
        /* do not manipulate our control entries */
        if (ldb_dn_is_special(req->op.mod.message->dn)) {
                return ldb_next_request(module, req);
        }
 
+       sd_propagation_control = ldb_request_get_control(req,
+                                       DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
+       if (sd_propagation_control != NULL) {
+               if (req->op.mod.message->num_elements != 1) {
+                       return ldb_module_operr(module);
+               }
+               ret = strcmp(req->op.mod.message->elements[0].name,
+                            "nTSecurityDescriptor");
+               if (ret != 0) {
+                       return ldb_module_operr(module);
+               }
+
+               return ldb_next_request(module, req);
+       }
+
        ldb = ldb_module_get_ctx(module);
 
        ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
@@ -2987,7 +3005,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
                        talloc_free(tmp_ctx);
                        return ret;
                }
-               msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
+               msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
        }
 
        switch (next_deletion_state){
@@ -3410,17 +3428,20 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
        struct replPropertyMetaData1 *rmd_name, *omd_name;
        struct ldb_message *msg;
 
+       req->callback = callback;
+
        if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
                /* call the normal callback for everything except
                   conflicts */
-               return callback(req, ares);
+               return ldb_module_done(req, ares->controls, ares->response, ares->error);
        }
 
        ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
        if (ret != LDB_SUCCESS) {
-               return ret;
+               ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to determine if we are an RODC when attempting to form conflict DN: %s", ldb_errstring(ldb_module_get_ctx(ar->module)));
+               return ldb_module_done(req, ares->controls, ares->response, LDB_ERR_OPERATIONS_ERROR);
        }
-       /*
+       /*
         * we have a conflict, and need to decide if we will keep the
         * new record or the old record
         */
@@ -3435,7 +3456,7 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
                conflict_dn = req->op.rename.newdn;
                break;
        default:
-               return ldb_module_operr(ar->module);
+               return ldb_module_done(req, ares->controls, ares->response, ldb_module_operr(ar->module));
        }
 
        if (rodc) {
@@ -3532,7 +3553,7 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
                        goto failed;
                }
 
-               DEBUG(1,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
+               DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
                         ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
 
                /* re-submit the request, but with a different
@@ -3567,7 +3588,7 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
                        goto failed;
                }
 
-               DEBUG(1,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
+               DEBUG(2,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
                         ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
 
                ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
@@ -3589,8 +3610,6 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
                        goto failed;
                }
 
-               req->callback = callback;
-
                return ldb_next_request(ar->module, req);
        }
 
@@ -3599,7 +3618,7 @@ failed:
         * will stop with an error, but there is not much else we can
         * do
         */
-       return callback(req, ares);
+       return ldb_module_done(req, ares->controls, ares->response, ares->error);
 }
 
 /*
@@ -3644,15 +3663,7 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
        struct ldb_val md_value;
        unsigned int i;
        int ret;
-
-       /*
-        * TODO: check if the parent object exist
-        */
-
-       /*
-        * TODO: handle the conflict case where an object with the
-        *       same name exist
-        */
+       bool remote_isDeleted = false;
 
        ldb = ldb_module_get_ctx(ar->module);
        msg = ar->objs->objects[ar->index_current].msg;
@@ -3697,6 +3708,9 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
                }
        }
 
+       remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
+                                                    "isDeleted", false);
+
        /*
         * the meta data array is already sorted by the caller
         */
@@ -3716,6 +3730,15 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
 
        replmd_ldb_message_sort(msg, ar->schema);
 
+       if (!remote_isDeleted) {
+               ret = dsdb_module_schedule_sd_propagation(ar->module,
+                                                         ar->objs->partition_dn,
+                                                         msg->dn, true);
+               if (ret != LDB_SUCCESS) {
+                       return replmd_replicated_request_error(ar, ret);
+               }
+       }
+
        if (DEBUGLVL(4)) {
                char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
                DEBUG(4, ("DRS replication add message:\n%s\n", s));
@@ -3764,6 +3787,10 @@ static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request
        }
        if (ares->error != LDB_SUCCESS &&
            ares->error != LDB_ERR_NO_SUCH_OBJECT) {
+               /*
+                * TODO: deal with the above error that the parent object doesn't exist
+                */
+
                return ldb_module_done(ar->req, ares->controls,
                                        ares->response, ares->error);
        }
@@ -3843,7 +3870,11 @@ static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request
                break;
 
        case LDB_REPLY_DONE:
-               ret = replmd_replicated_apply_add(ar);
+               if (ar->search_msg != NULL) {
+                       ret = replmd_replicated_apply_merge(ar);
+               } else {
+                       ret = replmd_replicated_apply_add(ar);
+               }
                if (ret != LDB_SUCCESS) {
                        return ldb_module_done(ar->req, NULL, NULL, ret);
                }
@@ -3869,7 +3900,11 @@ static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_re
        ldb = ldb_module_get_ctx(ar->module);
 
        if (!ar->objs->objects[ar->index_current].parent_guid_value.data) {
-               return replmd_replicated_apply_add(ar);
+               if (ar->search_msg != NULL) {
+                       return replmd_replicated_apply_merge(ar);
+               } else {
+                       return replmd_replicated_apply_add(ar);
+               }
        }
 
        tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].parent_guid_value);
@@ -3908,81 +3943,52 @@ static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_re
  */
 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
                                           struct ldb_message *msg,
-                                          struct replPropertyMetaDataBlob *rmd,
-                                          struct replPropertyMetaDataBlob *omd,
                                           struct ldb_request *parent)
 {
-       struct replPropertyMetaData1 *md_remote;
-       struct replPropertyMetaData1 *md_local;
-
-       if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
-               /* no rename */
-               return LDB_SUCCESS;
-       }
-
-       /* now we need to check for double renames. We could have a
-        * local rename pending which our replication partner hasn't
-        * received yet. We choose which one wins by looking at the
-        * attribute stamps on the two objects, the newer one wins
-        */
-       md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
-       md_local  = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
-       /* if there is no name attribute then we have to assume the
-          object we've received is in fact newer */
-       if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING ||
-           !md_remote || !md_local ||
-           replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
-               struct ldb_request *req;
-               int ret;
-               TALLOC_CTX *tmp_ctx = talloc_new(msg);
-               struct ldb_result *res;
-
-               DEBUG(4,("replmd_replicated_request rename %s => %s\n",
-                        ldb_dn_get_linearized(ar->search_msg->dn),
-                        ldb_dn_get_linearized(msg->dn)));
-
+       struct ldb_request *req;
+       int ret;
+       TALLOC_CTX *tmp_ctx = talloc_new(msg);
+       struct ldb_result *res;
 
-               res = talloc_zero(tmp_ctx, struct ldb_result);
-               if (!res) {
-                       talloc_free(tmp_ctx);
-                       return ldb_oom(ldb_module_get_ctx(ar->module));
-               }
-
-               /* pass rename to the next module
-                * so it doesn't appear as an originating update */
-               ret = ldb_build_rename_req(&req, ldb_module_get_ctx(ar->module), tmp_ctx,
-                                          ar->search_msg->dn, msg->dn,
-                                          NULL,
-                                          ar,
-                                          replmd_op_rename_callback,
-                                          parent);
-               LDB_REQ_SET_LOCATION(req);
-               if (ret != LDB_SUCCESS) {
-                       talloc_free(tmp_ctx);
-                       return ret;
-               }
+       DEBUG(4,("replmd_replicated_request rename %s => %s\n",
+                ldb_dn_get_linearized(ar->search_msg->dn),
+                ldb_dn_get_linearized(msg->dn)));
 
-               ret = dsdb_request_add_controls(req, DSDB_MODIFY_RELAX);
-               if (ret != LDB_SUCCESS) {
-                       talloc_free(tmp_ctx);
-                       return ret;
-               }
 
-               ret = ldb_next_request(ar->module, req);
+       res = talloc_zero(tmp_ctx, struct ldb_result);
+       if (!res) {
+               talloc_free(tmp_ctx);
+               return ldb_oom(ldb_module_get_ctx(ar->module));
+       }
 
-               if (ret == LDB_SUCCESS) {
-                       ret = ldb_wait(req->handle, LDB_WAIT_ALL);
-               }
+       /* pass rename to the next module
+        * so it doesn't appear as an originating update */
+       ret = ldb_build_rename_req(&req, ldb_module_get_ctx(ar->module), tmp_ctx,
+                                  ar->search_msg->dn, msg->dn,
+                                  NULL,
+                                  ar,
+                                  replmd_op_rename_callback,
+                                  parent);
+       LDB_REQ_SET_LOCATION(req);
+       if (ret != LDB_SUCCESS) {
+               talloc_free(tmp_ctx);
+               return ret;
+       }
 
+       ret = dsdb_request_add_controls(req, DSDB_MODIFY_RELAX);
+       if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
                return ret;
        }
 
-       /* we're going to keep our old object */
-       DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
-                ldb_dn_get_linearized(ar->search_msg->dn),
-                ldb_dn_get_linearized(msg->dn)));
-       return LDB_SUCCESS;
+       ret = ldb_next_request(ar->module, req);
+
+       if (ret == LDB_SUCCESS) {
+               ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+       }
+
+       talloc_free(tmp_ctx);
+       return ret;
 }
 
 
@@ -4002,6 +4008,12 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
        unsigned int removed_attrs = 0;
        int ret;
        int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
+       bool isDeleted = false;
+       bool local_isDeleted = false;
+       bool remote_isDeleted = false;
+       bool take_remote_isDeleted = false;
+       bool sd_updated = false;
+       bool renamed = false;
 
        ldb = ldb_module_get_ctx(ar->module);
        msg = ar->objs->objects[ar->index_current].msg;
@@ -4025,8 +4037,27 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
                }
        }
 
-       /* handle renames that come in over DRS */
-       ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd, ar->req);
+       local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
+                                                   "isDeleted", false);
+       remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
+                                                    "isDeleted", false);
+
+       if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0) {
+               ret = LDB_SUCCESS;
+       } else {
+               /*
+                * handle renames, even just by case that come in over
+                * DRS.  Changes in the parent DN don't hit us here,
+                * because the search for a parent will clean up those
+                * components.
+                *
+                * We also have already filtered out the case where
+                * the peer has an older name to what we have (see
+                * replmd_replicated_apply_search_callback())
+                */
+               renamed = true;
+               ret = replmd_replicated_handle_rename(ar, msg, ar->req);
+       }
 
        /*
         * This particular error code means that we already tried the
@@ -4065,6 +4096,7 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
                /* Set the callback to one that will fix up the name to be a conflict DN */
                callback = replmd_op_name_modify_callback;
                msg->dn = new_dn;
+               renamed = true;
        } else if (ret != LDB_SUCCESS) {
                ldb_debug(ldb, LDB_DEBUG_FATAL,
                          "replmd_replicated_request rename %s => %s failed - %s\n",
@@ -4122,6 +4154,16 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
                                        }
                                }
                                nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
+                               switch (nmd.ctr.ctr1.array[j].attid) {
+                               case DRSUAPI_ATTID_ntSecurityDescriptor:
+                                       sd_updated = true;
+                                       break;
+                               case DRSUAPI_ATTID_isDeleted:
+                                       take_remote_isDeleted = true;
+                                       break;
+                               default:
+                                       break;
+                               }
                                found = true;
                                break;
                        }
@@ -4151,6 +4193,16 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
                        }
                }
                nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
+               switch (nmd.ctr.ctr1.array[ni].attid) {
+               case DRSUAPI_ATTID_ntSecurityDescriptor:
+                       sd_updated = true;
+                       break;
+               case DRSUAPI_ATTID_isDeleted:
+                       take_remote_isDeleted = true;
+                       break;
+               default:
+                       break;
+               }
                ni++;
        }
 
@@ -4185,6 +4237,25 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
        ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
                  ar->index_current, msg->num_elements);
 
+       if (take_remote_isDeleted) {
+               isDeleted = remote_isDeleted;
+       } else {
+               isDeleted = local_isDeleted;
+       }
+
+       if (renamed) {
+               sd_updated = true;
+       }
+
+       if (sd_updated && !isDeleted) {
+               ret = dsdb_module_schedule_sd_propagation(ar->module,
+                                                         ar->objs->partition_dn,
+                                                         msg->dn, true);
+               if (ret != LDB_SUCCESS) {
+                       return ldb_operr(ldb);
+               }
+       }
+
        /* create the meta data value */
        ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
                                       (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
@@ -4270,17 +4341,91 @@ static int replmd_replicated_apply_search_callback(struct ldb_request *req,
                break;
 
        case LDB_REPLY_DONE:
+       {
+               struct replPropertyMetaData1 *md_remote;
+               struct replPropertyMetaData1 *md_local;
+
+               struct replPropertyMetaDataBlob omd;
+               const struct ldb_val *omd_value;
+               struct replPropertyMetaDataBlob *rmd;
+               struct ldb_message *msg;
+
                ar->objs->objects[ar->index_current].last_known_parent = NULL;
 
-               if (ar->search_msg != NULL) {
-                       ret = replmd_replicated_apply_merge(ar);
-               } else {
+               /*
+                * This is the ADD case, find the appropriate parent,
+                * as this object doesn't exist locally:
+                */
+               if (ar->search_msg == NULL) {
                        ret = replmd_replicated_apply_search_for_parent(ar);
+                       if (ret != LDB_SUCCESS) {
+                               return ldb_module_done(ar->req, NULL, NULL, ret);
+                       }
+                       talloc_free(ares);
+                       return LDB_SUCCESS;
+               }
+
+               /*
+                * Otherwise, in the MERGE case, work out if we are
+                * attempting a rename, and if so find the parent the
+                * newly renamed object wants to belong under (which
+                * may not be the parent in it's attached string DN
+                */
+               rmd = ar->objs->objects[ar->index_current].meta_data;
+               ZERO_STRUCT(omd);
+               omd.version = 1;
+
+               /* find existing meta data */
+               omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
+               if (omd_value) {
+                       enum ndr_err_code ndr_err;
+                       ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
+                                                      (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
+                       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                               NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
+                               return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
+                       }
+
+                       if (omd.version != 1) {
+                               return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
+                       }
+               }
+
+               /*
+                * now we need to check for double renames. We could have a
+                * local rename pending which our replication partner hasn't
+                * received yet. We choose which one wins by looking at the
+                * attribute stamps on the two objects, the newer one wins
+                */
+               md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
+               md_local  = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
+               /* if there is no name attribute then we have to assume the
+                  object we've received is in fact newer */
+               if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING ||
+                   !md_remote || !md_local ||
+                   replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
+                       ret = replmd_replicated_apply_search_for_parent(ar);
+               } else {
+                       msg = ar->objs->objects[ar->index_current].msg;
+
+                       /* Otherwise, just merge on the existing object, force no rename */
+                       DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
+                                ldb_dn_get_linearized(ar->search_msg->dn),
+                                ldb_dn_get_linearized(msg->dn)));
+
+                       /*
+                        * This assignment ensures that the strcmp()
+                        * in replmd_replicated_apply_merge() avoids
+                        * the rename call
+                        */
+                       msg->dn = ar->search_msg->dn;
+                       ret = replmd_replicated_apply_merge(ar);
                }
                if (ret != LDB_SUCCESS) {
                        return ldb_module_done(ar->req, NULL, NULL, ret);
                }
        }
+       }
 
        talloc_free(ares);
        return LDB_SUCCESS;
@@ -4451,7 +4596,7 @@ static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *a
         *
         * plus optional values from our old vector and the one from the source_dsa
         */
-       nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
+       nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
        if (ruv) nuv.ctr.ctr2.count += ruv->count;
        nuv.ctr.ctr2.cursors = talloc_array(ar,
                                            struct drsuapi_DsReplicaCursor2,
@@ -4485,12 +4630,8 @@ static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *a
 
                        found = true;
 
-                       /*
-                        * we update only the highest_usn and not the latest_sync_success time,
-                        * because the last success stands for direct replication
-                        */
                        if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
-                               nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
+                               nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
                        }
                        break;
                }
@@ -4502,43 +4643,6 @@ static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *a
                ni++;
        }
 
-       /*
-        * merge in the current highwatermark for the source_dsa
-        */
-       found = false;
-       for (j=0; j < ni; j++) {
-               if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
-                               &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
-                       continue;
-               }
-
-               found = true;
-
-               /*
-                * here we update the highest_usn and last_sync_success time
-                * because we're directly replicating from the source_dsa
-                *
-                * and use the tmp_highest_usn because this is what we have just applied
-                * to our ldb
-                */
-               nuv.ctr.ctr2.cursors[j].highest_usn             = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
-               nuv.ctr.ctr2.cursors[j].last_sync_success       = now;
-               break;
-       }
-       if (!found) {
-               /*
-                * here we update the highest_usn and last_sync_success time
-                * because we're directly replicating from the source_dsa
-                *
-                * and use the tmp_highest_usn because this is what we have just applied
-                * to our ldb
-                */
-               nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
-               nuv.ctr.ctr2.cursors[ni].highest_usn            = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
-               nuv.ctr.ctr2.cursors[ni].last_sync_success      = now;
-               ni++;
-       }
-
        /*
         * finally correct the size of the cursors array
         */
@@ -4574,7 +4678,9 @@ static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *a
        ZERO_STRUCT(nrf);
        nrf.version                                     = 1;
        nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
-       nrf.ctr.ctr1.highwatermark.highest_usn          = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
+       nrf.ctr.ctr1.last_attempt                       = now;
+       nrf.ctr.ctr1.last_success                       = now;
+       nrf.ctr.ctr1.result_last_attempt                = WERR_OK;
 
        /*
         * first see if we already have a repsFrom value for the current source dsa