diff options
-rw-r--r-- | source4/rpc_server/drsuapi/getncchanges.c | 47 |
1 files changed, 38 insertions, 9 deletions
diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 10965a3e81..511925a479 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -45,8 +45,11 @@ struct drsuapi_getncchanges_state { struct ldb_dn *ncRoot_dn; bool is_schema_nc; uint64_t min_usn; + uint64_t max_usn; struct drsuapi_DsReplicaHighWaterMark last_hwm; struct ldb_dn *last_dn; + struct drsuapi_DsReplicaHighWaterMark final_hwm; + struct drsuapi_DsReplicaCursor2CtrEx *final_udv; struct drsuapi_DsReplicaLinkedAttribute *la_list; uint32_t la_count; bool la_sorted; @@ -1740,6 +1743,18 @@ allowed: extra_filter = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "object filter"); getnc_state->min_usn = req10->highwatermark.highest_usn; + getnc_state->max_usn = getnc_state->min_usn; + + getnc_state->final_udv = talloc_zero(getnc_state, + struct drsuapi_DsReplicaCursor2CtrEx); + if (getnc_state->final_udv == NULL) { + return WERR_NOMEM; + } + werr = get_nc_changes_udv(sam_ctx, getnc_state->ncRoot_dn, + getnc_state->final_udv); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } if (req10->extended_op == DRSUAPI_EXOP_NONE) { werr = getncchanges_collect_objects(b_state, mem_ctx, req10, @@ -1767,6 +1782,10 @@ allowed: changes[i].dn = search_res->msgs[i]->dn; changes[i].guid = samdb_result_guid(search_res->msgs[i], "objectGUID"); changes[i].usn = ldb_msg_find_attr_as_uint64(search_res->msgs[i], "uSNChanged", 0); + + if (changes[i].usn > getnc_state->max_usn) { + getnc_state->max_usn = changes[i].usn; + } } if (req10->replica_flags & DRSUAPI_DRS_GET_ANC) { @@ -1788,6 +1807,10 @@ allowed: } } + getnc_state->final_hwm.tmp_highest_usn = getnc_state->max_usn; + getnc_state->final_hwm.reserved_usn = 0; + getnc_state->final_hwm.highest_usn = getnc_state->max_usn; + talloc_free(search_res); talloc_free(changes); } @@ -1920,6 +1943,18 @@ allowed: } uSN = ldb_msg_find_attr_as_int(msg, "uSNChanged", -1); + if (uSN > getnc_state->max_usn) { + /* + * Only report the max_usn we had at the start + * of the replication cycle. + * + * If this object has changed lately we better + * let the destination dsa refetch the change. + * This is better than the risk of loosing some + * objects or linked attributes. + */ + uSN = 0; + } if (uSN > r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn) { r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn = uSN; r->out.ctr->ctr6.new_highwatermark.reserved_usn = 0; @@ -2022,15 +2057,9 @@ allowed: if (!r->out.ctr->ctr6.more_data) { talloc_steal(mem_ctx, getnc_state->la_list); - r->out.ctr->ctr6.uptodateness_vector = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2CtrEx); - r->out.ctr->ctr6.new_highwatermark.highest_usn = r->out.ctr->ctr6.new_highwatermark.tmp_highest_usn; - r->out.ctr->ctr6.new_highwatermark.reserved_usn = 0; - - werr = get_nc_changes_udv(sam_ctx, getnc_state->ncRoot_dn, - r->out.ctr->ctr6.uptodateness_vector); - if (!W_ERROR_IS_OK(werr)) { - return werr; - } + r->out.ctr->ctr6.new_highwatermark = getnc_state->final_hwm; + r->out.ctr->ctr6.uptodateness_vector = talloc_move(mem_ctx, + &getnc_state->final_udv); talloc_free(getnc_state); b_state->getncchanges_state = NULL; |