diff options
author | Andrew Tridgell <tridge@samba.org> | 2004-03-31 06:45:39 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2004-03-31 06:45:39 +0000 |
commit | 58d50a614f1b4a3fc6b60ad5f777d987263fe54f (patch) | |
tree | 6fc8efe5b4cc66f6e86ad6c11969d000860a253b /source4/lib/ldb/ldb_tdb/ldb_search.c | |
parent | 4aa785b1b23d0add18d5fec6fb6c5b37a6feecac (diff) | |
download | samba-58d50a614f1b4a3fc6b60ad5f777d987263fe54f.tar.gz samba-58d50a614f1b4a3fc6b60ad5f777d987263fe54f.tar.bz2 samba-58d50a614f1b4a3fc6b60ad5f777d987263fe54f.zip |
make a more recent snapshot of ldb available to interested
people. Note that I decided to make it LGPL.
ldb is not finished yet, but enough of it is there for people to get
an idea of what it does, and quite a few simple tests work
(This used to be commit dc6f41f9e777d37f883303ddef0d96840d80f78e)
Diffstat (limited to 'source4/lib/ldb/ldb_tdb/ldb_search.c')
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_search.c | 482 |
1 files changed, 482 insertions, 0 deletions
diff --git a/source4/lib/ldb/ldb_tdb/ldb_search.c b/source4/lib/ldb/ldb_tdb/ldb_search.c new file mode 100644 index 0000000000..952053c920 --- /dev/null +++ b/source4/lib/ldb/ldb_tdb/ldb_search.c @@ -0,0 +1,482 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ldb search functions + * + * Description: functions to search ldb+tdb databases + * + * Author: Andrew Tridgell + */ + +#include "includes.h" +#include "ldb_tdb/ldb_tdb.h" + +/* + free a message that has all parts separately allocated +*/ +static void msg_free_all_parts(struct ldb_message *msg) +{ + int i; + if (msg->dn) free(msg->dn); + for (i=0;i<msg->num_elements;i++) { + if (msg->elements[i].name) free(msg->elements[i].name); + if (msg->elements[i].value.data) free(msg->elements[i].value.data); + } + free(msg->elements); + free(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 +*/ +static struct ldb_val ldb_val_dup(const struct ldb_val *v) +{ + struct ldb_val v2; + v2.length = v->length; + if (v->length == 0) { + v2.data = NULL; + return v2; + } + + /* the +1 is to cope with buggy C library routines like strndup + that look one byte beyond */ + v2.data = malloc(v->length+1); + if (!v2.data) { + v2.length = 0; + return v2; + } + + memcpy(v2.data, v->data, v->length); + ((char *)v2.data)[v->length] = 0; + return v2; +} + + + +/* + add one element to a message +*/ +static int msg_add_element(struct ldb_message *ret, const struct ldb_message_element *el) +{ + struct ldb_message_element *e2; + + e2 = realloc_p(ret->elements, struct ldb_message_element, ret->num_elements+1); + if (!e2) { + return -1; + } + ret->elements = e2; + + e2[ret->num_elements].name = strdup(el->name); + if (!e2[ret->num_elements].name) { + return -1; + } + e2[ret->num_elements].value = ldb_val_dup(&el->value); + if (e2[ret->num_elements].value.length != el->value.length) { + return -1; + } + + ret->num_elements++; + + return 0; +} + +/* + add all elements from one message into another + */ +static int msg_add_all_elements(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) { + return -1; + } + } + + return 0; +} + + +/* + pull the specified list of attributes from a message + */ +static struct ldb_message *ltdb_pull_attrs(struct ldb_context *ldb, + const struct ldb_message *msg, + const char **attrs) +{ + struct ldb_message *ret; + int i; + + ret = malloc_p(struct ldb_message); + if (!ret) { + return NULL; + } + + ret->dn = strdup(msg->dn); + if (!ret->dn) { + free(ret); + return NULL; + } + + ret->num_elements = 0; + ret->elements = NULL; + ret->private = NULL; + + if (!attrs) { + if (msg_add_all_elements(ret, msg) != 0) { + msg_free_all_parts(ret); + return NULL; + } + return ret; + } + + for (i=0;attrs[i];i++) { + int j; + + if (strcmp(attrs[i], "*") == 0) { + if (msg_add_all_elements(ret, msg) != 0) { + msg_free_all_parts(ret); + return NULL; + } + continue; + } + j = ldb_msg_find_attr(msg, attrs[i]); + if (j == -1) { + 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); + } + + return ret; +} + + + +/* + see if a ldb_val is a wildcard +*/ +int ltdb_has_wildcard(const struct ldb_val *val) +{ + if (val->length == 1 && ((char *)val->data)[0] == '*') { + return 1; + } + return 0; +} + + +/* + free the results of a ltdb_search_dn1 search +*/ +void ltdb_search_dn1_free(struct ldb_context *ldb, struct ldb_message *msg) +{ + free(msg->dn); + free(msg->private); + if (msg->elements) free(msg->elements); +} + + +/* + search the database for a single simple dn, returning all attributes + in a single message + + return 1 on success, 0 on record-not-found and -1 on error +*/ +int ltdb_search_dn1(struct ldb_context *ldb, const char *dn, struct ldb_message *msg) +{ + struct ltdb_private *ltdb = ldb->private; + int ret; + TDB_DATA tdb_key, tdb_data; + + /* form the key */ + tdb_key = ltdb_key(dn); + if (!tdb_key.dptr) { + return -1; + } + + tdb_data = tdb_fetch(ltdb->tdb, tdb_key); + free(tdb_key.dptr); + if (!tdb_data.dptr) { + return 0; + } + + msg->dn = strdup(dn); + if (!msg->dn) { + free(tdb_data.dptr); + return -1; + } + msg->private = tdb_data.dptr; + msg->num_elements = 0; + msg->elements = NULL; + + ret = ltdb_unpack_data(ldb, &tdb_data, msg); + if (ret == -1) { + free(tdb_data.dptr); + return -1; + } + + return 1; +} + + +/* + 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) +{ + int ret; + struct ldb_message msg, *msg2; + + ret = ltdb_search_dn1(ldb, dn, &msg); + if (ret != 1) { + return ret; + } + + msg2 = ltdb_pull_attrs(ldb, &msg, attrs); + + ltdb_search_dn1_free(ldb, &msg); + + if (!msg2) { + return -1; + } + + *res = malloc_array_p(struct ldb_message *, 2); + if (! *res) { + msg_free_all_parts(msg2); + return -1; + } + + (*res)[0] = msg2; + (*res)[1] = NULL; + + return 1; +} + + +/* + add a set of attributes from a record to a set of results + return 0 on success, -1 on failure +*/ +int ltdb_add_attr_results(struct ldb_context *ldb, struct ldb_message *msg, + const char *attrs[], + unsigned int *count, + struct ldb_message ***res) +{ + struct ldb_message *msg2; + struct ldb_message **res2; + + /* pull the attributes that the user wants */ + msg2 = ltdb_pull_attrs(ldb, msg, attrs); + if (!msg2) { + return -1; + } + + /* add to the results list */ + res2 = realloc_p(*res, struct ldb_message *, (*count)+2); + if (!res2) { + msg_free_all_parts(msg2); + return -1; + } + + (*res) = res2; + + (*res)[*count] = msg2; + (*res)[(*count)+1] = NULL; + (*count)++; + + return 0; +} + + +/* + internal search state during a full db search +*/ +struct ltdb_search_info { + struct ldb_context *ldb; + struct ldb_parse_tree *tree; + const char *base; + enum ldb_scope scope; + const char **attrs; + struct ldb_message **msgs; + int failures; + int count; +}; + + +/* + search function for a non-indexed search + */ +static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) +{ + struct ltdb_search_info *sinfo = state; + struct ldb_message msg; + int ret; + + if (key.dsize < 4 || + strncmp(key.dptr, "DN=", 3) != 0) { + return 0; + } + + msg.dn = key.dptr + 3; + + /* unpack the record */ + ret = ltdb_unpack_data(sinfo->ldb, &data, &msg); + if (ret == -1) { + sinfo->failures++; + return 0; + } + + /* see if it matches the given expression */ + if (!ldb_message_match(sinfo->ldb, &msg, sinfo->tree, + sinfo->base, sinfo->scope)) { + if (msg.elements) free(msg.elements); + return 0; + } + + ret = ltdb_add_attr_results(sinfo->ldb, &msg, sinfo->attrs, &sinfo->count, &sinfo->msgs); + + if (ret == -1) { + sinfo->failures++; + } + + if (msg.elements) free(msg.elements); + + return ret; +} + + +/* + free a set of search results +*/ +int ltdb_search_free(struct ldb_context *ldb, struct ldb_message **msgs) +{ + int i; + + if (!msgs) return 0; + + for (i=0;msgs[i];i++) { + msg_free_all_parts(msgs[i]); + } + + free(msgs); + + return 0; +} + +/* + search the database with a LDAP-like expression. + this is the "full search" non-indexed varient +*/ +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) +{ + struct ltdb_private *ltdb = ldb->private; + int ret; + struct ltdb_search_info sinfo; + + sinfo.tree = tree; + sinfo.ldb = ldb; + sinfo.scope = scope; + sinfo.base = base; + sinfo.attrs = attrs; + sinfo.msgs = NULL; + sinfo.count = 0; + sinfo.failures = 0; + + ret = tdb_traverse(ltdb->tdb, search_func, &sinfo); + + if (ret == -1) { + ltdb_search_free(ldb, sinfo.msgs); + return -1; + } + + *res = sinfo.msgs; + return sinfo.count; +} + + +/* + search the database with a LDAP-like expression. + choses a search method +*/ +int ltdb_search(struct ldb_context *ldb, const char *base, + enum ldb_scope scope, const char *expression, + const char *attrs[], struct ldb_message ***res) +{ + struct ldb_parse_tree *tree; + int ret; + + *res = NULL; + + /* form a parse tree for the expression */ + tree = ldb_parse_tree(expression); + if (!tree) { + return -1; + } + + if (tree->operation == LDB_OP_SIMPLE && + strcmp(tree->u.simple.attr, "dn") == 0 && + !ltdb_has_wildcard(&tree->u.simple.value)) { + /* yay! its a nice simple one */ + ret = ltdb_search_dn(ldb, tree->u.simple.value.data, attrs, res); + } else { + ret = ltdb_search_indexed(ldb, base, scope, tree, attrs, res); + if (ret == -1) { + ret = ltdb_search_full(ldb, base, scope, tree, attrs, res); + } + } + + ldb_parse_tree_free(tree); + + return ret; +} + |