013b341d42a36a68bdd6378632f19d2a999679c9
[jelmer/samba4-debian.git] / source / 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 3 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, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb search functions
28  *
29  *  Description: functions to search ldb+tdb databases
30  *
31  *  Author: Andrew Tridgell
32  */
33
34 #include "ldb_includes.h"
35
36 #include "ldb_tdb.h"
37
38 /*
39   add one element to a message
40 */
41 static int msg_add_element(struct ldb_message *ret, 
42                            const struct ldb_message_element *el,
43                            int check_duplicates)
44 {
45         unsigned int i;
46         struct ldb_message_element *e2, *elnew;
47
48         if (check_duplicates && ldb_msg_find_element(ret, el->name)) {
49                 /* its already there */
50                 return 0;
51         }
52
53         e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1);
54         if (!e2) {
55                 return -1;
56         }
57         ret->elements = e2;
58         
59         elnew = &e2[ret->num_elements];
60
61         elnew->name = talloc_strdup(ret->elements, el->name);
62         if (!elnew->name) {
63                 return -1;
64         }
65
66         if (el->num_values) {
67                 elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values);
68                 if (!elnew->values) {
69                         return -1;
70                 }
71         } else {
72                 elnew->values = NULL;
73         }
74
75         for (i=0;i<el->num_values;i++) {
76                 elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]);
77                 if (elnew->values[i].length != el->values[i].length) {
78                         return -1;
79                 }
80         }
81
82         elnew->num_values = el->num_values;
83
84         ret->num_elements++;
85
86         return 0;
87 }
88
89 /*
90   add the special distinguishedName element
91 */
92 static int msg_add_distinguished_name(struct ldb_message *msg)
93 {
94         struct ldb_message_element el;
95         struct ldb_val val;
96         int ret;
97
98         el.flags = 0;
99         el.name = "distinguishedName";
100         el.num_values = 1;
101         el.values = &val;
102         val.data = (uint8_t *)ldb_dn_alloc_linearized(msg, msg->dn);
103         val.length = strlen((char *)val.data);
104         
105         ret = msg_add_element(msg, &el, 1);
106         return ret;
107 }
108
109 /*
110   add all elements from one message into another
111  */
112 static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret,
113                                 const struct ldb_message *msg)
114 {
115         struct ldb_context *ldb = module->ldb;
116         unsigned int i;
117         int check_duplicates = (ret->num_elements != 0);
118
119         if (msg_add_distinguished_name(ret) != 0) {
120                 return -1;
121         }
122
123         for (i=0;i<msg->num_elements;i++) {
124                 const struct ldb_schema_attribute *a;
125                 a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
126                 if (a->flags & LDB_ATTR_FLAG_HIDDEN) {
127                         continue;
128                 }
129                 if (msg_add_element(ret, &msg->elements[i],
130                                     check_duplicates) != 0) {
131                         return -1;
132                 }
133         }
134
135         return 0;
136 }
137
138
139 /*
140   pull the specified list of attributes from a message
141  */
142 static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module, 
143                                            TALLOC_CTX *mem_ctx, 
144                                            const struct ldb_message *msg, 
145                                            const char * const *attrs)
146 {
147         struct ldb_message *ret;
148         int i;
149
150         ret = talloc(mem_ctx, struct ldb_message);
151         if (!ret) {
152                 return NULL;
153         }
154
155         ret->dn = ldb_dn_copy(ret, msg->dn);
156         if (!ret->dn) {
157                 talloc_free(ret);
158                 return NULL;
159         }
160
161         ret->num_elements = 0;
162         ret->elements = NULL;
163
164         if (!attrs) {
165                 if (msg_add_all_elements(module, ret, msg) != 0) {
166                         talloc_free(ret);
167                         return NULL;
168                 }
169                 return ret;
170         }
171
172         for (i=0;attrs[i];i++) {
173                 struct ldb_message_element *el;
174
175                 if (strcmp(attrs[i], "*") == 0) {
176                         if (msg_add_all_elements(module, ret, msg) != 0) {
177                                 talloc_free(ret);
178                                 return NULL;
179                         }
180                         continue;
181                 }
182
183                 if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
184                         if (msg_add_distinguished_name(ret) != 0) {
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, 1) != 0) {
195                         talloc_free(ret);
196                         return NULL;                            
197                 }
198         }
199
200         return ret;
201 }
202
203
204 /*
205   search the database for a single simple dn, returning all attributes
206   in a single message
207
208   return LDB_ERR_NO_SUCH_OBJECT on record-not-found
209   and LDB_SUCCESS on success
210 */
211 int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg)
212 {
213         struct ltdb_private *ltdb = module->private_data;
214         int ret;
215         TDB_DATA tdb_key, tdb_data;
216
217         memset(msg, 0, sizeof(*msg));
218
219         /* form the key */
220         tdb_key = ltdb_key(module, dn);
221         if (!tdb_key.dptr) {
222                 return LDB_ERR_OPERATIONS_ERROR;
223         }
224
225         tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
226         talloc_free(tdb_key.dptr);
227         if (!tdb_data.dptr) {
228                 return LDB_ERR_NO_SUCH_OBJECT;
229         }
230
231         msg->num_elements = 0;
232         msg->elements = NULL;
233
234         ret = ltdb_unpack_data(module, &tdb_data, msg);
235         free(tdb_data.dptr);
236         if (ret == -1) {
237                 return LDB_ERR_OPERATIONS_ERROR;                
238         }
239
240         if (!msg->dn) {
241                 msg->dn = ldb_dn_copy(msg, dn);
242         }
243         if (!msg->dn) {
244                 return LDB_ERR_OPERATIONS_ERROR;
245         }
246
247         return LDB_SUCCESS;
248 }
249
250 /*
251   lock the database for read - use by ltdb_search
252 */
253 static int ltdb_lock_read(struct ldb_module *module)
254 {
255         struct ltdb_private *ltdb = module->private_data;
256         return tdb_lockall_read(ltdb->tdb);
257 }
258
259 /*
260   unlock the database after a ltdb_lock_read()
261 */
262 static int ltdb_unlock_read(struct ldb_module *module)
263 {
264         struct ltdb_private *ltdb = module->private_data;
265         return tdb_unlockall_read(ltdb->tdb);
266 }
267
268 /*
269   add a set of attributes from a record to a set of results
270   return 0 on success, -1 on failure
271 */
272 int ltdb_add_attr_results(struct ldb_module *module, 
273                           TALLOC_CTX *mem_ctx, 
274                           struct ldb_message *msg,
275                           const char * const attrs[], 
276                           unsigned int *count, 
277                           struct ldb_message ***res)
278 {
279         struct ldb_message *msg2;
280         struct ldb_message **res2;
281
282         /* pull the attributes that the user wants */
283         msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs);
284         if (!msg2) {
285                 return -1;
286         }
287
288         /* add to the results list */
289         res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2);
290         if (!res2) {
291                 talloc_free(msg2);
292                 return -1;
293         }
294
295         (*res) = res2;
296
297         (*res)[*count] = talloc_move(*res, &msg2);
298         (*res)[(*count)+1] = NULL;
299         (*count)++;
300
301         return 0;
302 }
303
304
305
306 /*
307   filter the specified list of attributes from a message
308   removing not requested attrs.
309  */
310 int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
311 {
312         int i, keep_all = 0;
313
314         if (attrs) {
315                 /* check for special attrs */
316                 for (i = 0; attrs[i]; i++) {
317                         if (strcmp(attrs[i], "*") == 0) {
318                                 keep_all = 1;
319                                 break;
320                         }
321
322                         if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
323                                 if (msg_add_distinguished_name(msg) != 0) {
324                                         return -1;
325                                 }
326                         }
327                 }
328         } else {
329                 keep_all = 1;
330         }
331         
332         if (keep_all) {
333                 if (msg_add_distinguished_name(msg) != 0) {
334                         return -1;
335                 }
336                 return 0;
337         }
338
339         for (i = 0; i < msg->num_elements; i++) {
340                 int j, found;
341                 
342                 for (j = 0, found = 0; attrs[j]; j++) {
343                         if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) {
344                                 found = 1;
345                                 break;
346                         }
347                 }
348
349                 if (!found) {
350                         ldb_msg_remove_attr(msg, msg->elements[i].name);
351                         i--;
352                 }
353         }
354
355         return 0;
356 }
357
358 /*
359   search function for a non-indexed search
360  */
361 static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
362 {
363         struct ldb_handle *handle = talloc_get_type(state, struct ldb_handle);
364         struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
365         struct ldb_reply *ares = NULL;
366         int ret;
367
368         if (key.dsize < 4 || 
369             strncmp((char *)key.dptr, "DN=", 3) != 0) {
370                 return 0;
371         }
372
373         ares = talloc_zero(ac, struct ldb_reply);
374         if (!ares) {
375                 handle->status = LDB_ERR_OPERATIONS_ERROR;
376                 handle->state = LDB_ASYNC_DONE;
377                 return -1;
378         }
379
380         ares->message = ldb_msg_new(ares);
381         if (!ares->message) {
382                 handle->status = LDB_ERR_OPERATIONS_ERROR;
383                 handle->state = LDB_ASYNC_DONE;
384                 talloc_free(ares);
385                 return -1;
386         }
387
388         /* unpack the record */
389         ret = ltdb_unpack_data(ac->module, &data, ares->message);
390         if (ret == -1) {
391                 talloc_free(ares);
392                 return -1;
393         }
394
395         if (!ares->message->dn) {
396                 ares->message->dn = ldb_dn_new(ares->message, ac->module->ldb, (char *)key.dptr + 3);
397                 if (ares->message->dn == NULL) {
398                         handle->status = LDB_ERR_OPERATIONS_ERROR;
399                         handle->state = LDB_ASYNC_DONE;
400                         talloc_free(ares);
401                         return -1;
402                 }
403         }
404
405         /* see if it matches the given expression */
406         if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, 
407                                ac->base, ac->scope)) {
408                 talloc_free(ares);
409                 return 0;
410         }
411
412         /* filter the attributes that the user wants */
413         ret = ltdb_filter_attrs(ares->message, ac->attrs);
414
415         if (ret == -1) {
416                 handle->status = LDB_ERR_OPERATIONS_ERROR;
417                 handle->state = LDB_ASYNC_DONE;
418                 talloc_free(ares);
419                 return -1;
420         }
421
422         ares->type = LDB_REPLY_ENTRY;
423         handle->state = LDB_ASYNC_PENDING;
424         handle->status = ac->callback(ac->module->ldb, ac->context, ares);
425
426         if (handle->status != LDB_SUCCESS) {
427                 /* don't try to free ares here, the callback is in charge of that */
428                 return -1;
429         }       
430
431         return 0;
432 }
433
434
435 /*
436   search the database with a LDAP-like expression.
437   this is the "full search" non-indexed variant
438 */
439 static int ltdb_search_full(struct ldb_handle *handle)
440 {
441         struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
442         struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private);
443         int ret;
444
445         ret = tdb_traverse_read(ltdb->tdb, search_func, handle);
446
447         if (ret == -1) {
448                 handle->status = LDB_ERR_OPERATIONS_ERROR;
449         }
450
451         handle->state = LDB_ASYNC_DONE;
452         return LDB_SUCCESS;
453 }
454
455 /*
456   search the database with a LDAP-like expression.
457   choses a search method
458 */
459 int ltdb_search(struct ldb_module *module, struct ldb_request *req)
460 {
461         struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
462         struct ltdb_context *ltdb_ac;
463         struct ldb_reply *ares;
464         int ret;
465
466         if ((( ! ldb_dn_is_valid(req->op.search.base)) || ldb_dn_is_null(req->op.search.base)) &&
467             (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL))
468                 return LDB_ERR_OPERATIONS_ERROR;
469
470         if (ltdb_lock_read(module) != 0) {
471                 return LDB_ERR_OPERATIONS_ERROR;
472         }
473
474         if (ltdb_cache_load(module) != 0) {
475                 ltdb_unlock_read(module);
476                 return LDB_ERR_OPERATIONS_ERROR;
477         }
478
479         if (req->op.search.tree == NULL) {
480                 ltdb_unlock_read(module);
481                 return LDB_ERR_OPERATIONS_ERROR;
482         }
483
484         req->handle = init_ltdb_handle(ltdb, module, req);
485         if (req->handle == NULL) {
486                 ltdb_unlock_read(module);
487                 return LDB_ERR_OPERATIONS_ERROR;
488         }
489         ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
490
491         ltdb_ac->tree = req->op.search.tree;
492         ltdb_ac->scope = req->op.search.scope;
493         ltdb_ac->base = req->op.search.base;
494         ltdb_ac->attrs = req->op.search.attrs;
495
496         ret = ltdb_search_indexed(req->handle);
497         if (ret == LDB_ERR_OPERATIONS_ERROR) {
498                 ret = ltdb_search_full(req->handle);
499         }
500         if (ret != LDB_SUCCESS) {
501                 ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n");
502                 req->handle->state = LDB_ASYNC_DONE;
503                 req->handle->status = ret;
504         }
505
506         /* Finally send an LDB_REPLY_DONE packet when searching is finished */
507
508         ares = talloc_zero(req, struct ldb_reply);
509         if (!ares) {
510                 ltdb_unlock_read(module);
511                 return LDB_ERR_OPERATIONS_ERROR;
512         }
513
514         req->handle->state = LDB_ASYNC_DONE;
515         ares->type = LDB_REPLY_DONE;
516
517         ret = req->callback(module->ldb, req->context, ares);
518         req->handle->status = ret;
519
520         ltdb_unlock_read(module);
521
522         return LDB_SUCCESS;
523 }
524