r10305: start implementing better error handling
[metze/samba/wip.git] / source4 / lib / ldb / ldb_tdb / ldb_search.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Tridgell  2004
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9    
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.
14
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.
19
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
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldb search functions
29  *
30  *  Description: functions to search ldb+tdb databases
31  *
32  *  Author: Andrew Tridgell
33  */
34
35 #include "includes.h"
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_errors.h"
38 #include "ldb/include/ldb_private.h"
39 #include "ldb/ldb_tdb/ldb_tdb.h"
40
41 /*
42   add one element to a message
43 */
44 static int msg_add_element(struct ldb_context *ldb, 
45                            struct ldb_message *ret, const struct ldb_message_element *el)
46 {
47         unsigned int i;
48         struct ldb_message_element *e2, *elnew;
49
50         e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1);
51         if (!e2) {
52                 return -1;
53         }
54         ret->elements = e2;
55         
56         elnew = &e2[ret->num_elements];
57
58         elnew->name = talloc_strdup(ret->elements, el->name);
59         if (!elnew->name) {
60                 return -1;
61         }
62
63         if (el->num_values) {
64                 elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values);
65                 if (!elnew->values) {
66                         return -1;
67                 }
68         } else {
69                 elnew->values = NULL;
70         }
71
72         for (i=0;i<el->num_values;i++) {
73                 elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]);
74                 if (elnew->values[i].length != el->values[i].length) {
75                         return -1;
76                 }
77         }
78
79         elnew->num_values = el->num_values;
80
81         ret->num_elements++;
82
83         return 0;
84 }
85
86 /*
87   add all elements from one message into another
88  */
89 static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret,
90                                 const struct ldb_message *msg)
91 {
92         struct ldb_context *ldb = module->ldb;
93         unsigned int i;
94
95         for (i=0;i<msg->num_elements;i++) {
96                 const struct ldb_attrib_handler *h;
97                 h = ldb_attrib_handler(ldb, msg->elements[i].name);
98                 if (ldb_dn_is_special(msg->dn) && (h->flags & LDB_ATTR_FLAG_HIDDEN)) {
99                         continue;
100                 }
101                 if (msg_add_element(ldb, ret, &msg->elements[i]) != 0) {
102                         return -1;
103                 }
104         }
105
106         return 0;
107 }
108
109
110 /*
111   pull the specified list of attributes from a message
112  */
113 static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module, 
114                                            const struct ldb_message *msg, 
115                                            const char * const *attrs)
116 {
117         struct ldb_context *ldb = module->ldb;
118         struct ldb_message *ret;
119         int i;
120
121         ret = talloc(ldb, struct ldb_message);
122         if (!ret) {
123                 return NULL;
124         }
125
126         ret->dn = ldb_dn_copy(ret, msg->dn);
127         if (!ret->dn) {
128                 talloc_free(ret);
129                 return NULL;
130         }
131
132         ret->num_elements = 0;
133         ret->elements = NULL;
134
135         if (!attrs) {
136                 if (msg_add_all_elements(module, ret, msg) != 0) {
137                         talloc_free(ret);
138                         return NULL;
139                 }
140                 return ret;
141         }
142
143         for (i=0;attrs[i];i++) {
144                 struct ldb_message_element *el;
145
146                 if (strcmp(attrs[i], "*") == 0) {
147                         if (msg_add_all_elements(module, ret, msg) != 0) {
148                                 talloc_free(ret);
149                                 return NULL;
150                         }
151                         continue;
152                 }
153
154                 if (ldb_attr_cmp(attrs[i], "dn") == 0 ||
155                     ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
156                         struct ldb_message_element el2;
157                         struct ldb_val val;
158
159                         el2.flags = 0;
160                         el2.name = talloc_strdup(ret, attrs[i]);
161                         if (!el2.name) {
162                                 talloc_free(ret);
163                                 return NULL;                            
164                         }
165                         el2.num_values = 1;
166                         el2.values = &val;
167                         val.data = ldb_dn_linearize(ret, ret->dn);
168                         val.length = strlen(val.data);
169
170                         if (msg_add_element(ldb, ret, &el2) != 0) {
171                                 talloc_free(ret);
172                                 return NULL;                            
173                         }
174                         talloc_free(discard_const_p(char, el2.name));
175                         continue;
176                 }
177
178                 el = ldb_msg_find_element(msg, attrs[i]);
179                 if (!el) {
180                         continue;
181                 }
182                 if (msg_add_element(ldb, ret, el) != 0) {
183                         talloc_free(ret);
184                         return NULL;                            
185                 }
186         }
187
188         return ret;
189 }
190
191
192 /*
193   search the database for a single simple dn, returning all attributes
194   in a single message
195
196   return 1 on success, 0 on record-not-found and -1 on error
197 */
198 int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct ldb_message *msg)
199 {
200         struct ltdb_private *ltdb = module->private_data;
201         int ret;
202         TDB_DATA tdb_key, tdb_data, tdb_data2;
203
204         memset(msg, 0, sizeof(*msg));
205
206         /* form the key */
207         tdb_key = ltdb_key(module, dn);
208         if (!tdb_key.dptr) {
209                 return -1;
210         }
211
212         tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
213         talloc_free(tdb_key.dptr);
214         if (!tdb_data.dptr) {
215                 return 0;
216         }
217
218         tdb_data2.dptr = talloc_memdup(msg, tdb_data.dptr, tdb_data.dsize);
219         free(tdb_data.dptr);
220         if (!tdb_data2.dptr) {
221                 return -1;
222         }
223         tdb_data2.dsize = tdb_data.dsize;
224
225         msg->num_elements = 0;
226         msg->elements = NULL;
227
228         ret = ltdb_unpack_data(module, &tdb_data2, msg);
229         if (ret == -1) {
230                 talloc_free(tdb_data2.dptr);
231                 return -1;              
232         }
233
234         if (!msg->dn) {
235                 msg->dn = ldb_dn_copy(tdb_data2.dptr, dn);
236         }
237         if (!msg->dn) {
238                 talloc_free(tdb_data2.dptr);
239                 return -1;
240         }
241
242         return 1;
243 }
244
245
246 /*
247   search the database for a single simple dn
248 */
249 static int ltdb_search_dn(struct ldb_module *module, const struct ldb_dn *dn,
250                           const char * const attrs[], struct ldb_message ***res)
251 {
252         struct ldb_context *ldb = module->ldb;
253         int ret;
254         struct ldb_message *msg, *msg2;
255
256         *res = NULL;
257
258         if (ltdb_lock_read(module) != 0) {
259                 return -1;
260         }
261
262         if (ltdb_cache_load(module) != 0) {
263                 ltdb_unlock_read(module);
264                 return -1;
265         }
266
267         *res = talloc_array(ldb, struct ldb_message *, 2);
268         if (! *res) {
269                 goto failed;
270         }
271
272         msg = talloc(*res, struct ldb_message);
273         if (msg == NULL) {
274                 goto failed;
275         }
276
277         ret = ltdb_search_dn1(module, dn, msg);
278         if (ret != 1) {
279                 talloc_free(*res);
280                 *res = NULL;
281                 ltdb_unlock_read(module);
282                 return 0;
283         }
284
285         msg2 = ltdb_pull_attrs(module, msg, attrs);
286
287         talloc_free(msg);
288         if (!msg2) {
289                 goto failed;
290         }
291
292         (*res)[0] = talloc_steal(*res, msg2);
293         (*res)[1] = NULL;
294
295         ltdb_unlock_read(module);
296
297         return 1;
298
299 failed:
300         talloc_free(*res);
301         ltdb_unlock_read(module);
302         return -1;
303 }
304
305
306 /*
307   add a set of attributes from a record to a set of results
308   return 0 on success, -1 on failure
309 */
310 int ltdb_add_attr_results(struct ldb_module *module, struct ldb_message *msg,
311                           const char * const attrs[], 
312                           int *count, 
313                           struct ldb_message ***res)
314 {
315         struct ldb_context *ldb = module->ldb;
316         struct ldb_message *msg2;
317         struct ldb_message **res2;
318
319         /* pull the attributes that the user wants */
320         msg2 = ltdb_pull_attrs(module, msg, attrs);
321         if (!msg2) {
322                 return -1;
323         }
324
325         /* add to the results list */
326         res2 = talloc_realloc(ldb, *res, struct ldb_message *, (*count)+2);
327         if (!res2) {
328                 talloc_free(msg2);
329                 return -1;
330         }
331
332         (*res) = res2;
333
334         (*res)[*count] = talloc_steal(*res, msg2);
335         (*res)[(*count)+1] = NULL;
336         (*count)++;
337
338         return 0;
339 }
340
341
342 /*
343   internal search state during a full db search
344 */
345 struct ltdb_search_info {
346         struct ldb_module *module;
347         struct ldb_parse_tree *tree;
348         const struct ldb_dn *base;
349         enum ldb_scope scope;
350         const char * const *attrs;
351         struct ldb_message **msgs;
352         int failures;
353         int count;
354 };
355
356
357 /*
358   search function for a non-indexed search
359  */
360 static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
361 {
362         struct ltdb_search_info *sinfo = state;
363         struct ldb_message *msg;
364         int ret;
365
366         if (key.dsize < 4 || 
367             strncmp(key.dptr, "DN=", 3) != 0) {
368                 return 0;
369         }
370
371         msg = talloc(sinfo, struct ldb_message);
372         if (msg == NULL) {
373                 return -1;
374         }
375
376         /* unpack the record */
377         ret = ltdb_unpack_data(sinfo->module, &data, msg);
378         if (ret == -1) {
379                 sinfo->failures++;
380                 talloc_free(msg);
381                 return 0;
382         }
383
384         if (!msg->dn) {
385                 msg->dn = ldb_dn_explode(msg, key.dptr + 3);
386                 if (msg->dn == NULL) {
387                         talloc_free(msg);
388                         return -1;
389                 }
390         }
391
392         /* see if it matches the given expression */
393         if (!ldb_match_msg(sinfo->module->ldb, msg, sinfo->tree, 
394                                sinfo->base, sinfo->scope)) {
395                 talloc_free(msg);
396                 return 0;
397         }
398
399         ret = ltdb_add_attr_results(sinfo->module, msg, sinfo->attrs, &sinfo->count, &sinfo->msgs);
400
401         if (ret == -1) {
402                 sinfo->failures++;
403         }
404
405         talloc_free(msg);
406
407         return ret;
408 }
409
410
411 /*
412   search the database with a LDAP-like expression.
413   this is the "full search" non-indexed variant
414 */
415 static int ltdb_search_full(struct ldb_module *module, 
416                             const struct ldb_dn *base,
417                             enum ldb_scope scope,
418                             struct ldb_parse_tree *tree,
419                             const char * const attrs[], struct ldb_message ***res)
420 {
421         struct ltdb_private *ltdb = module->private_data;
422         int ret, count;
423         struct ltdb_search_info *sinfo;
424
425         sinfo = talloc(ltdb, struct ltdb_search_info);
426         if (sinfo == NULL) {
427                 return -1;
428         }
429
430         sinfo->tree = tree;
431         sinfo->module = module;
432         sinfo->scope = scope;
433         sinfo->base = base;
434         sinfo->attrs = attrs;
435         sinfo->msgs = NULL;
436         sinfo->count = 0;
437         sinfo->failures = 0;
438
439         ret = tdb_traverse(ltdb->tdb, search_func, sinfo);
440
441         if (ret == -1) {
442                 talloc_free(sinfo);
443                 return -1;
444         }
445
446         *res = talloc_steal(ltdb, sinfo->msgs);
447         count = sinfo->count;
448
449         talloc_free(sinfo);
450
451         return count;
452 }
453
454
455 /*
456   search the database with a LDAP-like expression.
457   choses a search method
458 */
459 int ltdb_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
460                        enum ldb_scope scope, struct ldb_parse_tree *tree,
461                        const char * const attrs[], struct ldb_message ***res)
462 {
463         int ret;
464
465         if ((base == NULL || base->comp_num == 0) &&
466             (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) return -1;
467
468         /* it is important that we handle dn queries this way, and not
469            via a full db search, otherwise ldb is horribly slow */
470         if (tree->operation == LDB_OP_EQUALITY &&
471             (ldb_attr_cmp(tree->u.equality.attr, "dn") == 0 ||
472              ldb_attr_cmp(tree->u.equality.attr, "distinguishedName") == 0)) {
473                 struct ldb_dn *dn;
474                 dn = ldb_dn_explode(module->ldb, tree->u.equality.value.data);
475                 if (dn == NULL) {
476                         return LDB_ERR_INVALID_DN_SYNTAX;
477                 }
478                 ret = ltdb_search_dn(module, dn, attrs, res);
479                 talloc_free(dn);
480                 return ret;
481         }
482
483         if (ltdb_lock_read(module) != 0) {
484                 return -1;
485         }
486
487         if (ltdb_cache_load(module) != 0) {
488                 ltdb_unlock_read(module);
489                 return -1;
490         }
491
492         *res = NULL;
493
494         ret = ltdb_search_indexed(module, base, scope, tree, attrs, res);
495         if (ret == -1) {
496                 ret = ltdb_search_full(module, base, scope, tree, attrs, res);
497         }
498
499         ltdb_unlock_read(module);
500
501         return ret;
502 }
503
504
505 /*
506   search the database with a LDAP-like expression.
507   choses a search method
508 */
509 int ltdb_search(struct ldb_module *module, const struct ldb_dn *base,
510                 enum ldb_scope scope, const char *expression,
511                 const char * const attrs[], struct ldb_message ***res)
512 {
513         struct ltdb_private *ltdb = module->private_data;
514         struct ldb_parse_tree *tree;
515         int ret;
516
517         if ((base == NULL || base->comp_num == 0) &&
518             (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) return -1;
519
520         /* check if we are looking for a simple dn */
521         if (scope == LDB_SCOPE_BASE && (expression == NULL || expression[0] == '\0')) {
522                 ret = ltdb_search_dn(module, base, attrs, res);
523                 return ret;
524         }
525
526         tree = ldb_parse_tree(ltdb, expression);
527         if (tree == NULL) {
528                 char *err_string = talloc_strdup(module, "expression parse failed");
529                 if (err_string) ldb_set_errstring(module, err_string);
530                 return -1;
531         }
532
533         ret = ltdb_search_bytree(module, base, scope, tree, attrs, res);
534         talloc_free(tree);
535         return ret;
536 }
537