/*
ldb database library
- Copyright (C) Andrew Tridgell 2004
- Copyright (C) Stefan Metzmacher 2004
- Copyright (C) Simo Sorce 2006-2008
-
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2006-2008
+ Copyright (C) Matthias Dieter Wallnöfer 2009
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
* - description: make it possible to use event contexts
* date: Jan 2008
* Author: Simo Sorce
+ *
+ * - description: fix up memory leaks and small bugs
+ * date: Oct 2009
+ * Author: Matthias Dieter Wallnöfer
*/
-#include "ldb_includes.h"
-
#include "ldb_tdb.h"
*/
int ltdb_lock_read(struct ldb_module *module)
{
- struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data;
+ void *data = ldb_module_get_private(module);
+ struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
if (ltdb->in_transaction == 0) {
return tdb_lockall_read(ltdb->tdb);
}
*/
int ltdb_unlock_read(struct ldb_module *module)
{
- struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data;
+ void *data = ldb_module_get_private(module);
+ struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
if (ltdb->in_transaction == 0) {
return tdb_unlockall_read(ltdb->tdb);
}
*/
struct TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn)
{
- struct ldb_context *ldb = module->ldb;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
TDB_DATA key;
char *key_str = NULL;
const char *dn_folded = NULL;
static int ltdb_check_special_dn(struct ldb_module *module,
const struct ldb_message *msg)
{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
int i, j;
if (! ldb_dn_is_special(msg->dn) ||
! ldb_dn_check_special(msg->dn, LTDB_ATTRIBUTES)) {
- return 0;
+ return LDB_SUCCESS;
}
/* we have @ATTRIBUTES, let's check attributes are fine */
/* should we check that we deny multivalued attributes ? */
for (i = 0; i < msg->num_elements; i++) {
+ if (ldb_attr_cmp(msg->elements[i].name, "distinguishedName") == 0) continue;
+
for (j = 0; j < msg->elements[i].num_values; j++) {
if (ltdb_check_at_attributes_values(&msg->elements[i].values[j]) != 0) {
- ldb_set_errstring(module->ldb, "Invalid attribute value in an @ATTRIBUTES entry");
+ ldb_set_errstring(ldb, "Invalid attribute value in an @ATTRIBUTES entry");
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
}
}
}
- return 0;
+ return LDB_SUCCESS;
}
ret = ltdb_reindex(module);
}
+ /* If the modify was to a normal record, or any special except @BASEINFO, update the seq number */
if (ret == LDB_SUCCESS &&
!(ldb_dn_is_special(dn) &&
ldb_dn_check_special(dn, LTDB_BASEINFO)) ) {
ret = ltdb_increase_sequence_number(module);
}
+ /* If the modify was to @OPTIONS, reload the cache */
+ if (ldb_dn_is_special(dn) &&
+ (ldb_dn_check_special(dn, LTDB_OPTIONS)) ) {
+ ret = ltdb_cache_reload(module);
+ }
+
return ret;
}
*/
int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs)
{
- struct ltdb_private *ltdb =
- talloc_get_type(module->private_data, struct ltdb_private);
+ void *data = ldb_module_get_private(module);
+ struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
TDB_DATA tdb_key, tdb_data;
- int ret;
+ int ret = LDB_SUCCESS;
tdb_key = ltdb_key(module, msg->dn);
if (!tdb_key.dptr) {
static int ltdb_add_internal(struct ldb_module *module,
const struct ldb_message *msg)
{
- int ret;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ int ret = LDB_SUCCESS, i;
ret = ltdb_check_special_dn(module, msg);
if (ret != LDB_SUCCESS) {
- return ret;
+ goto done;
}
if (ltdb_cache_load(module) != 0) {
- return LDB_ERR_OPERATIONS_ERROR;
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
}
- ret = ltdb_store(module, msg, TDB_INSERT);
+ for (i=0;i<msg->num_elements;i++) {
+ struct ldb_message_element *el = &msg->elements[i];
+ const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name);
- if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
- ldb_asprintf_errstring(module->ldb,
- "Entry %s already exists",
- ldb_dn_get_linearized(msg->dn));
- return ret;
+ if (el->num_values == 0) {
+ ldb_asprintf_errstring(ldb, "attribute %s on %s specified, but with 0 values (illegal)",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ ret = LDB_ERR_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+ if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
+ if (el->num_values > 1) {
+ ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ ret = LDB_ERR_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+ }
}
- if (ret == LDB_SUCCESS) {
- ret = ltdb_index_one(module, msg, 1);
- if (ret != LDB_SUCCESS) {
- return ret;
+ ret = ltdb_store(module, msg, TDB_INSERT);
+ if (ret != LDB_SUCCESS) {
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ ldb_asprintf_errstring(ldb,
+ "Entry %s already exists",
+ ldb_dn_get_linearized(msg->dn));
}
+ goto done;
+ }
- ret = ltdb_modified(module, msg->dn);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ ret = ltdb_index_one(module, msg, 1);
+ if (ret != LDB_SUCCESS) {
+ goto done;
}
+ ret = ltdb_modified(module, msg->dn);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
+done:
return ret;
}
{
struct ldb_module *module = ctx->module;
struct ldb_request *req = ctx->req;
- int tret;
+ int ret = LDB_SUCCESS;
- req->handle->state = LDB_ASYNC_PENDING;
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
- tret = ltdb_add_internal(module, req->op.add.message);
- if (tret != LDB_SUCCESS) {
- return tret;
+ if (ltdb_cache_load(module) != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- return LDB_SUCCESS;
+ ret = ltdb_add_internal(module, req->op.add.message);
+
+ return ret;
}
/*
*/
int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn)
{
- struct ltdb_private *ltdb =
- talloc_get_type(module->private_data, struct ltdb_private);
+ void *data = ldb_module_get_private(module);
+ struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
TDB_DATA tdb_key;
int ret;
static int ltdb_delete_internal(struct ldb_module *module, struct ldb_dn *dn)
{
struct ldb_message *msg;
- int ret;
+ int ret = LDB_SUCCESS;
msg = talloc(module, struct ldb_message);
if (msg == NULL) {
{
struct ldb_module *module = ctx->module;
struct ldb_request *req = ctx->req;
- int tret;
+ int ret = LDB_SUCCESS;
- req->handle->state = LDB_ASYNC_PENDING;
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
if (ltdb_cache_load(module) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
- tret = ltdb_delete_internal(module, req->op.del.dn);
- if (tret != LDB_SUCCESS) {
- return tret;
- }
+ ret = ltdb_delete_internal(module, req->op.del.dn);
- return LDB_SUCCESS;
+ return ret;
}
/*
struct ldb_message_element *e2;
unsigned int i;
+ if (el->num_values == 0) {
+ /* nothing to do here - we don't add empty elements */
+ return 0;
+ }
+
e2 = talloc_realloc(msg, msg->elements, struct ldb_message_element,
msg->num_elements+1);
if (!e2) {
e2->name = el->name;
e2->flags = el->flags;
- e2->values = NULL;
- if (el->num_values != 0) {
- e2->values = talloc_array(msg->elements,
- struct ldb_val, el->num_values);
- if (!e2->values) {
- errno = ENOMEM;
- return -1;
- }
+ e2->values = talloc_array(msg->elements,
+ struct ldb_val, el->num_values);
+ if (!e2->values) {
+ errno = ENOMEM;
+ return -1;
}
for (i=0;i<el->num_values;i++) {
e2->values[i] = el->values[i];
}
e2->num_values = el->num_values;
- msg->num_elements++;
+ ++msg->num_elements;
return 0;
}
msg->num_elements--;
i--;
msg->elements = talloc_realloc(msg, msg->elements,
- struct ldb_message_element,
- msg->num_elements);
+ struct ldb_message_element,
+ msg->num_elements);
+
+ /* per definition we find in a canonicalised message an
+ attribute only once. So we are finished here. */
+ return 0;
}
}
- return 0;
+ /* Not found */
+ return -1;
}
/*
const char *name,
const struct ldb_val *val)
{
- struct ldb_context *ldb = module->ldb;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
unsigned int i;
int found;
struct ldb_message_element *el;
return msg_delete_attribute(module, ldb,
msg, name);
}
+
+ /* per definition we find in a canonicalised message an
+ attribute value only once. So we are finished here */
return 0;
}
}
+ /* Not found */
return -1;
}
int ltdb_modify_internal(struct ldb_module *module,
const struct ldb_message *msg)
{
- struct ldb_context *ldb = module->ldb;
- struct ltdb_private *ltdb =
- talloc_get_type(module->private_data, struct ltdb_private);
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ void *data = ldb_module_get_private(module);
+ struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
TDB_DATA tdb_key, tdb_data;
struct ldb_message *msg2;
unsigned i, j;
- int ret, idx;
+ int ret = LDB_SUCCESS, idx;
tdb_key = ltdb_key(module, msg->dn);
if (!tdb_key.dptr) {
msg2 = talloc(tdb_key.dptr, struct ldb_message);
if (msg2 == NULL) {
- talloc_free(tdb_key.dptr);
- return LDB_ERR_OTHER;
+ free(tdb_data.dptr);
+ ret = LDB_ERR_OTHER;
+ goto done;
}
ret = ltdb_unpack_data(module, &tdb_data, msg2);
+ free(tdb_data.dptr);
if (ret == -1) {
ret = LDB_ERR_OTHER;
- goto failed;
+ goto done;
}
if (!msg2->dn) {
msg2->dn = msg->dn;
}
- for (i=0;i<msg->num_elements;i++) {
- struct ldb_message_element *el = &msg->elements[i];
- struct ldb_message_element *el2;
+ for (i=0; i<msg->num_elements; i++) {
+ struct ldb_message_element *el = &msg->elements[i], *el2;
struct ldb_val *vals;
+ const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name);
const char *dn;
- switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
+ if (ldb_attr_cmp(el->name, "distinguishedName") == 0) {
+ ldb_asprintf_errstring(ldb, "it is not permitted to perform a modify on 'distinguishedName' (use rename instead): %s",
+ ldb_dn_get_linearized(msg->dn));
+ ret = LDB_ERR_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+ switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
case LDB_FLAG_MOD_ADD:
- /* add this element to the message. fail if it
- already exists */
- idx = find_element(msg2, el->name);
+ if (el->num_values == 0) {
+ ldb_asprintf_errstring(ldb, "attribute %s on %s specified, but with 0 values (illigal)",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ ret = LDB_ERR_CONSTRAINT_VIOLATION;
+ goto done;
+ }
+ if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
+ if (el->num_values > 1) {
+ ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ goto done;
+ }
+ }
+
+ /* Checks if element already exists */
+ idx = find_element(msg2, el->name);
if (idx == -1) {
if (msg_add_element(ldb, msg2, el) != 0) {
ret = LDB_ERR_OTHER;
- goto failed;
+ goto done;
}
- continue;
- }
-
- el2 = &msg2->elements[idx];
-
- /* An attribute with this name already exists,
- * add all values if they don't already exist
- * (check both the other elements to be added,
- * and those already in the db). */
-
- for (j=0;j<el->num_values;j++) {
- if (ldb_msg_find_val(el2, &el->values[j])) {
- ldb_asprintf_errstring(module->ldb, "%s: value #%d already exists", el->name, j);
+ } else {
+ /* We cannot add another value on a existing one
+ if the attribute is single-valued */
+ if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
+ ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
+ el->name, ldb_dn_get_linearized(msg->dn));
ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
- goto failed;
+ goto done;
}
- if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {
- ldb_asprintf_errstring(module->ldb, "%s: value #%d provided more than once", el->name, j);
- ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
- goto failed;
+
+ el2 = &(msg2->elements[idx]);
+
+ /* Check that values don't exist yet on multi-
+ valued attributes or aren't provided twice */
+ for (j=0; j<el->num_values; j++) {
+ if (ldb_msg_find_val(el2, &el->values[j]) != NULL) {
+ ldb_asprintf_errstring(ldb, "%s: value #%d already exists", el->name, j);
+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ goto done;
+ }
+ if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {
+ ldb_asprintf_errstring(ldb, "%s: value #%d provided more than once", el->name, j);
+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ goto done;
+ }
}
- }
- vals = talloc_realloc(msg2->elements, el2->values, struct ldb_val,
- el2->num_values + el->num_values);
+ /* Now combine existing and new values to a new
+ attribute record */
+ vals = talloc_realloc(msg2->elements,
+ el2->values, struct ldb_val,
+ el2->num_values + el->num_values);
+ if (vals == NULL) {
+ ldb_oom(ldb);
+ ret = LDB_ERR_OTHER;
+ goto done;
+ }
- if (vals == NULL) {
- ret = LDB_ERR_OTHER;
- goto failed;
- }
+ for (j=0; j<el->num_values; j++) {
+ vals[el2->num_values + j] =
+ ldb_val_dup(vals, &el->values[j]);
+ }
- for (j=0;j<el->num_values;j++) {
- vals[el2->num_values + j] =
- ldb_val_dup(vals, &el->values[j]);
+ el2->values = vals;
+ el2->num_values += el->num_values;
}
- el2->values = vals;
- el2->num_values += el->num_values;
-
break;
case LDB_FLAG_MOD_REPLACE:
- /* replace all elements of this attribute name with the elements
- listed. The attribute not existing is not an error */
- msg_delete_attribute(module, ldb, msg2, el->name);
+ if (a && a->flags & LDB_ATTR_FLAG_SINGLE_VALUE) {
+ if (el->num_values > 1) {
+ ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
+ el->name, ldb_dn_get_linearized(msg->dn));
+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ goto done;
+ }
+ }
- for (j=0;j<el->num_values;j++) {
+ for (j=0; j<el->num_values; j++) {
if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {
- ldb_asprintf_errstring(module->ldb, "%s: value #%d provided more than once", el->name, j);
+ ldb_asprintf_errstring(ldb, "%s: value #%d provided more than once", el->name, j);
ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
- goto failed;
+ goto done;
}
}
- /* add the replacement element, if not empty */
- if (el->num_values != 0 &&
- msg_add_element(ldb, msg2, el) != 0) {
+ /* Delete the attribute if it exists in the DB */
+ msg_delete_attribute(module, ldb, msg2, el->name);
+
+ /* Recreate it with the new values */
+ if (msg_add_element(ldb, msg2, el) != 0) {
ret = LDB_ERR_OTHER;
- goto failed;
+ goto done;
}
+
break;
case LDB_FLAG_MOD_DELETE:
-
dn = ldb_dn_get_linearized(msg->dn);
if (dn == NULL) {
ret = LDB_ERR_OTHER;
- goto failed;
+ goto done;
}
- /* we could be being asked to delete all
- values or just some values */
if (msg->elements[i].num_values == 0) {
- if (msg_delete_attribute(module, ldb, msg2,
+ /* Delete the whole attribute */
+ if (msg_delete_attribute(module, ldb, msg2,
msg->elements[i].name) != 0) {
- ldb_asprintf_errstring(module->ldb, "No such attribute: %s for delete on %s", msg->elements[i].name, dn);
+ ldb_asprintf_errstring(ldb, "No such attribute: %s for delete on %s",
+ msg->elements[i].name, dn);
ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
- goto failed;
+ goto done;
}
- break;
- }
- for (j=0;j<msg->elements[i].num_values;j++) {
- if (msg_delete_element(module,
- msg2,
- msg->elements[i].name,
- &msg->elements[i].values[j]) != 0) {
- ldb_asprintf_errstring(module->ldb, "No matching attribute value when deleting attribute: %s on %s", msg->elements[i].name, dn);
- ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
- goto failed;
- }
- ret = ltdb_index_del_value(module, dn, &msg->elements[i], j);
- if (ret != LDB_SUCCESS) {
- goto failed;
+ } else {
+ /* Delete specified values from an attribute */
+ for (j=0; j < msg->elements[i].num_values; j++) {
+ if (msg_delete_element(module,
+ msg2,
+ msg->elements[i].name,
+ &msg->elements[i].values[j]) != 0) {
+ ldb_asprintf_errstring(ldb, "No matching attribute value when deleting attribute: %s on %s",
+ msg->elements[i].name, dn);
+ ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
+ goto done;
+ }
+
+ ret = ltdb_index_del_value(module, dn,
+ &msg->elements[i], j);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
}
}
+
break;
default:
- ldb_asprintf_errstring(module->ldb,
+ ldb_asprintf_errstring(ldb,
"Invalid ldb_modify flags on %s: 0x%x",
msg->elements[i].name,
msg->elements[i].flags & LDB_FLAG_MOD_MASK);
ret = LDB_ERR_PROTOCOL_ERROR;
- goto failed;
+ goto done;
}
}
- /* we've made all the mods
- * save the modified record back into the database */
ret = ltdb_store(module, msg2, TDB_MODIFY);
if (ret != LDB_SUCCESS) {
- goto failed;
+ goto done;
}
ret = ltdb_modified(module, msg->dn);
if (ret != LDB_SUCCESS) {
- goto failed;
+ goto done;
}
+done:
talloc_free(tdb_key.dptr);
- free(tdb_data.dptr);
- return ret;
-
-failed:
- talloc_free(tdb_key.dptr);
- free(tdb_data.dptr);
return ret;
}
{
struct ldb_module *module = ctx->module;
struct ldb_request *req = ctx->req;
- int tret;
-
- req->handle->state = LDB_ASYNC_PENDING;
+ int ret = LDB_SUCCESS;
- tret = ltdb_check_special_dn(module, req->op.mod.message);
- if (tret != LDB_SUCCESS) {
- return tret;
+ ret = ltdb_check_special_dn(module, req->op.mod.message);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
+
if (ltdb_cache_load(module) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
- tret = ltdb_modify_internal(module, req->op.mod.message);
- if (tret != LDB_SUCCESS) {
- return tret;
- }
+ ret = ltdb_modify_internal(module, req->op.mod.message);
- return LDB_SUCCESS;
+ return ret;
}
/*
struct ldb_module *module = ctx->module;
struct ldb_request *req = ctx->req;
struct ldb_message *msg;
- int tret;
+ int ret = LDB_SUCCESS;
- req->handle->state = LDB_ASYNC_PENDING;
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
if (ltdb_cache_load(ctx->module) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
msg = talloc(ctx, struct ldb_message);
if (msg == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
}
/* in case any attribute of the message was indexed, we need
to fetch the old record */
- tret = ltdb_search_dn1(module, req->op.rename.olddn, msg);
- if (tret != LDB_SUCCESS) {
+ ret = ltdb_search_dn1(module, req->op.rename.olddn, msg);
+ if (ret != LDB_SUCCESS) {
/* not finding the old record is an error */
- return tret;
+ goto done;
}
msg->dn = ldb_dn_copy(msg, req->op.rename.newdn);
- if (!msg->dn) {
- return LDB_ERR_OPERATIONS_ERROR;
+ if (msg->dn == NULL) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
}
- if (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) == 0) {
- /* The rename operation is apparently only changing case -
- the DNs are the same. Delete the old DN before adding
- the new one to avoid a TDB_ERR_EXISTS error.
+ /* Always delete first then add, to avoid conflicts with
+ * unique indexes. We rely on the transaction to make this
+ * atomic
+ */
+ ret = ltdb_delete_internal(module, req->op.rename.olddn);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
- The only drawback to this is that if the delete
- succeeds but the add fails, we rely on the
- transaction to roll this all back. */
- tret = ltdb_delete_internal(module, req->op.rename.olddn);
- if (tret != LDB_SUCCESS) {
- return tret;
- }
+ ret = ltdb_add_internal(module, msg);
- tret = ltdb_add_internal(module, msg);
- if (tret != LDB_SUCCESS) {
- return tret;
- }
- } else {
- /* The rename operation is changing DNs. Try to add the new
- DN first to avoid clobbering another DN not related to
- this rename operation. */
- tret = ltdb_add_internal(module, msg);
- if (tret != LDB_SUCCESS) {
- return tret;
- }
+done:
+ return ret;
+}
- tret = ltdb_delete_internal(module, req->op.rename.olddn);
- if (tret != LDB_SUCCESS) {
- ltdb_delete_internal(module, req->op.rename.newdn);
- return LDB_ERR_OPERATIONS_ERROR;
- }
+static int ltdb_start_trans(struct ldb_module *module)
+{
+ void *data = ldb_module_get_private(module);
+ struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
+
+ if (tdb_transaction_start(ltdb->tdb) != 0) {
+ return ltdb_err_map(tdb_error(ltdb->tdb));
}
+ ltdb->in_transaction++;
+
+ ltdb_index_transaction_start(module);
+
return LDB_SUCCESS;
}
-static int ltdb_start_trans(struct ldb_module *module)
+static int ltdb_prepare_commit(struct ldb_module *module)
{
- struct ltdb_private *ltdb =
- talloc_get_type(module->private_data, struct ltdb_private);
+ void *data = ldb_module_get_private(module);
+ struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
- if (tdb_transaction_start(ltdb->tdb) != 0) {
+ if (ltdb->in_transaction != 1) {
+ return LDB_SUCCESS;
+ }
+
+ if (ltdb_index_transaction_commit(module) != 0) {
+ tdb_transaction_cancel(ltdb->tdb);
+ ltdb->in_transaction--;
return ltdb_err_map(tdb_error(ltdb->tdb));
}
- ltdb->in_transaction++;
+ if (tdb_transaction_prepare_commit(ltdb->tdb) != 0) {
+ ltdb->in_transaction--;
+ return ltdb_err_map(tdb_error(ltdb->tdb));
+ }
+
+ ltdb->prepared_commit = true;
return LDB_SUCCESS;
}
static int ltdb_end_trans(struct ldb_module *module)
{
- struct ltdb_private *ltdb =
- talloc_get_type(module->private_data, struct ltdb_private);
+ void *data = ldb_module_get_private(module);
+ struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
+
+ if (!ltdb->prepared_commit) {
+ int ret = ltdb_prepare_commit(module);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
ltdb->in_transaction--;
+ ltdb->prepared_commit = false;
if (tdb_transaction_commit(ltdb->tdb) != 0) {
return ltdb_err_map(tdb_error(ltdb->tdb));
static int ltdb_del_trans(struct ldb_module *module)
{
- struct ltdb_private *ltdb =
- talloc_get_type(module->private_data, struct ltdb_private);
+ void *data = ldb_module_get_private(module);
+ struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
ltdb->in_transaction--;
+ if (ltdb_index_transaction_cancel(module) != 0) {
+ tdb_transaction_cancel(ltdb->tdb);
+ return ltdb_err_map(tdb_error(ltdb->tdb));
+ }
+
if (tdb_transaction_cancel(ltdb->tdb) != 0) {
return ltdb_err_map(tdb_error(ltdb->tdb));
}
static int ltdb_sequence_number(struct ltdb_context *ctx,
struct ldb_extended **ext)
{
+ struct ldb_context *ldb;
struct ldb_module *module = ctx->module;
struct ldb_request *req = ctx->req;
TALLOC_CTX *tmp_ctx;
struct ldb_message *msg = NULL;
struct ldb_dn *dn;
const char *date;
- int ret;
+ int ret = LDB_SUCCESS;
+
+ ldb = ldb_module_get_ctx(module);
seq = talloc_get_type(req->op.extended.data,
struct ldb_seqnum_request);
return LDB_ERR_OPERATIONS_ERROR;
}
- req->handle->state = LDB_ASYNC_PENDING;
+ ldb_request_set_state(req, LDB_ASYNC_PENDING);
if (ltdb_lock_read(module) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
goto done;
}
- dn = ldb_dn_new(tmp_ctx, module->ldb, LTDB_BASEINFO);
+ dn = ldb_dn_new(tmp_ctx, ldb, LTDB_BASEINFO);
msg = talloc(tmp_ctx, struct ldb_message);
if (msg == NULL) {
(*ext)->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
(*ext)->data = talloc_steal(*ext, res);
- ret = LDB_SUCCESS;
-
done:
talloc_free(tmp_ctx);
ltdb_unlock_read(module);
return ret;
}
-static void ltdb_request_done(struct ldb_request *req, int error)
+static void ltdb_request_done(struct ltdb_context *ctx, int error)
{
+ struct ldb_context *ldb;
+ struct ldb_request *req;
struct ldb_reply *ares;
+ ldb = ldb_module_get_ctx(ctx->module);
+ req = ctx->req;
+
/* if we already returned an error just return */
- if (req->handle->status != LDB_SUCCESS) {
+ if (ldb_request_get_status(req) != LDB_SUCCESS) {
return;
}
ares = talloc_zero(req, struct ldb_reply);
if (!ares) {
- ldb_oom(req->handle->ldb);
+ ldb_oom(ldb);
req->callback(req, NULL);
return;
}
req->callback(req, ares);
}
-static void ltdb_timeout(struct event_context *ev,
- struct timed_event *te,
+static void ltdb_timeout(struct tevent_context *ev,
+ struct tevent_timer *te,
struct timeval t,
void *private_data)
{
struct ltdb_context *ctx;
ctx = talloc_get_type(private_data, struct ltdb_context);
- ltdb_request_done(ctx->req, LDB_ERR_TIME_LIMIT_EXCEEDED);
+ if (!ctx->request_terminated) {
+ /* request is done now */
+ ltdb_request_done(ctx, LDB_ERR_TIME_LIMIT_EXCEEDED);
+ }
+
+ if (!ctx->request_terminated) {
+ /* neutralize the spy */
+ ctx->spy->ctx = NULL;
+ }
+ talloc_free(ctx);
}
-static void ltdb_request_extended_done(struct ldb_request *req,
+static void ltdb_request_extended_done(struct ltdb_context *ctx,
struct ldb_extended *ext,
int error)
{
+ struct ldb_context *ldb;
+ struct ldb_request *req;
struct ldb_reply *ares;
+ ldb = ldb_module_get_ctx(ctx->module);
+ req = ctx->req;
+
/* if we already returned an error just return */
- if (req->handle->status != LDB_SUCCESS) {
+ if (ldb_request_get_status(req) != LDB_SUCCESS) {
return;
}
ares = talloc_zero(req, struct ldb_reply);
if (!ares) {
- ldb_oom(req->handle->ldb);
+ ldb_oom(ldb);
req->callback(req, NULL);
return;
}
ret = LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
}
- ltdb_request_extended_done(ctx->req, ext, ret);
+ ltdb_request_extended_done(ctx, ext, ret);
}
-static void ltdb_callback(struct event_context *ev,
- struct timed_event *te,
+static void ltdb_callback(struct tevent_context *ev,
+ struct tevent_timer *te,
struct timeval t,
void *private_data)
{
ctx = talloc_get_type(private_data, struct ltdb_context);
+ if (ctx->request_terminated) {
+ goto done;
+ }
+
switch (ctx->req->operation) {
case LDB_SEARCH:
ret = ltdb_search(ctx);
break;
case LDB_EXTENDED:
ltdb_handle_extended(ctx);
- return;
+ goto done;
default:
/* no other op supported */
ret = LDB_ERR_UNWILLING_TO_PERFORM;
}
- if (!ctx->callback_failed) {
- ltdb_request_done(ctx->req, ret);
+ if (!ctx->request_terminated) {
+ /* request is done now */
+ ltdb_request_done(ctx, ret);
+ }
+
+done:
+ if (!ctx->request_terminated) {
+ /* neutralize the spy */
+ ctx->spy->ctx = NULL;
+ }
+ talloc_free(ctx);
+}
+
+static int ltdb_request_destructor(void *ptr)
+{
+ struct ltdb_req_spy *spy = talloc_get_type(ptr, struct ltdb_req_spy);
+
+ if (spy->ctx != NULL) {
+ spy->ctx->request_terminated = true;
}
+
+ return 0;
}
static int ltdb_handle_request(struct ldb_module *module,
- struct ldb_request *req)
+ struct ldb_request *req)
{
- struct event_context *ev;
+ struct ldb_context *ldb;
+ struct tevent_context *ev;
struct ltdb_context *ac;
- struct timed_event *te;
+ struct tevent_timer *te;
struct timeval tv;
if (check_critical_controls(req->controls)) {
return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
}
+ ldb = ldb_module_get_ctx(module);
+
if (req->starttime == 0 || req->timeout == 0) {
- ldb_set_errstring(module->ldb, "Invalid timeout settings");
+ ldb_set_errstring(ldb, "Invalid timeout settings");
return LDB_ERR_TIME_LIMIT_EXCEEDED;
}
- ev = ldb_get_event_context(module->ldb);
+ ev = ldb_get_event_context(ldb);
- ac = talloc_zero(req, struct ltdb_context);
+ ac = talloc_zero(ldb, struct ltdb_context);
if (ac == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
+ ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
tv.tv_sec = 0;
tv.tv_usec = 0;
- te = event_add_timed(ev, ac, tv, ltdb_callback, ac);
+ te = tevent_add_timer(ev, ac, tv, ltdb_callback, ac);
if (NULL == te) {
+ talloc_free(ac);
return LDB_ERR_OPERATIONS_ERROR;
}
-
tv.tv_sec = req->starttime + req->timeout;
- te = event_add_timed(ev, ac, tv, ltdb_timeout, ac);
- if (NULL == te) {
+ ac->timeout_event = tevent_add_timer(ev, ac, tv, ltdb_timeout, ac);
+ if (NULL == ac->timeout_event) {
+ talloc_free(ac);
return LDB_ERR_OPERATIONS_ERROR;
}
+ /* set a spy so that we do not try to use the request context
+ * if it is freed before ltdb_callback fires */
+ ac->spy = talloc(req, struct ltdb_req_spy);
+ if (NULL == ac->spy) {
+ talloc_free(ac);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac->spy->ctx = ac;
+
+ talloc_set_destructor((TALLOC_CTX *)ac->spy, ltdb_request_destructor);
+
return LDB_SUCCESS;
}
.extended = ltdb_handle_request,
.start_transaction = ltdb_start_trans,
.end_transaction = ltdb_end_trans,
+ .prepare_commit = ltdb_prepare_commit,
.del_transaction = ltdb_del_trans,
};
*/
static int ltdb_connect(struct ldb_context *ldb, const char *url,
unsigned int flags, const char *options[],
- struct ldb_module **module)
+ struct ldb_module **_module)
{
+ struct ldb_module *module;
const char *path;
int tdb_flags, open_flags;
struct ltdb_private *ltdb;
/* note that we use quite a large default hash size */
ltdb->tdb = ltdb_wrap_open(ltdb, path, 10000,
tdb_flags, open_flags,
- ldb->create_perms, ldb);
+ ldb_get_create_perms(ldb), ldb);
if (!ltdb->tdb) {
ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Unable to open tdb '%s'\n", path);
+ "Unable to open tdb '%s'", path);
talloc_free(ltdb);
return -1;
}
ltdb->sequence_number = 0;
- *module = talloc(ldb, struct ldb_module);
- if ((*module) == NULL) {
- ldb_oom(ldb);
+ module = ldb_module_new(ldb, ldb, "ldb_tdb backend", <db_ops);
+ if (!module) {
talloc_free(ltdb);
return -1;
}
- talloc_set_name_const(*module, "ldb_tdb backend");
- (*module)->ldb = ldb;
- (*module)->prev = (*module)->next = NULL;
- (*module)->private_data = ltdb;
- (*module)->ops = <db_ops;
+ ldb_module_set_private(module, ltdb);
- if (ltdb_cache_load(*module) != 0) {
- talloc_free(*module);
+ if (ltdb_cache_load(module) != 0) {
+ talloc_free(module);
talloc_free(ltdb);
return -1;
}
+ *_module = module;
return 0;
}