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
=
215 (struct ltdb_private
*)module
->private_data
;
217 TDB_DATA tdb_key
, tdb_data
;
219 memset(msg
, 0, sizeof(*msg
));
222 tdb_key
= ltdb_key(module
, dn
);
227 tdb_data
= tdb_fetch(ltdb
->tdb
, tdb_key
);
228 talloc_free(tdb_key
.dptr
);
229 if (!tdb_data
.dptr
) {
233 msg
->num_elements
= 0;
234 msg
->elements
= NULL
;
236 ret
= ltdb_unpack_data(module
, &tdb_data
, msg
);
243 msg
->dn
= ldb_dn_copy(msg
, dn
);
253 lock the database for read - use by ltdb_search
255 static int ltdb_lock_read(struct ldb_module
*module
)
257 struct ltdb_private
*ltdb
=
258 (struct ltdb_private
*)module
->private_data
;
259 return tdb_lockall_read(ltdb
->tdb
);
263 unlock the database after a ltdb_lock_read()
265 static int ltdb_unlock_read(struct ldb_module
*module
)
267 struct ltdb_private
*ltdb
=
268 (struct ltdb_private
*)module
->private_data
;
269 return tdb_unlockall_read(ltdb
->tdb
);
273 add a set of attributes from a record to a set of results
274 return 0 on success, -1 on failure
276 int ltdb_add_attr_results(struct ldb_module
*module
,
278 struct ldb_message
*msg
,
279 const char * const attrs
[],
281 struct ldb_message
***res
)
283 struct ldb_message
*msg2
;
284 struct ldb_message
**res2
;
286 /* pull the attributes that the user wants */
287 msg2
= ltdb_pull_attrs(module
, mem_ctx
, msg
, attrs
);
292 /* add to the results list */
293 res2
= talloc_realloc(mem_ctx
, *res
, struct ldb_message
*, (*count
)+2);
301 (*res
)[*count
] = talloc_move(*res
, &msg2
);
302 (*res
)[(*count
)+1] = NULL
;
311 filter the specified list of attributes from a message
312 removing not requested attrs.
314 int ltdb_filter_attrs(struct ldb_message
*msg
, const char * const *attrs
)
319 /* check for special attrs */
320 for (i
= 0; attrs
[i
]; i
++) {
321 if (strcmp(attrs
[i
], "*") == 0) {
326 if (ldb_attr_cmp(attrs
[i
], "distinguishedName") == 0) {
327 if (msg_add_distinguished_name(msg
) != 0) {
337 if (msg_add_distinguished_name(msg
) != 0) {
343 for (i
= 0; i
< msg
->num_elements
; i
++) {
346 for (j
= 0, found
= 0; attrs
[j
]; j
++) {
347 if (ldb_attr_cmp(msg
->elements
[i
].name
, attrs
[j
]) == 0) {
354 ldb_msg_remove_attr(msg
, msg
->elements
[i
].name
);
363 search function for a non-indexed search
365 static int search_func(struct tdb_context
*tdb
, TDB_DATA key
, TDB_DATA data
, void *state
)
367 struct ldb_handle
*handle
= talloc_get_type(state
, struct ldb_handle
);
368 struct ltdb_context
*ac
= talloc_get_type(handle
->private_data
, struct ltdb_context
);
369 struct ldb_reply
*ares
= NULL
;
373 strncmp((char *)key
.dptr
, "DN=", 3) != 0) {
377 ares
= talloc_zero(ac
, struct ldb_reply
);
379 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
380 handle
->state
= LDB_ASYNC_DONE
;
384 ares
->message
= ldb_msg_new(ares
);
385 if (!ares
->message
) {
386 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
387 handle
->state
= LDB_ASYNC_DONE
;
392 /* unpack the record */
393 ret
= ltdb_unpack_data(ac
->module
, &data
, ares
->message
);
399 if (!ares
->message
->dn
) {
400 ares
->message
->dn
= ldb_dn_explode(ares
->message
, (char *)key
.dptr
+ 3);
401 if (ares
->message
->dn
== NULL
) {
402 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
403 handle
->state
= LDB_ASYNC_DONE
;
409 /* see if it matches the given expression */
410 if (!ldb_match_msg(ac
->module
->ldb
, ares
->message
, ac
->tree
,
411 ac
->base
, ac
->scope
)) {
416 /* filter the attributes that the user wants */
417 ret
= ltdb_filter_attrs(ares
->message
, ac
->attrs
);
420 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
421 handle
->state
= LDB_ASYNC_DONE
;
426 ares
->type
= LDB_REPLY_ENTRY
;
427 handle
->state
= LDB_ASYNC_PENDING
;
428 handle
->status
= ac
->callback(ac
->module
->ldb
, ac
->context
, ares
);
430 if (handle
->status
!= LDB_SUCCESS
) {
431 /* don't try to free ares here, the callback is in charge of that */
440 search the database with a LDAP-like expression.
441 this is the "full search" non-indexed variant
443 static int ltdb_search_full(struct ldb_handle
*handle
)
445 struct ltdb_context
*ac
= talloc_get_type(handle
->private_data
, struct ltdb_context
);
446 struct ltdb_private
*ltdb
= talloc_get_type(ac
->module
->private_data
, struct ltdb_private
);
449 ret
= tdb_traverse_read(ltdb
->tdb
, search_func
, handle
);
452 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
455 handle
->state
= LDB_ASYNC_DONE
;
460 search the database with a LDAP-like expression.
461 choses a search method
463 int ltdb_search(struct ldb_module
*module
, struct ldb_request
*req
)
465 struct ltdb_private
*ltdb
= talloc_get_type(module
->private_data
, struct ltdb_private
);
466 struct ltdb_context
*ltdb_ac
;
467 struct ldb_reply
*ares
;
470 if ((req
->op
.search
.base
== NULL
|| ldb_dn_get_comp_num(req
->op
.search
.base
) == 0) &&
471 (req
->op
.search
.scope
== LDB_SCOPE_BASE
|| req
->op
.search
.scope
== LDB_SCOPE_ONELEVEL
))
472 return LDB_ERR_OPERATIONS_ERROR
;
474 if (ltdb_lock_read(module
) != 0) {
475 return LDB_ERR_OPERATIONS_ERROR
;
478 if (ltdb_cache_load(module
) != 0) {
479 ltdb_unlock_read(module
);
480 return LDB_ERR_OPERATIONS_ERROR
;
483 if (req
->op
.search
.tree
== NULL
) {
484 ltdb_unlock_read(module
);
485 return LDB_ERR_OPERATIONS_ERROR
;
488 req
->handle
= init_ltdb_handle(ltdb
, module
, req
);
489 if (req
->handle
== NULL
) {
490 ltdb_unlock_read(module
);
491 return LDB_ERR_OPERATIONS_ERROR
;
493 ltdb_ac
= talloc_get_type(req
->handle
->private_data
, struct ltdb_context
);
495 ltdb_ac
->tree
= req
->op
.search
.tree
;
496 ltdb_ac
->scope
= req
->op
.search
.scope
;
497 ltdb_ac
->base
= req
->op
.search
.base
;
498 ltdb_ac
->attrs
= req
->op
.search
.attrs
;
500 ret
= ltdb_search_indexed(req
->handle
);
502 ret
= ltdb_search_full(req
->handle
);
504 if (ret
!= LDB_SUCCESS
) {
505 ldb_set_errstring(module
->ldb
, "Indexed and full searches both failed!\n");
506 req
->handle
->state
= LDB_ASYNC_DONE
;
507 req
->handle
->status
= ret
;
510 /* Finally send an LDB_REPLY_DONE packet when searching is finished */
512 ares
= talloc_zero(req
, struct ldb_reply
);
514 ltdb_unlock_read(module
);
515 return LDB_ERR_OPERATIONS_ERROR
;
518 req
->handle
->state
= LDB_ASYNC_DONE
;
519 ares
->type
= LDB_REPLY_DONE
;
521 ret
= req
->callback(module
->ldb
, req
->context
, ares
);
522 req
->handle
->status
= ret
;
524 ltdb_unlock_read(module
);