r606: added a HIDDEN attribute on fields in ldb (in @ATTRIBUTES). This allows you...
[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/ldb_tdb/ldb_tdb.h"
37
38 /*
39   free a message that has all parts separately allocated
40 */
41 static void msg_free_all_parts(struct ldb_context *ldb, struct ldb_message *msg)
42 {
43         int i, j;
44         ldb_free(ldb, msg->dn);
45         for (i=0;i<msg->num_elements;i++) {
46                 ldb_free(ldb, msg->elements[i].name);
47                 for (j=0;j<msg->elements[i].num_values;j++) {
48                         ldb_free(ldb, msg->elements[i].values[j].data);
49                 }
50                 ldb_free(ldb, msg->elements[i].values);
51         }
52         ldb_free(ldb, msg->elements);
53         ldb_free(ldb, msg);
54 }
55
56
57 /*
58   duplicate a ldb_val structure
59 */
60 struct ldb_val ldb_val_dup(struct ldb_context *ldb,
61                            const struct ldb_val *v)
62 {
63         struct ldb_val v2;
64         v2.length = v->length;
65         if (v->length == 0) {
66                 v2.data = NULL;
67                 return v2;
68         }
69
70         /* the +1 is to cope with buggy C library routines like strndup
71            that look one byte beyond */
72         v2.data = ldb_malloc(ldb, v->length+1);
73         if (!v2.data) {
74                 v2.length = 0;
75                 return v2;
76         }
77
78         memcpy(v2.data, v->data, v->length);
79         ((char *)v2.data)[v->length] = 0;
80         return v2;
81 }
82
83
84
85 /*
86   add one element to a message
87 */
88 static int msg_add_element(struct ldb_context *ldb, 
89                            struct ldb_message *ret, const struct ldb_message_element *el)
90 {
91         int i;
92         struct ldb_message_element *e2, *elnew;
93
94         e2 = ldb_realloc_p(ldb, ret->elements, struct ldb_message_element, ret->num_elements+1);
95         if (!e2) {
96                 return -1;
97         }
98         ret->elements = e2;
99         
100         elnew = &e2[ret->num_elements];
101
102         elnew->name = ldb_strdup(ldb, el->name);
103         if (!elnew->name) {
104                 return -1;
105         }
106
107         if (el->num_values) {
108                 elnew->values = ldb_malloc_array_p(ldb, struct ldb_val, el->num_values);
109                 if (!elnew->values) {
110                         return -1;
111                 }
112         } else {
113                 elnew->values = NULL;
114         }
115
116         for (i=0;i<el->num_values;i++) {
117                 elnew->values[i] = ldb_val_dup(ldb, &el->values[i]);
118                 if (elnew->values[i].length != el->values[i].length) {
119                         return -1;
120                 }
121         }
122
123         elnew->num_values = el->num_values;
124
125         ret->num_elements++;
126
127         return 0;
128 }
129
130 /*
131   add all elements from one message into another
132  */
133 static int msg_add_all_elements(struct ldb_context *ldb, struct ldb_message *ret,
134                                 const struct ldb_message *msg)
135 {
136         int i;
137         for (i=0;i<msg->num_elements;i++) {
138                 int flags = ltdb_attribute_flags(ldb, msg->elements[i].name);
139                 if (flags & LTDB_FLAG_HIDDEN) {
140                         continue;
141                 }
142                 if (msg_add_element(ldb, ret, &msg->elements[i]) != 0) {
143                         return -1;
144                 }
145         }
146
147         return 0;
148 }
149
150
151 /*
152   pull the specified list of attributes from a message
153  */
154 static struct ldb_message *ltdb_pull_attrs(struct ldb_context *ldb, 
155                                            const struct ldb_message *msg, 
156                                            const char * const *attrs)
157 {
158         struct ldb_message *ret;
159         int i;
160
161         ret = ldb_malloc_p(ldb, struct ldb_message);
162         if (!ret) {
163                 return NULL;
164         }
165
166         ret->dn = ldb_strdup(ldb, msg->dn);
167         if (!ret->dn) {
168                 ldb_free(ldb, ret);
169                 return NULL;
170         }
171
172         ret->num_elements = 0;
173         ret->elements = NULL;
174         ret->private_data = NULL;
175
176         if (!attrs) {
177                 if (msg_add_all_elements(ldb, ret, msg) != 0) {
178                         msg_free_all_parts(ldb, ret);
179                         return NULL;
180                 }
181                 return ret;
182         }
183
184         for (i=0;attrs[i];i++) {
185                 struct ldb_message_element *el;
186
187                 if (strcmp(attrs[i], "*") == 0) {
188                         if (msg_add_all_elements(ldb, ret, msg) != 0) {
189                                 msg_free_all_parts(ldb, ret);
190                                 return NULL;
191                         }
192                         continue;
193                 }
194
195                 el = ldb_msg_find_element(msg, attrs[i]);
196                 if (!el) {
197                         continue;
198                 }
199                 if (msg_add_element(ldb, ret, el) != 0) {
200                         msg_free_all_parts(ldb, ret);
201                         return NULL;                            
202                 }
203         }
204
205         return ret;
206 }
207
208
209
210 /*
211   see if a ldb_val is a wildcard
212   return 1 if yes, 0 if no
213 */
214 int ltdb_has_wildcard(struct ldb_context *ldb, const char *attr_name, 
215                       const struct ldb_val *val)
216 {
217         int flags;
218
219         /* all attribute types recognise the "*" wildcard */
220         if (val->length == 1 && strncmp((char *)val->data, "*", 1) == 0) {
221                 return 1;
222         }
223
224         if (strpbrk(val->data, "*?") == NULL) {
225                 return 0;
226         }
227
228         flags = ltdb_attribute_flags(ldb, attr_name);
229         if (flags & LTDB_FLAG_WILDCARD) {
230                 return 1;
231         }
232
233         return 0;
234 }
235
236
237 /*
238   free the results of a ltdb_search_dn1 search
239 */
240 void ltdb_search_dn1_free(struct ldb_context *ldb, struct ldb_message *msg)
241 {
242         int i;
243         ldb_free(ldb, msg->private_data);
244         for (i=0;i<msg->num_elements;i++) {
245                 ldb_free(ldb, msg->elements[i].values);
246         }
247         ldb_free(ldb, msg->elements);
248         memset(msg, 0, sizeof(*msg));
249 }
250
251
252 /*
253   search the database for a single simple dn, returning all attributes
254   in a single message
255
256   return 1 on success, 0 on record-not-found and -1 on error
257 */
258 int ltdb_search_dn1(struct ldb_context *ldb, const char *dn, struct ldb_message *msg)
259 {
260         struct ltdb_private *ltdb = ldb->private_data;
261         int ret;
262         TDB_DATA tdb_key, tdb_data, tdb_data2;
263
264         memset(msg, 0, sizeof(*msg));
265
266         /* form the key */
267         tdb_key = ltdb_key(ldb, dn);
268         if (!tdb_key.dptr) {
269                 return -1;
270         }
271
272         tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
273         ldb_free(ldb, tdb_key.dptr);
274         if (!tdb_data.dptr) {
275                 return 0;
276         }
277
278         tdb_data2.dptr = ldb_malloc(ldb, tdb_data.dsize);
279         if (!tdb_data2.dptr) {
280                 free(tdb_data.dptr);
281                 return -1;
282         }
283         memcpy(tdb_data2.dptr, tdb_data.dptr, tdb_data.dsize);
284         free(tdb_data.dptr);
285         tdb_data2.dsize = tdb_data.dsize;
286
287         msg->private_data = tdb_data2.dptr;
288         msg->num_elements = 0;
289         msg->elements = NULL;
290
291         ret = ltdb_unpack_data(ldb, &tdb_data2, msg);
292         if (ret == -1) {
293                 free(tdb_data2.dptr);
294                 return -1;              
295         }
296
297         if (!msg->dn) {
298                 msg->dn = ldb_strdup(ldb, dn);
299         }
300         if (!msg->dn) {
301                 ldb_free(ldb, tdb_data2.dptr);
302                 return -1;
303         }
304
305         return 1;
306 }
307
308
309 /*
310   search the database for a single simple dn
311 */
312 int ltdb_search_dn(struct ldb_context *ldb, char *dn,
313                    const char * const attrs[], struct ldb_message ***res)
314 {
315         int ret;
316         struct ldb_message msg, *msg2;
317
318         ret = ltdb_search_dn1(ldb, dn, &msg);
319         if (ret != 1) {
320                 return ret;
321         }
322
323         msg2 = ltdb_pull_attrs(ldb, &msg, attrs);
324
325         ltdb_search_dn1_free(ldb, &msg);
326
327         if (!msg2) {
328                 return -1;              
329         }
330
331         *res = ldb_malloc_array_p(ldb, struct ldb_message *, 2);
332         if (! *res) {
333                 msg_free_all_parts(ldb, msg2);
334                 return -1;              
335         }
336
337         (*res)[0] = msg2;
338         (*res)[1] = NULL;
339
340         return 1;
341 }
342
343
344 /*
345   add a set of attributes from a record to a set of results
346   return 0 on success, -1 on failure
347 */
348 int ltdb_add_attr_results(struct ldb_context *ldb, struct ldb_message *msg,
349                           const char * const attrs[], 
350                           unsigned int *count, 
351                           struct ldb_message ***res)
352 {
353         struct ldb_message *msg2;
354         struct ldb_message **res2;
355
356         /* pull the attributes that the user wants */
357         msg2 = ltdb_pull_attrs(ldb, msg, attrs);
358         if (!msg2) {
359                 return -1;
360         }
361
362         /* add to the results list */
363         res2 = ldb_realloc_p(ldb, *res, struct ldb_message *, (*count)+2);
364         if (!res2) {
365                 msg_free_all_parts(ldb, msg2);
366                 return -1;
367         }
368
369         (*res) = res2;
370
371         (*res)[*count] = msg2;
372         (*res)[(*count)+1] = NULL;
373         (*count)++;
374
375         return 0;
376 }
377
378
379 /*
380   internal search state during a full db search
381 */
382 struct ltdb_search_info {
383         struct ldb_context *ldb;
384         struct ldb_parse_tree *tree;
385         const char *base;
386         enum ldb_scope scope;
387         const char * const *attrs;
388         struct ldb_message **msgs;
389         int failures;
390         int count;
391 };
392
393
394 /*
395   search function for a non-indexed search
396  */
397 static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
398 {
399         struct ltdb_search_info *sinfo = state;
400         struct ldb_message msg;
401         int ret;
402
403         if (key.dsize < 4 || 
404             strncmp(key.dptr, "DN=", 3) != 0) {
405                 return 0;
406         }
407
408         /* unpack the record */
409         ret = ltdb_unpack_data(sinfo->ldb, &data, &msg);
410         if (ret == -1) {
411                 sinfo->failures++;
412                 return 0;
413         }
414
415         if (!msg.dn) {
416                 msg.dn = key.dptr + 3;
417         }
418
419         /* see if it matches the given expression */
420         if (!ldb_message_match(sinfo->ldb, &msg, sinfo->tree, 
421                                sinfo->base, sinfo->scope)) {
422                 ltdb_unpack_data_free(sinfo->ldb, &msg);
423                 return 0;
424         }
425
426         ret = ltdb_add_attr_results(sinfo->ldb, &msg, sinfo->attrs, &sinfo->count, &sinfo->msgs);
427
428         if (ret == -1) {
429                 sinfo->failures++;
430         }
431
432         ltdb_unpack_data_free(sinfo->ldb, &msg);
433
434         return ret;
435 }
436
437
438 /*
439   free a set of search results
440 */
441 int ltdb_search_free(struct ldb_context *ldb, struct ldb_message **msgs)
442 {
443         struct ltdb_private *ltdb = ldb->private_data;
444         int i;
445
446         ltdb->last_err_string = NULL;
447         
448         if (!msgs) return 0;
449
450         for (i=0;msgs[i];i++) {
451                 msg_free_all_parts(ldb, msgs[i]);
452         }
453
454         ldb_free(ldb, msgs);
455
456         return 0;
457 }
458
459 /*
460   search the database with a LDAP-like expression.
461   this is the "full search" non-indexed varient
462 */
463 static int ltdb_search_full(struct ldb_context *ldb, 
464                             const char *base,
465                             enum ldb_scope scope,
466                             struct ldb_parse_tree *tree,
467                             const char * const attrs[], struct ldb_message ***res)
468 {
469         struct ltdb_private *ltdb = ldb->private_data;
470         int ret;
471         struct ltdb_search_info sinfo;
472
473         sinfo.tree = tree;
474         sinfo.ldb = ldb;
475         sinfo.scope = scope;
476         sinfo.base = base;
477         sinfo.attrs = attrs;
478         sinfo.msgs = NULL;
479         sinfo.count = 0;
480         sinfo.failures = 0;
481
482         ret = tdb_traverse(ltdb->tdb, search_func, &sinfo);
483
484         if (ret == -1) {
485                 ltdb_search_free(ldb, sinfo.msgs);
486                 return -1;
487         }
488
489         *res = sinfo.msgs;
490         return sinfo.count;
491 }
492
493
494 /*
495   search the database with a LDAP-like expression.
496   choses a search method
497 */
498 int ltdb_search(struct ldb_context *ldb, const char *base,
499                 enum ldb_scope scope, const char *expression,
500                 const char * const attrs[], struct ldb_message ***res)
501 {
502         struct ltdb_private *ltdb = ldb->private_data;
503         struct ldb_parse_tree *tree;
504         int ret;
505
506         ltdb->last_err_string = NULL;
507
508         if (ltdb_cache_load(ldb) != 0) {
509                 return -1;
510         }
511
512         *res = NULL;
513
514         /* form a parse tree for the expression */
515         tree = ldb_parse_tree(ldb, expression);
516         if (!tree) {
517                 ltdb->last_err_string = "expression parse failed";
518                 return -1;
519         }
520
521         if (tree->operation == LDB_OP_SIMPLE && 
522             ldb_attr_cmp(tree->u.simple.attr, "dn") == 0 &&
523             !ltdb_has_wildcard(ldb, tree->u.simple.attr, &tree->u.simple.value)) {
524                 /* yay! its a nice simple one */
525                 ret = ltdb_search_dn(ldb, tree->u.simple.value.data, attrs, res);
526         } else {
527                 ret = ltdb_search_indexed(ldb, base, scope, tree, attrs, res);
528                 if (ret == -1) {
529                         ret = ltdb_search_full(ldb, base, scope, tree, attrs, res);
530                 }
531         }
532
533         ldb_parse_tree_free(ldb, tree);
534
535         return ret;
536 }
537