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