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