From 23a8fad22bbcd41ee2583d96831295887fe48edc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 1 Oct 2010 16:19:28 -0700 Subject: s4-drs: fixed comparison login in replicated renames we need to ensure we only ever compare USNs from the same originating invocation ID. Autobuild-User: Andrew Tridgell Autobuild-Date: Sat Oct 2 01:45:19 UTC 2010 on sn-devel-104 --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 117 +++++++++++++++--------- 1 file changed, 72 insertions(+), 45 deletions(-) (limited to 'source4') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 198bb802cb..b459405b57 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2896,19 +2896,23 @@ static bool replmd_update_is_newer(const struct GUID *current_invocation_id, const struct GUID *update_invocation_id, uint32_t current_version, uint32_t update_version, + uint32_t current_usn, + uint32_t update_usn, NTTIME current_change_time, NTTIME update_change_time) { - if (update_version != current_version) { - return update_version > current_version; + if (GUID_compare(update_invocation_id, current_invocation_id) == 0) { + if (update_usn != current_usn) { + return update_usn >= current_usn; + } } - if (update_change_time > current_change_time) { - return true; + if (update_version != current_version) { + return update_version >= current_version; } - if (update_change_time == current_change_time) { - return GUID_compare(update_invocation_id, current_invocation_id) > 0; + if (update_change_time != current_change_time) { + return update_change_time >= current_change_time; } - return false; + return GUID_compare(update_invocation_id, current_invocation_id) >= 0; } static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m, @@ -2918,6 +2922,8 @@ static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 * &new_m->originating_invocation_id, cur_m->version, new_m->version, + cur_m->originating_usn, + new_m->originating_usn, cur_m->originating_change_time, new_m->originating_change_time); } @@ -2937,6 +2943,52 @@ replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob return NULL; } + +/* + handle renames that come in over DRS replication + */ +static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar, + struct ldb_message *msg, + struct replPropertyMetaDataBlob *rmd, + struct replPropertyMetaDataBlob *omd) +{ + 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_ATTRIBUTE_name); + md_local = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTRIBUTE_name); + /* if there is no name attribute then we have to assume the + object we've received is in fact newer */ + if (!md_remote || !md_local || + replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) { + DEBUG(4,("replmd_replicated_request rename %s => %s\n", + ldb_dn_get_linearized(ar->search_msg->dn), + ldb_dn_get_linearized(msg->dn))); + /* pass rename to the next module + * so it doesn't appear as an originating update */ + return dsdb_module_rename(ar->module, + ar->search_msg->dn, msg->dn, + DSDB_FLAG_NEXT_MODULE | DSDB_MODIFY_RELAX); + } + + /* 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; +} + + static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) { struct ldb_context *ldb; @@ -2948,8 +3000,6 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) const struct ldb_val *omd_value; struct replPropertyMetaDataBlob nmd; struct ldb_val nmd_value; - struct replPropertyMetaData1 *md_remote; - struct replPropertyMetaData1 *md_local; unsigned int i; uint32_t j,ni=0; unsigned int removed_attrs = 0; @@ -2976,42 +3026,15 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) } } - /* check if remote 'name' has change, - * which indicates a rename operation */ - md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTRIBUTE_name); - if (md_remote) { - md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTRIBUTE_name); - if (!md_local) { - DEBUG(0,(__location__ ": No md_local in RPMD\n")); - return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR); - } - if (replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) { - if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) { - DEBUG(0,(__location__ ": DNs don't match in RPMD: %s %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_dn_get_linearized(ar->search_msg->dn))); - return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR); - } - /* TODO: Find appropriate local name (dn) for the object - * and modify msg->dn appropriately */ - - DEBUG(4,("replmd_replicated_request rename %s => %s\n", - ldb_dn_get_linearized(ar->search_msg->dn), - ldb_dn_get_linearized(msg->dn))); - /* pass rename to the next module - * so it doesn't appear as an originating update */ - ret = dsdb_module_rename(ar->module, - ar->search_msg->dn, msg->dn, - DSDB_FLAG_NEXT_MODULE); - if (ret != LDB_SUCCESS) { - ldb_debug(ldb, LDB_DEBUG_FATAL, - "replmd_replicated_request rename %s => %s failed - %s\n", - ldb_dn_get_linearized(ar->search_msg->dn), - ldb_dn_get_linearized(msg->dn), - ldb_errstring(ldb)); - return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR); - } - } + /* handle renames that come in over DRS */ + ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd); + if (ret != LDB_SUCCESS) { + ldb_debug(ldb, LDB_DEBUG_FATAL, + "replmd_replicated_request rename %s => %s failed - %s\n", + ldb_dn_get_linearized(ar->search_msg->dn), + ldb_dn_get_linearized(msg->dn), + ldb_errstring(ldb)); + return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR); } ZERO_STRUCT(nmd); @@ -3920,17 +3943,21 @@ linked_attributes[0]: /* see if this update is newer than what we have already */ struct GUID invocation_id = GUID_zero(); uint32_t version = 0; + uint32_t originating_usn = 0; NTTIME change_time = 0; uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn); dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID"); dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION"); + dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN"); dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME"); if (!replmd_update_is_newer(&invocation_id, &la->meta_data.originating_invocation_id, version, la->meta_data.version, + originating_usn, + la->meta_data.originating_usn, change_time, la->meta_data.originating_change_time)) { DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n", -- cgit