1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-26 10:04:02 +03:00

replmd: Move link conflict handling into separate function

Link conflict handling is a corner-case. The logic in
replmd_process_linked_attribute() is already reasonably busy/complex.
Split out the handling of link conflicts into a separate function so
that it doesn't detract from the core replmd_process_linked_attribute()
logic too much.

This refactor should not alter functionality.

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>
This commit is contained in:
Tim Beale 2017-09-28 10:22:55 +13:00 committed by Andrew Bartlett
parent 82b56e63b5
commit 841e724e29

View File

@ -7275,6 +7275,100 @@ static int replmd_delete_link_value(struct ldb_module *module,
return ret;
}
/**
* Checks for a conflict in single-valued link attributes, and tries to
* resolve the problem if possible.
*
* Single-valued links should only ever have one active value. If we already
* have an active link value, and during replication we receive an active link
* value for a different target DN, then we need to resolve this inconsistency
* and determine which value should be active. If the received info is better/
* newer than the existing link attribute, then we need to set our existing
* link as deleted. If the received info is worse/older, then we should continue
* to add it, but set it as an inactive link.
*
* Note that this is a corner-case that is unlikely to happen (but if it does
* happen, we don't want it to break replication completely).
*
* @param pdn the parsed DN corresponding to the received link
* target (note this is NULL if the link does not already exist in our DB)
* @param pdn_list all the source object's Parsed-DNs for this attribute, i.e.
* any existing active or inactive values for the attribute in our DB.
* @param dsdb_dn the target DN for the received link attribute
* @param add_as_inactive gets set to true if the received link is worse than
* the existing link - it should still be added, but as an inactive link.
*/
static int replmd_check_singleval_la_conflict(struct ldb_module *module,
struct replmd_private *replmd_private,
TALLOC_CTX *mem_ctx,
struct ldb_dn *src_obj_dn,
struct drsuapi_DsReplicaLinkedAttribute *la,
struct dsdb_dn *dsdb_dn,
struct parsed_dn *pdn,
struct parsed_dn *pdn_list,
struct ldb_message_element *old_el,
const struct dsdb_schema *schema,
const struct dsdb_attribute *attr,
uint64_t seq_num,
bool *add_as_inactive)
{
struct parsed_dn *active_pdn = NULL;
struct parsed_dn *conflict_pdn = NULL;
int ret;
/*
* check if there's a conflict for single-valued links, i.e. an active
* linked attribute already exists, but it has a different target value
*/
ret = replmd_get_active_singleval_link(module, mem_ctx, pdn_list,
old_el->num_values, attr,
&active_pdn);
if (ret != LDB_SUCCESS) {
return ret;
}
if (active_pdn != pdn) {
conflict_pdn = active_pdn;
}
/* 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(src_obj_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, src_obj_dn, schema,
attr, seq_num, true,
&conflict_pdn->guid,
conflict_pdn->dsdb_dn,
conflict_pdn->v);
if (ret != LDB_SUCCESS) {
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));
/*
* we want to keep our existing active link and add the
* received link as inactive
*/
*add_as_inactive = true;
}
}
return LDB_SUCCESS;
}
/*
process one linked attribute structure
*/
@ -7295,7 +7389,6 @@ 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;
@ -7381,26 +7474,6 @@ static int replmd_process_linked_attribute(struct ldb_module *module,
return ret;
}
/*
* check if there's a conflict for single-valued links, i.e. an active
* linked attribute already exists, but it has a different target value
*/
if (active) {
struct parsed_dn *active_pdn = NULL;
ret = replmd_get_active_singleval_link(module, tmp_ctx, pdn_list,
old_el->num_values, attr,
&active_pdn);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ret;
}
if (active_pdn != pdn) {
conflict_pdn = active_pdn;
}
}
if (!replmd_link_update_is_newer(pdn, la)) {
DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
old_el->name, ldb_dn_get_linearized(msg->dn),
@ -7416,38 +7489,20 @@ 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));
/*
* we want to keep our existing active link and add the
* received link as inactive
*/
add_as_inactive = true;
/*
* check for single-valued link conflicts, i.e. an active linked
* attribute already exists, but it has a different target value
*/
if (active) {
ret = replmd_check_singleval_la_conflict(module, replmd_private,
tmp_ctx, msg->dn, la,
dsdb_dn, pdn, pdn_list,
old_el, schema, attr,
seq_num,
&add_as_inactive);
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return ret;
}
}