#include "ldb_kv.h"
#include "ldb_private.h"
-/*
- add one element to a message
-*/
-static int msg_add_element(struct ldb_message *ret,
- const struct ldb_message_element *el,
- int check_duplicates)
-{
- unsigned int i;
- struct ldb_message_element *e2, *elnew;
-
- if (check_duplicates && ldb_msg_find_element(ret, el->name)) {
- /* its already there */
- return 0;
- }
-
- e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1);
- if (!e2) {
- return -1;
- }
- ret->elements = e2;
-
- elnew = &e2[ret->num_elements];
-
- elnew->name = talloc_strdup(ret->elements, el->name);
- if (!elnew->name) {
- return -1;
- }
-
- if (el->num_values) {
- elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values);
- if (!elnew->values) {
- return -1;
- }
- } else {
- elnew->values = NULL;
- }
-
- for (i=0;i<el->num_values;i++) {
- elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]);
- if (elnew->values[i].length != el->values[i].length) {
- return -1;
- }
- }
-
- elnew->num_values = el->num_values;
- elnew->flags = el->flags;
-
- ret->num_elements++;
-
- return 0;
-}
-
/*
add the special distinguishedName element
*/
static int msg_add_distinguished_name(struct ldb_message *msg)
{
- struct ldb_message_element el;
- struct ldb_val val;
- int ret;
+ const char *dn_attr = "distinguishedName";
+ char *dn = NULL;
- el.flags = 0;
- el.name = "distinguishedName";
- el.num_values = 1;
- el.values = &val;
- el.flags = 0;
- val.data = (uint8_t *)ldb_dn_alloc_linearized(msg, msg->dn);
- if (val.data == NULL) {
- return -1;
+ if (ldb_msg_find_element(msg, dn_attr)) {
+ /*
+ * This should not happen, but this is
+ * existing behaviour...
+ */
+ return LDB_SUCCESS;
}
- val.length = strlen((char *)val.data);
- ret = msg_add_element(msg, &el, 1);
- return ret;
+ dn = ldb_dn_alloc_linearized(msg, msg->dn);
+ if (dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_msg_add_steal_string(msg, dn_attr, dn);
}
/*
* We can't use tdb_exists() directly on a key when the TDB
* key is the GUID one, not the DN based one. So we just do a
* normal search and avoid most of the allocation with the
- * LDB_UNPACK_DATA_FLAG_NO_DN and
- * LDB_UNPACK_DATA_FLAG_NO_ATTRS flags
+ * LDB_UNPACK_DATA_FLAG_NO_ATTRS flag
*/
msg = ldb_msg_new(module);
if (msg == NULL) {
if (ret == LDB_SUCCESS) {
const char *dn_linearized
= ldb_dn_get_linearized(dn);
- const char *msg_dn_linearlized
+ const char *msg_dn_linearized
= ldb_dn_get_linearized(msg->dn);
- if (strcmp(dn_linearized, msg_dn_linearlized) == 0) {
+ if (strcmp(dn_linearized, msg_dn_linearized) == 0) {
/*
* Re-use the full incoming DN for
* subtree checks
struct ldb_kv_parse_data_unpack_ctx {
struct ldb_message *msg;
struct ldb_module *module;
+ struct ldb_kv_private *ldb_kv;
unsigned int unpack_flags;
};
struct ldb_context *ldb = ldb_module_get_ctx(ctx->module);
struct ldb_val data_parse = data;
- if (ctx->unpack_flags & LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC) {
- /*
- * If we got LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC
- * we need at least do a memdup on the whole
- * data buffer as that may change later
- * and the caller needs a stable result.
- */
- data_parse.data = talloc_memdup(ctx->msg,
- data.data,
- data.length);
- if (data_parse.data == NULL) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Unable to allocate data(%d) for %*.*s\n",
- (int)data.length,
- (int)key.length, (int)key.length, key.data);
- return LDB_ERR_OPERATIONS_ERROR;
+ struct ldb_kv_private *ldb_kv = ctx->ldb_kv;
+
+ if ((ctx->unpack_flags & LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC)) {
+ if ((ldb_kv->kv_ops->options & LDB_KV_OPTION_STABLE_READ_LOCK) &&
+ (ctx->unpack_flags & LDB_UNPACK_DATA_FLAG_READ_LOCKED) &&
+ !ldb_kv->kv_ops->transaction_active(ldb_kv)) {
+ /*
+ * In the case where no transactions are active and
+ * we're in a read-lock, we can point directly into
+ * database memory.
+ *
+ * The database can't be changed underneath us and we
+ * will duplicate this data in the call to filter.
+ *
+ * This is seen in:
+ * - ldb_kv_index_filter
+ * - ldb_kv_search_and_return_base
+ */
+ } else {
+ /*
+ * In every other case, if we got
+ * LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC we need at least
+ * do a memdup on the whole data buffer as that may
+ * change later and the caller needs a stable result.
+ *
+ * During transactions, pointers could change and in
+ * TDB, there just aren't the same guarantees.
+ */
+ data_parse.data = talloc_memdup(ctx->msg,
+ data.data,
+ data.length);
+ if (data_parse.data == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Unable to allocate data(%d) for %*.*s\n",
+ (int)data.length,
+ (int)key.length, (int)key.length, key.data);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
}
}
struct ldb_kv_parse_data_unpack_ctx ctx = {
.msg = msg,
.module = module,
- .unpack_flags = unpack_flags
+ .unpack_flags = unpack_flags,
+ .ldb_kv = ldb_kv
};
memset(msg, 0, sizeof(*msg));
struct ldb_message *msg, *filtered_msg;
struct ldb_context *ldb = ldb_module_get_ctx(ctx->module);
const char *dn_linearized;
- const char *msg_dn_linearlized;
+ const char *msg_dn_linearized;
int ret;
bool matched;
ctx->base,
msg,
LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC |
- LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC);
+ LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC |
+ LDB_UNPACK_DATA_FLAG_READ_LOCKED);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
if (ldb_kv->check_base == false) {
}
dn_linearized = ldb_dn_get_linearized(ctx->base);
- msg_dn_linearlized = ldb_dn_get_linearized(msg->dn);
+ msg_dn_linearized = ldb_dn_get_linearized(msg->dn);
- if (strcmp(dn_linearized, msg_dn_linearlized) == 0) {
+ if (strcmp(dn_linearized, msg_dn_linearized) == 0) {
/*
* If the DN is exactly the same string, then
* re-use the full incoming DN for the