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
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 for (j
=0;j
<msg
->elements
[i
].num_values
;j
++) {
48 if (msg
->elements
[i
].values
[j
].data
)
49 free(msg
->elements
[i
].values
[j
].data
);
51 if (msg
->elements
[i
].values
) free(msg
->elements
[i
].values
);
59 TODO: this should take advantage of the sorted nature of the message
61 return index of the attribute, or -1 if not found
63 int ldb_msg_find_attr(const struct ldb_message
*msg
, const char *attr
)
66 for (i
=0;i
<msg
->num_elements
;i
++) {
67 if (strcmp(msg
->elements
[i
].name
, attr
) == 0) {
75 duplicate a ldb_val structure
77 struct ldb_val
ldb_val_dup(const struct ldb_val
*v
)
80 v2
.length
= v
->length
;
86 /* the +1 is to cope with buggy C library routines like strndup
87 that look one byte beyond */
88 v2
.data
= malloc(v
->length
+1);
94 memcpy(v2
.data
, v
->data
, v
->length
);
95 ((char *)v2
.data
)[v
->length
] = 0;
102 add one element to a message
104 static int msg_add_element(struct ldb_message
*ret
, const struct ldb_message_element
*el
)
107 struct ldb_message_element
*e2
, *elnew
;
109 e2
= realloc_p(ret
->elements
, struct ldb_message_element
, ret
->num_elements
+1);
115 elnew
= &e2
[ret
->num_elements
];
117 elnew
->name
= strdup(el
->name
);
122 if (el
->num_values
) {
123 elnew
->values
= malloc_array_p(struct ldb_val
, el
->num_values
);
124 if (!elnew
->values
) {
128 elnew
->values
= NULL
;
131 for (i
=0;i
<el
->num_values
;i
++) {
132 elnew
->values
[i
] = ldb_val_dup(&el
->values
[i
]);
133 if (elnew
->values
[i
].length
!= el
->values
[i
].length
) {
138 elnew
->num_values
= el
->num_values
;
146 add all elements from one message into another
148 static int msg_add_all_elements(struct ldb_message
*ret
,
149 const struct ldb_message
*msg
)
152 for (i
=0;i
<msg
->num_elements
;i
++) {
153 if (msg_add_element(ret
, &msg
->elements
[i
]) != 0) {
163 pull the specified list of attributes from a message
165 static struct ldb_message
*ltdb_pull_attrs(struct ldb_context
*ldb
,
166 const struct ldb_message
*msg
,
169 struct ldb_message
*ret
;
172 ret
= malloc_p(struct ldb_message
);
177 ret
->dn
= strdup(msg
->dn
);
183 ret
->num_elements
= 0;
184 ret
->elements
= NULL
;
188 if (msg_add_all_elements(ret
, msg
) != 0) {
189 msg_free_all_parts(ret
);
195 for (i
=0;attrs
[i
];i
++) {
198 if (strcmp(attrs
[i
], "*") == 0) {
199 if (msg_add_all_elements(ret
, msg
) != 0) {
200 msg_free_all_parts(ret
);
205 j
= ldb_msg_find_attr(msg
, attrs
[i
]);
210 if (msg_add_element(ret
, &msg
->elements
[j
]) != 0) {
211 msg_free_all_parts(ret
);
214 } while (++j
< msg
->num_elements
&&
215 strcmp(attrs
[i
], msg
->elements
[j
].name
) == 0);
224 see if a ldb_val is a wildcard
226 int ltdb_has_wildcard(const struct ldb_val
*val
)
228 if (val
->length
== 1 && ((char *)val
->data
)[0] == '*') {
236 free the results of a ltdb_search_dn1 search
238 void ltdb_search_dn1_free(struct ldb_context
*ldb
, struct ldb_message
*msg
)
241 if (msg
->dn
) free(msg
->dn
);
242 if (msg
->private) free(msg
->private);
243 for (i
=0;i
<msg
->num_elements
;i
++) {
244 if (msg
->elements
[i
].values
) free(msg
->elements
[i
].values
);
246 if (msg
->elements
) free(msg
->elements
);
251 search the database for a single simple dn, returning all attributes
254 return 1 on success, 0 on record-not-found and -1 on error
256 int ltdb_search_dn1(struct ldb_context
*ldb
, const char *dn
, struct ldb_message
*msg
)
258 struct ltdb_private
*ltdb
= ldb
->private;
260 TDB_DATA tdb_key
, tdb_data
;
263 tdb_key
= ltdb_key(dn
);
268 tdb_data
= tdb_fetch(ltdb
->tdb
, tdb_key
);
270 if (!tdb_data
.dptr
) {
274 msg
->dn
= strdup(dn
);
279 msg
->private = tdb_data
.dptr
;
280 msg
->num_elements
= 0;
281 msg
->elements
= NULL
;
283 ret
= ltdb_unpack_data(ldb
, &tdb_data
, msg
);
294 search the database for a single simple dn
296 int ltdb_search_dn(struct ldb_context
*ldb
, char *dn
,
297 const char *attrs
[], struct ldb_message
***res
)
300 struct ldb_message msg
, *msg2
;
302 ret
= ltdb_search_dn1(ldb
, dn
, &msg
);
307 msg2
= ltdb_pull_attrs(ldb
, &msg
, attrs
);
309 ltdb_search_dn1_free(ldb
, &msg
);
315 *res
= malloc_array_p(struct ldb_message
*, 2);
317 msg_free_all_parts(msg2
);
329 add a set of attributes from a record to a set of results
330 return 0 on success, -1 on failure
332 int ltdb_add_attr_results(struct ldb_context
*ldb
, struct ldb_message
*msg
,
335 struct ldb_message
***res
)
337 struct ldb_message
*msg2
;
338 struct ldb_message
**res2
;
340 /* pull the attributes that the user wants */
341 msg2
= ltdb_pull_attrs(ldb
, msg
, attrs
);
346 /* add to the results list */
347 res2
= realloc_p(*res
, struct ldb_message
*, (*count
)+2);
349 msg_free_all_parts(msg2
);
355 (*res
)[*count
] = msg2
;
356 (*res
)[(*count
)+1] = NULL
;
364 internal search state during a full db search
366 struct ltdb_search_info
{
367 struct ldb_context
*ldb
;
368 struct ldb_parse_tree
*tree
;
370 enum ldb_scope scope
;
372 struct ldb_message
**msgs
;
379 search function for a non-indexed search
381 static int search_func(struct tdb_context
*tdb
, TDB_DATA key
, TDB_DATA data
, void *state
)
383 struct ltdb_search_info
*sinfo
= state
;
384 struct ldb_message msg
;
388 strncmp(key
.dptr
, "DN=", 3) != 0) {
392 msg
.dn
= key
.dptr
+ 3;
394 /* unpack the record */
395 ret
= ltdb_unpack_data(sinfo
->ldb
, &data
, &msg
);
401 /* see if it matches the given expression */
402 if (!ldb_message_match(sinfo
->ldb
, &msg
, sinfo
->tree
,
403 sinfo
->base
, sinfo
->scope
)) {
404 ltdb_unpack_data_free(&msg
);
408 ret
= ltdb_add_attr_results(sinfo
->ldb
, &msg
, sinfo
->attrs
, &sinfo
->count
, &sinfo
->msgs
);
414 ltdb_unpack_data_free(&msg
);
421 free a set of search results
423 int ltdb_search_free(struct ldb_context
*ldb
, struct ldb_message
**msgs
)
429 for (i
=0;msgs
[i
];i
++) {
430 msg_free_all_parts(msgs
[i
]);
439 search the database with a LDAP-like expression.
440 this is the "full search" non-indexed varient
442 static int ltdb_search_full(struct ldb_context
*ldb
,
444 enum ldb_scope scope
,
445 struct ldb_parse_tree
*tree
,
446 const char *attrs
[], struct ldb_message
***res
)
448 struct ltdb_private
*ltdb
= ldb
->private;
450 struct ltdb_search_info sinfo
;
461 ret
= tdb_traverse(ltdb
->tdb
, search_func
, &sinfo
);
464 ltdb_search_free(ldb
, sinfo
.msgs
);
474 search the database with a LDAP-like expression.
475 choses a search method
477 int ltdb_search(struct ldb_context
*ldb
, const char *base
,
478 enum ldb_scope scope
, const char *expression
,
479 const char *attrs
[], struct ldb_message
***res
)
481 struct ldb_parse_tree
*tree
;
486 /* form a parse tree for the expression */
487 tree
= ldb_parse_tree(expression
);
492 if (tree
->operation
== LDB_OP_SIMPLE
&&
493 strcmp(tree
->u
.simple
.attr
, "dn") == 0 &&
494 !ltdb_has_wildcard(&tree
->u
.simple
.value
)) {
495 /* yay! its a nice simple one */
496 ret
= ltdb_search_dn(ldb
, tree
->u
.simple
.value
.data
, attrs
, res
);
498 ret
= ltdb_search_indexed(ldb
, base
, scope
, tree
, attrs
, res
);
500 ret
= ltdb_search_full(ldb
, base
, scope
, tree
, attrs
, res
);
504 ldb_parse_tree_free(tree
);