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