r19725: sync samba3's ldb with samba4
[kai/samba-autobuild/.git] / source3 / 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 /*
252   lock the database for read - use by ltdb_search
253 */
254 static int ltdb_lock_read(struct ldb_module *module)
255 {
256         struct ltdb_private *ltdb = module->private_data;
257         return tdb_lockall_read(ltdb->tdb);
258 }
259
260 /*
261   unlock the database after a ltdb_lock_read()
262 */
263 static int ltdb_unlock_read(struct ldb_module *module)
264 {
265         struct ltdb_private *ltdb = module->private_data;
266         return tdb_unlockall_read(ltdb->tdb);
267 }
268
269 /*
270   add a set of attributes from a record to a set of results
271   return 0 on success, -1 on failure
272 */
273 int ltdb_add_attr_results(struct ldb_module *module, 
274                           TALLOC_CTX *mem_ctx, 
275                           struct ldb_message *msg,
276                           const char * const attrs[], 
277                           unsigned int *count, 
278                           struct ldb_message ***res)
279 {
280         struct ldb_message *msg2;
281         struct ldb_message **res2;
282
283         /* pull the attributes that the user wants */
284         msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs);
285         if (!msg2) {
286                 return -1;
287         }
288
289         /* add to the results list */
290         res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2);
291         if (!res2) {
292                 talloc_free(msg2);
293                 return -1;
294         }
295
296         (*res) = res2;
297
298         (*res)[*count] = talloc_move(*res, &msg2);
299         (*res)[(*count)+1] = NULL;
300         (*count)++;
301
302         return 0;
303 }
304
305
306
307 /*
308   filter the specified list of attributes from a message
309   removing not requested attrs.
310  */
311 int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
312 {
313         int i, keep_all = 0;
314
315         if (attrs) {
316                 /* check for special attrs */
317                 for (i = 0; attrs[i]; i++) {
318                         if (strcmp(attrs[i], "*") == 0) {
319                                 keep_all = 1;
320                                 break;
321                         }
322
323                         if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
324                                 if (msg_add_distinguished_name(msg) != 0) {
325                                         return -1;
326                                 }
327                         }
328                 }
329         } else {
330                 keep_all = 1;
331         }
332         
333         if (keep_all) {
334                 if (msg_add_distinguished_name(msg) != 0) {
335                         return -1;
336                 }
337                 return 0;
338         }
339
340         for (i = 0; i < msg->num_elements; i++) {
341                 int j, found;
342                 
343                 for (j = 0, found = 0; attrs[j]; j++) {
344                         if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) {
345                                 found = 1;
346                                 break;
347                         }
348                 }
349
350                 if (!found) {
351                         ldb_msg_remove_attr(msg, msg->elements[i].name);
352                         i--;
353                 }
354         }
355
356         return 0;
357 }
358
359 /*
360   search function for a non-indexed search
361  */
362 static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
363 {
364         struct ldb_handle *handle = talloc_get_type(state, struct ldb_handle);
365         struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
366         struct ldb_reply *ares = NULL;
367         int ret;
368
369         if (key.dsize < 4 || 
370             strncmp((char *)key.dptr, "DN=", 3) != 0) {
371                 return 0;
372         }
373
374         ares = talloc_zero(ac, struct ldb_reply);
375         if (!ares) {
376                 handle->status = LDB_ERR_OPERATIONS_ERROR;
377                 handle->state = LDB_ASYNC_DONE;
378                 return -1;
379         }
380
381         ares->message = ldb_msg_new(ares);
382         if (!ares->message) {
383                 handle->status = LDB_ERR_OPERATIONS_ERROR;
384                 handle->state = LDB_ASYNC_DONE;
385                 talloc_free(ares);
386                 return -1;
387         }
388
389         /* unpack the record */
390         ret = ltdb_unpack_data(ac->module, &data, ares->message);
391         if (ret == -1) {
392                 talloc_free(ares);
393                 return -1;
394         }
395
396         if (!ares->message->dn) {
397                 ares->message->dn = ldb_dn_explode(ares->message, (char *)key.dptr + 3);
398                 if (ares->message->dn == NULL) {
399                         handle->status = LDB_ERR_OPERATIONS_ERROR;
400                         handle->state = LDB_ASYNC_DONE;
401                         talloc_free(ares);
402                         return -1;
403                 }
404         }
405
406         /* see if it matches the given expression */
407         if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, 
408                                ac->base, ac->scope)) {
409                 talloc_free(ares);
410                 return 0;
411         }
412
413         /* filter the attributes that the user wants */
414         ret = ltdb_filter_attrs(ares->message, ac->attrs);
415
416         if (ret == -1) {
417                 handle->status = LDB_ERR_OPERATIONS_ERROR;
418                 handle->state = LDB_ASYNC_DONE;
419                 talloc_free(ares);
420                 return -1;
421         }
422
423         ares->type = LDB_REPLY_ENTRY;
424         handle->state = LDB_ASYNC_PENDING;
425         handle->status = ac->callback(ac->module->ldb, ac->context, ares);
426
427         if (handle->status != LDB_SUCCESS) {
428                 /* don't try to free ares here, the callback is in charge of that */
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 ldb_handle *handle)
441 {
442         struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
443         struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private);
444         int ret;
445
446         ret = tdb_traverse_read(ltdb->tdb, search_func, handle);
447
448         if (ret == -1) {
449                 handle->status = LDB_ERR_OPERATIONS_ERROR;
450         }
451
452         handle->state = LDB_ASYNC_DONE;
453         return LDB_SUCCESS;
454 }
455
456 /*
457   search the database with a LDAP-like expression.
458   choses a search method
459 */
460 int ltdb_search(struct ldb_module *module, struct ldb_request *req)
461 {
462         struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
463         struct ltdb_context *ltdb_ac;
464         struct ldb_reply *ares;
465         int ret;
466
467         if ((req->op.search.base == NULL || ldb_dn_get_comp_num(req->op.search.base) == 0) &&
468             (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL))
469                 return LDB_ERR_OPERATIONS_ERROR;
470
471         if (ltdb_lock_read(module) != 0) {
472                 return LDB_ERR_OPERATIONS_ERROR;
473         }
474
475         if (ltdb_cache_load(module) != 0) {
476                 ltdb_unlock_read(module);
477                 return LDB_ERR_OPERATIONS_ERROR;
478         }
479
480         if (req->op.search.tree == NULL) {
481                 ltdb_unlock_read(module);
482                 return LDB_ERR_OPERATIONS_ERROR;
483         }
484
485         req->handle = init_ltdb_handle(ltdb, module, req);
486         if (req->handle == NULL) {
487                 ltdb_unlock_read(module);
488                 return LDB_ERR_OPERATIONS_ERROR;
489         }
490         ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
491
492         ltdb_ac->tree = req->op.search.tree;
493         ltdb_ac->scope = req->op.search.scope;
494         ltdb_ac->base = req->op.search.base;
495         ltdb_ac->attrs = req->op.search.attrs;
496
497         ret = ltdb_search_indexed(req->handle);
498         if (ret == -1) {
499                 ret = ltdb_search_full(req->handle);
500         }
501         if (ret != LDB_SUCCESS) {
502                 ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n");
503                 req->handle->state = LDB_ASYNC_DONE;
504                 req->handle->status = ret;
505         }
506
507         /* Finally send an LDB_REPLY_DONE packet when searching is finished */
508
509         ares = talloc_zero(req, struct ldb_reply);
510         if (!ares) {
511                 ltdb_unlock_read(module);
512                 return LDB_ERR_OPERATIONS_ERROR;
513         }
514
515         req->handle->state = LDB_ASYNC_DONE;
516         ares->type = LDB_REPLY_DONE;
517
518         ret = req->callback(module->ldb, req->context, ares);
519         req->handle->status = ret;
520
521         ltdb_unlock_read(module);
522
523         return LDB_SUCCESS;
524 }
525