summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2010-10-01 16:19:28 -0700
committerAndrew Tridgell <tridge@samba.org>2010-10-02 01:45:19 +0000
commit23a8fad22bbcd41ee2583d96831295887fe48edc (patch)
tree71ecbbb7caa590ef874dab98a4a0b50ca6934b28
parent6e846ca1f3bd812bdba22101d8326987a0013858 (diff)
downloadsamba-23a8fad22bbcd41ee2583d96831295887fe48edc.tar.gz
samba-23a8fad22bbcd41ee2583d96831295887fe48edc.tar.bz2
samba-23a8fad22bbcd41ee2583d96831295887fe48edc.zip
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 <tridge@samba.org> Autobuild-Date: Sat Oct 2 01:45:19 UTC 2010 on sn-devel-104
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c117
1 files changed, 72 insertions, 45 deletions
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",