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