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