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) Simo Sorce <idra@samba.org> 2008 7 8 ** NOTE! The following LGPL license applies to the ldb 9 ** library. This does NOT imply that all of Samba is released 10 ** under the LGPL 11 12 This library is free software; you can redistribute it and/or 13 modify it under the terms of the GNU Lesser General Public 14 License as published by the Free Software Foundation; either 15 version 3 of the License, or (at your option) any later version. 16 17 This library 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 GNU 20 Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public 23 License along with this library; if not, see <http://www.gnu.org/licenses/>. 24 25*/ 26 27#include "ldb_includes.h" 28#include "ldb_map.h" 29#include "ldb_map_private.h" 30 31 32/* Mapping message elements 33 * ======================== */ 34 35/* Map a message element into the remote partition. */ 36static struct ldb_message_element *ldb_msg_el_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_message_element *old) 37{ 38 struct ldb_message_element *el; 39 int i; 40 41 el = talloc_zero(mem_ctx, struct ldb_message_element); 42 if (el == NULL) { 43 map_oom(module); 44 return NULL; 45 } 46 47 el->num_values = old->num_values; 48 el->values = talloc_array(el, struct ldb_val, el->num_values); 49 if (el->values == NULL) { 50 talloc_free(el); 51 map_oom(module); 52 return NULL; 53 } 54 55 el->name = map_attr_map_local(el, map, old->name); 56 57 for (i = 0; i < el->num_values; i++) { 58 el->values[i] = ldb_val_map_local(module, el->values, map, &old->values[i]); 59 } 60 61 return el; 62} 63 64/* Add a message element either to a local or to a remote message, 65 * depending on whether it goes into the local or remote partition. */ 66static int ldb_msg_el_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg, const char *attr_name, /* const char * const names[], */ const struct ldb_message_element *old) 67{ 68 const struct ldb_map_context *data = map_get_context(module); 69 const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name); 70 struct ldb_message_element *el=NULL; 71 struct ldb_context *ldb = ldb_module_get_ctx(module); 72 73 /* Unknown attribute: ignore */ 74 if (map == NULL) { 75 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: " 76 "Not mapping attribute '%s': no mapping found", 77 old->name); 78 goto local; 79 } 80 81 switch (map->type) { 82 case MAP_IGNORE: 83 goto local; 84 85 case MAP_CONVERT: 86 if (map->u.convert.convert_local == NULL) { 87 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: " 88 "Not mapping attribute '%s': " 89 "'convert_local' not set", 90 map->local_name); 91 goto local; 92 } 93 /* fall through */ 94 case MAP_KEEP: 95 case MAP_RENAME: 96 el = ldb_msg_el_map_local(module, remote, map, old); 97 break; 98 99 case MAP_GENERATE: 100 if (map->u.generate.generate_remote == NULL) { 101 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: " 102 "Not mapping attribute '%s': " 103 "'generate_remote' not set", 104 map->local_name); 105 goto local; 106 } 107 108 /* TODO: if this attr requires context: 109 * make sure all context attrs are mappable (in 'names') 110 * make sure all context attrs have already been mapped? 111 * maybe postpone generation until they have been mapped? 112 */ 113 114 map->u.generate.generate_remote(module, map->local_name, msg, remote, local); 115 return 0; 116 } 117 118 if (el == NULL) { 119 return -1; 120 } 121 122 return ldb_msg_add(remote, el, old->flags); 123 124local: 125 el = talloc(local, struct ldb_message_element); 126 if (el == NULL) { 127 map_oom(module); 128 return -1; 129 } 130 131 *el = *old; /* copy the old element */ 132 133 return ldb_msg_add(local, el, old->flags); 134} 135 136/* Mapping messages 137 * ================ */ 138 139/* Check whether a message will be (partially) mapped into the remote partition. */ 140static bool ldb_msg_check_remote(struct ldb_module *module, const struct ldb_message *msg) 141{ 142 const struct ldb_map_context *data = map_get_context(module); 143 bool ret; 144 int i; 145 146 for (i = 0; i < msg->num_elements; i++) { 147 ret = map_attr_check_remote(data, msg->elements[i].name); 148 if (ret) { 149 return ret; 150 } 151 } 152 153 return false; 154} 155 156/* Split message elements that stay in the local partition from those 157 * that are mapped into the remote partition. */ 158static int ldb_msg_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg) 159{ 160 /* const char * const names[]; */ 161 struct ldb_context *ldb; 162 int i, ret; 163 164 ldb = ldb_module_get_ctx(module); 165 166 for (i = 0; i < msg->num_elements; i++) { 167 /* Skip 'IS_MAPPED' */ 168 if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) { 169 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: " 170 "Skipping attribute '%s'", 171 msg->elements[i].name); 172 continue; 173 } 174 175 ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]); 176 if (ret) { 177 return ret; 178 } 179 } 180 181 return 0; 182} 183 184 185static int map_add_do_local(struct map_context *ac); 186static int map_modify_do_local(struct map_context *ac); 187static int map_delete_do_local(struct map_context *ac); 188static int map_rename_do_local(struct map_context *ac); 189static int map_rename_do_fixup(struct map_context *ac); 190static int map_rename_local_callback(struct ldb_request *req, 191 struct ldb_reply *ares); 192 193 194/***************************************************************************** 195 * COMMON INBOUND functions 196*****************************************************************************/ 197 198/* Store the DN of a single search result in context. */ 199static int map_search_self_callback(struct ldb_request *req, struct ldb_reply *ares) 200{ 201 struct ldb_context *ldb; 202 struct map_context *ac; 203 int ret; 204 205 ac = talloc_get_type(req->context, struct map_context); 206 ldb = ldb_module_get_ctx(ac->module); 207 208 if (!ares) { 209 return ldb_module_done(ac->req, NULL, NULL, 210 LDB_ERR_OPERATIONS_ERROR); 211 } 212 if (ares->error != LDB_SUCCESS) { 213 return ldb_module_done(ac->req, ares->controls, 214 ares->response, ares->error); 215 } 216 217 /* We are interested only in the single reply */ 218 switch(ares->type) { 219 case LDB_REPLY_ENTRY: 220 /* We have already found a remote DN */ 221 if (ac->local_dn) { 222 ldb_set_errstring(ldb, 223 "Too many results!"); 224 return ldb_module_done(ac->req, NULL, NULL, 225 LDB_ERR_OPERATIONS_ERROR); 226 } 227 228 /* Store local DN */ 229 ac->local_dn = talloc_steal(ac, ares->message->dn); 230 break; 231 232 case LDB_REPLY_DONE: 233 234 switch (ac->req->operation) { 235 case LDB_MODIFY: 236 ret = map_modify_do_local(ac); 237 break; 238 case LDB_DELETE: 239 ret = map_delete_do_local(ac); 240 break; 241 case LDB_RENAME: 242 ret = map_rename_do_local(ac); 243 break; 244 default: 245 /* if we get here we have definitely a problem */ 246 ret = LDB_ERR_OPERATIONS_ERROR; 247 } 248 if (ret != LDB_SUCCESS) { 249 return ldb_module_done(ac->req, NULL, NULL, 250 LDB_ERR_OPERATIONS_ERROR); 251 } 252 253 default: 254 /* ignore referrals */ 255 break; 256 } 257 258 talloc_free(ares); 259 return LDB_SUCCESS; 260} 261 262/* Build a request to search the local record by its DN. */ 263static int map_search_self_req(struct ldb_request **req, 264 struct map_context *ac, 265 struct ldb_dn *dn) 266{ 267 /* attrs[] is returned from this function in 268 * ac->search_req->op.search.attrs, so it must be static, as 269 * otherwise the compiler can put it on the stack */ 270 static const char * const attrs[] = { IS_MAPPED, NULL }; 271 struct ldb_parse_tree *tree; 272 273 /* Limit search to records with 'IS_MAPPED' present */ 274 tree = ldb_parse_tree(ac, "(" IS_MAPPED "=*)"); 275 if (tree == NULL) { 276 map_oom(ac->module); 277 return LDB_ERR_OPERATIONS_ERROR; 278 } 279 280 *req = map_search_base_req(ac, dn, attrs, tree, 281 ac, map_search_self_callback); 282 if (*req == NULL) { 283 return LDB_ERR_OPERATIONS_ERROR; 284 } 285 286 return LDB_SUCCESS; 287} 288 289static int map_op_local_callback(struct ldb_request *req, 290 struct ldb_reply *ares) 291{ 292 struct ldb_context *ldb; 293 struct map_context *ac; 294 int ret; 295 296 ac = talloc_get_type(req->context, struct map_context); 297 ldb = ldb_module_get_ctx(ac->module); 298 299 if (!ares) { 300 return ldb_module_done(ac->req, NULL, NULL, 301 LDB_ERR_OPERATIONS_ERROR); 302 } 303 if (ares->error != LDB_SUCCESS) { 304 return ldb_module_done(ac->req, ares->controls, 305 ares->response, ares->error); 306 } 307 308 if (ares->type != LDB_REPLY_DONE) { 309 ldb_set_errstring(ldb, "Invalid reply type!"); 310 return ldb_module_done(ac->req, NULL, NULL, 311 LDB_ERR_OPERATIONS_ERROR); 312 } 313 314 /* Do the remote request. */ 315 ret = ldb_next_remote_request(ac->module, ac->remote_req); 316 if (ret != LDB_SUCCESS) { 317 return ldb_module_done(ac->req, NULL, NULL, 318 LDB_ERR_OPERATIONS_ERROR); 319 } 320 321 return LDB_SUCCESS; 322} 323 324static int map_op_remote_callback(struct ldb_request *req, 325 struct ldb_reply *ares) 326{ 327 struct ldb_context *ldb; 328 struct map_context *ac; 329 330 ac = talloc_get_type(req->context, struct map_context); 331 ldb = ldb_module_get_ctx(ac->module); 332 333 if (!ares) { 334 return ldb_module_done(ac->req, NULL, NULL, 335 LDB_ERR_OPERATIONS_ERROR); 336 } 337 if (ares->error != LDB_SUCCESS) { 338 return ldb_module_done(ac->req, ares->controls, 339 ares->response, ares->error); 340 } 341 342 if (ares->type != LDB_REPLY_DONE) { 343 ldb_set_errstring(ldb, "Invalid reply type!"); 344 return ldb_module_done(ac->req, NULL, NULL, 345 LDB_ERR_OPERATIONS_ERROR); 346 } 347 348 return ldb_module_done(ac->req, ares->controls, 349 ares->response, ares->error); 350} 351 352 353/***************************************************************************** 354 * ADD operations 355*****************************************************************************/ 356 357 358/* Add a record. */ 359int map_add(struct ldb_module *module, struct ldb_request *req) 360{ 361 const struct ldb_message *msg = req->op.add.message; 362 struct ldb_context *ldb; 363 struct map_context *ac; 364 struct ldb_message *remote_msg; 365 const char *dn; 366 int ret; 367 368 ldb = ldb_module_get_ctx(module); 369 370 /* Do not manipulate our control entries */ 371 if (ldb_dn_is_special(msg->dn)) { 372 return ldb_next_request(module, req); 373 } 374 375 /* No mapping requested (perhaps no DN mapping specified), skip to next module */ 376 if (!ldb_dn_check_local(module, msg->dn)) { 377 return ldb_next_request(module, req); 378 } 379 380 /* No mapping needed, fail */ 381 if (!ldb_msg_check_remote(module, msg)) { 382 return LDB_ERR_OPERATIONS_ERROR; 383 } 384 385 /* Prepare context and handle */ 386 ac = map_init_context(module, req); 387 if (ac == NULL) { 388 return LDB_ERR_OPERATIONS_ERROR; 389 } 390 391 392 /* Prepare the local message */ 393 ac->local_msg = ldb_msg_new(ac); 394 if (ac->local_msg == NULL) { 395 map_oom(module); 396 return LDB_ERR_OPERATIONS_ERROR; 397 } 398 ac->local_msg->dn = msg->dn; 399 400 /* Prepare the remote message */ 401 remote_msg = ldb_msg_new(ac); 402 if (remote_msg == NULL) { 403 map_oom(module); 404 return LDB_ERR_OPERATIONS_ERROR; 405 } 406 remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn); 407 408 /* Split local from remote message */ 409 ldb_msg_partition(module, ac->local_msg, remote_msg, msg); 410 411 /* Prepare the remote operation */ 412 ret = ldb_build_add_req(&ac->remote_req, ldb, 413 ac, remote_msg, 414 req->controls, 415 ac, map_op_remote_callback, 416 req); 417 if (ret != LDB_SUCCESS) { 418 return LDB_ERR_OPERATIONS_ERROR; 419 } 420 421 if ((ac->local_msg->num_elements == 0) || 422 ( ! map_check_local_db(ac->module))) { 423 /* No local data or db, just run the remote request */ 424 return ldb_next_remote_request(ac->module, ac->remote_req); 425 } 426 427 /* Store remote DN in 'IS_MAPPED' */ 428 /* TODO: use GUIDs here instead */ 429 dn = ldb_dn_alloc_linearized(ac->local_msg, remote_msg->dn); 430 if (ldb_msg_add_string(ac->local_msg, IS_MAPPED, dn) != 0) { 431 return LDB_ERR_OPERATIONS_ERROR; 432 } 433 434 return map_add_do_local(ac); 435} 436 437/* Add the local record. */ 438static int map_add_do_local(struct map_context *ac) 439{ 440 struct ldb_request *local_req; 441 struct ldb_context *ldb; 442 int ret; 443 444 ldb = ldb_module_get_ctx(ac->module); 445 446 /* Prepare the local operation */ 447 ret = ldb_build_add_req(&local_req, ldb, ac, 448 ac->local_msg, 449 ac->req->controls, 450 ac, 451 map_op_local_callback, 452 ac->req); 453 if (ret != LDB_SUCCESS) { 454 return LDB_ERR_OPERATIONS_ERROR; 455 } 456 return ldb_next_request(ac->module, local_req); 457} 458 459/***************************************************************************** 460 * MODIFY operations 461*****************************************************************************/ 462 463/* Modify a record. */ 464int map_modify(struct ldb_module *module, struct ldb_request *req) 465{ 466 const struct ldb_message *msg = req->op.mod.message; 467 struct ldb_request *search_req; 468 struct ldb_message *remote_msg; 469 struct ldb_context *ldb; 470 struct map_context *ac; 471 int ret; 472 473 ldb = ldb_module_get_ctx(module); 474 475 /* Do not manipulate our control entries */ 476 if (ldb_dn_is_special(msg->dn)) { 477 return ldb_next_request(module, req); 478 } 479 480 /* No mapping requested (perhaps no DN mapping specified), skip to next module */ 481 if (!ldb_dn_check_local(module, msg->dn)) { 482 return ldb_next_request(module, req); 483 } 484 485 /* No mapping needed, skip to next module */ 486 /* TODO: What if the remote part exists, the local doesn't, 487 * and this request wants to modify local data and thus 488 * add the local record? */ 489 if (!ldb_msg_check_remote(module, msg)) { 490 return LDB_ERR_OPERATIONS_ERROR; 491 } 492 493 /* Prepare context and handle */ 494 ac = map_init_context(module, req); 495 if (ac == NULL) { 496 return LDB_ERR_OPERATIONS_ERROR; 497 } 498 499 /* Prepare the local message */ 500 ac->local_msg = ldb_msg_new(ac); 501 if (ac->local_msg == NULL) { 502 map_oom(module); 503 return LDB_ERR_OPERATIONS_ERROR; 504 } 505 ac->local_msg->dn = msg->dn; 506 507 /* Prepare the remote message */ 508 remote_msg = ldb_msg_new(ac->remote_req); 509 if (remote_msg == NULL) { 510 map_oom(module); 511 return LDB_ERR_OPERATIONS_ERROR; 512 } 513 remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn); 514 515 /* Split local from remote message */ 516 ldb_msg_partition(module, ac->local_msg, remote_msg, msg); 517 518 /* Prepare the remote operation */ 519 ret = ldb_build_mod_req(&ac->remote_req, ldb, 520 ac, remote_msg, 521 req->controls, 522 ac, map_op_remote_callback, 523 req); 524 if (ret != LDB_SUCCESS) { 525 return LDB_ERR_OPERATIONS_ERROR; 526 } 527 528 if ((ac->local_msg->num_elements == 0) || 529 ( ! map_check_local_db(ac->module))) { 530 /* No local data or db, just run the remote request */ 531 return ldb_next_remote_request(ac->module, ac->remote_req); 532 } 533 534 /* prepare the search operation */ 535 ret = map_search_self_req(&search_req, ac, msg->dn); 536 if (ret != LDB_SUCCESS) { 537 return LDB_ERR_OPERATIONS_ERROR; 538 } 539 540 return ldb_next_request(module, search_req); 541} 542 543/* Modify the local record. */ 544static int map_modify_do_local(struct map_context *ac) 545{ 546 struct ldb_request *local_req; 547 struct ldb_context *ldb; 548 char *dn; 549 int ret; 550 551 ldb = ldb_module_get_ctx(ac->module); 552 553 if (ac->local_dn == NULL) { 554 /* No local record present, add it instead */ 555 /* Add local 'IS_MAPPED' */ 556 /* TODO: use GUIDs here instead */ 557 if (ldb_msg_add_empty(ac->local_msg, IS_MAPPED, 558 LDB_FLAG_MOD_ADD, NULL) != 0) { 559 return LDB_ERR_OPERATIONS_ERROR; 560 } 561 dn = ldb_dn_alloc_linearized(ac->local_msg, 562 ac->remote_req->op.mod.message->dn); 563 if (ldb_msg_add_string(ac->local_msg, IS_MAPPED, dn) != 0) { 564 return LDB_ERR_OPERATIONS_ERROR; 565 } 566 567 /* Prepare the local operation */ 568 ret = ldb_build_add_req(&local_req, ldb, ac, 569 ac->local_msg, 570 ac->req->controls, 571 ac, 572 map_op_local_callback, 573 ac->req); 574 if (ret != LDB_SUCCESS) { 575 return LDB_ERR_OPERATIONS_ERROR; 576 } 577 } else { 578 /* Prepare the local operation */ 579 ret = ldb_build_mod_req(&local_req, ldb, ac, 580 ac->local_msg, 581 ac->req->controls, 582 ac, 583 map_op_local_callback, 584 ac->req); 585 if (ret != LDB_SUCCESS) { 586 return LDB_ERR_OPERATIONS_ERROR; 587 } 588 } 589 590 return ldb_next_request(ac->module, local_req); 591} 592 593/***************************************************************************** 594 * DELETE operations 595*****************************************************************************/ 596 597/* Delete a record. */ 598int map_delete(struct ldb_module *module, struct ldb_request *req) 599{ 600 struct ldb_request *search_req; 601 struct ldb_context *ldb; 602 struct map_context *ac; 603 int ret; 604 605 ldb = ldb_module_get_ctx(module); 606 607 /* Do not manipulate our control entries */ 608 if (ldb_dn_is_special(req->op.del.dn)) { 609 return ldb_next_request(module, req); 610 } 611 612 /* No mapping requested (perhaps no DN mapping specified). 613 * Skip to next module */ 614 if (!ldb_dn_check_local(module, req->op.del.dn)) { 615 return ldb_next_request(module, req); 616 } 617 618 /* Prepare context and handle */ 619 ac = map_init_context(module, req); 620 if (ac == NULL) { 621 return LDB_ERR_OPERATIONS_ERROR; 622 } 623 624 /* Prepare the remote operation */ 625 ret = ldb_build_del_req(&ac->remote_req, ldb, ac, 626 ldb_dn_map_local(module, ac, req->op.del.dn), 627 req->controls, 628 ac, 629 map_op_remote_callback, 630 req); 631 if (ret != LDB_SUCCESS) { 632 return LDB_ERR_OPERATIONS_ERROR; 633 } 634 635 /* No local db, just run the remote request */ 636 if (!map_check_local_db(ac->module)) { 637 /* Do the remote request. */ 638 return ldb_next_remote_request(ac->module, ac->remote_req); 639 } 640 641 /* Prepare the search operation */ 642 ret = map_search_self_req(&search_req, ac, req->op.del.dn); 643 if (ret != LDB_SUCCESS) { 644 map_oom(module); 645 return LDB_ERR_OPERATIONS_ERROR; 646 } 647 648 return ldb_next_request(module, search_req); 649} 650 651/* Delete the local record. */ 652static int map_delete_do_local(struct map_context *ac) 653{ 654 struct ldb_request *local_req; 655 struct ldb_context *ldb; 656 int ret; 657 658 ldb = ldb_module_get_ctx(ac->module); 659 660 /* No local record, continue remotely */ 661 if (ac->local_dn == NULL) { 662 /* Do the remote request. */ 663 return ldb_next_remote_request(ac->module, ac->remote_req); 664 } 665 666 /* Prepare the local operation */ 667 ret = ldb_build_del_req(&local_req, ldb, ac, 668 ac->req->op.del.dn, 669 ac->req->controls, 670 ac, 671 map_op_local_callback, 672 ac->req); 673 if (ret != LDB_SUCCESS) { 674 return LDB_ERR_OPERATIONS_ERROR; 675 } 676 return ldb_next_request(ac->module, local_req); 677} 678 679/***************************************************************************** 680 * RENAME operations 681*****************************************************************************/ 682 683/* Rename a record. */ 684int map_rename(struct ldb_module *module, struct ldb_request *req) 685{ 686 struct ldb_request *search_req; 687 struct ldb_context *ldb; 688 struct map_context *ac; 689 int ret; 690 691 ldb = ldb_module_get_ctx(module); 692 693 /* Do not manipulate our control entries */ 694 if (ldb_dn_is_special(req->op.rename.olddn)) { 695 return ldb_next_request(module, req); 696 } 697 698 /* No mapping requested (perhaps no DN mapping specified). 699 * Skip to next module */ 700 if ((!ldb_dn_check_local(module, req->op.rename.olddn)) && 701 (!ldb_dn_check_local(module, req->op.rename.newdn))) { 702 return ldb_next_request(module, req); 703 } 704 705 /* Rename into/out of the mapped partition requested, bail out */ 706 if (!ldb_dn_check_local(module, req->op.rename.olddn) || 707 !ldb_dn_check_local(module, req->op.rename.newdn)) { 708 return LDB_ERR_AFFECTS_MULTIPLE_DSAS; 709 } 710 711 /* Prepare context and handle */ 712 ac = map_init_context(module, req); 713 if (ac == NULL) { 714 return LDB_ERR_OPERATIONS_ERROR; 715 } 716 717 /* Prepare the remote operation */ 718 ret = ldb_build_rename_req(&ac->remote_req, ldb, ac, 719 ldb_dn_map_local(module, ac, req->op.rename.olddn), 720 ldb_dn_map_local(module, ac, req->op.rename.newdn), 721 req->controls, 722 ac, map_op_remote_callback, 723 req); 724 if (ret != LDB_SUCCESS) { 725 return LDB_ERR_OPERATIONS_ERROR; 726 } 727 728 /* No local db, just run the remote request */ 729 if (!map_check_local_db(ac->module)) { 730 /* Do the remote request. */ 731 return ldb_next_remote_request(ac->module, ac->remote_req); 732 } 733 734 /* Prepare the search operation */ 735 ret = map_search_self_req(&search_req, ac, req->op.rename.olddn); 736 if (ret != LDB_SUCCESS) { 737 map_oom(module); 738 return LDB_ERR_OPERATIONS_ERROR; 739 } 740 741 return ldb_next_request(module, search_req); 742} 743 744/* Rename the local record. */ 745static int map_rename_do_local(struct map_context *ac) 746{ 747 struct ldb_request *local_req; 748 struct ldb_context *ldb; 749 int ret; 750 751 ldb = ldb_module_get_ctx(ac->module); 752 753 /* No local record, continue remotely */ 754 if (ac->local_dn == NULL) { 755 /* Do the remote request. */ 756 return ldb_next_remote_request(ac->module, ac->remote_req); 757 } 758 759 /* Prepare the local operation */ 760 ret = ldb_build_rename_req(&local_req, ldb, ac, 761 ac->req->op.rename.olddn, 762 ac->req->op.rename.newdn, 763 ac->req->controls, 764 ac, 765 map_rename_local_callback, 766 ac->req); 767 if (ret != LDB_SUCCESS) { 768 return LDB_ERR_OPERATIONS_ERROR; 769 } 770 771 return ldb_next_request(ac->module, local_req); 772} 773 774static int map_rename_local_callback(struct ldb_request *req, 775 struct ldb_reply *ares) 776{ 777 struct ldb_context *ldb; 778 struct map_context *ac; 779 int ret; 780 781 ac = talloc_get_type(req->context, struct map_context); 782 ldb = ldb_module_get_ctx(ac->module); 783 784 if (!ares) { 785 return ldb_module_done(ac->req, NULL, NULL, 786 LDB_ERR_OPERATIONS_ERROR); 787 } 788 if (ares->error != LDB_SUCCESS) { 789 return ldb_module_done(ac->req, ares->controls, 790 ares->response, ares->error); 791 } 792 793 if (ares->type != LDB_REPLY_DONE) { 794 ldb_set_errstring(ldb, "Invalid reply type!"); 795 return ldb_module_done(ac->req, NULL, NULL, 796 LDB_ERR_OPERATIONS_ERROR); 797 } 798 799 /* proceed with next step */ 800 ret = map_rename_do_fixup(ac); 801 if (ret != LDB_SUCCESS) { 802 return ldb_module_done(ac->req, NULL, NULL, 803 LDB_ERR_OPERATIONS_ERROR); 804 } 805 806 return LDB_SUCCESS; 807} 808 809/* Update the local 'IS_MAPPED' attribute. */ 810static int map_rename_do_fixup(struct map_context *ac) 811{ 812 struct ldb_request *local_req; 813 814 /* Prepare the fixup operation */ 815 /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */ 816 local_req = map_build_fixup_req(ac, 817 ac->req->op.rename.newdn, 818 ac->remote_req->op.rename.newdn, 819 ac, 820 map_op_local_callback); 821 if (local_req == NULL) { 822 return LDB_ERR_OPERATIONS_ERROR; 823 } 824 825 return ldb_next_request(ac->module, local_req); 826} 827