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