#include "includes.h"
#include "ldb_module.h"
-#include "dlinklist.h"
+#include "util/dlinklist.h"
#include "dsdb/samdb/samdb.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "dsdb/samdb/ldb_modules/util.h"
struct la_private {
struct la_context *la_list;
struct la_op_store *next;
struct la_op_store *prev;
enum la_op {LA_OP_ADD, LA_OP_DEL} op;
- struct ldb_dn *dn;
+ struct GUID guid;
char *name;
char *value;
};
const struct dsdb_schema *schema;
struct ldb_module *module;
struct ldb_request *req;
- struct ldb_dn *partition_dn;
struct ldb_dn *add_dn;
struct ldb_dn *del_dn;
struct replace_context *rc;
{
struct ldb_context *ldb;
struct la_context *ac;
- const struct ldb_control *partition_ctrl;
ldb = ldb_module_get_ctx(module);
return NULL;
}
- ac->schema = dsdb_get_schema(ldb);
+ ac->schema = dsdb_get_schema(ldb, ac);
ac->module = module;
ac->req = req;
- /* remember the partition DN that came in, if given */
- partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
- if (partition_ctrl) {
- const struct dsdb_control_current_partition *partition;
- partition = talloc_get_type(partition_ctrl->data,
- struct dsdb_control_current_partition);
- SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION);
-
- ac->partition_dn = ldb_dn_copy(ac, partition->dn);
+ return ac;
+}
+
+/*
+ turn a DN into a GUID
+ */
+static int la_guid_from_dn(struct la_context *ac, struct ldb_dn *dn, struct GUID *guid)
+{
+ int ret;
+ NTSTATUS status;
+
+ status = dsdb_get_extended_dn_guid(dn, guid, "GUID");
+ if (NT_STATUS_IS_OK(status)) {
+ return LDB_SUCCESS;
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ DEBUG(4,(__location__ ": Unable to parse GUID for dn %s\n",
+ ldb_dn_get_linearized(dn)));
+ return LDB_ERR_OPERATIONS_ERROR;
}
- return ac;
+ ret = dsdb_find_guid_by_dn(ldb_module_get_ctx(ac->module), dn, guid);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(4,(__location__ ": Failed to find GUID for dn %s\n",
+ ldb_dn_get_linearized(dn)));
+ return ret;
+ }
+ return LDB_SUCCESS;
}
+
/* Common routine to handle reading the attributes and creating a
* series of modify requests */
static int la_store_op(struct la_context *ac,
enum la_op op, struct ldb_val *dn,
- const char *name)
+ const char *name)
{
struct ldb_context *ldb;
struct la_op_store *os;
struct ldb_dn *op_dn;
+ int ret;
ldb = ldb_module_get_ctx(ac->module);
os->op = op;
- os->dn = talloc_steal(os, op_dn);
+ ret = la_guid_from_dn(ac, op_dn, &os->guid);
+ talloc_free(op_dn);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT && ac->req->operation == LDB_DELETE) {
+ /* we are deleting an object, and we've found it has a
+ * forward link to a target that no longer
+ * exists. This is not an error in the delete, and we
+ * should just not do the deferred delete of the
+ * target attribute
+ */
+ talloc_free(os);
+ return LDB_SUCCESS;
+ }
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
os->name = talloc_strdup(os, name);
if (!os->name) {
return LDB_SUCCESS;
}
-static int la_op_search_callback(struct ldb_request *req,
- struct ldb_reply *ares);
static int la_queue_mod_request(struct la_context *ac);
static int la_down_req(struct la_context *ac);
const struct dsdb_attribute *target_attr;
struct la_context *ac;
const char *attr_name;
+ struct ldb_control *ctrl;
int ret;
int i, j;
return ldb_next_request(module, req);
}
+ if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {
+ /* don't do anything special for linked attributes, repl_meta_data has done it */
+ return ldb_next_request(module, req);
+ }
+ ctrl->critical = false;
+
ac = linked_attributes_init(module, req);
if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
"attribute %s is not a valid attribute in schema", el->name);
return LDB_ERR_OBJECT_CLASS_VIOLATION;
}
- /* We have a valid attribute, now find out if it is linked */
- if (schema_attr->linkID == 0) {
+ /* We have a valid attribute, now find out if it is a forward link */
+ if ((schema_attr->linkID == 0) || ((schema_attr->linkID & 1) == 1)) {
continue;
}
- if ((schema_attr->linkID & 1) == 1) {
- /* Odd is for the target. Illegal to modify */
- ldb_asprintf_errstring(ldb,
- "attribute %s must not be modified directly, it is a linked attribute", el->name);
- return LDB_ERR_UNWILLING_TO_PERFORM;
- }
-
/* Even link IDs are for the originating attribute */
target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
if (!target_attr) {
if (ldb_dn_compare(ares->message->dn, ac->req->op.mod.message->dn) != 0) {
ldb_asprintf_errstring(ldb,
- "linked_attributes: %s is not the DN we were looking for", ldb_dn_get_linearized(ares->message->dn));
+ "linked_attributes: %s is not the DN we were looking for",
+ ldb_dn_get_linearized(ares->message->dn));
/* Guh? We only asked for this DN */
talloc_free(ares);
return ldb_module_done(ac->req, NULL, NULL,
struct la_context *ac;
struct ldb_request *search_req;
const char **attrs;
+ struct ldb_control *ctrl;
int ret;
return ldb_next_request(module, req);
}
+ if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {
+ /* don't do anything special for linked attributes, repl_meta_data has done it */
+ return ldb_next_request(module, req);
+ }
+ ctrl->critical = false;
+
ac = linked_attributes_init(module, req);
if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
"attribute %s is not a valid attribute in schema", el->name);
return LDB_ERR_OBJECT_CLASS_VIOLATION;
}
- /* We have a valid attribute, now find out if it is linked */
- if (schema_attr->linkID == 0) {
+ /* We have a valid attribute, now find out if it is a forward link
+ (Even link IDs are for the originating attribute) */
+ if ((schema_attr->linkID == 0) || ((schema_attr->linkID & 1) == 1)) {
continue;
}
-
- if ((schema_attr->linkID & 1) == 1) {
- /* Odd is for the target. Illegal to modify */
- ldb_asprintf_errstring(ldb,
- "attribute %s must not be modified directly, it is a linked attribute", el->name);
- return LDB_ERR_UNWILLING_TO_PERFORM;
- }
-
- /* Even link IDs are for the originating attribute */
-
+
/* Now find the target attribute */
target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
if (!target_attr) {
return ret;
}
-/* delete, rename */
-static int linked_attributes_del(struct ldb_module *module, struct ldb_request *req)
+static int linked_attributes_fix_links(struct ldb_module *module,
+ struct ldb_dn *old_dn, struct ldb_dn *new_dn,
+ struct ldb_message_element *el, struct dsdb_schema *schema,
+ const struct dsdb_attribute *schema_attr)
{
- struct ldb_context *ldb;
- struct ldb_request *search_req;
- struct la_context *ac;
- const char **attrs;
- WERROR werr;
- int ret;
-
- /* This gets complex: We need to:
- - Do a search for the entry
- - Wait for these result to appear
- - In the callback for the result, issue a modify
- request based on the linked attributes found
- - Wait for each modify result
- - Regain our sainity
- */
-
- ldb = ldb_module_get_ctx(module);
-
- ac = linked_attributes_init(module, req);
- if (!ac) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (!ac->schema) {
- /* without schema, this doesn't make any sense */
- return ldb_next_request(module, req);
- }
-
- werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs);
- if (!W_ERROR_IS_OK(werr)) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = ldb_build_search_req(&search_req, ldb, req,
- req->op.del.dn, LDB_SCOPE_BASE,
- "(objectClass=*)", attrs,
- NULL,
- ac, la_op_search_callback,
- req);
-
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- talloc_steal(search_req, attrs);
-
- return ldb_next_request(module, search_req);
-}
-
-/* delete, rename */
-static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
-{
- struct la_context *ac;
-
- /* This gets complex: We need to:
- - Do a search for the entry
- - Wait for these result to appear
- - In the callback for the result, issue a modify
- request based on the linked attributes found
- - Wait for each modify result
- - Regain our sainity
- */
-
- ac = linked_attributes_init(module, req);
- if (!ac) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (!ac->schema) {
- /* without schema, this doesn't make any sense */
- return ldb_next_request(module, req);
+ unsigned int i;
+ TALLOC_CTX *tmp_ctx = talloc_new(module);
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ const struct dsdb_attribute *target;
+ const char *attrs[2];
+
+ target = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
+ if (target == NULL) {
+ /* there is no counterpart link to change */
+ return LDB_SUCCESS;
}
- /* start with the original request */
- return la_down_req(ac);
-}
-
+ attrs[0] = target->lDAPDisplayName;
+ attrs[1] = NULL;
-static int la_op_search_callback(struct ldb_request *req,
- struct ldb_reply *ares)
-{
- struct ldb_context *ldb;
- struct la_context *ac;
- const struct dsdb_attribute *schema_attr;
- const struct dsdb_attribute *target_attr;
- const struct ldb_message_element *el;
- const char *attr_name;
- int i, j;
- int ret;
-
- ac = talloc_get_type(req->context, struct la_context);
- ldb = ldb_module_get_ctx(ac->module);
-
- if (!ares) {
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->error != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
- }
-
- /* Only entries are interesting, and we only want the olddn */
- switch (ares->type) {
- case LDB_REPLY_ENTRY:
- ret = ldb_dn_compare(ares->message->dn, req->op.search.base);
- if (ret != 0) {
- /* Guh? We only asked for this DN */
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
+ for (i=0; i<el->num_values; i++) {
+ struct dsdb_dn *dsdb_dn;
+ unsigned int j;
+ int ret;
+ struct ldb_result *res;
+ struct ldb_message *msg;
+ struct ldb_message_element *el2;
+
+ dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], schema_attr->syntax->ldap_oid);
+ if (dsdb_dn == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_INVALID_DN_SYNTAX;
}
- if (ares->message->num_elements == 0) {
- /* only bother at all if there were some
- * linked attributes found */
- talloc_free(ares);
- return LDB_SUCCESS;
+
+ ret = dsdb_module_search_dn(module, tmp_ctx, &res, dsdb_dn->dn,
+ attrs,
+ DSDB_SEARCH_SHOW_DELETED |
+ DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
+ DSDB_SEARCH_REVEAL_INTERNALS);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - remote not found - %s",
+ el->name, target->lDAPDisplayName,
+ ldb_dn_get_linearized(old_dn),
+ ldb_dn_get_linearized(dsdb_dn->dn),
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
}
+ msg = res->msgs[0];
- switch (ac->req->operation) {
- case LDB_DELETE:
- ac->del_dn = talloc_steal(ac, ares->message->dn);
- break;
- case LDB_RENAME:
- ac->add_dn = talloc_steal(ac, ares->message->dn);
- ac->del_dn = talloc_steal(ac, ac->req->op.rename.olddn);
- break;
- default:
- talloc_free(ares);
- ldb_set_errstring(ldb,
- "operations must be delete or rename");
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
+ if (msg->num_elements != 1 ||
+ ldb_attr_cmp(msg->elements[0].name, target->lDAPDisplayName) != 0) {
+ ldb_set_errstring(ldb, "Bad msg elements in linked_attributes_fix_links");
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
}
+ el2 = &msg->elements[0];
- for (i = 0; i < ares->message->num_elements; i++) {
- el = &ares->message->elements[i];
+ el2->flags = LDB_FLAG_MOD_REPLACE;
- schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
- if (!schema_attr) {
- ldb_asprintf_errstring(ldb,
- "attribute %s is not a valid attribute"
- " in schema", el->name);
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OBJECT_CLASS_VIOLATION);
+ /* find our DN in the values */
+ for (j=0; j<el2->num_values; j++) {
+ struct dsdb_dn *dsdb_dn2;
+ dsdb_dn2 = dsdb_dn_parse(msg, ldb, &el2->values[j], target->syntax->ldap_oid);
+ if (dsdb_dn2 == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_INVALID_DN_SYNTAX;
}
-
- /* Valid attribute, now find out if it is linked */
- if (schema_attr->linkID == 0) {
- /* Not a linked attribute, skip */
+ if (ldb_dn_compare(old_dn, dsdb_dn2->dn) != 0) {
continue;
}
-
- if ((schema_attr->linkID & 1) == 0) {
- /* Odd is for the target. */
- target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
- if (!target_attr) {
- continue;
- }
- attr_name = target_attr->lDAPDisplayName;
- } else {
- target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID - 1);
- if (!target_attr) {
- continue;
- }
- attr_name = target_attr->lDAPDisplayName;
+ ret = ldb_dn_update_components(dsdb_dn2->dn, new_dn);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
}
- for (j = 0; j < el->num_values; j++) {
- ret = la_store_op(ac, LA_OP_DEL,
- &el->values[j],
- attr_name);
- /* for renames, ensure we add it back */
- if (ret == LDB_SUCCESS
- && ac->req->operation == LDB_RENAME) {
- ret = la_store_op(ac, LA_OP_ADD,
- &el->values[j],
- attr_name);
- }
- if (ret != LDB_SUCCESS) {
- talloc_free(ares);
- return ldb_module_done(ac->req,
- NULL, NULL, ret);
- }
- }
+ el2->values[j] = data_blob_string_const(
+ dsdb_dn_get_extended_linearized(el2->values, dsdb_dn2, 1));
}
- break;
+ ret = dsdb_check_single_valued_link(target, el2);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
- case LDB_REPLY_REFERRAL:
- /* ignore */
- break;
+ ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s",
+ el->name, target->lDAPDisplayName,
+ ldb_dn_get_linearized(old_dn),
+ ldb_dn_get_linearized(dsdb_dn->dn),
+ ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
- case LDB_REPLY_DONE:
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+}
- talloc_free(ares);
+/* rename */
+static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_result *res;
+ struct ldb_message *msg;
+ unsigned int i;
+ int ret;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct dsdb_schema *schema;
+ /*
+ - load the current msg
+ - find any linked attributes
+ - if its a link then find the target object
+ - modify the target linked attributes with the new DN
+ */
+ ret = dsdb_module_search_dn(module, req, &res, req->op.rename.olddn,
+ NULL, DSDB_SEARCH_SHOW_DELETED);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
- switch (ac->req->operation) {
- case LDB_DELETE:
- /* start the mod requests chain */
- ret = la_down_req(ac);
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req, NULL, NULL, ret);
- }
- return ret;
+ schema = dsdb_get_schema(ldb, res);
+ if (!schema) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- case LDB_RENAME:
- /* start the mod requests chain */
- ret = la_queue_mod_request(ac);
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req, NULL, NULL,
- ret);
- }
+ msg = res->msgs[0];
+
+ for (i=0; i<msg->num_elements; i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ const struct dsdb_attribute *schema_attr
+ = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
+ if (!schema_attr || schema_attr->linkID == 0) {
+ continue;
+ }
+ ret = linked_attributes_fix_links(module, msg->dn, req->op.rename.newdn, el,
+ schema, schema_attr);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
return ret;
-
- default:
- talloc_free(ares);
- ldb_set_errstring(ldb,
- "operations must be delete or rename");
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
}
}
- talloc_free(ares);
- return LDB_SUCCESS;
+ talloc_free(res);
+
+ return ldb_next_request(module, req);
}
+
/* queue a linked attributes modify request in the la_private
structure */
static int la_queue_mod_request(struct la_context *ac)
}
-/* Having done the original rename try to fix up all the linked attributes */
-static int la_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
- int ret;
- struct la_context *ac;
- struct ldb_request *search_req;
- const char **attrs;
- WERROR werr;
- struct ldb_context *ldb;
-
- ac = talloc_get_type(req->context, struct la_context);
- ldb = ldb_module_get_ctx(ac->module);
-
- if (!ares) {
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->error != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
- }
-
- if (ares->type != LDB_REPLY_DONE) {
- ldb_set_errstring(ldb,
- "invalid ldb_reply_type in callback");
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
-
- werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs);
- if (!W_ERROR_IS_OK(werr)) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = ldb_build_search_req(&search_req, ldb, req,
- ac->req->op.rename.newdn, LDB_SCOPE_BASE,
- "(objectClass=*)", attrs,
- NULL,
- ac, la_op_search_callback,
- req);
-
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- talloc_steal(search_req, attrs);
-
- if (ret == LDB_SUCCESS) {
- ret = ldb_request_add_control(search_req,
- LDB_CONTROL_EXTENDED_DN_OID,
- false, NULL);
- }
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req, NULL, NULL,
- ret);
- }
-
- ac->op_controls = talloc_steal(ac, ares->controls);
- ac->op_response = talloc_steal(ac, ares->response);
-
- return ldb_next_request(ac->module, search_req);
-}
-
/* Having done the original add, then try to fix up all the linked attributes
This is done after the add so the links can get the extended DNs correctly.
ac, la_mod_del_callback,
ac->req);
break;
- case LDB_DELETE:
- ret = ldb_build_del_req(&down_req, ldb, ac,
- ac->req->op.del.dn,
- ac->req->controls,
- ac, la_mod_del_callback,
- ac->req);
- break;
- case LDB_RENAME:
- ret = ldb_build_rename_req(&down_req, ldb, ac,
- ac->req->op.rename.olddn,
- ac->req->op.rename.newdn,
- ac->req->controls,
- ac, la_rename_callback,
- ac->req);
- break;
default:
ret = LDB_ERR_OPERATIONS_ERROR;
}
use the GUID part of an extended DN to find the target DN, in case
it has moved
*/
-static int la_find_dn_target(struct ldb_module *module, struct la_context *ac, struct ldb_dn **dn)
+static int la_find_dn_target(struct ldb_module *module, struct la_context *ac,
+ struct GUID *guid, struct ldb_dn **dn)
{
- const struct ldb_val *guid;
- struct ldb_context *ldb;
- int ret;
- struct ldb_result *res;
- const char *attrs[] = { NULL };
- struct ldb_request *search_req;
- char *expression;
- struct ldb_search_options_control *options;
-
- ldb = ldb_module_get_ctx(ac->module);
-
- guid = ldb_dn_get_extended_component(*dn, "GUID");
- if (guid == NULL) {
- return LDB_SUCCESS;
- }
-
- expression = talloc_asprintf(ac, "objectGUID=%s", ldb_binary_encode(ac, *guid));
- if (!expression) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- res = talloc_zero(ac, struct ldb_result);
- if (!res) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = ldb_build_search_req(&search_req, ldb, ac,
- ldb_get_default_basedn(ldb),
- LDB_SCOPE_SUBTREE,
- expression, attrs,
- NULL,
- res, ldb_search_default_callback,
- NULL);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- /* we need to cope with cross-partition links, so search for
- the GUID over all partitions */
- options = talloc(search_req, struct ldb_search_options_control);
- if (options == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
-
- ret = ldb_request_add_control(search_req,
- LDB_CONTROL_SEARCH_OPTIONS_OID,
- true, options);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- ret = ldb_next_request(module, search_req);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
- if (ret != LDB_SUCCESS) {
- ldb_debug(ldb, LDB_DEBUG_ERROR, "GUID search failed (%s) for %s\n",
- ldb_errstring(ldb), ldb_dn_get_extended_linearized(ac, *dn, 1));
- return ret;
- }
-
- /* this really should be exactly 1, but there is a bug in the
- partitions module that can return two here with the
- search_options control set */
- if (res->count < 1) {
- ldb_debug(ldb, LDB_DEBUG_ERROR, "GUID search gave count=%d for %s\n",
- res->count, ldb_dn_get_extended_linearized(ac, *dn, 1));
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *dn = res->msgs[0]->dn;
-
- return LDB_SUCCESS;
+ return dsdb_find_dn_by_guid(ldb_module_get_ctx(ac->module), ac, guid, dn);
}
/* apply one la_context op change */
return LDB_ERR_OPERATIONS_ERROR;
}
- new_msg->dn = op->dn;
- ret = la_find_dn_target(module, ac, &new_msg->dn);
+ ret = la_find_dn_target(module, ac, &op->guid, &new_msg->dn);
if (ret != LDB_SUCCESS) {
return ret;
}
for (op = ac->ops; op; op=op->next) {
int ret = la_do_op_request(module, ac, op);
if (ret != LDB_SUCCESS) {
- return ret;
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ return ret;
+ }
}
}
}
la_private->la_list = NULL;
ldb_module_set_private(module, la_private);
- return LDB_SUCCESS;
+ return ldb_next_start_trans(module);
}
/*
- on end transaction we loop over our queued la_context structures and
- apply each of them
+ on prepare commit we loop over our queued la_context structures
+ and apply each of them
*/
-static int linked_attributes_end_transaction(struct ldb_module *module)
+static int linked_attributes_prepare_commit(struct ldb_module *module)
{
struct la_private *la_private =
talloc_get_type(ldb_module_get_private(module), struct la_private);
struct la_context *ac;
+ if (!la_private) {
+ /* prepare commit without begin_transaction - let someone else return the error, just don't segfault */
+ return ldb_next_prepare_commit(module);
+ }
/* walk the list backwards, to do the first entry first, as we
* added the entries with DLIST_ADD() which puts them at the
* start of the list */
ac->req = NULL;
ret = la_do_mod_request(module, ac);
if (ret != LDB_SUCCESS) {
- ret = la_do_mod_request(module, ac);
+ DEBUG(0,(__location__ ": Failed mod request ret=%d\n", ret));
+ talloc_free(la_private);
+ ldb_module_set_private(module, NULL);
return ret;
}
}
-
- return LDB_SUCCESS;
+
+ talloc_free(la_private);
+ ldb_module_set_private(module, NULL);
+
+ return ldb_next_prepare_commit(module);
}
static int linked_attributes_del_transaction(struct ldb_module *module)
talloc_get_type(ldb_module_get_private(module), struct la_private);
talloc_free(la_private);
ldb_module_set_private(module, NULL);
- return LDB_SUCCESS;
+ return ldb_next_del_trans(module);
}
.name = "linked_attributes",
.add = linked_attributes_add,
.modify = linked_attributes_modify,
- .del = linked_attributes_del,
.rename = linked_attributes_rename,
.start_transaction = linked_attributes_start_transaction,
- .end_transaction = linked_attributes_end_transaction,
+ .prepare_commit = linked_attributes_prepare_commit,
.del_transaction = linked_attributes_del_transaction,
};