r13823: make async_wait part of the modules ops
[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/includes.h"
37
38 #include "ldb/ldb_tdb/ldb_tdb.h"
39
40 /*
41   add one element to a message
42 */
43 static int msg_add_element(struct ldb_message *ret, 
44                            const struct ldb_message_element *el,
45                            int check_duplicates)
46 {
47         unsigned int i;
48         struct ldb_message_element *e2, *elnew;
49
50         if (check_duplicates && ldb_msg_find_element(ret, el->name)) {
51                 /* its already there */
52                 return 0;
53         }
54
55         e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1);
56         if (!e2) {
57                 return -1;
58         }
59         ret->elements = e2;
60         
61         elnew = &e2[ret->num_elements];
62
63         elnew->name = talloc_strdup(ret->elements, el->name);
64         if (!elnew->name) {
65                 return -1;
66         }
67
68         if (el->num_values) {
69                 elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values);
70                 if (!elnew->values) {
71                         return -1;
72                 }
73         } else {
74                 elnew->values = NULL;
75         }
76
77         for (i=0;i<el->num_values;i++) {
78                 elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]);
79                 if (elnew->values[i].length != el->values[i].length) {
80                         return -1;
81                 }
82         }
83
84         elnew->num_values = el->num_values;
85
86         ret->num_elements++;
87
88         return 0;
89 }
90
91 /*
92   add the special distinguishedName element
93 */
94 static int msg_add_distinguished_name(struct ldb_message *msg)
95 {
96         struct ldb_message_element el;
97         struct ldb_val val;
98         int ret;
99
100         el.flags = 0;
101         el.name = "distinguishedName";
102         el.num_values = 1;
103         el.values = &val;
104         val.data = (uint8_t *)ldb_dn_linearize(msg, msg->dn);
105         val.length = strlen((char *)val.data);
106         
107         ret = msg_add_element(msg, &el, 1);
108         return ret;
109 }
110
111 /*
112   add all elements from one message into another
113  */
114 static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret,
115                                 const struct ldb_message *msg)
116 {
117         struct ldb_context *ldb = module->ldb;
118         unsigned int i;
119         int check_duplicates = (ret->num_elements != 0);
120
121         if (msg_add_distinguished_name(ret) != 0) {
122                 return -1;
123         }
124
125         for (i=0;i<msg->num_elements;i++) {
126                 const struct ldb_attrib_handler *h;
127                 h = ldb_attrib_handler(ldb, msg->elements[i].name);
128                 if (h->flags & LDB_ATTR_FLAG_HIDDEN) {
129                         continue;
130                 }
131                 if (msg_add_element(ret, &msg->elements[i],
132                                     check_duplicates) != 0) {
133                         return -1;
134                 }
135         }
136
137         return 0;
138 }
139
140
141 /*
142   pull the specified list of attributes from a message
143  */
144 static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module, 
145                                            TALLOC_CTX *mem_ctx, 
146                                            const struct ldb_message *msg, 
147                                            const char * const *attrs)
148 {
149         struct ldb_message *ret;
150         int i;
151
152         ret = talloc(mem_ctx, struct ldb_message);
153         if (!ret) {
154                 return NULL;
155         }
156
157         ret->dn = ldb_dn_copy(ret, msg->dn);
158         if (!ret->dn) {
159                 talloc_free(ret);
160                 return NULL;
161         }
162
163         ret->num_elements = 0;
164         ret->elements = NULL;
165
166         if (!attrs) {
167                 if (msg_add_all_elements(module, ret, msg) != 0) {
168                         talloc_free(ret);
169                         return NULL;
170                 }
171                 return ret;
172         }
173
174         for (i=0;attrs[i];i++) {
175                 struct ldb_message_element *el;
176
177                 if (strcmp(attrs[i], "*") == 0) {
178                         if (msg_add_all_elements(module, ret, msg) != 0) {
179                                 talloc_free(ret);
180                                 return NULL;
181                         }
182                         continue;
183                 }
184
185                 if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
186                         if (msg_add_distinguished_name(ret) != 0) {
187                                 return NULL;
188                         }
189                         continue;
190                 }
191
192                 el = ldb_msg_find_element(msg, attrs[i]);
193                 if (!el) {
194                         continue;
195                 }
196                 if (msg_add_element(ret, el, 1) != 0) {
197                         talloc_free(ret);
198                         return NULL;                            
199                 }
200         }
201
202         return ret;
203 }
204
205
206 /*
207   search the database for a single simple dn, returning all attributes
208   in a single message
209
210   return 1 on success, 0 on record-not-found and -1 on error
211 */
212 int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct ldb_message *msg)
213 {
214         struct ltdb_private *ltdb = module->private_data;
215         int ret;
216         TDB_DATA tdb_key, tdb_data;
217
218         memset(msg, 0, sizeof(*msg));
219
220         /* form the key */
221         tdb_key = ltdb_key(module, dn);
222         if (!tdb_key.dptr) {
223                 return -1;
224         }
225
226         tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
227         talloc_free(tdb_key.dptr);
228         if (!tdb_data.dptr) {
229                 return 0;
230         }
231
232         msg->num_elements = 0;
233         msg->elements = NULL;
234
235         ret = ltdb_unpack_data(module, &tdb_data, msg);
236         free(tdb_data.dptr);
237         if (ret == -1) {
238                 return -1;              
239         }
240
241         if (!msg->dn) {
242                 msg->dn = ldb_dn_copy(msg, dn);
243         }
244         if (!msg->dn) {
245                 return -1;
246         }
247
248         return 1;
249 }
250
251 /* the lock key for search locking. Note that this is not a DN, its
252    just an arbitrary key to give to tdb. Also note that as we and
253    using transactions for all write operations and transactions take
254    care of their own locks, we don't need to do any locking anywhere
255    other than in ldb_search() */
256 #define LDBLOCK "INT_LDBLOCK"
257
258 /*
259   lock the database for read - use by ltdb_search
260 */
261 static int ltdb_lock_read(struct ldb_module *module)
262 {
263         struct ltdb_private *ltdb = module->private_data;
264         TDB_DATA key;
265
266         key.dptr = discard_const(LDBLOCK);
267         key.dsize = strlen(LDBLOCK);
268
269         return tdb_chainlock_read(ltdb->tdb, key);
270 }
271
272 /*
273   unlock the database after a ltdb_lock_read()
274 */
275 static int ltdb_unlock_read(struct ldb_module *module)
276 {
277         struct ltdb_private *ltdb = module->private_data;
278         TDB_DATA key;
279
280         key.dptr = discard_const(LDBLOCK);
281         key.dsize = strlen(LDBLOCK);
282
283         return tdb_chainunlock_read(ltdb->tdb, key);
284 }
285
286 /*
287   add a set of attributes from a record to a set of results
288   return 0 on success, -1 on failure
289 */
290 int ltdb_add_attr_results(struct ldb_module *module, 
291                           TALLOC_CTX *mem_ctx, 
292                           struct ldb_message *msg,
293                           const char * const attrs[], 
294                           unsigned int *count, 
295                           struct ldb_message ***res)
296 {
297         struct ldb_message *msg2;
298         struct ldb_message **res2;
299
300         /* pull the attributes that the user wants */
301         msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs);
302         if (!msg2) {
303                 return -1;
304         }
305
306         /* add to the results list */
307         res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2);
308         if (!res2) {
309                 talloc_free(msg2);
310                 return -1;
311         }
312
313         (*res) = res2;
314
315         (*res)[*count] = talloc_steal(*res, msg2);
316         (*res)[(*count)+1] = NULL;
317         (*count)++;
318
319         return 0;
320 }
321
322
323
324 /*
325   filter the specified list of attributes from a message
326   removing not requested attrs.
327  */
328 int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
329 {
330         int i, keep_all = 0;
331
332         if (attrs) {
333                 /* check for special attrs */
334                 for (i = 0; attrs[i]; i++) {
335                         if (strcmp(attrs[i], "*") == 0) {
336                                 keep_all = 1;
337                                 break;
338                         }
339
340                         if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
341                                 if (msg_add_distinguished_name(msg) != 0) {
342                                         return -1;
343                                 }
344                         }
345                 }
346         } else {
347                 keep_all = 1;
348         }
349         
350         if (keep_all) {
351                 if (msg_add_distinguished_name(msg) != 0) {
352                         return -1;
353                 }
354                 return 0;
355         }
356
357         for (i = 0; i < msg->num_elements; i++) {
358                 int j, found;
359                 
360                 for (j = 0, found = 0; attrs[j]; j++) {
361                         if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) {
362                                 found = 1;
363                                 break;
364                         }
365                 }
366
367                 if (!found) {
368                         ldb_msg_remove_attr(msg, msg->elements[i].name);
369                         i--;
370                 }
371         }
372
373         return 0;
374 }
375
376 /*
377   search function for a non-indexed search
378  */
379 static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
380 {
381         struct ldb_async_handle *handle = talloc_get_type(state, struct ldb_async_handle);
382         struct ltdb_async_context *ac = talloc_get_type(handle->private_data, struct ltdb_async_context);
383         struct ldb_async_result *ares = NULL;
384         int ret;
385
386         if (key.dsize < 4 || 
387             strncmp((char *)key.dptr, "DN=", 3) != 0) {
388                 return 0;
389         }
390
391         ares = talloc_zero(ac, struct ldb_async_result);
392         if (!ares) {
393                 handle->status = LDB_ERR_OPERATIONS_ERROR;
394                 handle->state = LDB_ASYNC_DONE;
395                 return -1;
396         }
397
398         ares->message = ldb_msg_new(ares);
399         if (!ares->message) {
400                 handle->status = LDB_ERR_OPERATIONS_ERROR;
401                 handle->state = LDB_ASYNC_DONE;
402                 talloc_free(ares);
403                 return -1;
404         }
405
406         /* unpack the record */
407         ret = ltdb_unpack_data(ac->module, &data, ares->message);
408         if (ret == -1) {
409                 talloc_free(ares);
410                 return -1;
411         }
412
413         if (!ares->message->dn) {
414                 ares->message->dn = ldb_dn_explode(ares->message, (char *)key.dptr + 3);
415                 if (ares->message->dn == NULL) {
416                         handle->status = LDB_ERR_OPERATIONS_ERROR;
417                         handle->state = LDB_ASYNC_DONE;
418                         talloc_free(ares);
419                         return -1;
420                 }
421         }
422
423         /* see if it matches the given expression */
424         if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, 
425                                ac->base, ac->scope)) {
426                 talloc_free(ares);
427                 return 0;
428         }
429
430         /* filter the attributes that the user wants */
431         ret = ltdb_filter_attrs(ares->message, ac->attrs);
432
433         if (ret == -1) {
434                 handle->status = LDB_ERR_OPERATIONS_ERROR;
435                 handle->state = LDB_ASYNC_DONE;
436                 talloc_free(ares);
437                 return -1;
438         }
439
440         ares->type = LDB_REPLY_ENTRY;
441         handle->state = LDB_ASYNC_PENDING;
442         handle->status = ac->callback(ac->module->ldb, ac->context, ares);
443
444         if (handle->status != LDB_SUCCESS) {
445                 /* don't try to free ares here, the callback is in charge of that */
446                 return -1;
447         }       
448
449         return 0;
450 }
451
452
453 /*
454   search the database with a LDAP-like expression.
455   this is the "full search" non-indexed variant
456 */
457 static int ltdb_search_full(struct ldb_async_handle *handle)
458 {
459         struct ltdb_async_context *ac = talloc_get_type(handle->private_data, struct ltdb_async_context);
460         struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private);
461         int ret;
462
463         ret = tdb_traverse_read(ltdb->tdb, search_func, handle);
464
465         handle->state = LDB_ASYNC_DONE;
466
467         if (ret == -1) {
468                 handle->status = LDB_ERR_OPERATIONS_ERROR;
469                 return handle->status;
470         }
471
472         handle->status = LDB_SUCCESS;
473         return handle->status;
474 }
475
476 static int ltdb_search_sync_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares)
477 {
478         struct ldb_result *res = NULL;
479         
480         if (!context) {
481                 ldb_set_errstring(ldb, talloc_strdup(ldb, "NULL Context in callback"));
482                 goto error;
483         }       
484
485         res = *((struct ldb_result **)context);
486
487         if (!res || !ares) {
488                 goto error;
489         }
490
491         if (ares->type == LDB_REPLY_ENTRY) {
492                 res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2);
493                 if (! res->msgs) {
494                         goto error;
495                 }
496
497                 res->msgs[res->count + 1] = NULL;
498
499                 res->msgs[res->count] = talloc_steal(res->msgs, ares->message);
500                 if (! res->msgs[res->count]) {
501                         goto error;
502                 }
503
504                 res->count++;
505         } else {
506                 ldb_debug(ldb, LDB_DEBUG_ERROR, "unrecognized async reply in ltdb_search_sync_callback!\n");
507                 goto error;
508         }
509
510         talloc_free(ares);
511         return LDB_SUCCESS;
512
513 error:
514         if (ares) talloc_free(ares);
515         if (res) talloc_free(res);
516         if (context) *((struct ldb_result **)context) = NULL;
517         return LDB_ERR_OPERATIONS_ERROR;
518 }
519
520 int ltdb_search_async(struct ldb_module *module, const struct ldb_dn *base,
521                       enum ldb_scope scope, struct ldb_parse_tree *tree,
522                       const char * const *attrs,
523                       void *context,
524                       int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
525                       int timeout,
526                       struct ldb_async_handle **handle)
527 {
528         struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
529         struct ltdb_async_context *ltdb_ac;
530         int ret;
531
532         if ((base == NULL || base->comp_num == 0) &&
533             (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL))
534                 return LDB_ERR_OPERATIONS_ERROR;
535
536         if (ltdb_lock_read(module) != 0) {
537                 return LDB_ERR_OPERATIONS_ERROR;
538         }
539
540         if (ltdb_cache_load(module) != 0) {
541                 ltdb_unlock_read(module);
542                 return LDB_ERR_OPERATIONS_ERROR;
543         }
544
545         if (tree == NULL) {
546                 ltdb_unlock_read(module);
547                 return LDB_ERR_OPERATIONS_ERROR;
548         }
549
550         *handle = init_ltdb_handle(ltdb, module, context, callback, timeout);
551         if (*handle == NULL) {
552                 talloc_free(*handle);
553                 ltdb_unlock_read(module);
554                 return LDB_ERR_OPERATIONS_ERROR;
555         }
556
557         ltdb_ac = talloc_get_type((*handle)->private_data, struct ltdb_async_context);
558
559         ltdb_ac->tree = tree;
560         ltdb_ac->scope = scope;
561         ltdb_ac->base = base;
562         ltdb_ac->attrs = attrs;
563
564         ret = ltdb_search_indexed(*handle);
565         if (ret == -1) {
566                 ret = ltdb_search_full(*handle);
567         }
568         if (ret != LDB_SUCCESS) {
569                 ldb_set_errstring(module->ldb, talloc_strdup(module->ldb, "Indexed and full searches both failed!\n"));
570                 talloc_free(*handle);
571                 *handle = NULL;
572         }
573
574         ltdb_unlock_read(module);
575
576         return ret;
577 }
578
579 /*
580   search the database with a LDAP-like expression.
581   choses a search method
582 */
583 int ltdb_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
584                        enum ldb_scope scope, struct ldb_parse_tree *tree,
585                        const char * const attrs[], struct ldb_result **res)
586 {
587         struct ldb_async_handle *handle;
588         int ret;
589
590         *res = talloc_zero(module, struct ldb_result);
591         if (! *res) {
592                 return LDB_ERR_OPERATIONS_ERROR;
593         }
594
595         ret = ltdb_search_async(module, base, scope, tree, attrs,
596                                 res, &ltdb_search_sync_callback,
597                                 0, &handle);
598
599         if (ret != LDB_SUCCESS)
600                 return ret;
601
602         ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL);
603
604         talloc_free(handle);
605         return ret;
606 }
607
608