summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c170
1 files changed, 152 insertions, 18 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 7e1d7189b1..249dd61a4a 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -1170,7 +1170,8 @@ static int replmd_modify_la_add(struct ldb_module *module,
/* add the new ones on to the end of the old values, constructing a new el->values */
el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
- struct ldb_val, old_num_values+num_new_values);
+ struct ldb_val,
+ old_num_values+num_new_values);
if (el->values == NULL) {
ldb_module_oom(module);
return LDB_ERR_OPERATIONS_ERROR;
@@ -1193,20 +1194,6 @@ static int replmd_modify_la_add(struct ldb_module *module,
/*
- handle replacing a linked attribute
- */
-static int replmd_modify_la_replace(struct ldb_module *module,
- struct ldb_message *msg,
- struct ldb_message_element *el,
- struct ldb_message_element *old_el,
- const struct dsdb_attribute *schema_attr,
- uint64_t seq_num,
- time_t t)
-{
- return LDB_SUCCESS;
-}
-
-/*
handle deleting all active linked attributes
*/
static int replmd_modify_la_delete(struct ldb_module *module,
@@ -1266,7 +1253,7 @@ static int replmd_modify_la_delete(struct ldb_module *module,
el->name, GUID_string(tmp_ctx, p->guid));
return LDB_ERR_NO_SUCH_ATTRIBUTE;
}
- v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
+ v = ldb_dn_get_extended_component(p2->dsdb_dn->dn, "DELETED");
if (v) {
ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
el->name, GUID_string(tmp_ctx, p->guid));
@@ -1307,6 +1294,134 @@ static int replmd_modify_la_delete(struct ldb_module *module,
return LDB_SUCCESS;
}
+/*
+ handle replacing a linked attribute
+ */
+static int replmd_modify_la_replace(struct ldb_module *module,
+ struct ldb_message *msg,
+ struct ldb_message_element *el,
+ struct ldb_message_element *old_el,
+ const struct dsdb_attribute *schema_attr,
+ uint64_t seq_num,
+ time_t t)
+{
+ int i;
+ struct parsed_dn *dns, *old_dns;
+ TALLOC_CTX *tmp_ctx = talloc_new(msg);
+ int ret;
+ const struct GUID *invocation_id;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_val *new_values = NULL;
+ uint32_t num_new_values = 0;
+ unsigned old_num_values = old_el?old_el->num_values:0;
+
+ /* check if there is nothing to replace */
+ if ((!old_el || old_el->num_values == 0) &&
+ el->num_values == 0) {
+ return LDB_SUCCESS;
+ }
+
+ ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ invocation_id = samdb_ntds_invocation_id(ldb);
+ if (!invocation_id) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* mark all the old ones as deleted */
+ for (i=0; i<old_num_values; i++) {
+ struct parsed_dn *old_p = &old_dns[i];
+ struct parsed_dn *p;
+ const struct ldb_val *v;
+
+ p = parsed_dn_find(dns, el->num_values, old_p->guid);
+ if (p) {
+ /* we don't delete it if we are re-adding it */
+ continue;
+ }
+ v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED");
+ if (v) continue;
+
+ ret = replmd_update_la_val(old_el->values, old_p->v, old_p, old_p,
+ invocation_id, seq_num, t, true);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+
+ /* for each new value, either update its meta-data, or add it
+ * to old_el
+ */
+ for (i=0; i<el->num_values; i++) {
+ struct parsed_dn *p = &dns[i], *old_p;
+
+ if (old_dns &&
+ (old_p = parsed_dn_find(old_dns,
+ old_num_values, p->guid)) != NULL) {
+ /* update in place */
+ ret = replmd_update_la_val(old_el->values, old_p->v, old_p,
+ old_p, invocation_id,
+ seq_num, t, false);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ } else {
+ /* add a new one */
+ new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
+ num_new_values+1);
+ if (new_values == NULL) {
+ ldb_module_oom(module);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = replmd_build_la_val(new_values, &new_values[num_new_values], &dns[i],
+ invocation_id, seq_num, t);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ num_new_values++;
+ }
+ }
+
+ /* add the new values to the end of old_el */
+ if (num_new_values != 0) {
+ el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
+ struct ldb_val, old_num_values+num_new_values);
+ if (el->values == NULL) {
+ ldb_module_oom(module);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ memcpy(&el->values[old_num_values], &new_values[0],
+ sizeof(struct ldb_val)*num_new_values);
+ el->num_values = old_num_values + num_new_values;
+ talloc_steal(msg->elements, new_values);
+ } else {
+ el->values = old_el->values;
+ el->num_values = old_el->num_values;
+ talloc_steal(msg->elements, el->values);
+ }
+
+ talloc_free(tmp_ctx);
+
+ /* we now tell the backend to replace all existing values
+ with the one we have constructed */
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ return LDB_SUCCESS;
+}
/*
@@ -1340,6 +1455,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
DSDB_SEARCH_SHOW_DELETED |
+ DSDB_SEARCH_REVEAL_INTERNALS |
DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
if (ret != LDB_SUCCESS) {
return ret;
@@ -1348,7 +1464,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
for (i=0; i<msg->num_elements; i++) {
struct ldb_message_element *el = &msg->elements[i];
- struct ldb_message_element *old_el;
+ struct ldb_message_element *old_el, *new_el;
const struct dsdb_attribute *schema_attr
= dsdb_attribute_by_lDAPDisplayName(schema, el->name);
if (!schema_attr) {
@@ -1366,7 +1482,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
return LDB_ERR_UNWILLING_TO_PERFORM;
}
old_el = ldb_msg_find_element(old_msg, el->name);
- switch (el->flags) {
+ switch (el->flags & LDB_FLAG_MOD_MASK) {
case LDB_FLAG_MOD_REPLACE:
ret = replmd_modify_la_replace(module, msg, el, old_el, schema_attr, seq_num, t);
break;
@@ -1382,6 +1498,24 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
el->flags, el->name);
return LDB_ERR_UNWILLING_TO_PERFORM;
}
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (old_el) {
+ ldb_msg_remove_attr(old_msg, el->name);
+ }
+ ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
+ new_el->num_values = el->num_values;
+ new_el->values = el->values;
+
+ /* TODO: this relises a bit too heavily on the exact
+ behaviour of ldb_msg_find_element and
+ ldb_msg_remove_element */
+ old_el = ldb_msg_find_element(msg, el->name);
+ if (old_el != el) {
+ ldb_msg_remove_element(msg, old_el);
+ i--;
+ }
}
talloc_free(res);