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
);
252 lock the database for read - use by ltdb_search
254 static int ltdb_lock_read(struct ldb_module
*module
)
256 struct ltdb_private
*ltdb
= module
->private_data
;
257 return tdb_lockall_read(ltdb
->tdb
);
261 unlock the database after a ltdb_lock_read()
263 static int ltdb_unlock_read(struct ldb_module
*module
)
265 struct ltdb_private
*ltdb
= module
->private_data
;
266 return tdb_unlockall_read(ltdb
->tdb
);
270 add a set of attributes from a record to a set of results
271 return 0 on success, -1 on failure
273 int ltdb_add_attr_results(struct ldb_module
*module
,
275 struct ldb_message
*msg
,
276 const char * const attrs
[],
278 struct ldb_message
***res
)
280 struct ldb_message
*msg2
;
281 struct ldb_message
**res2
;
283 /* pull the attributes that the user wants */
284 msg2
= ltdb_pull_attrs(module
, mem_ctx
, msg
, attrs
);
289 /* add to the results list */
290 res2
= talloc_realloc(mem_ctx
, *res
, struct ldb_message
*, (*count
)+2);
298 (*res
)[*count
] = talloc_move(*res
, &msg2
);
299 (*res
)[(*count
)+1] = NULL
;
308 filter the specified list of attributes from a message
309 removing not requested attrs.
311 int ltdb_filter_attrs(struct ldb_message
*msg
, const char * const *attrs
)
316 /* check for special attrs */
317 for (i
= 0; attrs
[i
]; i
++) {
318 if (strcmp(attrs
[i
], "*") == 0) {
323 if (ldb_attr_cmp(attrs
[i
], "distinguishedName") == 0) {
324 if (msg_add_distinguished_name(msg
) != 0) {
334 if (msg_add_distinguished_name(msg
) != 0) {
340 for (i
= 0; i
< msg
->num_elements
; i
++) {
343 for (j
= 0, found
= 0; attrs
[j
]; j
++) {
344 if (ldb_attr_cmp(msg
->elements
[i
].name
, attrs
[j
]) == 0) {
351 ldb_msg_remove_attr(msg
, msg
->elements
[i
].name
);
360 search function for a non-indexed search
362 static int search_func(struct tdb_context
*tdb
, TDB_DATA key
, TDB_DATA data
, void *state
)
364 struct ldb_handle
*handle
= talloc_get_type(state
, struct ldb_handle
);
365 struct ltdb_context
*ac
= talloc_get_type(handle
->private_data
, struct ltdb_context
);
366 struct ldb_reply
*ares
= NULL
;
370 strncmp((char *)key
.dptr
, "DN=", 3) != 0) {
374 ares
= talloc_zero(ac
, struct ldb_reply
);
376 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
377 handle
->state
= LDB_ASYNC_DONE
;
381 ares
->message
= ldb_msg_new(ares
);
382 if (!ares
->message
) {
383 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
384 handle
->state
= LDB_ASYNC_DONE
;
389 /* unpack the record */
390 ret
= ltdb_unpack_data(ac
->module
, &data
, ares
->message
);
396 if (!ares
->message
->dn
) {
397 ares
->message
->dn
= ldb_dn_explode(ares
->message
, (char *)key
.dptr
+ 3);
398 if (ares
->message
->dn
== NULL
) {
399 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
400 handle
->state
= LDB_ASYNC_DONE
;
406 /* see if it matches the given expression */
407 if (!ldb_match_msg(ac
->module
->ldb
, ares
->message
, ac
->tree
,
408 ac
->base
, ac
->scope
)) {
413 /* filter the attributes that the user wants */
414 ret
= ltdb_filter_attrs(ares
->message
, ac
->attrs
);
417 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
418 handle
->state
= LDB_ASYNC_DONE
;
423 ares
->type
= LDB_REPLY_ENTRY
;
424 handle
->state
= LDB_ASYNC_PENDING
;
425 handle
->status
= ac
->callback(ac
->module
->ldb
, ac
->context
, ares
);
427 if (handle
->status
!= LDB_SUCCESS
) {
428 /* don't try to free ares here, the callback is in charge of that */
437 search the database with a LDAP-like expression.
438 this is the "full search" non-indexed variant
440 static int ltdb_search_full(struct ldb_handle
*handle
)
442 struct ltdb_context
*ac
= talloc_get_type(handle
->private_data
, struct ltdb_context
);
443 struct ltdb_private
*ltdb
= talloc_get_type(ac
->module
->private_data
, struct ltdb_private
);
446 ret
= tdb_traverse_read(ltdb
->tdb
, search_func
, handle
);
449 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
452 handle
->state
= LDB_ASYNC_DONE
;
457 search the database with a LDAP-like expression.
458 choses a search method
460 int ltdb_search(struct ldb_module
*module
, struct ldb_request
*req
)
462 struct ltdb_private
*ltdb
= talloc_get_type(module
->private_data
, struct ltdb_private
);
463 struct ltdb_context
*ltdb_ac
;
464 struct ldb_reply
*ares
;
467 if ((req
->op
.search
.base
== NULL
|| req
->op
.search
.base
->comp_num
== 0) &&
468 (req
->op
.search
.scope
== LDB_SCOPE_BASE
|| req
->op
.search
.scope
== LDB_SCOPE_ONELEVEL
))
469 return LDB_ERR_OPERATIONS_ERROR
;
471 if (ltdb_lock_read(module
) != 0) {
472 return LDB_ERR_OPERATIONS_ERROR
;
475 if (ltdb_cache_load(module
) != 0) {
476 ltdb_unlock_read(module
);
477 return LDB_ERR_OPERATIONS_ERROR
;
480 if (req
->op
.search
.tree
== NULL
) {
481 ltdb_unlock_read(module
);
482 return LDB_ERR_OPERATIONS_ERROR
;
485 req
->handle
= init_ltdb_handle(ltdb
, module
, req
);
486 if (req
->handle
== NULL
) {
487 ltdb_unlock_read(module
);
488 return LDB_ERR_OPERATIONS_ERROR
;
490 ltdb_ac
= talloc_get_type(req
->handle
->private_data
, struct ltdb_context
);
492 ltdb_ac
->tree
= req
->op
.search
.tree
;
493 ltdb_ac
->scope
= req
->op
.search
.scope
;
494 ltdb_ac
->base
= req
->op
.search
.base
;
495 ltdb_ac
->attrs
= req
->op
.search
.attrs
;
497 ret
= ltdb_search_indexed(req
->handle
);
499 ret
= ltdb_search_full(req
->handle
);
501 if (ret
!= LDB_SUCCESS
) {
502 ldb_set_errstring(module
->ldb
, "Indexed and full searches both failed!\n");
503 req
->handle
->state
= LDB_ASYNC_DONE
;
504 req
->handle
->status
= ret
;
507 /* Finally send an LDB_REPLY_DONE packet when searching is finished */
509 ares
= talloc_zero(req
, struct ldb_reply
);
511 ltdb_unlock_read(module
);
512 return LDB_ERR_OPERATIONS_ERROR
;
515 req
->handle
->state
= LDB_ASYNC_DONE
;
516 ares
->type
= LDB_REPLY_DONE
;
518 ret
= req
->callback(module
->ldb
, req
->context
, ares
);
519 req
->handle
->status
= ret
;
521 ltdb_unlock_read(module
);