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_move(*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_handle *handle = talloc_get_type(state, struct ldb_handle);
382 struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
383 struct ldb_reply *ares = NULL;
387 strncmp((char *)key.dptr, "DN=", 3) != 0) {
391 ares = talloc_zero(ac, struct ldb_reply);
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_handle *handle)
459 struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_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);
466 handle->status = LDB_ERR_OPERATIONS_ERROR;
469 handle->state = LDB_ASYNC_DONE;
474 search the database with a LDAP-like expression.
475 choses a search method
477 int ltdb_search(struct ldb_module *module, struct ldb_request *req)
479 struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
480 struct ltdb_context *ltdb_ac;
481 struct ldb_reply *ares;
484 if ((req->op.search.base == NULL || req->op.search.base->comp_num == 0) &&
485 (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL))
486 return LDB_ERR_OPERATIONS_ERROR;
488 if (ltdb_lock_read(module) != 0) {
489 return LDB_ERR_OPERATIONS_ERROR;
492 if (ltdb_cache_load(module) != 0) {
493 ltdb_unlock_read(module);
494 return LDB_ERR_OPERATIONS_ERROR;
497 if (req->op.search.tree == NULL) {
498 ltdb_unlock_read(module);
499 return LDB_ERR_OPERATIONS_ERROR;
502 req->handle = init_ltdb_handle(ltdb, module, req);
503 if (req->handle == NULL) {
504 ltdb_unlock_read(module);
505 return LDB_ERR_OPERATIONS_ERROR;
507 ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
509 ltdb_ac->tree = req->op.search.tree;
510 ltdb_ac->scope = req->op.search.scope;
511 ltdb_ac->base = req->op.search.base;
512 ltdb_ac->attrs = req->op.search.attrs;
514 ret = ltdb_search_indexed(req->handle);
516 ret = ltdb_search_full(req->handle);
518 if (ret != LDB_SUCCESS) {
519 ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n");
520 req->handle->state = LDB_ASYNC_DONE;
521 req->handle->status = ret;
524 /* Finally send an LDB_REPLY_DONE packet when searching is finished */
526 ares = talloc_zero(req, struct ldb_reply);
528 ltdb_unlock_read(module);
529 return LDB_ERR_OPERATIONS_ERROR;
532 req->handle->state = LDB_ASYNC_DONE;
533 ares->type = LDB_REPLY_DONE;
535 ret = req->callback(module->ldb, req->context, ares);
536 req->handle->status = ret;
538 ltdb_unlock_read(module);