ldb_kv: Use ldb_msg_add_steal_value() in msg_add_distinguished_name()
[bbaumbach/samba-autobuild/.git] / lib / ldb / ldb_key_value / ldb_kv_search.c
index aa086a88d9a6ce4e9e951223cd18b95b69014f18..7a6ae5668b002342739888800466bab030d95f23 100644 (file)
 #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);
 }
 
 /*
@@ -132,8 +80,7 @@ int ldb_kv_search_base(struct ldb_module *module,
         * 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) {
@@ -144,10 +91,10 @@ int ldb_kv_search_base(struct ldb_module *module,
        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
@@ -177,6 +124,7 @@ int ldb_kv_search_base(struct ldb_module *module,
 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;
 };
 
@@ -190,22 +138,44 @@ static int ldb_kv_parse_data_unpack(struct ldb_val key,
        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;
+                       }
                }
        }
 
@@ -243,7 +213,8 @@ int ldb_kv_search_key(struct ldb_module *module,
        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));
@@ -623,7 +594,7 @@ static int ldb_kv_search_and_return_base(struct ldb_kv_private *ldb_kv,
        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;
 
@@ -635,7 +606,8 @@ static int ldb_kv_search_and_return_base(struct ldb_kv_private *ldb_kv,
                                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) {
@@ -676,9 +648,9 @@ static int ldb_kv_search_and_return_base(struct ldb_kv_private *ldb_kv,
        }
 
        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