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