/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- ldb_list_find
- ldb_dn_key
- ldb_msg_find_idx
- list_cmp
- ltdb_index_dn_simple
- ltdb_index_dn_objectclass
- ltdb_index_dn_leaf
- list_intersect
- list_union
- ltdb_index_dn_or
- ltdb_index_dn_not
- ltdb_index_dn_and
- ltdb_index_dn
- ltdb_index_filter
- ltdb_search_indexed
- ltdb_index_add1_new
- ltdb_index_add1_add
- ltdb_index_add1
- ltdb_index_add0
- ltdb_index_add
- ltdb_index_del_value
- ltdb_index_del
- delete_index
- re_index
- ltdb_reindex
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 tdb backend - indexing
28 *
29 * Description: indexing routines for ldb tdb backend
30 *
31 * Author: Andrew Tridgell
32 */
33
34 #include "includes.h"
35 #include "ldb/include/includes.h"
36
37 #include "ldb/ldb_tdb/ldb_tdb.h"
38
39 /*
40 find an element in a list, using the given comparison function and
41 assuming that the list is already sorted using comp_fn
42
43 return -1 if not found, or the index of the first occurance of needle if found
44 */
45 static int ldb_list_find(const void *needle,
/* [<][>][^][v][top][bottom][index][help] */
46 const void *base, size_t nmemb, size_t size,
47 comparison_fn_t comp_fn)
48 {
49 const char *base_p = (const char *)base;
50 size_t min_i, max_i, test_i;
51
52 if (nmemb == 0) {
53 return -1;
54 }
55
56 min_i = 0;
57 max_i = nmemb-1;
58
59 while (min_i < max_i) {
60 int r;
61
62 test_i = (min_i + max_i) / 2;
63 /* the following cast looks strange, but is
64 correct. The key to understanding it is that base_p
65 is a pointer to an array of pointers, so we have to
66 dereference it after casting to void **. The strange
67 const in the middle gives us the right type of pointer
68 after the dereference (tridge) */
69 r = comp_fn(needle, *(void * const *)(base_p + (size * test_i)));
70 if (r == 0) {
71 /* scan back for first element */
72 while (test_i > 0 &&
73 comp_fn(needle, *(void * const *)(base_p + (size * (test_i-1)))) == 0) {
74 test_i--;
75 }
76 return test_i;
77 }
78 if (r < 0) {
79 if (test_i == 0) {
80 return -1;
81 }
82 max_i = test_i - 1;
83 }
84 if (r > 0) {
85 min_i = test_i + 1;
86 }
87 }
88
89 if (comp_fn(needle, *(void * const *)(base_p + (size * min_i))) == 0) {
90 return min_i;
91 }
92
93 return -1;
94 }
95
96 struct dn_list {
97 unsigned int count;
98 char **dn;
99 };
100
101 /*
102 return the dn key to be used for an index
103 caller frees
104 */
105 static struct ldb_dn *ldb_dn_key(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
106 const char *attr, const struct ldb_val *value)
107 {
108 struct ldb_dn *ret;
109 char *dn;
110 struct ldb_val v;
111 const struct ldb_attrib_handler *h;
112 char *attr_folded;
113
114 attr_folded = ldb_attr_casefold(ldb, attr);
115 if (!attr_folded) {
116 return NULL;
117 }
118
119 h = ldb_attrib_handler(ldb, attr);
120 if (h->canonicalise_fn(ldb, ldb, value, &v) != 0) {
121 /* canonicalisation can be refused. For example,
122 a attribute that takes wildcards will refuse to canonicalise
123 if the value contains a wildcard */
124 talloc_free(attr_folded);
125 return NULL;
126 }
127 if (ldb_should_b64_encode(&v)) {
128 char *vstr = ldb_base64_encode(ldb, (char *)v.data, v.length);
129 if (!vstr) return NULL;
130 dn = talloc_asprintf(ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr);
131 talloc_free(vstr);
132 if (v.data != value->data) {
133 talloc_free(v.data);
134 }
135 talloc_free(attr_folded);
136 if (dn == NULL) return NULL;
137 goto done;
138 }
139
140 dn = talloc_asprintf(ldb, "%s:%s:%.*s",
141 LTDB_INDEX, attr_folded, (int)v.length, (char *)v.data);
142
143 if (v.data != value->data) {
144 talloc_free(v.data);
145 }
146 talloc_free(attr_folded);
147
148 done:
149 ret = ldb_dn_explode(ldb, dn);
150 talloc_free(dn);
151 return ret;
152 }
153
154 /*
155 see if a attribute value is in the list of indexed attributes
156 */
157 static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr,
/* [<][>][^][v][top][bottom][index][help] */
158 unsigned int *v_idx, const char *key)
159 {
160 unsigned int i, j;
161 for (i=0;i<msg->num_elements;i++) {
162 if (ldb_attr_cmp(msg->elements[i].name, key) == 0) {
163 const struct ldb_message_element *el =
164 &msg->elements[i];
165 for (j=0;j<el->num_values;j++) {
166 if (ldb_attr_cmp((char *)el->values[j].data, attr) == 0) {
167 if (v_idx) {
168 *v_idx = j;
169 }
170 return i;
171 }
172 }
173 }
174 }
175 return -1;
176 }
177
178 /* used in sorting dn lists */
179 static int list_cmp(const char **s1, const char **s2)
/* [<][>][^][v][top][bottom][index][help] */
180 {
181 return strcmp(*s1, *s2);
182 }
183
184 /*
185 return a list of dn's that might match a simple indexed search or
186 */
187 static int ltdb_index_dn_simple(struct ldb_module *module,
/* [<][>][^][v][top][bottom][index][help] */
188 const struct ldb_parse_tree *tree,
189 const struct ldb_message *index_list,
190 struct dn_list *list)
191 {
192 struct ldb_context *ldb = module->ldb;
193 struct ldb_dn *dn;
194 int ret;
195 unsigned int i, j;
196 struct ldb_message *msg;
197
198 list->count = 0;
199 list->dn = NULL;
200
201 /* if the attribute isn't in the list of indexed attributes then
202 this node needs a full search */
203 if (ldb_msg_find_idx(index_list, tree->u.equality.attr, NULL, LTDB_IDXATTR) == -1) {
204 return -1;
205 }
206
207 /* the attribute is indexed. Pull the list of DNs that match the
208 search criterion */
209 dn = ldb_dn_key(ldb, tree->u.equality.attr, &tree->u.equality.value);
210 if (!dn) return -1;
211
212 msg = talloc(list, struct ldb_message);
213 if (msg == NULL) {
214 return -1;
215 }
216
217 ret = ltdb_search_dn1(module, dn, msg);
218 talloc_free(dn);
219 if (ret == 0 || ret == -1) {
220 return ret;
221 }
222
223 for (i=0;i<msg->num_elements;i++) {
224 struct ldb_message_element *el;
225
226 if (strcmp(msg->elements[i].name, LTDB_IDX) != 0) {
227 continue;
228 }
229
230 el = &msg->elements[i];
231
232 list->dn = talloc_array(list, char *, el->num_values);
233 if (!list->dn) {
234 talloc_free(msg);
235 return -1;
236 }
237
238 for (j=0;j<el->num_values;j++) {
239 list->dn[list->count] =
240 talloc_strdup(list->dn, (char *)el->values[j].data);
241 if (!list->dn[list->count]) {
242 talloc_free(msg);
243 return -1;
244 }
245 list->count++;
246 }
247 }
248
249 talloc_free(msg);
250
251 if (list->count > 1) {
252 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp);
253 }
254
255 return 1;
256 }
257
258
259 static int list_union(struct ldb_context *, struct dn_list *, const struct dn_list *);
260
261 /*
262 return a list of dn's that might match a simple indexed search on
263 the special objectclass attribute
264 */
265 static int ltdb_index_dn_objectclass(struct ldb_module *module,
/* [<][>][^][v][top][bottom][index][help] */
266 const struct ldb_parse_tree *tree,
267 const struct ldb_message *index_list,
268 struct dn_list *list)
269 {
270 struct ldb_context *ldb = module->ldb;
271 unsigned int i;
272 int ret;
273 const char *target = (const char *)tree->u.equality.value.data;
274 const char **subclasses;
275
276 list->count = 0;
277 list->dn = NULL;
278
279 ret = ltdb_index_dn_simple(module, tree, index_list, list);
280
281 subclasses = ldb_subclass_list(module->ldb, target);
282
283 if (subclasses == NULL) {
284 return ret;
285 }
286
287 for (i=0;subclasses[i];i++) {
288 struct ldb_parse_tree tree2;
289 struct dn_list *list2;
290 tree2.operation = LDB_OP_EQUALITY;
291 tree2.u.equality.attr = LTDB_OBJECTCLASS;
292 if (!tree2.u.equality.attr) {
293 return -1;
294 }
295 tree2.u.equality.value.data =
296 (uint8_t *)talloc_strdup(list, subclasses[i]);
297 if (tree2.u.equality.value.data == NULL) {
298 return -1;
299 }
300 tree2.u.equality.value.length = strlen(subclasses[i]);
301 list2 = talloc(list, struct dn_list);
302 if (list2 == NULL) {
303 talloc_free(tree2.u.equality.value.data);
304 return -1;
305 }
306 if (ltdb_index_dn_objectclass(module, &tree2,
307 index_list, list2) == 1) {
308 if (list->count == 0) {
309 *list = *list2;
310 ret = 1;
311 } else {
312 list_union(ldb, list, list2);
313 talloc_free(list2);
314 }
315 }
316 talloc_free(tree2.u.equality.value.data);
317 }
318
319 return ret;
320 }
321
322 /*
323 return a list of dn's that might match a leaf indexed search
324 */
325 static int ltdb_index_dn_leaf(struct ldb_module *module,
/* [<][>][^][v][top][bottom][index][help] */
326 const struct ldb_parse_tree *tree,
327 const struct ldb_message *index_list,
328 struct dn_list *list)
329 {
330 if (ldb_attr_cmp(tree->u.equality.attr, LTDB_OBJECTCLASS) == 0) {
331 return ltdb_index_dn_objectclass(module, tree, index_list, list);
332 }
333 if (ldb_attr_dn(tree->u.equality.attr) == 0) {
334 list->dn = talloc_array(list, char *, 1);
335 if (list->dn == NULL) {
336 ldb_oom(module->ldb);
337 return -1;
338 }
339 list->dn[0] = talloc_strdup(list->dn, (char *)tree->u.equality.value.data);
340 if (list->dn[0] == NULL) {
341 ldb_oom(module->ldb);
342 return -1;
343 }
344 list->count = 1;
345 return 1;
346 }
347 return ltdb_index_dn_simple(module, tree, index_list, list);
348 }
349
350
351 /*
352 list intersection
353 list = list & list2
354 relies on the lists being sorted
355 */
356 static int list_intersect(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
357 struct dn_list *list, const struct dn_list *list2)
358 {
359 struct dn_list *list3;
360 unsigned int i;
361
362 if (list->count == 0 || list2->count == 0) {
363 /* 0 & X == 0 */
364 return 0;
365 }
366
367 list3 = talloc(ldb, struct dn_list);
368 if (list3 == NULL) {
369 return -1;
370 }
371
372 list3->dn = talloc_array(list3, char *, list->count);
373 if (!list3->dn) {
374 talloc_free(list3);
375 return -1;
376 }
377 list3->count = 0;
378
379 for (i=0;i<list->count;i++) {
380 if (ldb_list_find(list->dn[i], list2->dn, list2->count,
381 sizeof(char *), (comparison_fn_t)strcmp) != -1) {
382 list3->dn[list3->count] = talloc_move(list3->dn, &list->dn[i]);
383 list3->count++;
384 } else {
385 talloc_free(list->dn[i]);
386 }
387 }
388
389 talloc_free(list->dn);
390 list->dn = talloc_move(list, &list3->dn);
391 list->count = list3->count;
392 talloc_free(list3);
393
394 return 0;
395 }
396
397
398 /*
399 list union
400 list = list | list2
401 relies on the lists being sorted
402 */
403 static int list_union(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
404 struct dn_list *list, const struct dn_list *list2)
405 {
406 unsigned int i;
407 char **d;
408 unsigned int count = list->count;
409
410 if (list->count == 0 && list2->count == 0) {
411 /* 0 | 0 == 0 */
412 return 0;
413 }
414
415 d = talloc_realloc(list, list->dn, char *, list->count + list2->count);
416 if (!d) {
417 return -1;
418 }
419 list->dn = d;
420
421 for (i=0;i<list2->count;i++) {
422 if (ldb_list_find(list2->dn[i], list->dn, count,
423 sizeof(char *), (comparison_fn_t)strcmp) == -1) {
424 list->dn[list->count] = talloc_strdup(list->dn, list2->dn[i]);
425 if (!list->dn[list->count]) {
426 return -1;
427 }
428 list->count++;
429 }
430 }
431
432 if (list->count != count) {
433 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp);
434 }
435
436 return 0;
437 }
438
439 static int ltdb_index_dn(struct ldb_module *module,
440 const struct ldb_parse_tree *tree,
441 const struct ldb_message *index_list,
442 struct dn_list *list);
443
444
445 /*
446 OR two index results
447 */
448 static int ltdb_index_dn_or(struct ldb_module *module,
/* [<][>][^][v][top][bottom][index][help] */
449 const struct ldb_parse_tree *tree,
450 const struct ldb_message *index_list,
451 struct dn_list *list)
452 {
453 struct ldb_context *ldb = module->ldb;
454 unsigned int i;
455 int ret;
456
457 ret = -1;
458 list->dn = NULL;
459 list->count = 0;
460
461 for (i=0;i<tree->u.list.num_elements;i++) {
462 struct dn_list *list2;
463 int v;
464
465 list2 = talloc(module, struct dn_list);
466 if (list2 == NULL) {
467 return -1;
468 }
469
470 v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
471
472 if (v == 0) {
473 /* 0 || X == X */
474 if (ret == -1) {
475 ret = 0;
476 }
477 talloc_free(list2);
478 continue;
479 }
480
481 if (v == -1) {
482 /* 1 || X == 1 */
483 talloc_free(list->dn);
484 talloc_free(list2);
485 return -1;
486 }
487
488 if (ret == -1) {
489 ret = 1;
490 list->dn = talloc_move(list, &list2->dn);
491 list->count = list2->count;
492 } else {
493 if (list_union(ldb, list, list2) == -1) {
494 talloc_free(list2);
495 return -1;
496 }
497 ret = 1;
498 }
499 talloc_free(list2);
500 }
501
502 if (list->count == 0) {
503 return 0;
504 }
505
506 return ret;
507 }
508
509
510 /*
511 NOT an index results
512 */
513 static int ltdb_index_dn_not(struct ldb_module *module,
/* [<][>][^][v][top][bottom][index][help] */
514 const struct ldb_parse_tree *tree,
515 const struct ldb_message *index_list,
516 struct dn_list *list)
517 {
518 /* the only way to do an indexed not would be if we could
519 negate the not via another not or if we knew the total
520 number of database elements so we could know that the
521 existing expression covered the whole database.
522
523 instead, we just give up, and rely on a full index scan
524 (unless an outer & manages to reduce the list)
525 */
526 return -1;
527 }
528
529 /*
530 AND two index results
531 */
532 static int ltdb_index_dn_and(struct ldb_module *module,
/* [<][>][^][v][top][bottom][index][help] */
533 const struct ldb_parse_tree *tree,
534 const struct ldb_message *index_list,
535 struct dn_list *list)
536 {
537 struct ldb_context *ldb = module->ldb;
538 unsigned int i;
539 int ret;
540
541 ret = -1;
542 list->dn = NULL;
543 list->count = 0;
544
545 for (i=0;i<tree->u.list.num_elements;i++) {
546 struct dn_list *list2;
547 int v;
548
549 list2 = talloc(module, struct dn_list);
550 if (list2 == NULL) {
551 return -1;
552 }
553
554 v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
555
556 if (v == 0) {
557 /* 0 && X == 0 */
558 talloc_free(list->dn);
559 talloc_free(list2);
560 return 0;
561 }
562
563 if (v == -1) {
564 talloc_free(list2);
565 continue;
566 }
567
568 if (ret == -1) {
569 ret = 1;
570 talloc_free(list->dn);
571 list->dn = talloc_move(list, &list2->dn);
572 list->count = list2->count;
573 } else {
574 if (list_intersect(ldb, list, list2) == -1) {
575 talloc_free(list2);
576 return -1;
577 }
578 }
579
580 talloc_free(list2);
581
582 if (list->count == 0) {
583 talloc_free(list->dn);
584 return 0;
585 }
586 }
587
588 return ret;
589 }
590
591 /*
592 return a list of dn's that might match a indexed search or
593 -1 if an error. return 0 for no matches, or 1 for matches
594 */
595 static int ltdb_index_dn(struct ldb_module *module,
/* [<][>][^][v][top][bottom][index][help] */
596 const struct ldb_parse_tree *tree,
597 const struct ldb_message *index_list,
598 struct dn_list *list)
599 {
600 int ret = -1;
601
602 switch (tree->operation) {
603 case LDB_OP_AND:
604 ret = ltdb_index_dn_and(module, tree, index_list, list);
605 break;
606
607 case LDB_OP_OR:
608 ret = ltdb_index_dn_or(module, tree, index_list, list);
609 break;
610
611 case LDB_OP_NOT:
612 ret = ltdb_index_dn_not(module, tree, index_list, list);
613 break;
614
615 case LDB_OP_EQUALITY:
616 ret = ltdb_index_dn_leaf(module, tree, index_list, list);
617 break;
618
619 case LDB_OP_SUBSTRING:
620 case LDB_OP_GREATER:
621 case LDB_OP_LESS:
622 case LDB_OP_PRESENT:
623 case LDB_OP_APPROX:
624 case LDB_OP_EXTENDED:
625 /* we can't index with fancy bitops yet */
626 ret = -1;
627 break;
628 }
629
630 return ret;
631 }
632
633 /*
634 filter a candidate dn_list from an indexed search into a set of results
635 extracting just the given attributes
636 */
637 static int ltdb_index_filter(const struct dn_list *dn_list,
/* [<][>][^][v][top][bottom][index][help] */
638 struct ldb_handle *handle)
639 {
640 struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
641 struct ldb_reply *ares = NULL;
642 unsigned int i;
643
644 if (!ac) {
645 return LDB_ERR_OPERATIONS_ERROR;
646 }
647
648 for (i = 0; i < dn_list->count; i++) {
649 struct ldb_dn *dn;
650 int ret;
651
652 ares = talloc_zero(ac, struct ldb_reply);
653 if (!ares) {
654 handle->status = LDB_ERR_OPERATIONS_ERROR;
655 handle->state = LDB_ASYNC_DONE;
656 return LDB_ERR_OPERATIONS_ERROR;
657 }
658
659 ares->message = ldb_msg_new(ares);
660 if (!ares->message) {
661 handle->status = LDB_ERR_OPERATIONS_ERROR;
662 handle->state = LDB_ASYNC_DONE;
663 talloc_free(ares);
664 return LDB_ERR_OPERATIONS_ERROR;
665 }
666
667
668 dn = ldb_dn_explode(ares->message, dn_list->dn[i]);
669 if (dn == NULL) {
670 talloc_free(ares);
671 return LDB_ERR_OPERATIONS_ERROR;
672 }
673
674 ret = ltdb_search_dn1(ac->module, dn, ares->message);
675 talloc_free(dn);
676 if (ret == 0) {
677 /* the record has disappeared? yes, this can happen */
678 talloc_free(ares);
679 continue;
680 }
681
682 if (ret == -1) {
683 /* an internal error */
684 talloc_free(ares);
685 return LDB_ERR_OPERATIONS_ERROR;
686 }
687
688 if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, ac->base, ac->scope)) {
689 talloc_free(ares);
690 continue;
691 }
692
693 /* filter the attributes that the user wants */
694 ret = ltdb_filter_attrs(ares->message, ac->attrs);
695
696 if (ret == -1) {
697 handle->status = LDB_ERR_OPERATIONS_ERROR;
698 handle->state = LDB_ASYNC_DONE;
699 talloc_free(ares);
700 return LDB_ERR_OPERATIONS_ERROR;
701 }
702
703 ares->type = LDB_REPLY_ENTRY;
704 handle->state = LDB_ASYNC_PENDING;
705 handle->status = ac->callback(ac->module->ldb, ac->context, ares);
706
707 if (handle->status != LDB_SUCCESS) {
708 handle->state = LDB_ASYNC_DONE;
709 return handle->status;
710 }
711 }
712
713 return LDB_SUCCESS;
714 }
715
716 /*
717 search the database with a LDAP-like expression using indexes
718 returns -1 if an indexed search is not possible, in which
719 case the caller should call ltdb_search_full()
720 */
721 int ltdb_search_indexed(struct ldb_handle *handle)
/* [<][>][^][v][top][bottom][index][help] */
722 {
723 struct ltdb_context *ac;
724 struct ltdb_private *ltdb;
725 struct dn_list *dn_list;
726 int ret;
727
728 if (!(ac = talloc_get_type(handle->private_data,
729 struct ltdb_context)) ||
730 !(ltdb = talloc_get_type(ac->module->private_data,
731 struct ltdb_private))) {
732 return -1;
733 }
734
735 if (ltdb->cache->indexlist->num_elements == 0 &&
736 ac->scope != LDB_SCOPE_BASE) {
737 /* no index list? must do full search */
738 return -1;
739 }
740
741 dn_list = talloc(handle, struct dn_list);
742 if (dn_list == NULL) {
743 return -1;
744 }
745
746 if (ac->scope == LDB_SCOPE_BASE) {
747 /* with BASE searches only one DN can match */
748 dn_list->dn = talloc_array(dn_list, char *, 1);
749 if (dn_list->dn == NULL) {
750 ldb_oom(ac->module->ldb);
751 return -1;
752 }
753 dn_list->dn[0] = ldb_dn_linearize(dn_list, ac->base);
754 if (dn_list->dn[0] == NULL) {
755 ldb_oom(ac->module->ldb);
756 return -1;
757 }
758 dn_list->count = 1;
759 ret = 1;
760 } else {
761 ret = ltdb_index_dn(ac->module, ac->tree, ltdb->cache->indexlist, dn_list);
762 }
763
764 if (ret == 1) {
765 /* we've got a candidate list - now filter by the full tree
766 and extract the needed attributes */
767 ret = ltdb_index_filter(dn_list, handle);
768 handle->status = ret;
769 handle->state = LDB_ASYNC_DONE;
770 }
771
772 talloc_free(dn_list);
773
774 return ret;
775 }
776
777 /*
778 add a index element where this is the first indexed DN for this value
779 */
780 static int ltdb_index_add1_new(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
781 struct ldb_message *msg,
782 struct ldb_message_element *el,
783 const char *dn)
784 {
785 struct ldb_message_element *el2;
786
787 /* add another entry */
788 el2 = talloc_realloc(msg, msg->elements,
789 struct ldb_message_element, msg->num_elements+1);
790 if (!el2) {
791 return -1;
792 }
793
794 msg->elements = el2;
795 msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, LTDB_IDX);
796 if (!msg->elements[msg->num_elements].name) {
797 return -1;
798 }
799 msg->elements[msg->num_elements].num_values = 0;
800 msg->elements[msg->num_elements].values = talloc(msg->elements, struct ldb_val);
801 if (!msg->elements[msg->num_elements].values) {
802 return -1;
803 }
804 msg->elements[msg->num_elements].values[0].length = strlen(dn);
805 msg->elements[msg->num_elements].values[0].data = discard_const_p(uint8_t, dn);
806 msg->elements[msg->num_elements].num_values = 1;
807 msg->num_elements++;
808
809 return 0;
810 }
811
812
813 /*
814 add a index element where this is not the first indexed DN for this
815 value
816 */
817 static int ltdb_index_add1_add(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
818 struct ldb_message *msg,
819 struct ldb_message_element *el,
820 int idx,
821 const char *dn)
822 {
823 struct ldb_val *v2;
824 unsigned int i;
825
826 /* for multi-valued attributes we can end up with repeats */
827 for (i=0;i<msg->elements[idx].num_values;i++) {
828 if (strcmp(dn, (char *)msg->elements[idx].values[i].data) == 0) {
829 return 0;
830 }
831 }
832
833 v2 = talloc_realloc(msg->elements, msg->elements[idx].values,
834 struct ldb_val,
835 msg->elements[idx].num_values+1);
836 if (!v2) {
837 return -1;
838 }
839 msg->elements[idx].values = v2;
840
841 msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn);
842 msg->elements[idx].values[msg->elements[idx].num_values].data = discard_const_p(uint8_t, dn);
843 msg->elements[idx].num_values++;
844
845 return 0;
846 }
847
848 /*
849 add an index entry for one message element
850 */
851 static int ltdb_index_add1(struct ldb_module *module, const char *dn,
/* [<][>][^][v][top][bottom][index][help] */
852 struct ldb_message_element *el, int v_idx)
853 {
854 struct ldb_context *ldb = module->ldb;
855 struct ldb_message *msg;
856 struct ldb_dn *dn_key;
857 int ret;
858 unsigned int i;
859
860 msg = talloc(module, struct ldb_message);
861 if (msg == NULL) {
862 errno = ENOMEM;
863 return -1;
864 }
865
866 dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
867 if (!dn_key) {
868 talloc_free(msg);
869 errno = ENOMEM;
870 return -1;
871 }
872 talloc_steal(msg, dn_key);
873
874 ret = ltdb_search_dn1(module, dn_key, msg);
875 if (ret == -1) {
876 talloc_free(msg);
877 return -1;
878 }
879
880 if (ret == 0) {
881 msg->dn = dn_key;
882 msg->num_elements = 0;
883 msg->elements = NULL;
884 }
885
886 for (i=0;i<msg->num_elements;i++) {
887 if (strcmp(LTDB_IDX, msg->elements[i].name) == 0) {
888 break;
889 }
890 }
891
892 if (i == msg->num_elements) {
893 ret = ltdb_index_add1_new(ldb, msg, el, dn);
894 } else {
895 ret = ltdb_index_add1_add(ldb, msg, el, i, dn);
896 }
897
898 if (ret == 0) {
899 ret = ltdb_store(module, msg, TDB_REPLACE);
900 }
901
902 talloc_free(msg);
903
904 return ret;
905 }
906
907 static int ltdb_index_add0(struct ldb_module *module, const char *dn,
/* [<][>][^][v][top][bottom][index][help] */
908 struct ldb_message_element *elements, int num_el)
909 {
910 struct ltdb_private *ltdb =
911 (struct ltdb_private *)module->private_data;
912 int ret;
913 unsigned int i, j;
914
915 if (dn[0] == '@') {
916 return 0;
917 }
918
919 if (ltdb->cache->indexlist->num_elements == 0) {
920 /* no indexed fields */
921 return 0;
922 }
923
924 for (i = 0; i < num_el; i++) {
925 ret = ldb_msg_find_idx(ltdb->cache->indexlist, elements[i].name,
926 NULL, LTDB_IDXATTR);
927 if (ret == -1) {
928 continue;
929 }
930 for (j = 0; j < elements[i].num_values; j++) {
931 ret = ltdb_index_add1(module, dn, &elements[i], j);
932 if (ret == -1) {
933 return -1;
934 }
935 }
936 }
937
938 return 0;
939 }
940
941 /*
942 add the index entries for a new record
943 return -1 on failure
944 */
945 int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg)
/* [<][>][^][v][top][bottom][index][help] */
946 {
947 struct ltdb_private *ltdb =
948 (struct ltdb_private *)module->private_data;
949 char *dn;
950 int ret;
951
952 dn = ldb_dn_linearize(ltdb, msg->dn);
953 if (dn == NULL) {
954 return -1;
955 }
956
957 ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements);
958
959 talloc_free(dn);
960
961 return ret;
962 }
963
964
965 /*
966 delete an index entry for one message element
967 */
968 int ltdb_index_del_value(struct ldb_module *module, const char *dn,
/* [<][>][^][v][top][bottom][index][help] */
969 struct ldb_message_element *el, int v_idx)
970 {
971 struct ldb_context *ldb = module->ldb;
972 struct ldb_message *msg;
973 struct ldb_dn *dn_key;
974 int ret, i;
975 unsigned int j;
976
977 if (dn[0] == '@') {
978 return 0;
979 }
980
981 dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
982 if (!dn_key) {
983 return -1;
984 }
985
986 msg = talloc(dn_key, struct ldb_message);
987 if (msg == NULL) {
988 talloc_free(dn_key);
989 return -1;
990 }
991
992 ret = ltdb_search_dn1(module, dn_key, msg);
993 if (ret == -1) {
994 talloc_free(dn_key);
995 return -1;
996 }
997
998 if (ret == 0) {
999 /* it wasn't indexed. Did we have an earlier error? If we did then
1000 its gone now */
1001 talloc_free(dn_key);
1002 return 0;
1003 }
1004
1005 i = ldb_msg_find_idx(msg, dn, &j, LTDB_IDX);
1006 if (i == -1) {
1007 ldb_debug(ldb, LDB_DEBUG_ERROR,
1008 "ERROR: dn %s not found in %s\n", dn,
1009 ldb_dn_linearize(dn_key, dn_key));
1010 /* it ain't there. hmmm */
1011 talloc_free(dn_key);
1012 return 0;
1013 }
1014
1015 if (j != msg->elements[i].num_values - 1) {
1016 memmove(&msg->elements[i].values[j],
1017 &msg->elements[i].values[j+1],
1018 (msg->elements[i].num_values-(j+1)) *
1019 sizeof(msg->elements[i].values[0]));
1020 }
1021 msg->elements[i].num_values--;
1022
1023 if (msg->elements[i].num_values == 0) {
1024 ret = ltdb_delete_noindex(module, dn_key);
1025 } else {
1026 ret = ltdb_store(module, msg, TDB_REPLACE);
1027 }
1028
1029 talloc_free(dn_key);
1030
1031 return ret;
1032 }
1033
1034 /*
1035 delete the index entries for a record
1036 return -1 on failure
1037 */
1038 int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg)
/* [<][>][^][v][top][bottom][index][help] */
1039 {
1040 struct ltdb_private *ltdb =
1041 (struct ltdb_private *)module->private_data;
1042 int ret;
1043 char *dn;
1044 unsigned int i, j;
1045
1046 /* find the list of indexed fields */
1047 if (ltdb->cache->indexlist->num_elements == 0) {
1048 /* no indexed fields */
1049 return 0;
1050 }
1051
1052 if (ldb_dn_is_special(msg->dn)) {
1053 return 0;
1054 }
1055
1056 dn = ldb_dn_linearize(ltdb, msg->dn);
1057 if (dn == NULL) {
1058 return -1;
1059 }
1060
1061 for (i = 0; i < msg->num_elements; i++) {
1062 ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name,
1063 NULL, LTDB_IDXATTR);
1064 if (ret == -1) {
1065 continue;
1066 }
1067 for (j = 0; j < msg->elements[i].num_values; j++) {
1068 ret = ltdb_index_del_value(module, dn, &msg->elements[i], j);
1069 if (ret == -1) {
1070 talloc_free(dn);
1071 return -1;
1072 }
1073 }
1074 }
1075
1076 talloc_free(dn);
1077 return 0;
1078 }
1079
1080
1081 /*
1082 traversal function that deletes all @INDEX records
1083 */
1084 static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
/* [<][>][^][v][top][bottom][index][help] */
1085 {
1086 const char *dn = "DN=" LTDB_INDEX ":";
1087 if (strncmp((char *)key.dptr, dn, strlen(dn)) == 0) {
1088 return tdb_delete(tdb, key);
1089 }
1090 return 0;
1091 }
1092
1093 /*
1094 traversal function that adds @INDEX records during a re index
1095 */
1096 static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
/* [<][>][^][v][top][bottom][index][help] */
1097 {
1098 struct ldb_module *module = (struct ldb_module *)state;
1099 struct ldb_message *msg;
1100 char *dn = NULL;
1101 int ret;
1102 TDB_DATA key2;
1103
1104 if (strncmp((char *)key.dptr, "DN=@", 4) == 0 ||
1105 strncmp((char *)key.dptr, "DN=", 3) != 0) {
1106 return 0;
1107 }
1108
1109 msg = talloc(module, struct ldb_message);
1110 if (msg == NULL) {
1111 return -1;
1112 }
1113
1114 ret = ltdb_unpack_data(module, &data, msg);
1115 if (ret != 0) {
1116 talloc_free(msg);
1117 return -1;
1118 }
1119
1120 /* check if the DN key has changed, perhaps due to the
1121 case insensitivity of an element changing */
1122 key2 = ltdb_key(module, msg->dn);
1123 if (key2.dptr == NULL) {
1124 /* probably a corrupt record ... darn */
1125 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s\n",
1126 ldb_dn_linearize(msg, msg->dn));
1127 talloc_free(msg);
1128 return 0;
1129 }
1130 if (strcmp((char *)key2.dptr, (char *)key.dptr) != 0) {
1131 tdb_delete(tdb, key);
1132 tdb_store(tdb, key2, data, 0);
1133 }
1134 talloc_free(key2.dptr);
1135
1136 if (msg->dn == NULL) {
1137 dn = (char *)key.dptr + 3;
1138 } else {
1139 if (!(dn = ldb_dn_linearize(msg->dn, msg->dn))) {
1140 talloc_free(msg);
1141 return -1;
1142 }
1143 }
1144
1145 ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements);
1146
1147 talloc_free(msg);
1148
1149 return ret;
1150 }
1151
1152 /*
1153 force a complete reindex of the database
1154 */
1155 int ltdb_reindex(struct ldb_module *module)
/* [<][>][^][v][top][bottom][index][help] */
1156 {
1157 struct ltdb_private *ltdb =
1158 (struct ltdb_private *)module->private_data;
1159 int ret;
1160
1161 if (ltdb_cache_reload(module) != 0) {
1162 return -1;
1163 }
1164
1165 /* first traverse the database deleting any @INDEX records */
1166 ret = tdb_traverse(ltdb->tdb, delete_index, NULL);
1167 if (ret == -1) {
1168 return -1;
1169 }
1170
1171 /* now traverse adding any indexes for normal LDB records */
1172 ret = tdb_traverse(ltdb->tdb, re_index, module);
1173 if (ret == -1) {
1174 return -1;
1175 }
1176
1177 return 0;
1178 }