r574: - another attempt at const cleanliness in ldb
[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/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                 if (msg_add_element(ldb, ret, &msg->elements[i]) != 0) {
139                         return -1;
140                 }
141         }
142
143         return 0;
144 }
145
146
147 /*
148   pull the specified list of attributes from a message
149  */
150 static struct ldb_message *ltdb_pull_attrs(struct ldb_context *ldb, 
151                                            const struct ldb_message *msg, 
152                                            const char * const *attrs)
153 {
154         struct ldb_message *ret;
155         int i;
156
157         ret = ldb_malloc_p(ldb, struct ldb_message);
158         if (!ret) {
159                 return NULL;
160         }
161
162         ret->dn = ldb_strdup(ldb, msg->dn);
163         if (!ret->dn) {
164                 ldb_free(ldb, ret);
165                 return NULL;
166         }
167
168         ret->num_elements = 0;
169         ret->elements = NULL;
170         ret->private_data = NULL;
171
172         if (!attrs) {
173                 if (msg_add_all_elements(ldb, ret, msg) != 0) {
174                         msg_free_all_parts(ldb, ret);
175                         return NULL;
176                 }
177                 return ret;
178         }
179
180         for (i=0;attrs[i];i++) {
181                 struct ldb_message_element *el;
182
183                 if (strcmp(attrs[i], "*") == 0) {
184                         if (msg_add_all_elements(ldb, ret, msg) != 0) {
185                                 msg_free_all_parts(ldb, ret);
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(ldb, ret, el) != 0) {
196                         msg_free_all_parts(ldb, ret);
197                         return NULL;                            
198                 }
199         }
200
201         return ret;
202 }
203
204
205
206 /*
207   see if a ldb_val is a wildcard
208   return 1 if yes, 0 if no
209 */
210 int ltdb_has_wildcard(struct ldb_context *ldb, const char *attr_name, 
211                       const struct ldb_val *val)
212 {
213         int flags;
214
215         /* all attribute types recognise the "*" wildcard */
216         if (val->length == 1 && strncmp((char *)val->data, "*", 1) == 0) {
217                 return 1;
218         }
219
220         if (strpbrk(val->data, "*?") == NULL) {
221                 return 0;
222         }
223
224         flags = ltdb_attribute_flags(ldb, attr_name);
225         if (flags & LTDB_FLAG_WILDCARD) {
226                 return 1;
227         }
228
229         return 0;
230 }
231
232
233 /*
234   free the results of a ltdb_search_dn1 search
235 */
236 void ltdb_search_dn1_free(struct ldb_context *ldb, struct ldb_message *msg)
237 {
238         int i;
239         ldb_free(ldb, msg->private_data);
240         for (i=0;i<msg->num_elements;i++) {
241                 ldb_free(ldb, msg->elements[i].values);
242         }
243         ldb_free(ldb, msg->elements);
244         memset(msg, 0, sizeof(*msg));
245 }
246
247
248 /*
249   search the database for a single simple dn, returning all attributes
250   in a single message
251
252   return 1 on success, 0 on record-not-found and -1 on error
253 */
254 int ltdb_search_dn1(struct ldb_context *ldb, const char *dn, struct ldb_message *msg)
255 {
256         struct ltdb_private *ltdb = ldb->private_data;
257         int ret;
258         TDB_DATA tdb_key, tdb_data, tdb_data2;
259
260         /* form the key */
261         tdb_key = ltdb_key(ldb, dn);
262         if (!tdb_key.dptr) {
263                 return -1;
264         }
265
266         tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
267         ldb_free(ldb, tdb_key.dptr);
268         if (!tdb_data.dptr) {
269                 return 0;
270         }
271
272         tdb_data2.dptr = ldb_malloc(ldb, tdb_data.dsize);
273         if (!tdb_data2.dptr) {
274                 free(tdb_data.dptr);
275                 return -1;
276         }
277         memcpy(tdb_data2.dptr, tdb_data.dptr, tdb_data.dsize);
278         free(tdb_data.dptr);
279         tdb_data2.dsize = tdb_data.dsize;
280
281         msg->private_data = tdb_data2.dptr;
282         msg->num_elements = 0;
283         msg->elements = NULL;
284
285         ret = ltdb_unpack_data(ldb, &tdb_data2, msg);
286         if (ret == -1) {
287                 free(tdb_data2.dptr);
288                 return -1;              
289         }
290
291         if (!msg->dn) {
292                 msg->dn = ldb_strdup(ldb, dn);
293         }
294         if (!msg->dn) {
295                 ldb_free(ldb, tdb_data2.dptr);
296                 return -1;
297         }
298
299         return 1;
300 }
301
302
303 /*
304   search the database for a single simple dn
305 */
306 int ltdb_search_dn(struct ldb_context *ldb, char *dn,
307                    const char * const attrs[], struct ldb_message ***res)
308 {
309         int ret;
310         struct ldb_message msg, *msg2;
311
312         ret = ltdb_search_dn1(ldb, dn, &msg);
313         if (ret != 1) {
314                 return ret;
315         }
316
317         msg2 = ltdb_pull_attrs(ldb, &msg, attrs);
318
319         ltdb_search_dn1_free(ldb, &msg);
320
321         if (!msg2) {
322                 return -1;              
323         }
324
325         *res = ldb_malloc_array_p(ldb, struct ldb_message *, 2);
326         if (! *res) {
327                 msg_free_all_parts(ldb, msg2);
328                 return -1;              
329         }
330
331         (*res)[0] = msg2;
332         (*res)[1] = NULL;
333
334         return 1;
335 }
336
337
338 /*
339   add a set of attributes from a record to a set of results
340   return 0 on success, -1 on failure
341 */
342 int ltdb_add_attr_results(struct ldb_context *ldb, struct ldb_message *msg,
343                           const char * const attrs[], 
344                           unsigned int *count, 
345                           struct ldb_message ***res)
346 {
347         struct ldb_message *msg2;
348         struct ldb_message **res2;
349
350         /* pull the attributes that the user wants */
351         msg2 = ltdb_pull_attrs(ldb, msg, attrs);
352         if (!msg2) {
353                 return -1;
354         }
355
356         /* add to the results list */
357         res2 = ldb_realloc_p(ldb, *res, struct ldb_message *, (*count)+2);
358         if (!res2) {
359                 msg_free_all_parts(ldb, msg2);
360                 return -1;
361         }
362
363         (*res) = res2;
364
365         (*res)[*count] = msg2;
366         (*res)[(*count)+1] = NULL;
367         (*count)++;
368
369         return 0;
370 }
371
372
373 /*
374   internal search state during a full db search
375 */
376 struct ltdb_search_info {
377         struct ldb_context *ldb;
378         struct ldb_parse_tree *tree;
379         const char *base;
380         enum ldb_scope scope;
381         const char * const *attrs;
382         struct ldb_message **msgs;
383         int failures;
384         int count;
385 };
386
387
388 /*
389   search function for a non-indexed search
390  */
391 static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
392 {
393         struct ltdb_search_info *sinfo = state;
394         struct ldb_message msg;
395         int ret;
396
397         if (key.dsize < 4 || 
398             strncmp(key.dptr, "DN=", 3) != 0) {
399                 return 0;
400         }
401
402         /* unpack the record */
403         ret = ltdb_unpack_data(sinfo->ldb, &data, &msg);
404         if (ret == -1) {
405                 sinfo->failures++;
406                 return 0;
407         }
408
409         if (!msg.dn) {
410                 msg.dn = key.dptr + 3;
411         }
412
413         /* see if it matches the given expression */
414         if (!ldb_message_match(sinfo->ldb, &msg, sinfo->tree, 
415                                sinfo->base, sinfo->scope)) {
416                 ltdb_unpack_data_free(sinfo->ldb, &msg);
417                 return 0;
418         }
419
420         ret = ltdb_add_attr_results(sinfo->ldb, &msg, sinfo->attrs, &sinfo->count, &sinfo->msgs);
421
422         if (ret == -1) {
423                 sinfo->failures++;
424         }
425
426         ltdb_unpack_data_free(sinfo->ldb, &msg);
427
428         return ret;
429 }
430
431
432 /*
433   free a set of search results
434 */
435 int ltdb_search_free(struct ldb_context *ldb, struct ldb_message **msgs)
436 {
437         struct ltdb_private *ltdb = ldb->private_data;
438         int i;
439
440         ltdb->last_err_string = NULL;
441         
442         if (!msgs) return 0;
443
444         for (i=0;msgs[i];i++) {
445                 msg_free_all_parts(ldb, msgs[i]);
446         }
447
448         ldb_free(ldb, msgs);
449
450         return 0;
451 }
452
453 /*
454   search the database with a LDAP-like expression.
455   this is the "full search" non-indexed varient
456 */
457 static int ltdb_search_full(struct ldb_context *ldb, 
458                             const char *base,
459                             enum ldb_scope scope,
460                             struct ldb_parse_tree *tree,
461                             const char * const attrs[], struct ldb_message ***res)
462 {
463         struct ltdb_private *ltdb = ldb->private_data;
464         int ret;
465         struct ltdb_search_info sinfo;
466
467         sinfo.tree = tree;
468         sinfo.ldb = ldb;
469         sinfo.scope = scope;
470         sinfo.base = base;
471         sinfo.attrs = attrs;
472         sinfo.msgs = NULL;
473         sinfo.count = 0;
474         sinfo.failures = 0;
475
476         ret = tdb_traverse(ltdb->tdb, search_func, &sinfo);
477
478         if (ret == -1) {
479                 ltdb_search_free(ldb, sinfo.msgs);
480                 return -1;
481         }
482
483         *res = sinfo.msgs;
484         return sinfo.count;
485 }
486
487
488 /*
489   search the database with a LDAP-like expression.
490   choses a search method
491 */
492 int ltdb_search(struct ldb_context *ldb, const char *base,
493                 enum ldb_scope scope, const char *expression,
494                 const char * const attrs[], struct ldb_message ***res)
495 {
496         struct ltdb_private *ltdb = ldb->private_data;
497         struct ldb_parse_tree *tree;
498         int ret;
499
500         ltdb->last_err_string = NULL;
501
502         if (ltdb_cache_load(ldb) != 0) {
503                 return -1;
504         }
505
506         *res = NULL;
507
508         /* form a parse tree for the expression */
509         tree = ldb_parse_tree(ldb, expression);
510         if (!tree) {
511                 ltdb->last_err_string = "expression parse failed";
512                 return -1;
513         }
514
515         if (tree->operation == LDB_OP_SIMPLE && 
516             ldb_attr_cmp(tree->u.simple.attr, "dn") == 0 &&
517             !ltdb_has_wildcard(ldb, tree->u.simple.attr, &tree->u.simple.value)) {
518                 /* yay! its a nice simple one */
519                 ret = ltdb_search_dn(ldb, tree->u.simple.value.data, attrs, res);
520         } else {
521                 ret = ltdb_search_indexed(ldb, base, scope, tree, attrs, res);
522                 if (ret == -1) {
523                         ret = ltdb_search_full(ldb, base, scope, tree, attrs, res);
524                 }
525         }
526
527         ldb_parse_tree_free(ldb, tree);
528
529         return ret;
530 }
531