r25690: - only use a readonly traverse in ldb_search when not in a transaction. When...
[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 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 = (struct ltdb_private *)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 = (struct ltdb_private *)module->private_data;
256         if (ltdb->in_transaction == 0) {
257                 return tdb_lockall_read(ltdb->tdb);
258         }
259         return 0;
260 }
261
262 /*
263   unlock the database after a ltdb_lock_read()
264 */
265 static int ltdb_unlock_read(struct ldb_module *module)
266 {
267         struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data;
268         if (ltdb->in_transaction == 0) {
269                 return tdb_unlockall_read(ltdb->tdb);
270         }
271         return 0;
272 }
273
274 /*
275   add a set of attributes from a record to a set of results
276   return 0 on success, -1 on failure
277 */
278 int ltdb_add_attr_results(struct ldb_module *module, 
279                           TALLOC_CTX *mem_ctx, 
280                           struct ldb_message *msg,
281                           const char * const attrs[], 
282                           unsigned int *count, 
283                           struct ldb_message ***res)
284 {
285         struct ldb_message *msg2;
286         struct ldb_message **res2;
287
288         /* pull the attributes that the user wants */
289         msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs);
290         if (!msg2) {
291                 return -1;
292         }
293
294         /* add to the results list */
295         res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2);
296         if (!res2) {
297                 talloc_free(msg2);
298                 return -1;
299         }
300
301         (*res) = res2;
302
303         (*res)[*count] = talloc_move(*res, &msg2);
304         (*res)[(*count)+1] = NULL;
305         (*count)++;
306
307         return 0;
308 }
309
310
311
312 /*
313   filter the specified list of attributes from a message
314   removing not requested attrs.
315  */
316 int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
317 {
318         int i, keep_all = 0;
319
320         if (attrs) {
321                 /* check for special attrs */
322                 for (i = 0; attrs[i]; i++) {
323                         if (strcmp(attrs[i], "*") == 0) {
324                                 keep_all = 1;
325                                 break;
326                         }
327
328                         if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
329                                 if (msg_add_distinguished_name(msg) != 0) {
330                                         return -1;
331                                 }
332                         }
333                 }
334         } else {
335                 keep_all = 1;
336         }
337         
338         if (keep_all) {
339                 if (msg_add_distinguished_name(msg) != 0) {
340                         return -1;
341                 }
342                 return 0;
343         }
344
345         for (i = 0; i < msg->num_elements; i++) {
346                 int j, found;
347                 
348                 for (j = 0, found = 0; attrs[j]; j++) {
349                         if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) {
350                                 found = 1;
351                                 break;
352                         }
353                 }
354
355                 if (!found) {
356                         ldb_msg_remove_attr(msg, msg->elements[i].name);
357                         i--;
358                 }
359         }
360
361         return 0;
362 }
363
364 /*
365   search function for a non-indexed search
366  */
367 static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
368 {
369         struct ldb_handle *handle = talloc_get_type(state, struct ldb_handle);
370         struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
371         struct ldb_reply *ares = NULL;
372         int ret;
373
374         if (key.dsize < 4 || 
375             strncmp((char *)key.dptr, "DN=", 3) != 0) {
376                 return 0;
377         }
378
379         ares = talloc_zero(ac, struct ldb_reply);
380         if (!ares) {
381                 handle->status = LDB_ERR_OPERATIONS_ERROR;
382                 handle->state = LDB_ASYNC_DONE;
383                 return -1;
384         }
385
386         ares->message = ldb_msg_new(ares);
387         if (!ares->message) {
388                 handle->status = LDB_ERR_OPERATIONS_ERROR;
389                 handle->state = LDB_ASYNC_DONE;
390                 talloc_free(ares);
391                 return -1;
392         }
393
394         /* unpack the record */
395         ret = ltdb_unpack_data(ac->module, &data, ares->message);
396         if (ret == -1) {
397                 talloc_free(ares);
398                 return -1;
399         }
400
401         if (!ares->message->dn) {
402                 ares->message->dn = ldb_dn_new(ares->message, ac->module->ldb, (char *)key.dptr + 3);
403                 if (ares->message->dn == NULL) {
404                         handle->status = LDB_ERR_OPERATIONS_ERROR;
405                         handle->state = LDB_ASYNC_DONE;
406                         talloc_free(ares);
407                         return -1;
408                 }
409         }
410
411         /* see if it matches the given expression */
412         if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, 
413                                ac->base, ac->scope)) {
414                 talloc_free(ares);
415                 return 0;
416         }
417
418         /* filter the attributes that the user wants */
419         ret = ltdb_filter_attrs(ares->message, ac->attrs);
420
421         if (ret == -1) {
422                 handle->status = LDB_ERR_OPERATIONS_ERROR;
423                 handle->state = LDB_ASYNC_DONE;
424                 talloc_free(ares);
425                 return -1;
426         }
427
428         ares->type = LDB_REPLY_ENTRY;
429         handle->state = LDB_ASYNC_PENDING;
430         handle->status = ac->callback(ac->module->ldb, ac->context, ares);
431
432         if (handle->status != LDB_SUCCESS) {
433                 /* don't try to free ares here, the callback is in charge of that */
434                 return -1;
435         }       
436
437         return 0;
438 }
439
440
441 /*
442   search the database with a LDAP-like expression.
443   this is the "full search" non-indexed variant
444 */
445 static int ltdb_search_full(struct ldb_handle *handle)
446 {
447         struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
448         struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private);
449         int ret;
450
451         if (ltdb->in_transaction != 0) {
452                 ret = tdb_traverse(ltdb->tdb, search_func, handle);
453         } else {
454                 ret = tdb_traverse_read(ltdb->tdb, search_func, handle);
455         }
456
457         if (ret == -1) {
458                 handle->status = LDB_ERR_OPERATIONS_ERROR;
459         }
460
461         handle->state = LDB_ASYNC_DONE;
462         return LDB_SUCCESS;
463 }
464
465 /*
466   search the database with a LDAP-like expression.
467   choses a search method
468 */
469 int ltdb_search(struct ldb_module *module, struct ldb_request *req)
470 {
471         struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
472         struct ltdb_context *ltdb_ac;
473         struct ldb_reply *ares;
474         int ret;
475
476         if ((( ! ldb_dn_is_valid(req->op.search.base)) || ldb_dn_is_null(req->op.search.base)) &&
477             (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL))
478                 return LDB_ERR_OPERATIONS_ERROR;
479
480         if (ltdb_lock_read(module) != 0) {
481                 return LDB_ERR_OPERATIONS_ERROR;
482         }
483
484         if (ltdb_cache_load(module) != 0) {
485                 ltdb_unlock_read(module);
486                 return LDB_ERR_OPERATIONS_ERROR;
487         }
488
489         if (req->op.search.tree == NULL) {
490                 ltdb_unlock_read(module);
491                 return LDB_ERR_OPERATIONS_ERROR;
492         }
493
494         req->handle = init_ltdb_handle(ltdb, module, req);
495         if (req->handle == NULL) {
496                 ltdb_unlock_read(module);
497                 return LDB_ERR_OPERATIONS_ERROR;
498         }
499         ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
500
501         ltdb_ac->tree = req->op.search.tree;
502         ltdb_ac->scope = req->op.search.scope;
503         ltdb_ac->base = req->op.search.base;
504         ltdb_ac->attrs = req->op.search.attrs;
505
506         ret = ltdb_search_indexed(req->handle);
507         if (ret == LDB_ERR_OPERATIONS_ERROR) {
508                 ret = ltdb_search_full(req->handle);
509         }
510         if (ret != LDB_SUCCESS) {
511                 ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n");
512                 req->handle->state = LDB_ASYNC_DONE;
513                 req->handle->status = ret;
514         }
515
516         /* Finally send an LDB_REPLY_DONE packet when searching is finished */
517
518         ares = talloc_zero(req, struct ldb_reply);
519         if (!ares) {
520                 ltdb_unlock_read(module);
521                 return LDB_ERR_OPERATIONS_ERROR;
522         }
523
524         req->handle->state = LDB_ASYNC_DONE;
525         ares->type = LDB_REPLY_DONE;
526
527         ret = req->callback(module->ldb, req->context, ares);
528         req->handle->status = ret;
529
530         ltdb_unlock_read(module);
531
532         return LDB_SUCCESS;
533 }
534