r19314: Commit tridge's fixes for a big mem leak in ltdb I introduced
[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 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_move(*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_handle *handle = talloc_get_type(state, struct ldb_handle);
382         struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
383         struct ldb_reply *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_reply);
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_handle *handle)
458 {
459         struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_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         if (ret == -1) {
466                 handle->status = LDB_ERR_OPERATIONS_ERROR;
467         }
468
469         handle->state = LDB_ASYNC_DONE;
470         return LDB_SUCCESS;
471 }
472
473 /*
474   search the database with a LDAP-like expression.
475   choses a search method
476 */
477 int ltdb_search(struct ldb_module *module, struct ldb_request *req)
478 {
479         struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
480         struct ltdb_context *ltdb_ac;
481         struct ldb_reply *ares;
482         int ret;
483
484         if ((req->op.search.base == NULL || req->op.search.base->comp_num == 0) &&
485             (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL))
486                 return LDB_ERR_OPERATIONS_ERROR;
487
488         if (ltdb_lock_read(module) != 0) {
489                 return LDB_ERR_OPERATIONS_ERROR;
490         }
491
492         if (ltdb_cache_load(module) != 0) {
493                 ltdb_unlock_read(module);
494                 return LDB_ERR_OPERATIONS_ERROR;
495         }
496
497         if (req->op.search.tree == NULL) {
498                 ltdb_unlock_read(module);
499                 return LDB_ERR_OPERATIONS_ERROR;
500         }
501
502         req->handle = init_ltdb_handle(ltdb, module, req);
503         if (req->handle == NULL) {
504                 ltdb_unlock_read(module);
505                 return LDB_ERR_OPERATIONS_ERROR;
506         }
507         ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
508
509         ltdb_ac->tree = req->op.search.tree;
510         ltdb_ac->scope = req->op.search.scope;
511         ltdb_ac->base = req->op.search.base;
512         ltdb_ac->attrs = req->op.search.attrs;
513
514         ret = ltdb_search_indexed(req->handle);
515         if (ret == -1) {
516                 ret = ltdb_search_full(req->handle);
517         }
518         if (ret != LDB_SUCCESS) {
519                 ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n");
520                 req->handle->state = LDB_ASYNC_DONE;
521                 req->handle->status = ret;
522         }
523
524         /* Finally send an LDB_REPLY_DONE packet when searching is finished */
525
526         ares = talloc_zero(req, struct ldb_reply);
527         if (!ares) {
528                 ltdb_unlock_read(module);
529                 return LDB_ERR_OPERATIONS_ERROR;
530         }
531
532         req->handle->state = LDB_ASYNC_DONE;
533         ares->type = LDB_REPLY_DONE;
534
535         ret = req->callback(module->ldb, req->context, ares);
536         req->handle->status = ret;
537
538         ltdb_unlock_read(module);
539
540         return LDB_SUCCESS;
541 }
542