r23795: more v2->v3 conversion
[ira/wip.git] / source / 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, 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 "ldb_includes.h"
36
37 #include "ldb_tdb.h"
38
39 /*
40   add one element to a message
41 */
42 static int msg_add_element(struct ldb_message *ret, 
43                            const struct ldb_message_element *el,
44                            int check_duplicates)
45 {
46         unsigned int i;
47         struct ldb_message_element *e2, *elnew;
48
49         if (check_duplicates && ldb_msg_find_element(ret, el->name)) {
50                 /* its already there */
51                 return 0;
52         }
53
54         e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1);
55         if (!e2) {
56                 return -1;
57         }
58         ret->elements = e2;
59         
60         elnew = &e2[ret->num_elements];
61
62         elnew->name = talloc_strdup(ret->elements, el->name);
63         if (!elnew->name) {
64                 return -1;
65         }
66
67         if (el->num_values) {
68                 elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values);
69                 if (!elnew->values) {
70                         return -1;
71                 }
72         } else {
73                 elnew->values = NULL;
74         }
75
76         for (i=0;i<el->num_values;i++) {
77                 elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]);
78                 if (elnew->values[i].length != el->values[i].length) {
79                         return -1;
80                 }
81         }
82
83         elnew->num_values = el->num_values;
84
85         ret->num_elements++;
86
87         return 0;
88 }
89
90 /*
91   add the special distinguishedName element
92 */
93 static int msg_add_distinguished_name(struct ldb_message *msg)
94 {
95         struct ldb_message_element el;
96         struct ldb_val val;
97         int ret;
98
99         el.flags = 0;
100         el.name = "distinguishedName";
101         el.num_values = 1;
102         el.values = &val;
103         val.data = (uint8_t *)ldb_dn_alloc_linearized(msg, msg->dn);
104         val.length = strlen((char *)val.data);
105         
106         ret = msg_add_element(msg, &el, 1);
107         return ret;
108 }
109
110 /*
111   add all elements from one message into another
112  */
113 static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret,
114                                 const struct ldb_message *msg)
115 {
116         struct ldb_context *ldb = module->ldb;
117         unsigned int i;
118         int check_duplicates = (ret->num_elements != 0);
119
120         if (msg_add_distinguished_name(ret) != 0) {
121                 return -1;
122         }
123
124         for (i=0;i<msg->num_elements;i++) {
125                 const struct ldb_schema_attribute *a;
126                 a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
127                 if (a->flags & LDB_ATTR_FLAG_HIDDEN) {
128                         continue;
129                 }
130                 if (msg_add_element(ret, &msg->elements[i],
131                                     check_duplicates) != 0) {
132                         return -1;
133                 }
134         }
135
136         return 0;
137 }
138
139
140 /*
141   pull the specified list of attributes from a message
142  */
143 static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module, 
144                                            TALLOC_CTX *mem_ctx, 
145                                            const struct ldb_message *msg, 
146                                            const char * const *attrs)
147 {
148         struct ldb_message *ret;
149         int i;
150
151         ret = talloc(mem_ctx, struct ldb_message);
152         if (!ret) {
153                 return NULL;
154         }
155
156         ret->dn = ldb_dn_copy(ret, msg->dn);
157         if (!ret->dn) {
158                 talloc_free(ret);
159                 return NULL;
160         }
161
162         ret->num_elements = 0;
163         ret->elements = NULL;
164
165         if (!attrs) {
166                 if (msg_add_all_elements(module, ret, msg) != 0) {
167                         talloc_free(ret);
168                         return NULL;
169                 }
170                 return ret;
171         }
172
173         for (i=0;attrs[i];i++) {
174                 struct ldb_message_element *el;
175
176                 if (strcmp(attrs[i], "*") == 0) {
177                         if (msg_add_all_elements(module, ret, msg) != 0) {
178                                 talloc_free(ret);
179                                 return NULL;
180                         }
181                         continue;
182                 }
183
184                 if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
185                         if (msg_add_distinguished_name(ret) != 0) {
186                                 return NULL;
187                         }
188                         continue;
189                 }
190
191                 el = ldb_msg_find_element(msg, attrs[i]);
192                 if (!el) {
193                         continue;
194                 }
195                 if (msg_add_element(ret, el, 1) != 0) {
196                         talloc_free(ret);
197                         return NULL;                            
198                 }
199         }
200
201         return ret;
202 }
203
204
205 /*
206   search the database for a single simple dn, returning all attributes
207   in a single message
208
209   return LDB_ERR_NO_SUCH_OBJECT on record-not-found
210   and LDB_SUCCESS on success
211 */
212 int ltdb_search_dn1(struct ldb_module *module, 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 LDB_ERR_OPERATIONS_ERROR;
224         }
225
226         tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
227         talloc_free(tdb_key.dptr);
228         if (!tdb_data.dptr) {
229                 return LDB_ERR_NO_SUCH_OBJECT;
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 LDB_ERR_OPERATIONS_ERROR;                
239         }
240
241         if (!msg->dn) {
242                 msg->dn = ldb_dn_copy(msg, dn);
243         }
244         if (!msg->dn) {
245                 return LDB_ERR_OPERATIONS_ERROR;
246         }
247
248         return LDB_SUCCESS;
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_new(ares->message, ac->module->ldb, (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 ((( ! ldb_dn_is_valid(req->op.search.base)) || ldb_dn_is_null(req->op.search.base)) &&
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 == LDB_ERR_OPERATIONS_ERROR) {
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