4 Copyright (C) Andrew Tridgell 2004
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb search functions
30 * Description: functions to search ldb+tdb databases
32 * Author: Andrew Tridgell
36 #include "ldb_tdb/ldb_tdb.h"
39 free a message that has all parts separately allocated
41 static void msg_free_all_parts(struct ldb_message *msg)
44 if (msg->dn) free(msg->dn);
45 for (i=0;i<msg->num_elements;i++) {
46 if (msg->elements[i].name) free(msg->elements[i].name);
47 if (msg->elements[i].value.data) free(msg->elements[i].value.data);
55 TODO: this should take advantage of the sorted nature of the message
56 return index of the attribute, or -1 if not found
58 int ldb_msg_find_attr(const struct ldb_message *msg, const char *attr)
61 for (i=0;i<msg->num_elements;i++) {
62 if (strcmp(msg->elements[i].name, attr) == 0) {
70 duplicate a ldb_val structure
72 static struct ldb_val ldb_val_dup(const struct ldb_val *v)
75 v2.length = v->length;
81 /* the +1 is to cope with buggy C library routines like strndup
82 that look one byte beyond */
83 v2.data = malloc(v->length+1);
89 memcpy(v2.data, v->data, v->length);
90 ((char *)v2.data)[v->length] = 0;
97 add one element to a message
99 static int msg_add_element(struct ldb_message *ret, const struct ldb_message_element *el)
101 struct ldb_message_element *e2;
103 e2 = realloc_p(ret->elements, struct ldb_message_element, ret->num_elements+1);
109 e2[ret->num_elements].name = strdup(el->name);
110 if (!e2[ret->num_elements].name) {
113 e2[ret->num_elements].value = ldb_val_dup(&el->value);
114 if (e2[ret->num_elements].value.length != el->value.length) {
124 add all elements from one message into another
126 static int msg_add_all_elements(struct ldb_message *ret,
127 const struct ldb_message *msg)
130 for (i=0;i<msg->num_elements;i++) {
131 if (msg_add_element(ret, &msg->elements[i]) != 0) {
141 pull the specified list of attributes from a message
143 static struct ldb_message *ltdb_pull_attrs(struct ldb_context *ldb,
144 const struct ldb_message *msg,
147 struct ldb_message *ret;
150 ret = malloc_p(struct ldb_message);
155 ret->dn = strdup(msg->dn);
161 ret->num_elements = 0;
162 ret->elements = NULL;
166 if (msg_add_all_elements(ret, msg) != 0) {
167 msg_free_all_parts(ret);
173 for (i=0;attrs[i];i++) {
176 if (strcmp(attrs[i], "*") == 0) {
177 if (msg_add_all_elements(ret, msg) != 0) {
178 msg_free_all_parts(ret);
183 j = ldb_msg_find_attr(msg, attrs[i]);
188 if (msg_add_element(ret, &msg->elements[j]) != 0) {
189 msg_free_all_parts(ret);
192 } while (++j < msg->num_elements &&
193 strcmp(attrs[i], msg->elements[j].name) == 0);
202 see if a ldb_val is a wildcard
204 int ltdb_has_wildcard(const struct ldb_val *val)
206 if (val->length == 1 && ((char *)val->data)[0] == '*') {
214 free the results of a ltdb_search_dn1 search
216 void ltdb_search_dn1_free(struct ldb_context *ldb, struct ldb_message *msg)
220 if (msg->elements) free(msg->elements);
225 search the database for a single simple dn, returning all attributes
228 return 1 on success, 0 on record-not-found and -1 on error
230 int ltdb_search_dn1(struct ldb_context *ldb, const char *dn, struct ldb_message *msg)
232 struct ltdb_private *ltdb = ldb->private;
234 TDB_DATA tdb_key, tdb_data;
237 tdb_key = ltdb_key(dn);
242 tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
244 if (!tdb_data.dptr) {
248 msg->dn = strdup(dn);
253 msg->private = tdb_data.dptr;
254 msg->num_elements = 0;
255 msg->elements = NULL;
257 ret = ltdb_unpack_data(ldb, &tdb_data, msg);
268 search the database for a single simple dn
270 int ltdb_search_dn(struct ldb_context *ldb, char *dn,
271 const char *attrs[], struct ldb_message ***res)
274 struct ldb_message msg, *msg2;
276 ret = ltdb_search_dn1(ldb, dn, &msg);
281 msg2 = ltdb_pull_attrs(ldb, &msg, attrs);
283 ltdb_search_dn1_free(ldb, &msg);
289 *res = malloc_array_p(struct ldb_message *, 2);
291 msg_free_all_parts(msg2);
303 add a set of attributes from a record to a set of results
304 return 0 on success, -1 on failure
306 int ltdb_add_attr_results(struct ldb_context *ldb, struct ldb_message *msg,
309 struct ldb_message ***res)
311 struct ldb_message *msg2;
312 struct ldb_message **res2;
314 /* pull the attributes that the user wants */
315 msg2 = ltdb_pull_attrs(ldb, msg, attrs);
320 /* add to the results list */
321 res2 = realloc_p(*res, struct ldb_message *, (*count)+2);
323 msg_free_all_parts(msg2);
329 (*res)[*count] = msg2;
330 (*res)[(*count)+1] = NULL;
338 internal search state during a full db search
340 struct ltdb_search_info {
341 struct ldb_context *ldb;
342 struct ldb_parse_tree *tree;
344 enum ldb_scope scope;
346 struct ldb_message **msgs;
353 search function for a non-indexed search
355 static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
357 struct ltdb_search_info *sinfo = state;
358 struct ldb_message msg;
362 strncmp(key.dptr, "DN=", 3) != 0) {
366 msg.dn = key.dptr + 3;
368 /* unpack the record */
369 ret = ltdb_unpack_data(sinfo->ldb, &data, &msg);
375 /* see if it matches the given expression */
376 if (!ldb_message_match(sinfo->ldb, &msg, sinfo->tree,
377 sinfo->base, sinfo->scope)) {
378 if (msg.elements) free(msg.elements);
382 ret = ltdb_add_attr_results(sinfo->ldb, &msg, sinfo->attrs, &sinfo->count, &sinfo->msgs);
388 if (msg.elements) free(msg.elements);
395 free a set of search results
397 int ltdb_search_free(struct ldb_context *ldb, struct ldb_message **msgs)
403 for (i=0;msgs[i];i++) {
404 msg_free_all_parts(msgs[i]);
413 search the database with a LDAP-like expression.
414 this is the "full search" non-indexed varient
416 static int ltdb_search_full(struct ldb_context *ldb,
418 enum ldb_scope scope,
419 struct ldb_parse_tree *tree,
420 const char *attrs[], struct ldb_message ***res)
422 struct ltdb_private *ltdb = ldb->private;
424 struct ltdb_search_info sinfo;
435 ret = tdb_traverse(ltdb->tdb, search_func, &sinfo);
438 ltdb_search_free(ldb, sinfo.msgs);
448 search the database with a LDAP-like expression.
449 choses a search method
451 int ltdb_search(struct ldb_context *ldb, const char *base,
452 enum ldb_scope scope, const char *expression,
453 const char *attrs[], struct ldb_message ***res)
455 struct ldb_parse_tree *tree;
460 /* form a parse tree for the expression */
461 tree = ldb_parse_tree(expression);
466 if (tree->operation == LDB_OP_SIMPLE &&
467 strcmp(tree->u.simple.attr, "dn") == 0 &&
468 !ltdb_has_wildcard(&tree->u.simple.value)) {
469 /* yay! its a nice simple one */
470 ret = ltdb_search_dn(ldb, tree->u.simple.value.data, attrs, res);
472 ret = ltdb_search_indexed(ldb, base, scope, tree, attrs, res);
474 ret = ltdb_search_full(ldb, base, scope, tree, attrs, res);
478 ldb_parse_tree_free(tree);