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/include/includes.h"
38 #include "ldb/ldb_tdb/ldb_tdb.h"
41 add one element to a message
43 static int msg_add_element(struct ldb_message *ret,
44 const struct ldb_message_element *el,
48 struct ldb_message_element *e2, *elnew;
50 if (check_duplicates && ldb_msg_find_element(ret, el->name)) {
51 /* its already there */
55 e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1);
61 elnew = &e2[ret->num_elements];
63 elnew->name = talloc_strdup(ret->elements, el->name);
69 elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values);
77 for (i=0;i<el->num_values;i++) {
78 elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]);
79 if (elnew->values[i].length != el->values[i].length) {
84 elnew->num_values = el->num_values;
92 add the special distinguishedName element
94 static int msg_add_distinguished_name(struct ldb_message *msg)
96 struct ldb_message_element el;
101 el.name = "distinguishedName";
104 val.data = (uint8_t *)ldb_dn_linearize(msg, msg->dn);
105 val.length = strlen((char *)val.data);
107 ret = msg_add_element(msg, &el, 1);
112 add all elements from one message into another
114 static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret,
115 const struct ldb_message *msg)
117 struct ldb_context *ldb = module->ldb;
119 int check_duplicates = (ret->num_elements != 0);
121 if (msg_add_distinguished_name(ret) != 0) {
125 for (i=0;i<msg->num_elements;i++) {
126 const struct ldb_attrib_handler *h;
127 h = ldb_attrib_handler(ldb, msg->elements[i].name);
128 if (h->flags & LDB_ATTR_FLAG_HIDDEN) {
131 if (msg_add_element(ret, &msg->elements[i],
132 check_duplicates) != 0) {
142 pull the specified list of attributes from a message
144 static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module,
146 const struct ldb_message *msg,
147 const char * const *attrs)
149 struct ldb_message *ret;
152 ret = talloc(mem_ctx, struct ldb_message);
157 ret->dn = ldb_dn_copy(ret, msg->dn);
163 ret->num_elements = 0;
164 ret->elements = NULL;
167 if (msg_add_all_elements(module, ret, msg) != 0) {
174 for (i=0;attrs[i];i++) {
175 struct ldb_message_element *el;
177 if (strcmp(attrs[i], "*") == 0) {
178 if (msg_add_all_elements(module, ret, msg) != 0) {
185 if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
186 if (msg_add_distinguished_name(ret) != 0) {
192 el = ldb_msg_find_element(msg, attrs[i]);
196 if (msg_add_element(ret, el, 1) != 0) {
207 search the database for a single simple dn, returning all attributes
210 return 1 on success, 0 on record-not-found and -1 on error
212 int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct ldb_message *msg)
214 struct ltdb_private *ltdb = module->private_data;
216 TDB_DATA tdb_key, tdb_data;
218 memset(msg, 0, sizeof(*msg));
221 tdb_key = ltdb_key(module, dn);
226 tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
227 talloc_free(tdb_key.dptr);
228 if (!tdb_data.dptr) {
232 msg->num_elements = 0;
233 msg->elements = NULL;
235 ret = ltdb_unpack_data(module, &tdb_data, msg);
242 msg->dn = ldb_dn_copy(msg, dn);
251 /* the lock key for search locking. Note that this is not a DN, its
252 just an arbitrary key to give to tdb. Also note that as we and
253 using transactions for all write operations and transactions take
254 care of their own locks, we don't need to do any locking anywhere
255 other than in ldb_search() */
256 #define LDBLOCK "INT_LDBLOCK"
259 lock the database for read - use by ltdb_search
261 static int ltdb_lock_read(struct ldb_module *module)
263 struct ltdb_private *ltdb = module->private_data;
266 key.dptr = discard_const(LDBLOCK);
267 key.dsize = strlen(LDBLOCK);
269 return tdb_chainlock_read(ltdb->tdb, key);
273 unlock the database after a ltdb_lock_read()
275 static int ltdb_unlock_read(struct ldb_module *module)
277 struct ltdb_private *ltdb = module->private_data;
280 key.dptr = discard_const(LDBLOCK);
281 key.dsize = strlen(LDBLOCK);
283 return tdb_chainunlock_read(ltdb->tdb, key);
287 add a set of attributes from a record to a set of results
288 return 0 on success, -1 on failure
290 int ltdb_add_attr_results(struct ldb_module *module,
292 struct ldb_message *msg,
293 const char * const attrs[],
295 struct ldb_message ***res)
297 struct ldb_message *msg2;
298 struct ldb_message **res2;
300 /* pull the attributes that the user wants */
301 msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs);
306 /* add to the results list */
307 res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2);
315 (*res)[*count] = talloc_steal(*res, msg2);
316 (*res)[(*count)+1] = NULL;
325 filter the specified list of attributes from a message
326 removing not requested attrs.
328 int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
333 /* check for special attrs */
334 for (i = 0; attrs[i]; i++) {
335 if (strcmp(attrs[i], "*") == 0) {
340 if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
341 if (msg_add_distinguished_name(msg) != 0) {
351 if (msg_add_distinguished_name(msg) != 0) {
357 for (i = 0; i < msg->num_elements; i++) {
360 for (j = 0, found = 0; attrs[j]; j++) {
361 if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) {
368 ldb_msg_remove_attr(msg, msg->elements[i].name);
377 search function for a non-indexed search
379 static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
381 struct ldb_async_handle *handle = talloc_get_type(state, struct ldb_async_handle);
382 struct ltdb_async_context *ac = talloc_get_type(handle->private_data, struct ltdb_async_context);
383 struct ldb_async_result *ares = NULL;
387 strncmp((char *)key.dptr, "DN=", 3) != 0) {
391 ares = talloc_zero(ac, struct ldb_async_result);
393 handle->status = LDB_ERR_OPERATIONS_ERROR;
394 handle->state = LDB_ASYNC_DONE;
398 ares->message = ldb_msg_new(ares);
399 if (!ares->message) {
400 handle->status = LDB_ERR_OPERATIONS_ERROR;
401 handle->state = LDB_ASYNC_DONE;
406 /* unpack the record */
407 ret = ltdb_unpack_data(ac->module, &data, ares->message);
413 if (!ares->message->dn) {
414 ares->message->dn = ldb_dn_explode(ares->message, (char *)key.dptr + 3);
415 if (ares->message->dn == NULL) {
416 handle->status = LDB_ERR_OPERATIONS_ERROR;
417 handle->state = LDB_ASYNC_DONE;
423 /* see if it matches the given expression */
424 if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree,
425 ac->base, ac->scope)) {
430 /* filter the attributes that the user wants */
431 ret = ltdb_filter_attrs(ares->message, ac->attrs);
434 handle->status = LDB_ERR_OPERATIONS_ERROR;
435 handle->state = LDB_ASYNC_DONE;
440 ares->type = LDB_REPLY_ENTRY;
441 handle->state = LDB_ASYNC_PENDING;
442 handle->status = ac->callback(ac->module->ldb, ac->context, ares);
444 if (handle->status != LDB_SUCCESS) {
445 /* don't try to free ares here, the callback is in charge of that */
454 search the database with a LDAP-like expression.
455 this is the "full search" non-indexed variant
457 static int ltdb_search_full(struct ldb_async_handle *handle)
459 struct ltdb_async_context *ac = talloc_get_type(handle->private_data, struct ltdb_async_context);
460 struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private);
463 ret = tdb_traverse_read(ltdb->tdb, search_func, handle);
465 handle->state = LDB_ASYNC_DONE;
468 handle->status = LDB_ERR_OPERATIONS_ERROR;
469 return handle->status;
472 handle->status = LDB_SUCCESS;
473 return handle->status;
476 static int ltdb_search_sync_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares)
478 struct ldb_result *res;
481 ldb_set_errstring(ldb, talloc_strdup(ldb, "NULL Context in callback"));
485 res = *((struct ldb_result **)context);
491 if (ares->type == LDB_REPLY_ENTRY) {
492 res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2);
497 res->msgs[res->count + 1] = NULL;
499 res->msgs[res->count] = talloc_steal(res->msgs, ares->message);
500 if (! res->msgs[res->count]) {
506 ldb_debug(ldb, LDB_DEBUG_ERROR, "unrecognized async reply in ltdb_search_sync_callback!\n");
514 if (ares) talloc_free(ares);
515 if (res) talloc_free(res);
516 if (context) *((struct ldb_result **)context) = NULL;
517 return LDB_ERR_OPERATIONS_ERROR;
520 int ltdb_search_async(struct ldb_module *module, const struct ldb_dn *base,
521 enum ldb_scope scope, struct ldb_parse_tree *tree,
522 const char * const *attrs,
524 int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
526 struct ldb_async_handle **handle)
528 struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
529 struct ltdb_async_context *ltdb_ac;
532 if ((base == NULL || base->comp_num == 0) &&
533 (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL))
534 return LDB_ERR_OPERATIONS_ERROR;
536 if (ltdb_lock_read(module) != 0) {
537 return LDB_ERR_OPERATIONS_ERROR;
540 if (ltdb_cache_load(module) != 0) {
541 ltdb_unlock_read(module);
542 return LDB_ERR_OPERATIONS_ERROR;
546 ltdb_unlock_read(module);
547 return LDB_ERR_OPERATIONS_ERROR;
550 *handle = init_ltdb_handle(ltdb, module, context, callback, timeout);
551 if (*handle == NULL) {
552 talloc_free(*handle);
553 ltdb_unlock_read(module);
554 return LDB_ERR_OPERATIONS_ERROR;
557 ltdb_ac = talloc_get_type((*handle)->private_data, struct ltdb_async_context);
559 ltdb_ac->tree = tree;
560 ltdb_ac->scope = scope;
561 ltdb_ac->base = base;
562 ltdb_ac->attrs = attrs;
564 ret = ltdb_search_indexed(*handle);
566 ret = ltdb_search_full(*handle);
568 if (ret != LDB_SUCCESS) {
569 ldb_set_errstring(module->ldb, talloc_strdup(module->ldb, "Indexed and full searches both failed!\n"));
570 talloc_free(*handle);
574 ltdb_unlock_read(module);
580 search the database with a LDAP-like expression.
581 choses a search method
583 int ltdb_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
584 enum ldb_scope scope, struct ldb_parse_tree *tree,
585 const char * const attrs[], struct ldb_result **res)
587 struct ldb_async_handle *handle;
590 *res = talloc_zero(module, struct ldb_result);
592 return LDB_ERR_OPERATIONS_ERROR;
595 ret = ltdb_search_async(module, base, scope, tree, attrs,
596 res, <db_search_sync_callback,
599 if (ret != LDB_SUCCESS)
602 ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL);