summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorTim Beale <timbeale@catalyst.net.nz>2017-09-27 13:44:29 +1300
committerAndrew Bartlett <abartlet@samba.org>2017-10-20 04:05:21 +0200
commitf196897bc822f7133627477e77a4bcd98b8ceda6 (patch)
tree8c124e1aeccdcce5f72ed871953a2525a7608f04 /source4
parent70d532a5c79dc386bf55db1d32865044872a6905 (diff)
downloadsamba-f196897bc822f7133627477e77a4bcd98b8ceda6.tar.gz
replmd: Handle conflicts for single-valued link attributes better
If 2 DCs independently set a single-valued linked attribute to differing values, Samba should be able to resolve this problem when replication occurs. If the received information is better, then we want to set the existing link attribute in our DB as inactive. If our own information is better, then we still want to add the received link attribute, but mark it as inactive so that it doesn't clobber our own link. This still isn't a complete solution. When we add the received attribute as inactive, we really should be incrementing the version, updating the USN, etc. Also this only deals with the case where the received link is completely new (i.e. a received link conflicting with an existing inactive link isn't handled). BUG: https://bugzilla.samba.org/show_bug.cgi?id=13055 Signed-off-by: Tim Beale <timbeale@catalyst.net.nz> Reviewed-by: Garming Sam <garming@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'source4')
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c89
1 files changed, 82 insertions, 7 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 2a1069c0109..80a5cad2b14 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -7224,6 +7224,54 @@ static bool replmd_link_update_is_newer(struct parsed_dn *pdn,
la->meta_data.originating_change_time);
}
+/**
+ * Marks an existing linked attribute value as deleted in the DB
+ * @param pdn the parsed-DN of the target-value to delete
+ */
+static int replmd_delete_link_value(struct ldb_module *module,
+ struct replmd_private *replmd_private,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *src_obj_dn,
+ const struct dsdb_schema *schema,
+ const struct dsdb_attribute *attr,
+ uint64_t seq_num,
+ bool is_active,
+ struct GUID *target_guid,
+ struct dsdb_dn *target_dsdb_dn,
+ struct ldb_val *output_val)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ time_t t;
+ NTTIME now;
+ const struct GUID *invocation_id = NULL;
+ int ret;
+
+ t = time(NULL);
+ unix_to_nt_time(&now, t);
+
+ invocation_id = samdb_ntds_invocation_id(ldb);
+ if (invocation_id == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* if the existing link is active, remove its backlink */
+ if (is_active) {
+
+ ret = replmd_add_backlink(module, replmd_private, schema,
+ src_obj_dn, target_guid, false,
+ attr, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ /* mark the existing value as deleted */
+ ret = replmd_update_la_val(mem_ctx, output_val, target_dsdb_dn,
+ target_dsdb_dn, invocation_id, seq_num,
+ seq_num, now, true);
+ return ret;
+}
+
/*
process one linked attribute structure
*/
@@ -7244,6 +7292,7 @@ static int replmd_process_linked_attribute(struct ldb_module *module,
struct ldb_message_element *old_el;
time_t t = time(NULL);
struct parsed_dn *pdn_list, *pdn, *next;
+ struct parsed_dn *conflict_pdn = NULL;
struct GUID guid = GUID_zero();
bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
bool ignore_link;
@@ -7335,17 +7384,11 @@ static int replmd_process_linked_attribute(struct ldb_module *module,
*/
ret = replmd_get_active_singleval_link(module, tmp_ctx, pdn_list,
old_el->num_values, attr,
- &pdn);
+ &conflict_pdn);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ret;
}
-
- if (pdn != NULL) {
- DBG_WARNING("Link conflict for %s linked from %s\n",
- ldb_dn_get_linearized(pdn->dsdb_dn->dn),
- ldb_dn_get_linearized(msg->dn));
- }
}
if (!replmd_link_update_is_newer(pdn, la)) {
@@ -7363,6 +7406,38 @@ static int replmd_process_linked_attribute(struct ldb_module *module,
return ret;
}
+ /* resolve any single-valued link conflicts */
+ if (conflict_pdn != NULL) {
+
+ DBG_WARNING("Link conflict for %s attribute on %s\n",
+ attr->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
+
+ if (replmd_link_update_is_newer(conflict_pdn, la)) {
+ DBG_WARNING("Using received value %s, over existing target %s\n",
+ ldb_dn_get_linearized(dsdb_dn->dn),
+ ldb_dn_get_linearized(conflict_pdn->dsdb_dn->dn));
+
+ ret = replmd_delete_link_value(module, replmd_private,
+ old_el, msg->dn, schema,
+ attr, seq_num, true,
+ &conflict_pdn->guid,
+ conflict_pdn->dsdb_dn,
+ conflict_pdn->v);
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ } else {
+ DBG_WARNING("Using existing target %s, over received value %s\n",
+ ldb_dn_get_linearized(conflict_pdn->dsdb_dn->dn),
+ ldb_dn_get_linearized(dsdb_dn->dn));
+
+ /* don't add the link as active */
+ active = false;
+ }
+ }
+
if (pdn != NULL) {
uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);