4fb85103779eea50e81312cff3180c6d85e678cf
[obnox/samba/samba-obnox.git] / 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 3 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, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb search functions
28  *
29  *  Description: functions to search ldb+tdb databases
30  *
31  *  Author: Andrew Tridgell
32  */
33
34 #include "ldb_tdb.h"
35 #include <tdb.h>
36
37 /*
38   add one element to a message
39 */
40 static int msg_add_element(struct ldb_message *ret, 
41                            const struct ldb_message_element *el,
42                            int check_duplicates)
43 {
44         unsigned int i;
45         struct ldb_message_element *e2, *elnew;
46
47         if (check_duplicates && ldb_msg_find_element(ret, el->name)) {
48                 /* its already there */
49                 return 0;
50         }
51
52         e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1);
53         if (!e2) {
54                 return -1;
55         }
56         ret->elements = e2;
57         
58         elnew = &e2[ret->num_elements];
59
60         elnew->name = talloc_strdup(ret->elements, el->name);
61         if (!elnew->name) {
62                 return -1;
63         }
64
65         if (el->num_values) {
66                 elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values);
67                 if (!elnew->values) {
68                         return -1;
69                 }
70         } else {
71                 elnew->values = NULL;
72         }
73
74         for (i=0;i<el->num_values;i++) {
75                 elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]);
76                 if (elnew->values[i].length != el->values[i].length) {
77                         return -1;
78                 }
79         }
80
81         elnew->num_values = el->num_values;
82         elnew->flags = el->flags;
83
84         ret->num_elements++;
85
86         return 0;
87 }
88
89 /*
90   add the special distinguishedName element
91 */
92 static int msg_add_distinguished_name(struct ldb_message *msg)
93 {
94         struct ldb_message_element el;
95         struct ldb_val val;
96         int ret;
97
98         el.flags = 0;
99         el.name = "distinguishedName";
100         el.num_values = 1;
101         el.values = &val;
102         el.flags = 0;
103         val.data = (uint8_t *)ldb_dn_alloc_linearized(msg, msg->dn);
104         val.length = strlen((char *)val.data);
105         
106         ret = msg_add_element(msg, &el, 1);
107         return ret;
108 }
109
110 /*
111   add all elements from one message into another
112  */
113 static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret,
114                                 const struct ldb_message *msg)
115 {
116         struct ldb_context *ldb;
117         unsigned int i;
118         int check_duplicates = (ret->num_elements != 0);
119
120         ldb = ldb_module_get_ctx(module);
121
122         if (msg_add_distinguished_name(ret) != 0) {
123                 return -1;
124         }
125
126         for (i=0;i<msg->num_elements;i++) {
127                 const struct ldb_schema_attribute *a;
128                 a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
129                 if (a->flags & LDB_ATTR_FLAG_HIDDEN) {
130                         continue;
131                 }
132                 if (msg_add_element(ret, &msg->elements[i],
133                                     check_duplicates) != 0) {
134                         return -1;
135                 }
136         }
137
138         return 0;
139 }
140
141
142 /*
143   pull the specified list of attributes from a message
144  */
145 static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module, 
146                                            TALLOC_CTX *mem_ctx, 
147                                            const struct ldb_message *msg, 
148                                            const char * const *attrs)
149 {
150         struct ldb_message *ret;
151         unsigned int i;
152
153         ret = talloc(mem_ctx, struct ldb_message);
154         if (!ret) {
155                 return NULL;
156         }
157
158         ret->dn = ldb_dn_copy(ret, msg->dn);
159         if (!ret->dn) {
160                 talloc_free(ret);
161                 return NULL;
162         }
163
164         ret->num_elements = 0;
165         ret->elements = NULL;
166
167         if (!attrs) {
168                 if (msg_add_all_elements(module, ret, msg) != 0) {
169                         talloc_free(ret);
170                         return NULL;
171                 }
172                 return ret;
173         }
174
175         for (i=0;attrs[i];i++) {
176                 struct ldb_message_element *el;
177
178                 if (strcmp(attrs[i], "*") == 0) {
179                         if (msg_add_all_elements(module, ret, msg) != 0) {
180                                 talloc_free(ret);
181                                 return NULL;
182                         }
183                         continue;
184                 }
185
186                 if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
187                         if (msg_add_distinguished_name(ret) != 0) {
188                                 return NULL;
189                         }
190                         continue;
191                 }
192
193                 el = ldb_msg_find_element(msg, attrs[i]);
194                 if (!el) {
195                         continue;
196                 }
197                 if (msg_add_element(ret, el, 1) != 0) {
198                         talloc_free(ret);
199                         return NULL;                            
200                 }
201         }
202
203         return ret;
204 }
205
206 /*
207   search the database for a single simple dn.
208   return LDB_ERR_NO_SUCH_OBJECT on record-not-found
209   and LDB_SUCCESS on success
210 */
211 static int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn)
212 {
213         void *data = ldb_module_get_private(module);
214         struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
215         TDB_DATA tdb_key;
216         int exists;
217
218         if (ldb_dn_is_null(dn)) {
219                 return LDB_ERR_NO_SUCH_OBJECT;
220         }
221
222         /* form the key */
223         tdb_key = ltdb_key(module, dn);
224         if (!tdb_key.dptr) {
225                 return LDB_ERR_OPERATIONS_ERROR;
226         }
227
228         exists = tdb_exists(ltdb->tdb, tdb_key);
229         talloc_free(tdb_key.dptr);
230                 
231         if (exists) {
232                 return LDB_SUCCESS;
233         }
234         return LDB_ERR_NO_SUCH_OBJECT;
235 }
236
237 struct ltdb_parse_data_unpack_ctx {
238         struct ldb_message *msg;
239         struct ldb_module *module;
240 };
241
242 static int ltdb_parse_data_unpack(TDB_DATA key, TDB_DATA data,
243                                   void *private_data)
244 {
245         struct ltdb_parse_data_unpack_ctx *ctx = private_data;
246
247         struct ldb_context *ldb = ldb_module_get_ctx(ctx->module);
248         int ret = ltdb_unpack_data(ldb, &data, ctx->msg);
249         if (ret == -1) {
250                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid data for index %*.*s\n",
251                           (int)key.dsize, (int)key.dsize, key.dptr);
252                 return LDB_ERR_OPERATIONS_ERROR;                
253         }
254         return ret;
255 }
256
257 /*
258   search the database for a single simple dn, returning all attributes
259   in a single message
260
261   return LDB_ERR_NO_SUCH_OBJECT on record-not-found
262   and LDB_SUCCESS on success
263 */
264 int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg)
265 {
266         void *data = ldb_module_get_private(module);
267         struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
268         int ret;
269         TDB_DATA tdb_key;
270         struct ltdb_parse_data_unpack_ctx ctx = {
271                 .msg = msg,
272                 .module = module
273         };
274
275         /* form the key */
276         tdb_key = ltdb_key(module, dn);
277         if (!tdb_key.dptr) {
278                 return LDB_ERR_OPERATIONS_ERROR;
279         }
280
281         memset(msg, 0, sizeof(*msg));
282
283         msg->num_elements = 0;
284         msg->elements = NULL;
285
286         ret = tdb_parse_record(ltdb->tdb, tdb_key, 
287                                ltdb_parse_data_unpack, &ctx); 
288         talloc_free(tdb_key.dptr);
289         
290         if (ret == -1) {
291                 if (tdb_error(ltdb->tdb) == TDB_ERR_NOEXIST) {
292                         return LDB_ERR_NO_SUCH_OBJECT;
293                 }
294                 return LDB_ERR_OPERATIONS_ERROR;
295         } else if (ret != LDB_SUCCESS) {
296                 return ret;
297         }
298         
299         if (!msg->dn) {
300                 msg->dn = ldb_dn_copy(msg, dn);
301         }
302         if (!msg->dn) {
303                 return LDB_ERR_OPERATIONS_ERROR;
304         }
305
306         return LDB_SUCCESS;
307 }
308
309 /*
310   add a set of attributes from a record to a set of results
311   return 0 on success, -1 on failure
312 */
313 int ltdb_add_attr_results(struct ldb_module *module, 
314                           TALLOC_CTX *mem_ctx, 
315                           struct ldb_message *msg,
316                           const char * const attrs[], 
317                           unsigned int *count, 
318                           struct ldb_message ***res)
319 {
320         struct ldb_message *msg2;
321         struct ldb_message **res2;
322
323         /* pull the attributes that the user wants */
324         msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs);
325         if (!msg2) {
326                 return -1;
327         }
328
329         /* add to the results list */
330         res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2);
331         if (!res2) {
332                 talloc_free(msg2);
333                 return -1;
334         }
335
336         (*res) = res2;
337
338         (*res)[*count] = talloc_move(*res, &msg2);
339         (*res)[(*count)+1] = NULL;
340         (*count)++;
341
342         return 0;
343 }
344
345
346
347 /*
348   filter the specified list of attributes from a message
349   removing not requested attrs.
350  */
351 int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
352 {
353         unsigned int i;
354         int keep_all = 0;
355         struct ldb_message_element *el2;
356         uint32_t num_elements;
357
358         if (attrs) {
359                 /* check for special attrs */
360                 for (i = 0; attrs[i]; i++) {
361                         if (strcmp(attrs[i], "*") == 0) {
362                                 keep_all = 1;
363                                 break;
364                         }
365
366                         if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
367                                 if (msg_add_distinguished_name(msg) != 0) {
368                                         return -1;
369                                 }
370                         }
371                 }
372         } else {
373                 keep_all = 1;
374         }
375         
376         if (keep_all) {
377                 if (msg_add_distinguished_name(msg) != 0) {
378                         return -1;
379                 }
380                 return 0;
381         }
382
383         el2 = talloc_array(msg, struct ldb_message_element, msg->num_elements);
384         if (el2 == NULL) {
385                 return -1;
386         }
387         num_elements = 0;
388
389         for (i = 0; i < msg->num_elements; i++) {
390                 unsigned int j;
391                 int found = 0;
392                 
393                 for (j = 0; attrs[j]; j++) {
394                         if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) {
395                                 found = 1;
396                                 break;
397                         }
398                 }
399
400                 if (found) {
401                         el2[num_elements] = msg->elements[i];
402                         talloc_steal(el2, el2[num_elements].name);
403                         talloc_steal(el2, el2[num_elements].values);
404                         num_elements++;
405                 }
406         }
407
408         talloc_free(msg->elements);
409         msg->elements = talloc_realloc(msg, el2, struct ldb_message_element, msg->num_elements);
410         if (msg->elements == NULL) {
411                 return -1;
412         }
413         msg->num_elements = num_elements;
414
415         return 0;
416 }
417
418 /*
419   search function for a non-indexed search
420  */
421 static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
422 {
423         struct ldb_context *ldb;
424         struct ltdb_context *ac;
425         struct ldb_message *msg;
426         int ret;
427         bool matched;
428
429         ac = talloc_get_type(state, struct ltdb_context);
430         ldb = ldb_module_get_ctx(ac->module);
431
432         if (key.dsize < 4 || 
433             strncmp((char *)key.dptr, "DN=", 3) != 0) {
434                 return 0;
435         }
436
437         msg = ldb_msg_new(ac);
438         if (!msg) {
439                 return -1;
440         }
441
442         /* unpack the record */
443         ret = ltdb_unpack_data(ldb, &data, msg);
444         if (ret == -1) {
445                 talloc_free(msg);
446                 return -1;
447         }
448
449         if (!msg->dn) {
450                 msg->dn = ldb_dn_new(msg, ldb,
451                                      (char *)key.dptr + 3);
452                 if (msg->dn == NULL) {
453                         talloc_free(msg);
454                         return -1;
455                 }
456         }
457
458         /* see if it matches the given expression */
459         ret = ldb_match_msg_error(ldb, msg,
460                                   ac->tree, ac->base, ac->scope, &matched);
461         if (ret != LDB_SUCCESS) {
462                 talloc_free(msg);
463                 return -1;
464         }
465         if (!matched) {
466                 talloc_free(msg);
467                 return 0;
468         }
469
470         /* filter the attributes that the user wants */
471         ret = ltdb_filter_attrs(msg, ac->attrs);
472
473         if (ret == -1) {
474                 talloc_free(msg);
475                 return -1;
476         }
477
478         ret = ldb_module_send_entry(ac->req, msg, NULL);
479         if (ret != LDB_SUCCESS) {
480                 ac->request_terminated = true;
481                 /* the callback failed, abort the operation */
482                 return -1;
483         }
484
485         return 0;
486 }
487
488
489 /*
490   search the database with a LDAP-like expression.
491   this is the "full search" non-indexed variant
492 */
493 static int ltdb_search_full(struct ltdb_context *ctx)
494 {
495         void *data = ldb_module_get_private(ctx->module);
496         struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
497         int ret;
498
499         if (ltdb->in_transaction != 0) {
500                 ret = tdb_traverse(ltdb->tdb, search_func, ctx);
501         } else {
502                 ret = tdb_traverse_read(ltdb->tdb, search_func, ctx);
503         }
504
505         if (ret < 0) {
506                 return LDB_ERR_OPERATIONS_ERROR;
507         }
508
509         return LDB_SUCCESS;
510 }
511
512 /*
513   search the database with a LDAP-like expression.
514   choses a search method
515 */
516 int ltdb_search(struct ltdb_context *ctx)
517 {
518         struct ldb_context *ldb;
519         struct ldb_module *module = ctx->module;
520         struct ldb_request *req = ctx->req;
521         void *data = ldb_module_get_private(module);
522         struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
523         int ret;
524
525         ldb = ldb_module_get_ctx(module);
526
527         ldb_request_set_state(req, LDB_ASYNC_PENDING);
528
529         if (ltdb_lock_read(module) != 0) {
530                 return LDB_ERR_OPERATIONS_ERROR;
531         }
532
533         if (ltdb_cache_load(module) != 0) {
534                 ltdb_unlock_read(module);
535                 return LDB_ERR_OPERATIONS_ERROR;
536         }
537
538         if (req->op.search.tree == NULL) {
539                 ltdb_unlock_read(module);
540                 return LDB_ERR_OPERATIONS_ERROR;
541         }
542
543         if ((req->op.search.base == NULL) || (ldb_dn_is_null(req->op.search.base) == true)) {
544
545                 /* Check what we should do with a NULL dn */
546                 switch (req->op.search.scope) {
547                 case LDB_SCOPE_BASE:
548                         ldb_asprintf_errstring(ldb, 
549                                                "NULL Base DN invalid for a base search");
550                         ret = LDB_ERR_INVALID_DN_SYNTAX;
551                         break;
552                 case LDB_SCOPE_ONELEVEL:
553                         ldb_asprintf_errstring(ldb, 
554                                                "NULL Base DN invalid for a one-level search");
555                         ret = LDB_ERR_INVALID_DN_SYNTAX;        
556                         break;
557                 case LDB_SCOPE_SUBTREE:
558                 default:
559                         /* We accept subtree searches from a NULL base DN, ie over the whole DB */
560                         ret = LDB_SUCCESS;
561                 }
562         } else if (ldb_dn_is_valid(req->op.search.base) == false) {
563
564                 /* We don't want invalid base DNs here */
565                 ldb_asprintf_errstring(ldb, 
566                                        "Invalid Base DN: %s", 
567                                        ldb_dn_get_linearized(req->op.search.base));
568                 ret = LDB_ERR_INVALID_DN_SYNTAX;
569
570         } else if (ltdb->check_base) {
571                 /* This database has been marked as 'checkBaseOnSearch', so do a spot check of the base dn */
572                 ret = ltdb_search_base(module, req->op.search.base);
573                 
574                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
575                         ldb_asprintf_errstring(ldb, 
576                                                "No such Base DN: %s", 
577                                                ldb_dn_get_linearized(req->op.search.base));
578                 }
579                         
580         } else {
581                 /* If we are not checking the base DN life is easy */
582                 ret = LDB_SUCCESS;
583         }
584
585         ctx->tree = req->op.search.tree;
586         ctx->scope = req->op.search.scope;
587         ctx->base = req->op.search.base;
588         ctx->attrs = req->op.search.attrs;
589
590         if (ret == LDB_SUCCESS) {
591                 uint32_t match_count = 0;
592
593                 ret = ltdb_search_indexed(ctx, &match_count);
594                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
595                         /* Not in the index, therefore OK! */
596                         ret = LDB_SUCCESS;
597                         
598                 }
599                 /* Check if we got just a normal error.
600                  * In that case proceed to a full search unless we got a
601                  * callback error */
602                 if ( ! ctx->request_terminated && ret != LDB_SUCCESS) {
603                         /* Not indexed, so we need to do a full scan */
604                         if (ltdb->warn_unindexed) {
605                                 /* useful for debugging when slow performance
606                                  * is caused by unindexed searches */
607                                 char *expression = ldb_filter_from_tree(ctx, ctx->tree);
608                                 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb FULL SEARCH: %s SCOPE: %s DN: %s\n",
609                                                         expression,
610                                                         req->op.search.scope==LDB_SCOPE_BASE?"base":
611                                                         req->op.search.scope==LDB_SCOPE_ONELEVEL?"one":
612                                                         req->op.search.scope==LDB_SCOPE_SUBTREE?"sub":"UNKNOWN",
613                                                         ldb_dn_get_linearized(req->op.search.base));
614
615                                 talloc_free(expression);
616                         }
617                         if (match_count != 0) {
618                                 /* the indexing code gave an error
619                                  * after having returned at least one
620                                  * entry. This means the indexes are
621                                  * corrupt or a database record is
622                                  * corrupt. We cannot continue with a
623                                  * full search or we may return
624                                  * duplicate entries
625                                  */
626                                 ltdb_unlock_read(module);
627                                 return LDB_ERR_OPERATIONS_ERROR;
628                         }
629                         ret = ltdb_search_full(ctx);
630                         if (ret != LDB_SUCCESS) {
631                                 ldb_set_errstring(ldb, "Indexed and full searches both failed!\n");
632                         }
633                 }
634         }
635
636         ltdb_unlock_read(module);
637
638         return ret;
639 }
640