diff options
author | Tim Beale <timbeale@catalyst.net.nz> | 2017-09-27 13:44:29 +1300 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2017-10-20 04:05:21 +0200 |
commit | f196897bc822f7133627477e77a4bcd98b8ceda6 (patch) | |
tree | 8c124e1aeccdcce5f72ed871953a2525a7608f04 /source4 | |
parent | 70d532a5c79dc386bf55db1d32865044872a6905 (diff) | |
download | samba-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.c | 89 |
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); |