Line data Source code
1 : /*
2 : ldb database mapping module
3 :
4 : Copyright (C) Jelmer Vernooij 2005
5 : Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
6 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
7 : Copyright (C) Simo Sorce <idra@samba.org> 2008
8 :
9 : ** NOTE! The following LGPL license applies to the ldb
10 : ** library. This does NOT imply that all of Samba is released
11 : ** under the LGPL
12 :
13 : This library is free software; you can redistribute it and/or
14 : modify it under the terms of the GNU Lesser General Public
15 : License as published by the Free Software Foundation; either
16 : version 3 of the License, or (at your option) any later version.
17 :
18 : This library is distributed in the hope that it will be useful,
19 : but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 : Lesser General Public License for more details.
22 :
23 : You should have received a copy of the GNU Lesser General Public
24 : License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 :
26 : */
27 :
28 : #include "replace.h"
29 : #include "system/filesys.h"
30 : #include "system/time.h"
31 : #include "ldb_map.h"
32 : #include "ldb_map_private.h"
33 :
34 :
35 : /* Mapping attributes
36 : * ================== */
37 :
38 : /* Select attributes that stay in the local partition. */
39 162 : static const char **map_attrs_select_local(struct ldb_module *module, void *mem_ctx, const char * const *attrs)
40 : {
41 162 : const struct ldb_map_context *data = map_get_context(module);
42 162 : const char **result;
43 162 : unsigned int i, last;
44 :
45 162 : if (attrs == NULL)
46 0 : return NULL;
47 :
48 162 : last = 0;
49 162 : result = talloc_array(mem_ctx, const char *, 1);
50 162 : if (result == NULL) {
51 0 : goto failed;
52 : }
53 162 : result[0] = NULL;
54 :
55 673 : for (i = 0; attrs[i]; i++) {
56 : /* Wildcards and ignored attributes are kept locally */
57 1010 : if ((ldb_attr_cmp(attrs[i], "*") == 0) ||
58 499 : (!map_attr_check_remote(data, attrs[i]))) {
59 264 : result = talloc_realloc(mem_ctx, result, const char *, last+2);
60 264 : if (result == NULL) {
61 0 : goto failed;
62 : }
63 :
64 264 : result[last] = talloc_strdup(result, attrs[i]);
65 264 : result[last+1] = NULL;
66 264 : last++;
67 : }
68 : }
69 :
70 0 : return result;
71 :
72 0 : failed:
73 0 : talloc_free(result);
74 0 : map_oom(module);
75 0 : return NULL;
76 : }
77 :
78 : /* Collect attributes that are mapped into the remote partition. */
79 162 : static const char **map_attrs_collect_remote(struct ldb_module *module, void *mem_ctx,
80 : const char * const *attrs)
81 : {
82 162 : const struct ldb_map_context *data = map_get_context(module);
83 162 : const char **result;
84 162 : const struct ldb_map_attribute *map;
85 162 : const char *name=NULL;
86 162 : unsigned int i, j, last;
87 162 : int ret;
88 :
89 162 : last = 0;
90 162 : result = talloc_array(mem_ctx, const char *, 1);
91 162 : if (result == NULL) {
92 0 : goto failed;
93 : }
94 162 : result[0] = NULL;
95 :
96 661 : for (i = 0; attrs[i]; i++) {
97 : /* Wildcards are kept remotely, too */
98 511 : if (ldb_attr_cmp(attrs[i], "*") == 0) {
99 12 : const char **new_attrs = NULL;
100 12 : ret = map_attrs_merge(module, mem_ctx, &new_attrs, attrs);
101 12 : if (ret != LDB_SUCCESS) {
102 0 : goto failed;
103 : }
104 12 : ret = map_attrs_merge(module, mem_ctx, &new_attrs, data->wildcard_attributes);
105 12 : if (ret != LDB_SUCCESS) {
106 0 : goto failed;
107 : }
108 :
109 12 : attrs = new_attrs;
110 12 : break;
111 : }
112 : }
113 :
114 673 : for (i = 0; attrs[i]; i++) {
115 : /* Wildcards are kept remotely, too */
116 511 : if (ldb_attr_cmp(attrs[i], "*") == 0) {
117 : /* Add all 'include in wildcard' attributes */
118 12 : name = attrs[i];
119 12 : goto named;
120 : }
121 :
122 : /* Add remote names of mapped attrs */
123 499 : map = map_attr_find_local(data, attrs[i]);
124 499 : if (map == NULL) {
125 151 : continue;
126 : }
127 :
128 348 : switch (map->type) {
129 101 : case LDB_MAP_IGNORE:
130 101 : continue;
131 :
132 31 : case LDB_MAP_KEEP:
133 31 : name = attrs[i];
134 31 : goto named;
135 :
136 211 : case LDB_MAP_RENAME:
137 : case LDB_MAP_RENDROP:
138 : case LDB_MAP_CONVERT:
139 211 : name = map->u.rename.remote_name;
140 211 : goto named;
141 :
142 0 : case LDB_MAP_GENERATE:
143 : /* Add all remote names of "generate" attrs */
144 10 : for (j = 0; map->u.generate.remote_names[j]; j++) {
145 5 : result = talloc_realloc(mem_ctx, result, const char *, last+2);
146 5 : if (result == NULL) {
147 0 : goto failed;
148 : }
149 :
150 5 : result[last] = talloc_strdup(result, map->u.generate.remote_names[j]);
151 5 : result[last+1] = NULL;
152 5 : last++;
153 : }
154 5 : continue;
155 : }
156 :
157 254 : named: /* We found a single remote name, add that */
158 254 : result = talloc_realloc(mem_ctx, result, const char *, last+2);
159 254 : if (result == NULL) {
160 0 : goto failed;
161 : }
162 :
163 254 : result[last] = talloc_strdup(result, name);
164 254 : result[last+1] = NULL;
165 254 : last++;
166 : }
167 :
168 0 : return result;
169 :
170 0 : failed:
171 0 : talloc_free(result);
172 0 : map_oom(module);
173 0 : return NULL;
174 : }
175 :
176 : /* Split attributes that stay in the local partition from those that
177 : * are mapped into the remote partition. */
178 162 : static int map_attrs_partition(struct ldb_module *module, void *mem_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *attrs)
179 : {
180 324 : *local_attrs = map_attrs_select_local(module, mem_ctx, attrs);
181 162 : *remote_attrs = map_attrs_collect_remote(module, mem_ctx, attrs);
182 :
183 162 : return 0;
184 : }
185 :
186 : /* Mapping message elements
187 : * ======================== */
188 :
189 : /* Add an element to a message, overwriting any old identically named elements. */
190 704 : static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_element *el)
191 : {
192 704 : struct ldb_message_element *old;
193 704 : unsigned j;
194 704 : old = ldb_msg_find_element(msg, el->name);
195 :
196 : /* no local result, add as new element */
197 704 : if (old == NULL) {
198 618 : if (ldb_msg_add_empty(msg, el->name, 0, &old) != 0) {
199 0 : return LDB_ERR_OPERATIONS_ERROR;
200 : }
201 : }
202 : else {
203 86 : talloc_free(old->values);
204 : }
205 :
206 704 : old->values = talloc_array(msg->elements, struct ldb_val, el->num_values);
207 704 : old->num_values = el->num_values;
208 704 : if (old->values == NULL) {
209 0 : return LDB_ERR_OPERATIONS_ERROR;
210 : }
211 : /* copy the values into the element */
212 1459 : for (j=0;j<el->num_values;j++) {
213 755 : old->values[j] = ldb_val_dup(old->values, &el->values[j]);
214 755 : if (old->values[j].data == NULL && el->values[j].length != 0) {
215 0 : return LDB_ERR_OPERATIONS_ERROR;
216 : }
217 : }
218 :
219 0 : return 0;
220 : }
221 :
222 : /* Map a message element back into the local partition. */
223 527 : static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *module,
224 : void *mem_ctx,
225 : const struct ldb_map_attribute *map,
226 : const char *attr_name,
227 : const struct ldb_message_element *old)
228 : {
229 527 : const struct ldb_map_context *data = map_get_context(module);
230 527 : const char *local_attr_name = attr_name;
231 527 : struct ldb_message_element *el;
232 527 : unsigned int i;
233 :
234 527 : el = talloc_zero(mem_ctx, struct ldb_message_element);
235 527 : if (el == NULL) {
236 0 : map_oom(module);
237 0 : return NULL;
238 : }
239 :
240 527 : el->values = talloc_array(el, struct ldb_val, old->num_values);
241 527 : if (el->values == NULL) {
242 0 : talloc_free(el);
243 0 : map_oom(module);
244 0 : return NULL;
245 : }
246 :
247 45780 : for (i = 0; data->attribute_maps[i].local_name; i++) {
248 45322 : struct ldb_map_attribute *am = &data->attribute_maps[i];
249 45322 : if (((am->type == LDB_MAP_RENAME || am->type == LDB_MAP_RENDROP) &&
250 4743 : !strcmp(am->u.rename.remote_name, attr_name))
251 45322 : || (am->type == LDB_MAP_CONVERT &&
252 4743 : !strcmp(am->u.convert.remote_name, attr_name))) {
253 :
254 0 : local_attr_name = am->local_name;
255 0 : break;
256 : }
257 : }
258 :
259 527 : el->name = talloc_strdup(el, local_attr_name);
260 527 : if (el->name == NULL) {
261 0 : talloc_free(el);
262 0 : map_oom(module);
263 0 : return NULL;
264 : }
265 :
266 1101 : for (i = 0; i < old->num_values; i++) {
267 578 : el->values[i] = ldb_val_map_remote(module, el->values, map, &old->values[i]);
268 : /* Conversions might fail, in which case bail */
269 578 : if (!el->values[i].data) {
270 4 : talloc_free(el);
271 4 : return NULL;
272 : }
273 574 : el->num_values++;
274 : }
275 :
276 0 : return el;
277 : }
278 :
279 : /* Merge a remote message element into a local message. */
280 3338 : static int ldb_msg_el_merge(struct ldb_module *module, struct ldb_message *local,
281 : struct ldb_message *remote, const char *attr_name)
282 : {
283 3338 : const struct ldb_map_context *data = map_get_context(module);
284 3338 : const struct ldb_map_attribute *map;
285 3338 : struct ldb_message_element *old, *el=NULL;
286 3338 : const char *remote_name = NULL;
287 3338 : struct ldb_context *ldb;
288 :
289 3338 : ldb = ldb_module_get_ctx(module);
290 :
291 : /* We handle wildcards in ldb_msg_el_merge_wildcard */
292 3338 : if (ldb_attr_cmp(attr_name, "*") == 0) {
293 0 : return LDB_SUCCESS;
294 : }
295 :
296 3310 : map = map_attr_find_local(data, attr_name);
297 :
298 : /* Unknown attribute in remote message:
299 : * skip, attribute was probably auto-generated */
300 3310 : if (map == NULL) {
301 0 : return LDB_SUCCESS;
302 : }
303 :
304 3179 : switch (map->type) {
305 0 : case LDB_MAP_IGNORE:
306 0 : break;
307 262 : case LDB_MAP_CONVERT:
308 262 : remote_name = map->u.convert.remote_name;
309 262 : break;
310 186 : case LDB_MAP_KEEP:
311 186 : remote_name = attr_name;
312 186 : break;
313 611 : case LDB_MAP_RENAME:
314 : case LDB_MAP_RENDROP:
315 611 : remote_name = map->u.rename.remote_name;
316 611 : break;
317 0 : case LDB_MAP_GENERATE:
318 0 : break;
319 : }
320 :
321 3179 : switch (map->type) {
322 0 : case LDB_MAP_IGNORE:
323 0 : return LDB_SUCCESS;
324 :
325 262 : case LDB_MAP_CONVERT:
326 262 : if (map->u.convert.convert_remote == NULL) {
327 0 : ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
328 : "Skipping attribute '%s': "
329 : "'convert_remote' not set",
330 : attr_name);
331 0 : return LDB_SUCCESS;
332 : }
333 :
334 1059 : FALL_THROUGH;
335 : case LDB_MAP_KEEP:
336 : case LDB_MAP_RENAME:
337 : case LDB_MAP_RENDROP:
338 1059 : old = ldb_msg_find_element(remote, remote_name);
339 1059 : if (old) {
340 527 : el = ldb_msg_el_map_remote(module, local, map, attr_name, old);
341 : } else {
342 0 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
343 : }
344 527 : break;
345 :
346 50 : case LDB_MAP_GENERATE:
347 50 : if (map->u.generate.generate_local == NULL) {
348 0 : ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
349 : "Skipping attribute '%s': "
350 : "'generate_local' not set",
351 : attr_name);
352 0 : return LDB_SUCCESS;
353 : }
354 :
355 50 : el = map->u.generate.generate_local(module, local, attr_name, remote);
356 50 : if (!el) {
357 : /* Generation failure is probably due to lack of source attributes */
358 0 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
359 : }
360 0 : break;
361 : }
362 :
363 541 : if (el == NULL) {
364 4 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
365 : }
366 :
367 537 : return ldb_msg_replace(local, el);
368 : }
369 :
370 : /* Handle wildcard parts of merging a remote message element into a local message. */
371 28 : static int ldb_msg_el_merge_wildcard(struct ldb_module *module, struct ldb_message *local,
372 : struct ldb_message *remote)
373 : {
374 28 : const struct ldb_map_context *data = map_get_context(module);
375 28 : const struct ldb_map_attribute *map = map_attr_find_local(data, "*");
376 28 : struct ldb_message_element *el=NULL;
377 28 : unsigned int i;
378 28 : int ret;
379 :
380 : /* Perhaps we have a mapping for "*" */
381 28 : if (map && map->type == LDB_MAP_KEEP) {
382 : /* We copy everything over, and hope that anything with a
383 : more specific rule is overwritten */
384 0 : for (i = 0; i < remote->num_elements; i++) {
385 0 : el = ldb_msg_el_map_remote(module, local, map, remote->elements[i].name,
386 0 : &remote->elements[i]);
387 0 : if (el == NULL) {
388 0 : return LDB_ERR_OPERATIONS_ERROR;
389 : }
390 :
391 0 : ret = ldb_msg_replace(local, el);
392 0 : if (ret) {
393 0 : return ret;
394 : }
395 : }
396 : }
397 :
398 : /* Now walk the list of possible mappings, and apply each */
399 2436 : for (i = 0; data->attribute_maps[i].local_name; i++) {
400 2408 : ret = ldb_msg_el_merge(module, local, remote,
401 0 : data->attribute_maps[i].local_name);
402 2408 : if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
403 421 : continue;
404 1987 : } else if (ret) {
405 0 : return ret;
406 : } else {
407 1987 : continue;
408 : }
409 : }
410 :
411 0 : return LDB_SUCCESS;
412 : }
413 :
414 : /* Mapping messages
415 : * ================ */
416 :
417 : /* Merge two local messages into a single one. */
418 99 : static int ldb_msg_merge_local(struct ldb_module *module, struct ldb_message *msg1, struct ldb_message *msg2)
419 : {
420 99 : unsigned int i;
421 99 : int ret;
422 :
423 266 : for (i = 0; i < msg2->num_elements; i++) {
424 167 : ret = ldb_msg_replace(msg1, &msg2->elements[i]);
425 167 : if (ret) {
426 0 : return ret;
427 : }
428 : }
429 :
430 0 : return LDB_SUCCESS;
431 : }
432 :
433 : /* Merge a local and a remote message into a single local one. */
434 254 : static int ldb_msg_merge_remote(struct map_context *ac, struct ldb_message *local,
435 : struct ldb_message *remote)
436 : {
437 254 : unsigned int i;
438 254 : int ret;
439 254 : const char * const *attrs = ac->all_attrs;
440 254 : if (!attrs) {
441 0 : ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
442 0 : if (ret) {
443 0 : return ret;
444 : }
445 : }
446 :
447 1156 : for (i = 0; attrs && attrs[i]; i++) {
448 930 : if (ldb_attr_cmp(attrs[i], "*") == 0) {
449 28 : ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
450 28 : if (ret) {
451 0 : return ret;
452 : }
453 0 : break;
454 : }
455 : }
456 :
457 : /* Try to map each attribute back;
458 : * Add to local message is possible,
459 : * Overwrite old local attribute if necessary */
460 1184 : for (i = 0; attrs && attrs[i]; i++) {
461 930 : ret = ldb_msg_el_merge(ac->module, local, remote,
462 0 : attrs[i]);
463 930 : if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
464 779 : } else if (ret) {
465 0 : return ret;
466 : }
467 : }
468 :
469 0 : return LDB_SUCCESS;
470 : }
471 :
472 : /* Mapping search results
473 : * ====================== */
474 :
475 : /* Map a search result back into the local partition. */
476 254 : static int map_reply_remote(struct map_context *ac, struct ldb_reply *ares)
477 : {
478 254 : struct ldb_message *msg;
479 254 : struct ldb_dn *dn;
480 254 : int ret;
481 :
482 : /* There is no result message, skip */
483 254 : if (ares->type != LDB_REPLY_ENTRY) {
484 0 : return 0;
485 : }
486 :
487 : /* Create a new result message */
488 254 : msg = ldb_msg_new(ares);
489 254 : if (msg == NULL) {
490 0 : map_oom(ac->module);
491 0 : return LDB_ERR_OPERATIONS_ERROR;
492 : }
493 :
494 : /* Merge remote message into new message */
495 254 : ret = ldb_msg_merge_remote(ac, msg, ares->message);
496 254 : if (ret) {
497 0 : talloc_free(msg);
498 0 : return ret;
499 : }
500 :
501 : /* Create corresponding local DN */
502 254 : dn = ldb_dn_map_rebase_remote(ac->module, msg, ares->message->dn);
503 254 : if (dn == NULL) {
504 0 : talloc_free(msg);
505 0 : return LDB_ERR_OPERATIONS_ERROR;
506 : }
507 254 : msg->dn = dn;
508 :
509 : /* Store new message with new DN as the result */
510 254 : talloc_free(ares->message);
511 254 : ares->message = msg;
512 :
513 254 : return 0;
514 : }
515 :
516 : /* Mapping parse trees
517 : * =================== */
518 :
519 : /* Check whether a parse tree can safely be split in two. */
520 112 : static bool ldb_parse_tree_check_splittable(const struct ldb_parse_tree *tree)
521 : {
522 112 : const struct ldb_parse_tree *subtree = tree;
523 112 : bool negate = false;
524 :
525 114 : while (subtree) {
526 114 : switch (subtree->operation) {
527 2 : case LDB_OP_NOT:
528 2 : negate = !negate;
529 2 : subtree = subtree->u.isnot.child;
530 2 : continue;
531 :
532 5 : case LDB_OP_AND:
533 5 : return !negate; /* if negate: False */
534 :
535 0 : case LDB_OP_OR:
536 0 : return negate; /* if negate: True */
537 :
538 0 : default:
539 0 : return true; /* simple parse tree */
540 : }
541 : }
542 :
543 0 : return true; /* no parse tree */
544 : }
545 :
546 : /* Collect a list of attributes required to match a given parse tree. */
547 441 : static int ldb_parse_tree_collect_attrs(struct ldb_module *module, void *mem_ctx, const char ***attrs, const struct ldb_parse_tree *tree)
548 : {
549 450 : const char *attr = NULL;
550 450 : const char **new_attrs;
551 450 : unsigned int i;
552 450 : int ret;
553 :
554 450 : if (tree == NULL) {
555 0 : return 0;
556 : }
557 :
558 450 : switch (tree->operation) {
559 0 : case LDB_OP_OR:
560 : case LDB_OP_AND: /* attributes stored in list of subtrees */
561 412 : for (i = 0; i < tree->u.list.num_elements; i++) {
562 558 : ret = ldb_parse_tree_collect_attrs(module, mem_ctx,
563 279 : attrs, tree->u.list.elements[i]);
564 279 : if (ret) {
565 0 : return ret;
566 : }
567 : }
568 0 : return 0;
569 :
570 9 : case LDB_OP_NOT: /* attributes stored in single subtree */
571 9 : return ldb_parse_tree_collect_attrs(module, mem_ctx, attrs, tree->u.isnot.child);
572 :
573 308 : default: /* single attribute in tree */
574 308 : attr = ldb_parse_tree_get_attr(tree);
575 308 : new_attrs = ldb_attr_list_copy_add(mem_ctx, *attrs, attr);
576 308 : if (new_attrs == NULL) {
577 0 : return ldb_module_oom(module);
578 : }
579 308 : talloc_free(*attrs);
580 308 : *attrs = new_attrs;
581 308 : return 0;
582 : }
583 : }
584 :
585 : static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
586 :
587 : /* Select a negated subtree that queries attributes in the local partition */
588 9 : static int map_subtree_select_local_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
589 : {
590 9 : struct ldb_parse_tree *child;
591 9 : int ret;
592 :
593 : /* Prepare new tree */
594 9 : *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
595 9 : if (*new == NULL) {
596 0 : map_oom(module);
597 0 : return LDB_ERR_OPERATIONS_ERROR;
598 : }
599 :
600 : /* Generate new subtree */
601 9 : ret = map_subtree_select_local(module, *new, &child, tree->u.isnot.child);
602 9 : if (ret) {
603 0 : talloc_free(*new);
604 0 : return ret;
605 : }
606 :
607 : /* Prune tree without subtree */
608 9 : if (child == NULL) {
609 4 : talloc_free(*new);
610 4 : *new = NULL;
611 4 : return 0;
612 : }
613 :
614 5 : (*new)->u.isnot.child = child;
615 :
616 5 : return ret;
617 : }
618 :
619 : /* Select a list of subtrees that query attributes in the local partition */
620 133 : static int map_subtree_select_local_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
621 : {
622 133 : unsigned int i, j;
623 133 : int ret=0;
624 :
625 : /* Prepare new tree */
626 133 : *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
627 133 : if (*new == NULL) {
628 0 : map_oom(module);
629 0 : return LDB_ERR_OPERATIONS_ERROR;
630 : }
631 :
632 : /* Prepare list of subtrees */
633 133 : (*new)->u.list.num_elements = 0;
634 133 : (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
635 133 : if ((*new)->u.list.elements == NULL) {
636 0 : map_oom(module);
637 0 : talloc_free(*new);
638 0 : return LDB_ERR_OPERATIONS_ERROR;
639 : }
640 :
641 : /* Generate new list of subtrees */
642 0 : j = 0;
643 412 : for (i = 0; i < tree->u.list.num_elements; i++) {
644 279 : struct ldb_parse_tree *child = NULL;
645 279 : ret = map_subtree_select_local(module, *new, &child, tree->u.list.elements[i]);
646 279 : if (ret) {
647 0 : talloc_free(*new);
648 0 : return ret;
649 : }
650 :
651 279 : if (child) {
652 122 : (*new)->u.list.elements[j] = child;
653 122 : j++;
654 : }
655 : }
656 :
657 : /* Prune tree without subtrees */
658 133 : if (j == 0) {
659 16 : talloc_free(*new);
660 16 : *new = NULL;
661 16 : return 0;
662 : }
663 :
664 : /* Fix subtree list size */
665 117 : (*new)->u.list.num_elements = j;
666 117 : (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
667 :
668 117 : return ret;
669 : }
670 :
671 : /* Select a simple subtree that queries attributes in the local partition */
672 128 : static int map_subtree_select_local_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
673 : {
674 : /* Prepare new tree */
675 128 : *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
676 128 : if (*new == NULL) {
677 0 : map_oom(module);
678 0 : return LDB_ERR_OPERATIONS_ERROR;
679 : }
680 :
681 0 : return 0;
682 : }
683 :
684 : /* Select subtrees that query attributes in the local partition */
685 450 : static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
686 : {
687 450 : const struct ldb_map_context *data = map_get_context(module);
688 :
689 450 : if (tree == NULL) {
690 0 : return 0;
691 : }
692 :
693 450 : if (tree->operation == LDB_OP_NOT) {
694 9 : return map_subtree_select_local_not(module, mem_ctx, new, tree);
695 : }
696 :
697 441 : if (tree->operation == LDB_OP_AND || tree->operation == LDB_OP_OR) {
698 133 : return map_subtree_select_local_list(module, mem_ctx, new, tree);
699 : }
700 :
701 308 : if (map_attr_check_remote(data, tree->u.equality.attr)) {
702 180 : *new = NULL;
703 180 : return 0;
704 : }
705 :
706 128 : return map_subtree_select_local_simple(module, mem_ctx, new, tree);
707 : }
708 :
709 : static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
710 :
711 : /* Collect a negated subtree that queries attributes in the remote partition */
712 9 : static int map_subtree_collect_remote_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
713 : {
714 9 : struct ldb_parse_tree *child;
715 9 : int ret;
716 :
717 : /* Prepare new tree */
718 9 : *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
719 9 : if (*new == NULL) {
720 0 : map_oom(module);
721 0 : return LDB_ERR_OPERATIONS_ERROR;
722 : }
723 :
724 : /* Generate new subtree */
725 9 : ret = map_subtree_collect_remote(module, *new, &child, tree->u.isnot.child);
726 9 : if (ret) {
727 0 : talloc_free(*new);
728 0 : return ret;
729 : }
730 :
731 : /* Prune tree without subtree */
732 9 : if (child == NULL) {
733 3 : talloc_free(*new);
734 3 : *new = NULL;
735 3 : return 0;
736 : }
737 :
738 6 : (*new)->u.isnot.child = child;
739 :
740 6 : return ret;
741 : }
742 :
743 : /* Collect a list of subtrees that query attributes in the remote partition */
744 133 : static int map_subtree_collect_remote_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
745 : {
746 133 : unsigned int i, j;
747 133 : int ret=0;
748 :
749 : /* Prepare new tree */
750 133 : *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
751 133 : if (*new == NULL) {
752 0 : map_oom(module);
753 0 : return LDB_ERR_OPERATIONS_ERROR;
754 : }
755 :
756 : /* Prepare list of subtrees */
757 133 : (*new)->u.list.num_elements = 0;
758 133 : (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
759 133 : if ((*new)->u.list.elements == NULL) {
760 0 : map_oom(module);
761 0 : talloc_free(*new);
762 0 : return LDB_ERR_OPERATIONS_ERROR;
763 : }
764 :
765 : /* Generate new list of subtrees */
766 0 : j = 0;
767 412 : for (i = 0; i < tree->u.list.num_elements; i++) {
768 279 : struct ldb_parse_tree *child;
769 279 : ret = map_subtree_collect_remote(module, *new, &child, tree->u.list.elements[i]);
770 279 : if (ret) {
771 0 : talloc_free(*new);
772 0 : return ret;
773 : }
774 :
775 279 : if (child) {
776 154 : (*new)->u.list.elements[j] = child;
777 154 : j++;
778 : }
779 : }
780 :
781 : /* Prune tree without subtrees */
782 133 : if (j == 0) {
783 5 : talloc_free(*new);
784 5 : *new = NULL;
785 5 : return 0;
786 : }
787 :
788 : /* Fix subtree list size */
789 128 : (*new)->u.list.num_elements = j;
790 128 : (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
791 :
792 128 : return ret;
793 : }
794 :
795 : /* Collect a simple subtree that queries attributes in the remote partition */
796 176 : int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree, const struct ldb_map_attribute *map)
797 : {
798 176 : const char *attr;
799 :
800 : /* Prepare new tree */
801 176 : *new = talloc(mem_ctx, struct ldb_parse_tree);
802 176 : if (*new == NULL) {
803 0 : map_oom(module);
804 0 : return LDB_ERR_OPERATIONS_ERROR;
805 : }
806 176 : **new = *tree;
807 :
808 176 : if (map->type == LDB_MAP_KEEP) {
809 : /* Nothing to do here */
810 0 : return 0;
811 : }
812 :
813 : /* Store attribute and value in new tree */
814 161 : switch (tree->operation) {
815 106 : case LDB_OP_PRESENT:
816 106 : attr = map_attr_map_local(*new, map, tree->u.present.attr);
817 106 : (*new)->u.present.attr = attr;
818 106 : break;
819 0 : case LDB_OP_SUBSTRING:
820 : {
821 0 : attr = map_attr_map_local(*new, map, tree->u.substring.attr);
822 0 : (*new)->u.substring.attr = attr;
823 0 : break;
824 : }
825 55 : case LDB_OP_EQUALITY:
826 55 : attr = map_attr_map_local(*new, map, tree->u.equality.attr);
827 55 : (*new)->u.equality.attr = attr;
828 55 : break;
829 0 : case LDB_OP_LESS:
830 : case LDB_OP_GREATER:
831 : case LDB_OP_APPROX:
832 0 : attr = map_attr_map_local(*new, map, tree->u.comparison.attr);
833 0 : (*new)->u.comparison.attr = attr;
834 0 : break;
835 0 : case LDB_OP_EXTENDED:
836 0 : attr = map_attr_map_local(*new, map, tree->u.extended.attr);
837 0 : (*new)->u.extended.attr = attr;
838 0 : break;
839 0 : default: /* unknown kind of simple subtree */
840 0 : talloc_free(*new);
841 0 : return LDB_ERR_OPERATIONS_ERROR;
842 : }
843 :
844 161 : if (attr == NULL) {
845 0 : talloc_free(*new);
846 0 : *new = NULL;
847 0 : return 0;
848 : }
849 :
850 161 : if (map->type == LDB_MAP_RENAME || map->type == LDB_MAP_RENDROP) {
851 : /* Nothing more to do here, the attribute has been renamed */
852 0 : return 0;
853 : }
854 :
855 : /* Store attribute and value in new tree */
856 142 : switch (tree->operation) {
857 0 : case LDB_OP_PRESENT:
858 0 : break;
859 0 : case LDB_OP_SUBSTRING:
860 : {
861 0 : int i;
862 : /* Map value */
863 0 : (*new)->u.substring.chunks = NULL;
864 0 : for (i=0; tree->u.substring.chunks && tree->u.substring.chunks[i]; i++) {
865 0 : (*new)->u.substring.chunks = talloc_realloc(*new, (*new)->u.substring.chunks, struct ldb_val *, i+2);
866 0 : if (!(*new)->u.substring.chunks) {
867 0 : talloc_free(*new);
868 0 : *new = NULL;
869 0 : return 0;
870 : }
871 0 : (*new)->u.substring.chunks[i] = talloc(*new, struct ldb_val);
872 0 : if (!(*new)->u.substring.chunks[i]) {
873 0 : talloc_free(*new);
874 0 : *new = NULL;
875 0 : return 0;
876 : }
877 0 : *(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, tree->u.substring.chunks[i]);
878 0 : (*new)->u.substring.chunks[i+1] = NULL;
879 : }
880 0 : break;
881 : }
882 36 : case LDB_OP_EQUALITY:
883 36 : (*new)->u.equality.value = ldb_val_map_local(module, *new, map, &tree->u.equality.value);
884 36 : break;
885 0 : case LDB_OP_LESS:
886 : case LDB_OP_GREATER:
887 : case LDB_OP_APPROX:
888 0 : (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, &tree->u.comparison.value);
889 0 : break;
890 0 : case LDB_OP_EXTENDED:
891 0 : (*new)->u.extended.value = ldb_val_map_local(module, *new, map, &tree->u.extended.value);
892 0 : (*new)->u.extended.rule_id = talloc_strdup(*new, tree->u.extended.rule_id);
893 0 : break;
894 0 : default: /* unknown kind of simple subtree */
895 0 : talloc_free(*new);
896 0 : return LDB_ERR_OPERATIONS_ERROR;
897 : }
898 :
899 0 : return 0;
900 : }
901 :
902 : /* Collect subtrees that query attributes in the remote partition */
903 450 : static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
904 : {
905 450 : const struct ldb_map_context *data = map_get_context(module);
906 450 : const struct ldb_map_attribute *map;
907 450 : struct ldb_context *ldb;
908 :
909 450 : ldb = ldb_module_get_ctx(module);
910 :
911 450 : if (tree == NULL) {
912 0 : return 0;
913 : }
914 :
915 450 : if (tree->operation == LDB_OP_NOT) {
916 9 : return map_subtree_collect_remote_not(module, mem_ctx, new, tree);
917 : }
918 :
919 441 : if ((tree->operation == LDB_OP_AND) || (tree->operation == LDB_OP_OR)) {
920 133 : return map_subtree_collect_remote_list(module, mem_ctx, new, tree);
921 : }
922 :
923 308 : if (!map_attr_check_remote(data, tree->u.equality.attr)) {
924 128 : *new = NULL;
925 128 : return 0;
926 : }
927 :
928 180 : map = map_attr_find_local(data, tree->u.equality.attr);
929 180 : if (map == NULL) {
930 0 : return LDB_ERR_OPERATIONS_ERROR;
931 : }
932 180 : if (map->convert_operator) {
933 0 : return map->convert_operator(module, mem_ctx, new, tree);
934 : }
935 :
936 180 : if (map->type == LDB_MAP_GENERATE) {
937 4 : ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
938 : "Skipping attribute '%s': "
939 : "'convert_operator' not set",
940 4 : tree->u.equality.attr);
941 4 : *new = NULL;
942 4 : return 0;
943 : }
944 :
945 176 : return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, map);
946 : }
947 :
948 : /* Split subtrees that query attributes in the local partition from
949 : * those that query the remote partition. */
950 162 : static int ldb_parse_tree_partition(struct ldb_module *module,
951 : void *mem_ctx,
952 : struct ldb_parse_tree **local_tree,
953 : struct ldb_parse_tree **remote_tree,
954 : const struct ldb_parse_tree *tree)
955 : {
956 162 : int ret;
957 :
958 162 : *local_tree = NULL;
959 162 : *remote_tree = NULL;
960 :
961 : /* No original tree */
962 162 : if (tree == NULL) {
963 0 : return 0;
964 : }
965 :
966 : /* Generate local tree */
967 162 : ret = map_subtree_select_local(module, mem_ctx, local_tree, tree);
968 162 : if (ret) {
969 0 : return ret;
970 : }
971 :
972 : /* Generate remote tree */
973 162 : ret = map_subtree_collect_remote(module, mem_ctx, remote_tree, tree);
974 162 : if (ret) {
975 0 : talloc_free(*local_tree);
976 0 : return ret;
977 : }
978 :
979 0 : return 0;
980 : }
981 :
982 : /* Collect a list of attributes required either explicitly from a
983 : * given list or implicitly from a given parse tree; split the
984 : * collected list into local and remote parts. */
985 162 : static int map_attrs_collect_and_partition(struct ldb_module *module, struct map_context *ac,
986 : const char * const *search_attrs,
987 : const struct ldb_parse_tree *tree)
988 : {
989 162 : void *tmp_ctx;
990 162 : const char **tree_attrs;
991 162 : const char **remote_attrs;
992 162 : const char **local_attrs;
993 162 : int ret;
994 :
995 : /* There is no tree, just partition the searched attributes */
996 162 : if (tree == NULL) {
997 0 : ret = map_attrs_partition(module, ac,
998 : &local_attrs, &remote_attrs, search_attrs);
999 0 : if (ret == 0) {
1000 0 : ac->local_attrs = local_attrs;
1001 0 : ac->remote_attrs = remote_attrs;
1002 0 : ac->all_attrs = search_attrs;
1003 : }
1004 0 : return ret;
1005 : }
1006 :
1007 : /* Create context for temporary memory */
1008 162 : tmp_ctx = talloc_new(ac);
1009 162 : if (tmp_ctx == NULL) {
1010 0 : goto oom;
1011 : }
1012 :
1013 : /* Prepare list of attributes from tree */
1014 162 : tree_attrs = talloc_array(tmp_ctx, const char *, 1);
1015 162 : if (tree_attrs == NULL) {
1016 0 : talloc_free(tmp_ctx);
1017 0 : goto oom;
1018 : }
1019 162 : tree_attrs[0] = NULL;
1020 :
1021 : /* Collect attributes from tree */
1022 162 : ret = ldb_parse_tree_collect_attrs(module, tmp_ctx, &tree_attrs, tree);
1023 162 : if (ret) {
1024 0 : goto done;
1025 : }
1026 :
1027 : /* Merge attributes from search operation */
1028 162 : ret = map_attrs_merge(module, tmp_ctx, &tree_attrs, search_attrs);
1029 162 : if (ret) {
1030 0 : goto done;
1031 : }
1032 :
1033 : /* Split local from remote attributes */
1034 162 : ret = map_attrs_partition(module, ac, &local_attrs,
1035 : &remote_attrs, tree_attrs);
1036 :
1037 162 : if (ret == 0) {
1038 162 : ac->local_attrs = local_attrs;
1039 162 : ac->remote_attrs = remote_attrs;
1040 162 : talloc_steal(ac, tree_attrs);
1041 162 : ac->all_attrs = tree_attrs;
1042 : }
1043 162 : done:
1044 : /* Free temporary memory */
1045 162 : talloc_free(tmp_ctx);
1046 162 : return ret;
1047 :
1048 0 : oom:
1049 0 : map_oom(module);
1050 0 : return LDB_ERR_OPERATIONS_ERROR;
1051 : }
1052 :
1053 :
1054 : /* Outbound requests: search
1055 : * ========================= */
1056 :
1057 : static int map_remote_search_callback(struct ldb_request *req,
1058 : struct ldb_reply *ares);
1059 : static int map_local_merge_callback(struct ldb_request *req,
1060 : struct ldb_reply *ares);
1061 : static int map_search_local(struct map_context *ac);
1062 :
1063 254 : static int map_save_entry(struct map_context *ac, struct ldb_reply *ares)
1064 : {
1065 254 : struct map_reply *mr;
1066 :
1067 254 : mr = talloc_zero(ac, struct map_reply);
1068 254 : if (mr == NULL) {
1069 0 : map_oom(ac->module);
1070 0 : return LDB_ERR_OPERATIONS_ERROR;
1071 : }
1072 254 : mr->remote = talloc_steal(mr, ares);
1073 254 : if (ac->r_current) {
1074 178 : ac->r_current->next = mr;
1075 : } else {
1076 : /* first entry */
1077 76 : ac->r_list = mr;
1078 : }
1079 254 : ac->r_current = mr;
1080 :
1081 254 : return LDB_SUCCESS;
1082 : }
1083 :
1084 : /* Pass a merged search result up the callback chain. */
1085 254 : int map_return_entry(struct map_context *ac, struct ldb_reply *ares)
1086 : {
1087 254 : struct ldb_message_element *el;
1088 254 : const char * const *attrs;
1089 254 : struct ldb_context *ldb;
1090 254 : unsigned int i;
1091 254 : int ret;
1092 254 : bool matched;
1093 :
1094 254 : ldb = ldb_module_get_ctx(ac->module);
1095 :
1096 : /* Merged result doesn't match original query, skip */
1097 508 : ret = ldb_match_msg_error(ldb, ares->message,
1098 254 : ac->req->op.search.tree,
1099 0 : ac->req->op.search.base,
1100 254 : ac->req->op.search.scope,
1101 : &matched);
1102 254 : if (ret != LDB_SUCCESS) return ret;
1103 254 : if (!matched) {
1104 258 : ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_map: "
1105 : "Skipping record '%s': "
1106 : "doesn't match original search",
1107 129 : ldb_dn_get_linearized(ares->message->dn));
1108 129 : return LDB_SUCCESS;
1109 : }
1110 :
1111 : /* Limit result to requested attrs */
1112 241 : if (ac->req->op.search.attrs &&
1113 116 : (! ldb_attr_in_list(ac->req->op.search.attrs, "*"))) {
1114 :
1115 116 : attrs = ac->req->op.search.attrs;
1116 116 : i = 0;
1117 :
1118 958 : while (i < ares->message->num_elements) {
1119 :
1120 842 : el = &ares->message->elements[i];
1121 842 : if ( ! ldb_attr_in_list(attrs, el->name)) {
1122 699 : ldb_msg_remove_element(ares->message, el);
1123 : } else {
1124 143 : i++;
1125 : }
1126 : }
1127 : }
1128 :
1129 125 : return ldb_module_send_entry(ac->req, ares->message, ares->controls);
1130 : }
1131 :
1132 : /* Search a record. */
1133 233 : int ldb_map_search(struct ldb_module *module, struct ldb_request *req)
1134 : {
1135 233 : struct ldb_parse_tree *remote_tree;
1136 233 : struct ldb_parse_tree *local_tree;
1137 233 : struct ldb_request *remote_req;
1138 233 : struct ldb_context *ldb;
1139 233 : struct map_context *ac;
1140 233 : int ret;
1141 :
1142 233 : const char *wildcard[] = { "*", NULL };
1143 233 : const char * const *attrs;
1144 :
1145 233 : ldb = ldb_module_get_ctx(module);
1146 :
1147 : /* if we're not yet initialized, go to the next module */
1148 233 : if (!ldb_module_get_private(module))
1149 11 : return ldb_next_request(module, req);
1150 :
1151 : /* Do not manipulate our control entries */
1152 222 : if (ldb_dn_is_special(req->op.search.base)) {
1153 52 : return ldb_next_request(module, req);
1154 : }
1155 :
1156 : /* No mapping requested, skip to next module */
1157 170 : if ((req->op.search.base) && (!ldb_dn_check_local(module, req->op.search.base))) {
1158 8 : return ldb_next_request(module, req);
1159 : }
1160 :
1161 : /* TODO: How can we be sure about which partition we are
1162 : * targeting when there is no search base? */
1163 :
1164 : /* Prepare context and handle */
1165 162 : ac = map_init_context(module, req);
1166 162 : if (ac == NULL) {
1167 0 : return LDB_ERR_OPERATIONS_ERROR;
1168 : }
1169 :
1170 : /* It is easier to deal with the two different ways of
1171 : * expressing the wildcard in the same codepath */
1172 162 : attrs = req->op.search.attrs;
1173 162 : if (attrs == NULL) {
1174 12 : attrs = wildcard;
1175 : }
1176 :
1177 : /* Split local from remote attrs */
1178 324 : ret = map_attrs_collect_and_partition(module, ac,
1179 162 : attrs, req->op.search.tree);
1180 162 : if (ret) {
1181 0 : return LDB_ERR_OPERATIONS_ERROR;
1182 : }
1183 :
1184 : /* Split local from remote tree */
1185 324 : ret = ldb_parse_tree_partition(module, ac,
1186 : &local_tree, &remote_tree,
1187 162 : req->op.search.tree);
1188 162 : if (ret) {
1189 0 : return LDB_ERR_OPERATIONS_ERROR;
1190 : }
1191 :
1192 162 : if (((local_tree != NULL) && (remote_tree != NULL)) &&
1193 224 : (!ldb_parse_tree_check_splittable(req->op.search.tree))) {
1194 : /* The query can't safely be split, enumerate the remote partition */
1195 107 : local_tree = NULL;
1196 107 : remote_tree = NULL;
1197 : }
1198 :
1199 162 : if (local_tree == NULL) {
1200 : /* Construct default local parse tree */
1201 146 : local_tree = talloc_zero(ac, struct ldb_parse_tree);
1202 146 : if (local_tree == NULL) {
1203 0 : map_oom(ac->module);
1204 0 : return LDB_ERR_OPERATIONS_ERROR;
1205 : }
1206 :
1207 146 : local_tree->operation = LDB_OP_PRESENT;
1208 146 : local_tree->u.present.attr = talloc_strdup(local_tree, IS_MAPPED);
1209 : }
1210 162 : if (remote_tree == NULL) {
1211 : /* Construct default remote parse tree */
1212 119 : remote_tree = ldb_parse_tree(ac, NULL);
1213 119 : if (remote_tree == NULL) {
1214 0 : return LDB_ERR_OPERATIONS_ERROR;
1215 : }
1216 : }
1217 :
1218 162 : ac->local_tree = local_tree;
1219 :
1220 : /* Prepare the remote operation */
1221 162 : ret = ldb_build_search_req_ex(&remote_req, ldb, ac,
1222 : req->op.search.base,
1223 : req->op.search.scope,
1224 : remote_tree,
1225 : ac->remote_attrs,
1226 : req->controls,
1227 : ac, map_remote_search_callback,
1228 : req);
1229 162 : LDB_REQ_SET_LOCATION(remote_req);
1230 162 : if (ret != LDB_SUCCESS) {
1231 0 : return LDB_ERR_OPERATIONS_ERROR;
1232 : }
1233 :
1234 162 : return ldb_next_remote_request(module, remote_req);
1235 : }
1236 :
1237 : /* Now, search the local part of a remote search result. */
1238 416 : static int map_remote_search_callback(struct ldb_request *req,
1239 : struct ldb_reply *ares)
1240 : {
1241 416 : struct map_context *ac;
1242 416 : int ret;
1243 :
1244 416 : ac = talloc_get_type(req->context, struct map_context);
1245 :
1246 416 : if (!ares) {
1247 0 : return ldb_module_done(ac->req, NULL, NULL,
1248 : LDB_ERR_OPERATIONS_ERROR);
1249 : }
1250 416 : if (ares->error != LDB_SUCCESS) {
1251 19 : return ldb_module_done(ac->req, ares->controls,
1252 : ares->response, ares->error);
1253 : }
1254 :
1255 397 : switch (ares->type) {
1256 0 : case LDB_REPLY_REFERRAL:
1257 :
1258 : /* ignore referrals */
1259 0 : talloc_free(ares);
1260 0 : return LDB_SUCCESS;
1261 :
1262 254 : case LDB_REPLY_ENTRY:
1263 :
1264 : /* Map result record into a local message */
1265 254 : ret = map_reply_remote(ac, ares);
1266 254 : if (ret) {
1267 0 : talloc_free(ares);
1268 0 : return ldb_module_done(ac->req, NULL, NULL,
1269 : LDB_ERR_OPERATIONS_ERROR);
1270 : }
1271 :
1272 : /* if we have no local db, then we can just return the reply to
1273 : * the upper layer, otherwise we must save it and process it
1274 : * when all replies have been gathered */
1275 254 : if ( ! map_check_local_db(ac->module)) {
1276 0 : ret = map_return_entry(ac, ares);
1277 : } else {
1278 254 : ret = map_save_entry(ac,ares);
1279 : }
1280 :
1281 254 : if (ret != LDB_SUCCESS) {
1282 0 : talloc_free(ares);
1283 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
1284 : }
1285 0 : break;
1286 :
1287 143 : case LDB_REPLY_DONE:
1288 :
1289 143 : if ( ! map_check_local_db(ac->module)) {
1290 0 : return ldb_module_done(ac->req, ares->controls,
1291 : ares->response, LDB_SUCCESS);
1292 : }
1293 :
1294 : /* reset the pointer to the start of the list */
1295 143 : ac->r_current = ac->r_list;
1296 :
1297 : /* no entry just return */
1298 143 : if (ac->r_current == NULL) {
1299 67 : ret = ldb_module_done(ac->req, ares->controls,
1300 : ares->response, LDB_SUCCESS);
1301 67 : talloc_free(ares);
1302 67 : return ret;
1303 : }
1304 :
1305 76 : ac->remote_done_ares = talloc_steal(ac, ares);
1306 :
1307 76 : ret = map_search_local(ac);
1308 76 : if (ret != LDB_SUCCESS) {
1309 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
1310 : }
1311 : }
1312 :
1313 0 : return LDB_SUCCESS;
1314 : }
1315 :
1316 254 : static int map_search_local(struct map_context *ac)
1317 : {
1318 254 : struct ldb_request *search_req;
1319 :
1320 254 : if (ac->r_current == NULL || ac->r_current->remote == NULL) {
1321 0 : return LDB_ERR_OPERATIONS_ERROR;
1322 : }
1323 :
1324 : /* Prepare local search request */
1325 : /* TODO: use GUIDs here instead? */
1326 508 : search_req = map_search_base_req(ac,
1327 254 : ac->r_current->remote->message->dn,
1328 : NULL, NULL,
1329 : ac, map_local_merge_callback);
1330 254 : if (search_req == NULL) {
1331 0 : return LDB_ERR_OPERATIONS_ERROR;
1332 : }
1333 :
1334 254 : return ldb_next_request(ac->module, search_req);
1335 : }
1336 :
1337 : /* Merge the remote and local parts of a search result. */
1338 353 : int map_local_merge_callback(struct ldb_request *req, struct ldb_reply *ares)
1339 : {
1340 353 : struct ldb_context *ldb;
1341 353 : struct map_context *ac;
1342 353 : int ret;
1343 :
1344 353 : ac = talloc_get_type(req->context, struct map_context);
1345 353 : ldb = ldb_module_get_ctx(ac->module);
1346 :
1347 353 : if (!ares) {
1348 0 : return ldb_module_done(ac->req, NULL, NULL,
1349 : LDB_ERR_OPERATIONS_ERROR);
1350 : }
1351 353 : if (ares->error != LDB_SUCCESS) {
1352 0 : return ldb_module_done(ac->req, ares->controls,
1353 : ares->response, ares->error);
1354 : }
1355 :
1356 353 : switch (ares->type) {
1357 99 : case LDB_REPLY_ENTRY:
1358 : /* We have already found a local record */
1359 99 : if (ac->r_current->local) {
1360 0 : talloc_free(ares);
1361 0 : ldb_set_errstring(ldb, "ldb_map: Too many results!");
1362 0 : return ldb_module_done(ac->req, NULL, NULL,
1363 : LDB_ERR_OPERATIONS_ERROR);
1364 : }
1365 :
1366 : /* Store local result */
1367 99 : ac->r_current->local = talloc_steal(ac->r_current, ares);
1368 :
1369 99 : break;
1370 :
1371 0 : case LDB_REPLY_REFERRAL:
1372 : /* ignore referrals */
1373 0 : talloc_free(ares);
1374 0 : break;
1375 :
1376 254 : case LDB_REPLY_DONE:
1377 : /* We don't need the local 'ares', but we will use the remote one from below */
1378 254 : talloc_free(ares);
1379 :
1380 : /* No local record found, map and send remote record */
1381 254 : if (ac->r_current->local != NULL) {
1382 : /* Merge remote into local message */
1383 198 : ret = ldb_msg_merge_local(ac->module,
1384 0 : ac->r_current->local->message,
1385 99 : ac->r_current->remote->message);
1386 99 : if (ret == LDB_SUCCESS) {
1387 99 : ret = map_return_entry(ac, ac->r_current->local);
1388 : }
1389 99 : if (ret != LDB_SUCCESS) {
1390 0 : return ldb_module_done(ac->req, NULL, NULL,
1391 : LDB_ERR_OPERATIONS_ERROR);
1392 : }
1393 : } else {
1394 155 : ret = map_return_entry(ac, ac->r_current->remote);
1395 155 : if (ret != LDB_SUCCESS) {
1396 0 : return ldb_module_done(ac->req,
1397 : NULL, NULL, ret);
1398 : }
1399 : }
1400 :
1401 254 : if (ac->r_current->next != NULL) {
1402 178 : ac->r_current = ac->r_current->next;
1403 178 : if (ac->r_current->remote->type == LDB_REPLY_ENTRY) {
1404 178 : ret = map_search_local(ac);
1405 178 : if (ret != LDB_SUCCESS) {
1406 0 : return ldb_module_done(ac->req,
1407 : NULL, NULL, ret);
1408 : }
1409 0 : break;
1410 : }
1411 : }
1412 :
1413 : /* ok we are done with all search, finally it is time to
1414 : * finish operations for this module */
1415 76 : return ldb_module_done(ac->req,
1416 0 : ac->remote_done_ares->controls,
1417 0 : ac->remote_done_ares->response,
1418 76 : ac->remote_done_ares->error);
1419 : }
1420 :
1421 0 : return LDB_SUCCESS;
1422 : }
|