r711: don't hide attributes inside the special ldb_tdb records (so the fact
[samba.git] / source4 / lib / ldb / ldb_tdb / ldb_search.c
index 5905231b32218bae1501b13c1a3d2c8333e32ab9..6b38a282961d7773c050c56435d4467c2c53abd9 100644 (file)
  */
 
 #include "includes.h"
-#include "ldb_tdb.h"
+#include "ldb/ldb_tdb/ldb_tdb.h"
 
 /*
   free a message that has all parts separately allocated
 */
-static void msg_free_all_parts(struct ldb_message *msg)
+static void msg_free_all_parts(struct ldb_context *ldb, struct ldb_message *msg)
 {
        int i, j;
-       if (msg->dn) free(msg->dn);
+       ldb_free(ldb, msg->dn);
        for (i=0;i<msg->num_elements;i++) {
-               if (msg->elements[i].name) free(msg->elements[i].name);
+               ldb_free(ldb, msg->elements[i].name);
                for (j=0;j<msg->elements[i].num_values;j++) {
-                       if (msg->elements[i].values[j].data) 
-                               free(msg->elements[i].values[j].data);
+                       ldb_free(ldb, msg->elements[i].values[j].data);
                }
-               if (msg->elements[i].values) free(msg->elements[i].values);
+               ldb_free(ldb, msg->elements[i].values);
        }
-       free(msg->elements);
-       free(msg);
+       ldb_free(ldb, msg->elements);
+       ldb_free(ldb, msg);
 }
 
 
-/*
-  TODO: this should take advantage of the sorted nature of the message
-
-  return index of the attribute, or -1 if not found
-*/
-int ldb_msg_find_attr(const struct ldb_message *msg, const char *attr)
-{
-       int i;
-       for (i=0;i<msg->num_elements;i++) {
-               if (strcmp(msg->elements[i].name, attr) == 0) {
-                       return i;
-               }
-       }
-       return -1;
-}
-
 /*
   duplicate a ldb_val structure
 */
-struct ldb_val ldb_val_dup(const struct ldb_val *v)
+struct ldb_val ldb_val_dup(struct ldb_context *ldb,
+                          const struct ldb_val *v)
 {
        struct ldb_val v2;
        v2.length = v->length;
@@ -85,7 +69,7 @@ struct ldb_val ldb_val_dup(const struct ldb_val *v)
 
        /* the +1 is to cope with buggy C library routines like strndup
           that look one byte beyond */
-       v2.data = malloc(v->length+1);
+       v2.data = ldb_malloc(ldb, v->length+1);
        if (!v2.data) {
                v2.length = 0;
                return v2;
@@ -101,12 +85,13 @@ struct ldb_val ldb_val_dup(const struct ldb_val *v)
 /*
   add one element to a message
 */
-static int msg_add_element(struct ldb_message *ret, const struct ldb_message_element *el)
+static int msg_add_element(struct ldb_context *ldb, 
+                          struct ldb_message *ret, const struct ldb_message_element *el)
 {
        int i;
        struct ldb_message_element *e2, *elnew;
 
-       e2 = realloc_p(ret->elements, struct ldb_message_element, ret->num_elements+1);
+       e2 = ldb_realloc_p(ldb, ret->elements, struct ldb_message_element, ret->num_elements+1);
        if (!e2) {
                return -1;
        }
@@ -114,13 +99,13 @@ static int msg_add_element(struct ldb_message *ret, const struct ldb_message_ele
        
        elnew = &e2[ret->num_elements];
 
-       elnew->name = strdup(el->name);
+       elnew->name = ldb_strdup(ldb, el->name);
        if (!elnew->name) {
                return -1;
        }
 
        if (el->num_values) {
-               elnew->values = malloc_array_p(struct ldb_val, el->num_values);
+               elnew->values = ldb_malloc_array_p(ldb, struct ldb_val, el->num_values);
                if (!elnew->values) {
                        return -1;
                }
@@ -129,7 +114,7 @@ static int msg_add_element(struct ldb_message *ret, const struct ldb_message_ele
        }
 
        for (i=0;i<el->num_values;i++) {
-               elnew->values[i] = ldb_val_dup(&el->values[i]);
+               elnew->values[i] = ldb_val_dup(ldb, &el->values[i]);
                if (elnew->values[i].length != el->values[i].length) {
                        return -1;
                }
@@ -145,12 +130,16 @@ static int msg_add_element(struct ldb_message *ret, const struct ldb_message_ele
 /*
   add all elements from one message into another
  */
-static int msg_add_all_elements(struct ldb_message *ret,
+static int msg_add_all_elements(struct ldb_context *ldb, struct ldb_message *ret,
                                const struct ldb_message *msg)
 {
        int i;
        for (i=0;i<msg->num_elements;i++) {
-               if (msg_add_element(ret, &msg->elements[i]) != 0) {
+               int flags = ltdb_attribute_flags(ldb, msg->elements[i].name);
+               if ((msg->dn[0] != '@') && (flags & LTDB_FLAG_HIDDEN)) {
+                       continue;
+               }
+               if (msg_add_element(ldb, ret, &msg->elements[i]) != 0) {
                        return -1;
                }
        }
@@ -164,55 +153,53 @@ static int msg_add_all_elements(struct ldb_message *ret,
  */
 static struct ldb_message *ltdb_pull_attrs(struct ldb_context *ldb, 
                                           const struct ldb_message *msg, 
-                                          const char **attrs)
+                                          const char * const *attrs)
 {
        struct ldb_message *ret;
        int i;
 
-       ret = malloc_p(struct ldb_message);
+       ret = ldb_malloc_p(ldb, struct ldb_message);
        if (!ret) {
                return NULL;
        }
 
-       ret->dn = strdup(msg->dn);
+       ret->dn = ldb_strdup(ldb, msg->dn);
        if (!ret->dn) {
-               free(ret);
+               ldb_free(ldb, ret);
                return NULL;
        }
 
        ret->num_elements = 0;
        ret->elements = NULL;
-       ret->private = NULL;
+       ret->private_data = NULL;
 
        if (!attrs) {
-               if (msg_add_all_elements(ret, msg) != 0) {
-                       msg_free_all_parts(ret);
+               if (msg_add_all_elements(ldb, ret, msg) != 0) {
+                       msg_free_all_parts(ldb, ret);
                        return NULL;
                }
                return ret;
        }
 
        for (i=0;attrs[i];i++) {
-               int j;
+               struct ldb_message_element *el;
 
                if (strcmp(attrs[i], "*") == 0) {
-                       if (msg_add_all_elements(ret, msg) != 0) {
-                               msg_free_all_parts(ret);
+                       if (msg_add_all_elements(ldb, ret, msg) != 0) {
+                               msg_free_all_parts(ldb, ret);
                                return NULL;
                        }
                        continue;
                }
-               j = ldb_msg_find_attr(msg, attrs[i]);
-               if (j == -1) {
+
+               el = ldb_msg_find_element(msg, attrs[i]);
+               if (!el) {
                        continue;
                }
-               do {
-                       if (msg_add_element(ret, &msg->elements[j]) != 0) {
-                               msg_free_all_parts(ret);
-                               return NULL;                            
-                       }
-               } while (++j < msg->num_elements && 
-                        strcmp(attrs[i], msg->elements[j].name) == 0);
+               if (msg_add_element(ldb, ret, el) != 0) {
+                       msg_free_all_parts(ldb, ret);
+                       return NULL;                            
+               }
        }
 
        return ret;
@@ -222,12 +209,27 @@ static struct ldb_message *ltdb_pull_attrs(struct ldb_context *ldb,
 
 /*
   see if a ldb_val is a wildcard
+  return 1 if yes, 0 if no
 */
-int ltdb_has_wildcard(const struct ldb_val *val)
+int ltdb_has_wildcard(struct ldb_context *ldb, const char *attr_name, 
+                     const struct ldb_val *val)
 {
-       if (val->length == 1 && ((char *)val->data)[0] == '*') {
+       int flags;
+
+       /* all attribute types recognise the "*" wildcard */
+       if (val->length == 1 && strncmp((char *)val->data, "*", 1) == 0) {
                return 1;
        }
+
+       if (strpbrk(val->data, "*?") == NULL) {
+               return 0;
+       }
+
+       flags = ltdb_attribute_flags(ldb, attr_name);
+       if (flags & LTDB_FLAG_WILDCARD) {
+               return 1;
+       }
+
        return 0;
 }
 
@@ -238,12 +240,12 @@ int ltdb_has_wildcard(const struct ldb_val *val)
 void ltdb_search_dn1_free(struct ldb_context *ldb, struct ldb_message *msg)
 {
        int i;
-       if (msg->dn) free(msg->dn);
-       if (msg->private) free(msg->private);
+       ldb_free(ldb, msg->private_data);
        for (i=0;i<msg->num_elements;i++) {
-               if (msg->elements[i].values) free(msg->elements[i].values);
+               ldb_free(ldb, msg->elements[i].values);
        }
-       if (msg->elements) free(msg->elements);
+       ldb_free(ldb, msg->elements);
+       memset(msg, 0, sizeof(*msg));
 }
 
 
@@ -255,37 +257,51 @@ void ltdb_search_dn1_free(struct ldb_context *ldb, struct ldb_message *msg)
 */
 int ltdb_search_dn1(struct ldb_context *ldb, const char *dn, struct ldb_message *msg)
 {
-       struct ltdb_private *ltdb = ldb->private;
+       struct ltdb_private *ltdb = ldb->private_data;
        int ret;
-       TDB_DATA tdb_key, tdb_data;
+       TDB_DATA tdb_key, tdb_data, tdb_data2;
+
+       memset(msg, 0, sizeof(*msg));
 
        /* form the key */
-       tdb_key = ltdb_key(dn);
+       tdb_key = ltdb_key(ldb, dn);
        if (!tdb_key.dptr) {
                return -1;
        }
 
        tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
-       free(tdb_key.dptr);
+       ldb_free(ldb, tdb_key.dptr);
        if (!tdb_data.dptr) {
                return 0;
        }
 
-       msg->dn = strdup(dn);
-       if (!msg->dn) {
+       tdb_data2.dptr = ldb_malloc(ldb, tdb_data.dsize);
+       if (!tdb_data2.dptr) {
                free(tdb_data.dptr);
                return -1;
        }
-       msg->private = tdb_data.dptr;
+       memcpy(tdb_data2.dptr, tdb_data.dptr, tdb_data.dsize);
+       free(tdb_data.dptr);
+       tdb_data2.dsize = tdb_data.dsize;
+
+       msg->private_data = tdb_data2.dptr;
        msg->num_elements = 0;
        msg->elements = NULL;
 
-       ret = ltdb_unpack_data(ldb, &tdb_data, msg);
+       ret = ltdb_unpack_data(ldb, &tdb_data2, msg);
        if (ret == -1) {
-               free(tdb_data.dptr);
+               free(tdb_data2.dptr);
                return -1;              
        }
 
+       if (!msg->dn) {
+               msg->dn = ldb_strdup(ldb, dn);
+       }
+       if (!msg->dn) {
+               ldb_free(ldb, tdb_data2.dptr);
+               return -1;
+       }
+
        return 1;
 }
 
@@ -294,7 +310,7 @@ int ltdb_search_dn1(struct ldb_context *ldb, const char *dn, struct ldb_message
   search the database for a single simple dn
 */
 int ltdb_search_dn(struct ldb_context *ldb, char *dn,
-                  const char *attrs[], struct ldb_message ***res)
+                  const char * const attrs[], struct ldb_message ***res)
 {
        int ret;
        struct ldb_message msg, *msg2;
@@ -312,9 +328,9 @@ int ltdb_search_dn(struct ldb_context *ldb, char *dn,
                return -1;              
        }
 
-       *res = malloc_array_p(struct ldb_message *, 2);
+       *res = ldb_malloc_array_p(ldb, struct ldb_message *, 2);
        if (! *res) {
-               msg_free_all_parts(msg2);
+               msg_free_all_parts(ldb, msg2);
                return -1;              
        }
 
@@ -330,7 +346,7 @@ int ltdb_search_dn(struct ldb_context *ldb, char *dn,
   return 0 on success, -1 on failure
 */
 int ltdb_add_attr_results(struct ldb_context *ldb, struct ldb_message *msg,
-                         const char *attrs[], 
+                         const char * const attrs[], 
                          unsigned int *count, 
                          struct ldb_message ***res)
 {
@@ -344,9 +360,9 @@ int ltdb_add_attr_results(struct ldb_context *ldb, struct ldb_message *msg,
        }
 
        /* add to the results list */
-       res2 = realloc_p(*res, struct ldb_message *, (*count)+2);
+       res2 = ldb_realloc_p(ldb, *res, struct ldb_message *, (*count)+2);
        if (!res2) {
-               msg_free_all_parts(msg2);
+               msg_free_all_parts(ldb, msg2);
                return -1;
        }
 
@@ -368,7 +384,7 @@ struct ltdb_search_info {
        struct ldb_parse_tree *tree;
        const char *base;
        enum ldb_scope scope;
-       const char **attrs;
+       const char * const *attrs;
        struct ldb_message **msgs;
        int failures;
        int count;
@@ -389,8 +405,6 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
                return 0;
        }
 
-       msg.dn = key.dptr + 3;
-
        /* unpack the record */
        ret = ltdb_unpack_data(sinfo->ldb, &data, &msg);
        if (ret == -1) {
@@ -398,10 +412,14 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
                return 0;
        }
 
+       if (!msg.dn) {
+               msg.dn = key.dptr + 3;
+       }
+
        /* see if it matches the given expression */
        if (!ldb_message_match(sinfo->ldb, &msg, sinfo->tree, 
                               sinfo->base, sinfo->scope)) {
-               ltdb_unpack_data_free(&msg);
+               ltdb_unpack_data_free(sinfo->ldb, &msg);
                return 0;
        }
 
@@ -411,7 +429,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
                sinfo->failures++;
        }
 
-       ltdb_unpack_data_free(&msg);
+       ltdb_unpack_data_free(sinfo->ldb, &msg);
 
        return ret;
 }
@@ -422,15 +440,18 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
 */
 int ltdb_search_free(struct ldb_context *ldb, struct ldb_message **msgs)
 {
+       struct ltdb_private *ltdb = ldb->private_data;
        int i;
 
+       ltdb->last_err_string = NULL;
+       
        if (!msgs) return 0;
 
        for (i=0;msgs[i];i++) {
-               msg_free_all_parts(msgs[i]);
+               msg_free_all_parts(ldb, msgs[i]);
        }
 
-       free(msgs);
+       ldb_free(ldb, msgs);
 
        return 0;
 }
@@ -443,9 +464,9 @@ static int ltdb_search_full(struct ldb_context *ldb,
                            const char *base,
                            enum ldb_scope scope,
                            struct ldb_parse_tree *tree,
-                           const char *attrs[], struct ldb_message ***res)
+                           const char * const attrs[], struct ldb_message ***res)
 {
-       struct ltdb_private *ltdb = ldb->private;
+       struct ltdb_private *ltdb = ldb->private_data;
        int ret;
        struct ltdb_search_info sinfo;
 
@@ -476,22 +497,30 @@ static int ltdb_search_full(struct ldb_context *ldb,
 */
 int ltdb_search(struct ldb_context *ldb, const char *base,
                enum ldb_scope scope, const char *expression,
-               const char *attrs[], struct ldb_message ***res)
+               const char * const attrs[], struct ldb_message ***res)
 {
+       struct ltdb_private *ltdb = ldb->private_data;
        struct ldb_parse_tree *tree;
        int ret;
 
+       ltdb->last_err_string = NULL;
+
+       if (ltdb_cache_load(ldb) != 0) {
+               return -1;
+       }
+
        *res = NULL;
 
        /* form a parse tree for the expression */
-       tree = ldb_parse_tree(expression);
+       tree = ldb_parse_tree(ldb, expression);
        if (!tree) {
+               ltdb->last_err_string = "expression parse failed";
                return -1;
        }
 
        if (tree->operation == LDB_OP_SIMPLE && 
-           strcmp(tree->u.simple.attr, "dn") == 0 &&
-           !ltdb_has_wildcard(&tree->u.simple.value)) {
+           ldb_attr_cmp(tree->u.simple.attr, "dn") == 0 &&
+           !ltdb_has_wildcard(ldb, tree->u.simple.attr, &tree->u.simple.value)) {
                /* yay! its a nice simple one */
                ret = ltdb_search_dn(ldb, tree->u.simple.value.data, attrs, res);
        } else {
@@ -501,7 +530,7 @@ int ltdb_search(struct ldb_context *ldb, const char *base,
                }
        }
 
-       ldb_parse_tree_free(tree);
+       ldb_parse_tree_free(ldb, tree);
 
        return ret;
 }