da899c361edac6da084545fbbb3885daccce30f9
[kai/samba.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 ldb_handle *handle = talloc_get_type(state, struct ldb_handle);
399         struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
400         struct ldb_reply *ares = NULL;
401         int ret;
402
403         if (key.dsize < 4 || 
404             strncmp((char *)key.dptr, "DN=", 3) != 0) {
405                 return 0;
406         }
407
408         ares = talloc_zero(ac, struct ldb_reply);
409         if (!ares) {
410                 handle->status = LDB_ERR_OPERATIONS_ERROR;
411                 handle->state = LDB_ASYNC_DONE;
412                 return -1;
413         }
414
415         ares->message = ldb_msg_new(ares);
416         if (!ares->message) {
417                 handle->status = LDB_ERR_OPERATIONS_ERROR;
418                 handle->state = LDB_ASYNC_DONE;
419                 talloc_free(ares);
420                 return -1;
421         }
422
423         /* unpack the record */
424         ret = ltdb_unpack_data(ac->module, &data, ares->message);
425         if (ret == -1) {
426                 talloc_free(ares);
427                 return -1;
428         }
429
430         if (!ares->message->dn) {
431                 ares->message->dn = ldb_dn_new(ares->message, ac->module->ldb, (char *)key.dptr + 3);
432                 if (ares->message->dn == NULL) {
433                         handle->status = LDB_ERR_OPERATIONS_ERROR;
434                         handle->state = LDB_ASYNC_DONE;
435                         talloc_free(ares);
436                         return -1;
437                 }
438         }
439
440         /* see if it matches the given expression */
441         if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, 
442                                ac->base, ac->scope)) {
443                 talloc_free(ares);
444                 return 0;
445         }
446
447         /* filter the attributes that the user wants */
448         ret = ltdb_filter_attrs(ares->message, ac->attrs);
449
450         if (ret == -1) {
451                 handle->status = LDB_ERR_OPERATIONS_ERROR;
452                 handle->state = LDB_ASYNC_DONE;
453                 talloc_free(ares);
454                 return -1;
455         }
456
457         ares->type = LDB_REPLY_ENTRY;
458         handle->state = LDB_ASYNC_PENDING;
459         handle->status = ac->callback(ac->module->ldb, ac->context, ares);
460
461         if (handle->status != LDB_SUCCESS) {
462                 /* don't try to free ares here, the callback is in charge of that */
463                 return -1;
464         }       
465
466         return 0;
467 }
468
469
470 /*
471   search the database with a LDAP-like expression.
472   this is the "full search" non-indexed variant
473 */
474 static int ltdb_search_full(struct ldb_handle *handle)
475 {
476         struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
477         struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private);
478         int ret;
479
480         if (ltdb->in_transaction != 0) {
481                 ret = tdb_traverse(ltdb->tdb, search_func, handle);
482         } else {
483                 ret = tdb_traverse_read(ltdb->tdb, search_func, handle);
484         }
485
486         if (ret == -1) {
487                 handle->status = LDB_ERR_OPERATIONS_ERROR;
488         }
489
490         handle->state = LDB_ASYNC_DONE;
491         return LDB_SUCCESS;
492 }
493
494 /*
495   search the database with a LDAP-like expression.
496   choses a search method
497 */
498 int ltdb_search(struct ldb_module *module, struct ldb_request *req)
499 {
500         struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
501         struct ltdb_context *ltdb_ac;
502         struct ldb_reply *ares;
503         int ret;
504
505         if (ltdb_lock_read(module) != 0) {
506                 return LDB_ERR_OPERATIONS_ERROR;
507         }
508
509         if (ltdb_cache_load(module) != 0) {
510                 ltdb_unlock_read(module);
511                 return LDB_ERR_OPERATIONS_ERROR;
512         }
513
514         if (req->op.search.tree == NULL) {
515                 ltdb_unlock_read(module);
516                 return LDB_ERR_OPERATIONS_ERROR;
517         }
518
519         req->handle = init_ltdb_handle(ltdb, module, req);
520         if (req->handle == NULL) {
521                 ltdb_unlock_read(module);
522                 return LDB_ERR_OPERATIONS_ERROR;
523         }
524
525         if ((req->op.search.base == NULL) || (ldb_dn_is_null(req->op.search.base) == true)) {
526
527                 /* Check what we should do with a NULL dn */
528                 switch (req->op.search.scope) {
529                 case LDB_SCOPE_BASE:
530                         ldb_asprintf_errstring(module->ldb, 
531                                                "NULL Base DN invalid for a base search");
532                         ret = LDB_ERR_INVALID_DN_SYNTAX;
533                         break;
534                 case LDB_SCOPE_ONELEVEL:
535                         ldb_asprintf_errstring(module->ldb, 
536                                                "NULL Base DN invalid for a one-level search");
537                         ret = LDB_ERR_INVALID_DN_SYNTAX;        
538                         break;
539                 case LDB_SCOPE_SUBTREE:
540                 default:
541                         /* We accept subtree searches from a NULL base DN, ie over the whole DB */
542                         ret = LDB_SUCCESS;
543                 }
544         } else if (ldb_dn_is_valid(req->op.search.base) == false) {
545
546                 /* We don't want invalid base DNs here */
547                 ldb_asprintf_errstring(module->ldb, 
548                                        "Invalid Base DN: %s", 
549                                        ldb_dn_get_linearized(req->op.search.base));
550                 ret = LDB_ERR_INVALID_DN_SYNTAX;
551
552         } else if (ltdb->check_base) {
553                 /* This database has been marked as 'checkBaseOnSearch', so do a spot check of the base dn */
554                 ret = ltdb_search_base(module, req->op.search.base);
555                 
556                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
557                         ldb_asprintf_errstring(module->ldb, 
558                                                "No such Base DN: %s", 
559                                                ldb_dn_get_linearized(req->op.search.base));
560                 }
561                         
562         } else {
563                 /* If we are not checking the base DN life is easy */
564                 ret = LDB_SUCCESS;
565         }
566
567         ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
568
569         ltdb_ac->tree = req->op.search.tree;
570         ltdb_ac->scope = req->op.search.scope;
571         ltdb_ac->base = req->op.search.base;
572         ltdb_ac->attrs = req->op.search.attrs;
573
574
575         if (ret == LDB_SUCCESS) {
576                 ret = ltdb_search_indexed(req->handle);
577                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
578                         /* Not in the index, therefore OK! */
579                         ret = LDB_SUCCESS;
580                         
581                 } else if (ret == LDB_ERR_OPERATIONS_ERROR) {
582                         /* Not indexed, so we need to do a full scan */
583                         ret = ltdb_search_full(req->handle);
584                         if (ret != LDB_SUCCESS) {
585                                 ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n");
586                         }
587                 }
588         }
589
590         if (ret != LDB_SUCCESS) {
591                 req->handle->state = LDB_ASYNC_DONE;
592                 req->handle->status = ret;
593         }
594
595         /* Finally send an LDB_REPLY_DONE packet when searching is finished */
596
597         ares = talloc_zero(req, struct ldb_reply);
598         if (!ares) {
599                 ltdb_unlock_read(module);
600                 return LDB_ERR_OPERATIONS_ERROR;
601         }
602
603         req->handle->state = LDB_ASYNC_DONE;
604
605         if (ret == LDB_SUCCESS) {
606                 ares->type = LDB_REPLY_DONE;
607                 
608                 ret = req->callback(module->ldb, req->context, ares);
609                 req->handle->status = ret;
610         }
611
612         ltdb_unlock_read(module);
613
614         return LDB_SUCCESS;
615 }
616