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