1/* 2 ldb database library - ildap backend 3 4 Copyright (C) Andrew Tridgell 2005 5 Copyright (C) Simo Sorce 2008 6 7 ** NOTE! The following LGPL license applies to the ldb 8 ** library. This does NOT imply that all of Samba is released 9 ** under the LGPL 10 11 This library is free software; you can redistribute it and/or 12 modify it under the terms of the GNU Lesser General Public 13 License as published by the Free Software Foundation; either 14 version 3 of the License, or (at your option) any later version. 15 16 This library is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 Lesser General Public License for more details. 20 21 You should have received a copy of the GNU Lesser General Public 22 License along with this library; if not, see <http://www.gnu.org/licenses/>. 23*/ 24 25/* 26 * Name: ldb_ildap 27 * 28 * Component: ldb ildap backend 29 * 30 * Description: This is a ldb backend for the internal ldap 31 * client library in Samba4. By using this backend we are 32 * independent of a system ldap library 33 * 34 * Author: Andrew Tridgell 35 * 36 * Modifications: 37 * 38 * - description: make the module use asyncronous calls 39 * date: Feb 2006 40 * author: Simo Sorce 41 */ 42 43#include "includes.h" 44#include "ldb_module.h" 45#include "dlinklist.h" 46 47#include "libcli/ldap/ldap.h" 48#include "libcli/ldap/ldap_client.h" 49#include "auth/auth.h" 50#include "auth/credentials/credentials.h" 51 52struct ildb_private { 53 struct ldap_connection *ldap; 54 struct tevent_context *event_ctx; 55}; 56 57struct ildb_context { 58 struct ldb_module *module; 59 struct ldb_request *req; 60 61 struct ildb_private *ildb; 62 struct ldap_request *ireq; 63 64 bool done; 65 66 struct ildb_destructor_ctx *dc; 67}; 68 69static void ildb_request_done(struct ildb_context *ctx, 70 struct ldb_control **ctrls, int error) 71{ 72 struct ldb_context *ldb; 73 struct ldb_reply *ares; 74 75 ldb = ldb_module_get_ctx(ctx->module); 76 77 ctx->done = true; 78 79 if (ctx->req == NULL) { 80 /* if the req has been freed already just return */ 81 return; 82 } 83 84 ares = talloc_zero(ctx->req, struct ldb_reply); 85 if (!ares) { 86 ldb_oom(ldb); 87 ctx->req->callback(ctx->req, NULL); 88 return; 89 } 90 ares->type = LDB_REPLY_DONE; 91 ares->controls = talloc_steal(ares, ctrls); 92 ares->error = error; 93 94 ctx->req->callback(ctx->req, ares); 95} 96 97static void ildb_auto_done_callback(struct tevent_context *ev, 98 struct tevent_timer *te, 99 struct timeval t, 100 void *private_data) 101{ 102 struct ildb_context *ac; 103 104 ac = talloc_get_type(private_data, struct ildb_context); 105 ildb_request_done(ac, NULL, LDB_SUCCESS); 106} 107 108/* 109 convert a ldb_message structure to a list of ldap_mod structures 110 ready for ildap_add() or ildap_modify() 111*/ 112static struct ldap_mod **ildb_msg_to_mods(void *mem_ctx, int *num_mods, 113 const struct ldb_message *msg, 114 int use_flags) 115{ 116 struct ldap_mod **mods; 117 unsigned int i; 118 int n = 0; 119 120 /* allocate maximum number of elements needed */ 121 mods = talloc_array(mem_ctx, struct ldap_mod *, msg->num_elements+1); 122 if (!mods) { 123 errno = ENOMEM; 124 return NULL; 125 } 126 mods[0] = NULL; 127 128 for (i = 0; i < msg->num_elements; i++) { 129 const struct ldb_message_element *el = &msg->elements[i]; 130 131 mods[n] = talloc(mods, struct ldap_mod); 132 if (!mods[n]) { 133 goto failed; 134 } 135 mods[n + 1] = NULL; 136 mods[n]->type = 0; 137 mods[n]->attrib = *el; 138 if (use_flags) { 139 switch (el->flags & LDB_FLAG_MOD_MASK) { 140 case LDB_FLAG_MOD_ADD: 141 mods[n]->type = LDAP_MODIFY_ADD; 142 break; 143 case LDB_FLAG_MOD_DELETE: 144 mods[n]->type = LDAP_MODIFY_DELETE; 145 break; 146 case LDB_FLAG_MOD_REPLACE: 147 mods[n]->type = LDAP_MODIFY_REPLACE; 148 break; 149 } 150 } 151 n++; 152 } 153 154 *num_mods = n; 155 return mods; 156 157failed: 158 talloc_free(mods); 159 return NULL; 160} 161 162 163/* 164 map an ildap NTSTATUS to a ldb error code 165*/ 166static int ildb_map_error(struct ldb_module *module, NTSTATUS status) 167{ 168 struct ildb_private *ildb; 169 struct ldb_context *ldb; 170 TALLOC_CTX *mem_ctx; 171 172 ildb = talloc_get_type(ldb_module_get_private(module), struct ildb_private); 173 ldb = ldb_module_get_ctx(module); 174 175 if (NT_STATUS_IS_OK(status)) { 176 return LDB_SUCCESS; 177 } 178 179 mem_ctx = talloc_new(ildb); 180 if (!mem_ctx) { 181 ldb_oom(ldb); 182 return LDB_ERR_OPERATIONS_ERROR; 183 } 184 ldb_set_errstring(ldb, 185 ldap_errstr(ildb->ldap, mem_ctx, status)); 186 talloc_free(mem_ctx); 187 if (NT_STATUS_IS_LDAP(status)) { 188 return NT_STATUS_LDAP_CODE(status); 189 } 190 return LDB_ERR_OPERATIONS_ERROR; 191} 192 193static void ildb_request_timeout(struct tevent_context *ev, struct tevent_timer *te, 194 struct timeval t, void *private_data) 195{ 196 struct ildb_context *ac = talloc_get_type(private_data, struct ildb_context); 197 198 if (ac->ireq->state == LDAP_REQUEST_PENDING) { 199 DLIST_REMOVE(ac->ireq->conn->pending, ac->ireq); 200 } 201 202 ildb_request_done(ac, NULL, LDB_ERR_TIME_LIMIT_EXCEEDED); 203} 204 205static void ildb_callback(struct ldap_request *req) 206{ 207 struct ldb_context *ldb; 208 struct ildb_context *ac; 209 NTSTATUS status; 210 struct ldap_SearchResEntry *search; 211 struct ldap_message *msg; 212 struct ldb_control **controls; 213 struct ldb_message *ldbmsg; 214 char *referral; 215 bool callback_failed; 216 bool request_done; 217 int ret; 218 int i; 219 220 ac = talloc_get_type(req->async.private_data, struct ildb_context); 221 ldb = ldb_module_get_ctx(ac->module); 222 callback_failed = false; 223 request_done = false; 224 controls = NULL; 225 226 if (!NT_STATUS_IS_OK(req->status)) { 227 ret = ildb_map_error(ac->module, req->status); 228 ildb_request_done(ac, NULL, ret); 229 return; 230 } 231 232 if (req->num_replies < 1) { 233 ret = LDB_ERR_OPERATIONS_ERROR; 234 ildb_request_done(ac, NULL, ret); 235 return; 236 } 237 238 switch (req->type) { 239 240 case LDAP_TAG_ModifyRequest: 241 if (req->replies[0]->type != LDAP_TAG_ModifyResponse) { 242 ret = LDB_ERR_PROTOCOL_ERROR; 243 break; 244 } 245 status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult); 246 ret = ildb_map_error(ac->module, status); 247 request_done = true; 248 break; 249 250 case LDAP_TAG_AddRequest: 251 if (req->replies[0]->type != LDAP_TAG_AddResponse) { 252 ret = LDB_ERR_PROTOCOL_ERROR; 253 return; 254 } 255 status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult); 256 ret = ildb_map_error(ac->module, status); 257 request_done = true; 258 break; 259 260 case LDAP_TAG_DelRequest: 261 if (req->replies[0]->type != LDAP_TAG_DelResponse) { 262 ret = LDB_ERR_PROTOCOL_ERROR; 263 return; 264 } 265 status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult); 266 ret = ildb_map_error(ac->module, status); 267 request_done = true; 268 break; 269 270 case LDAP_TAG_ModifyDNRequest: 271 if (req->replies[0]->type != LDAP_TAG_ModifyDNResponse) { 272 ret = LDB_ERR_PROTOCOL_ERROR; 273 return; 274 } 275 status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult); 276 ret = ildb_map_error(ac->module, status); 277 request_done = true; 278 break; 279 280 case LDAP_TAG_SearchRequest: 281 /* loop over all messages */ 282 for (i = 0; i < req->num_replies; i++) { 283 284 msg = req->replies[i]; 285 switch (msg->type) { 286 287 case LDAP_TAG_SearchResultDone: 288 289 status = ldap_check_response(ac->ireq->conn, &msg->r.GeneralResult); 290 if (!NT_STATUS_IS_OK(status)) { 291 ret = ildb_map_error(ac->module, status); 292 break; 293 } 294 295 controls = talloc_steal(ac, msg->controls); 296 if (msg->r.SearchResultDone.resultcode) { 297 if (msg->r.SearchResultDone.errormessage) { 298 ldb_set_errstring(ldb, msg->r.SearchResultDone.errormessage); 299 } 300 } 301 302 ret = msg->r.SearchResultDone.resultcode; 303 request_done = true; 304 break; 305 306 case LDAP_TAG_SearchResultEntry: 307 308 ldbmsg = ldb_msg_new(ac); 309 if (!ldbmsg) { 310 ret = LDB_ERR_OPERATIONS_ERROR; 311 break; 312 } 313 314 search = &(msg->r.SearchResultEntry); 315 316 ldbmsg->dn = ldb_dn_new(ldbmsg, ldb, search->dn); 317 if ( ! ldb_dn_validate(ldbmsg->dn)) { 318 ret = LDB_ERR_OPERATIONS_ERROR; 319 break; 320 } 321 ldbmsg->num_elements = search->num_attributes; 322 ldbmsg->elements = talloc_move(ldbmsg, &search->attributes); 323 324 controls = talloc_steal(ac, msg->controls); 325 326 ret = ldb_module_send_entry(ac->req, ldbmsg, controls); 327 if (ret != LDB_SUCCESS) { 328 callback_failed = true; 329 } 330 break; 331 332 case LDAP_TAG_SearchResultReference: 333 334 referral = talloc_strdup(ac, msg->r.SearchResultReference.referral); 335 336 ret = ldb_module_send_referral(ac->req, referral); 337 if (ret != LDB_SUCCESS) { 338 callback_failed = true; 339 } 340 break; 341 342 default: 343 /* TAG not handled, fail ! */ 344 ret = LDB_ERR_PROTOCOL_ERROR; 345 break; 346 } 347 348 if (ret != LDB_SUCCESS) { 349 break; 350 } 351 } 352 353 talloc_free(req->replies); 354 req->replies = NULL; 355 req->num_replies = 0; 356 357 break; 358 359 default: 360 ret = LDB_ERR_PROTOCOL_ERROR; 361 break; 362 } 363 364 if (ret != LDB_SUCCESS) { 365 366 /* if the callback failed the caller will have freed the 367 * request. Just return and don't try to use it */ 368 if ( ! callback_failed) { 369 request_done = true; 370 } 371 } 372 373 if (request_done) { 374 ildb_request_done(ac, controls, ret); 375 } 376 return; 377} 378 379static int ildb_request_send(struct ildb_context *ac, struct ldap_message *msg) 380{ 381 struct ldb_context *ldb; 382 struct ldap_request *req; 383 384 if (!ac) { 385 return LDB_ERR_OPERATIONS_ERROR; 386 } 387 388 ldb = ldb_module_get_ctx(ac->module); 389 390 req = ldap_request_send(ac->ildb->ldap, msg); 391 if (req == NULL) { 392 ldb_set_errstring(ldb, "async send request failed"); 393 return LDB_ERR_OPERATIONS_ERROR; 394 } 395 ac->ireq = talloc_steal(ac, req); 396 397 if (!ac->ireq->conn) { 398 ldb_set_errstring(ldb, "connection to remote LDAP server dropped?"); 399 return LDB_ERR_OPERATIONS_ERROR; 400 } 401 402 talloc_free(req->time_event); 403 req->time_event = NULL; 404 if (ac->req->timeout) { 405 req->time_event = tevent_add_timer(ac->ildb->event_ctx, ac, 406 timeval_current_ofs(ac->req->timeout, 0), 407 ildb_request_timeout, ac); 408 } 409 410 req->async.fn = ildb_callback; 411 req->async.private_data = ac; 412 413 return LDB_SUCCESS; 414} 415 416/* 417 search for matching records using an asynchronous function 418 */ 419static int ildb_search(struct ildb_context *ac) 420{ 421 struct ldb_context *ldb; 422 struct ldb_request *req = ac->req; 423 struct ldap_message *msg; 424 int n; 425 426 ldb = ldb_module_get_ctx(ac->module); 427 428 if (!req->callback || !req->context) { 429 ldb_set_errstring(ldb, "Async interface called with NULL callback function or NULL context"); 430 return LDB_ERR_OPERATIONS_ERROR; 431 } 432 433 if (req->op.search.tree == NULL) { 434 ldb_set_errstring(ldb, "Invalid expression parse tree"); 435 return LDB_ERR_OPERATIONS_ERROR; 436 } 437 438 msg = new_ldap_message(req); 439 if (msg == NULL) { 440 ldb_set_errstring(ldb, "Out of Memory"); 441 return LDB_ERR_OPERATIONS_ERROR; 442 } 443 444 msg->type = LDAP_TAG_SearchRequest; 445 446 if (req->op.search.base == NULL) { 447 msg->r.SearchRequest.basedn = talloc_strdup(msg, ""); 448 } else { 449 msg->r.SearchRequest.basedn = ldb_dn_get_extended_linearized(msg, req->op.search.base, 0); 450 } 451 if (msg->r.SearchRequest.basedn == NULL) { 452 ldb_set_errstring(ldb, "Unable to determine baseDN"); 453 talloc_free(msg); 454 return LDB_ERR_OPERATIONS_ERROR; 455 } 456 457 if (req->op.search.scope == LDB_SCOPE_DEFAULT) { 458 msg->r.SearchRequest.scope = LDB_SCOPE_SUBTREE; 459 } else { 460 msg->r.SearchRequest.scope = req->op.search.scope; 461 } 462 463 msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER; 464 msg->r.SearchRequest.timelimit = 0; 465 msg->r.SearchRequest.sizelimit = 0; 466 msg->r.SearchRequest.attributesonly = 0; 467 msg->r.SearchRequest.tree = discard_const(req->op.search.tree); 468 469 for (n = 0; req->op.search.attrs && req->op.search.attrs[n]; n++) /* noop */ ; 470 msg->r.SearchRequest.num_attributes = n; 471 msg->r.SearchRequest.attributes = req->op.search.attrs; 472 msg->controls = req->controls; 473 474 return ildb_request_send(ac, msg); 475} 476 477/* 478 add a record 479*/ 480static int ildb_add(struct ildb_context *ac) 481{ 482 struct ldb_request *req = ac->req; 483 struct ldap_message *msg; 484 struct ldap_mod **mods; 485 int i,n; 486 487 msg = new_ldap_message(req); 488 if (msg == NULL) { 489 return LDB_ERR_OPERATIONS_ERROR; 490 } 491 492 msg->type = LDAP_TAG_AddRequest; 493 494 msg->r.AddRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.add.message->dn, 0); 495 if (msg->r.AddRequest.dn == NULL) { 496 talloc_free(msg); 497 return LDB_ERR_INVALID_DN_SYNTAX; 498 } 499 500 mods = ildb_msg_to_mods(msg, &n, req->op.add.message, 0); 501 if (mods == NULL) { 502 talloc_free(msg); 503 return LDB_ERR_OPERATIONS_ERROR; 504 } 505 506 msg->r.AddRequest.num_attributes = n; 507 msg->r.AddRequest.attributes = talloc_array(msg, struct ldb_message_element, n); 508 if (msg->r.AddRequest.attributes == NULL) { 509 talloc_free(msg); 510 return LDB_ERR_OPERATIONS_ERROR; 511 } 512 513 for (i = 0; i < n; i++) { 514 msg->r.AddRequest.attributes[i] = mods[i]->attrib; 515 } 516 517 return ildb_request_send(ac, msg); 518} 519 520/* 521 modify a record 522*/ 523static int ildb_modify(struct ildb_context *ac) 524{ 525 struct ldb_request *req = ac->req; 526 struct ldap_message *msg; 527 struct ldap_mod **mods; 528 int i,n; 529 530 msg = new_ldap_message(req); 531 if (msg == NULL) { 532 return LDB_ERR_OPERATIONS_ERROR; 533 } 534 535 msg->type = LDAP_TAG_ModifyRequest; 536 537 msg->r.ModifyRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.mod.message->dn, 0); 538 if (msg->r.ModifyRequest.dn == NULL) { 539 talloc_free(msg); 540 return LDB_ERR_INVALID_DN_SYNTAX; 541 } 542 543 mods = ildb_msg_to_mods(msg, &n, req->op.mod.message, 1); 544 if (mods == NULL) { 545 talloc_free(msg); 546 return LDB_ERR_OPERATIONS_ERROR; 547 } 548 549 msg->r.ModifyRequest.num_mods = n; 550 msg->r.ModifyRequest.mods = talloc_array(msg, struct ldap_mod, n); 551 if (msg->r.ModifyRequest.mods == NULL) { 552 talloc_free(msg); 553 return LDB_ERR_OPERATIONS_ERROR; 554 } 555 556 for (i = 0; i < n; i++) { 557 msg->r.ModifyRequest.mods[i] = *mods[i]; 558 } 559 560 return ildb_request_send(ac, msg); 561} 562 563/* 564 delete a record 565*/ 566static int ildb_delete(struct ildb_context *ac) 567{ 568 struct ldb_request *req = ac->req; 569 struct ldap_message *msg; 570 571 msg = new_ldap_message(req); 572 if (msg == NULL) { 573 return LDB_ERR_OPERATIONS_ERROR; 574 } 575 576 msg->type = LDAP_TAG_DelRequest; 577 578 msg->r.DelRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.del.dn, 0); 579 if (msg->r.DelRequest.dn == NULL) { 580 talloc_free(msg); 581 return LDB_ERR_INVALID_DN_SYNTAX; 582 } 583 584 return ildb_request_send(ac, msg); 585} 586 587/* 588 rename a record 589*/ 590static int ildb_rename(struct ildb_context *ac) 591{ 592 struct ldb_request *req = ac->req; 593 struct ldap_message *msg; 594 595 msg = new_ldap_message(req); 596 if (msg == NULL) { 597 return LDB_ERR_OPERATIONS_ERROR; 598 } 599 600 msg->type = LDAP_TAG_ModifyDNRequest; 601 msg->r.ModifyDNRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.rename.olddn, 0); 602 if (msg->r.ModifyDNRequest.dn == NULL) { 603 talloc_free(msg); 604 return LDB_ERR_INVALID_DN_SYNTAX; 605 } 606 607 msg->r.ModifyDNRequest.newrdn = 608 talloc_asprintf(msg, "%s=%s", 609 ldb_dn_get_rdn_name(req->op.rename.newdn), 610 ldb_dn_escape_value(msg, *ldb_dn_get_rdn_val(req->op.rename.newdn))); 611 if (msg->r.ModifyDNRequest.newrdn == NULL) { 612 talloc_free(msg); 613 return LDB_ERR_OPERATIONS_ERROR; 614 } 615 616 msg->r.ModifyDNRequest.newsuperior = 617 ldb_dn_alloc_linearized(msg, ldb_dn_get_parent(msg, req->op.rename.newdn)); 618 if (msg->r.ModifyDNRequest.newsuperior == NULL) { 619 talloc_free(msg); 620 return LDB_ERR_INVALID_DN_SYNTAX; 621 } 622 623 msg->r.ModifyDNRequest.deleteolddn = true; 624 625 return ildb_request_send(ac, msg); 626} 627 628static int ildb_start_trans(struct ldb_module *module) 629{ 630 /* TODO implement a local locking mechanism here */ 631 632 return LDB_SUCCESS; 633} 634 635static int ildb_end_trans(struct ldb_module *module) 636{ 637 /* TODO implement a local transaction mechanism here */ 638 639 return LDB_SUCCESS; 640} 641 642static int ildb_del_trans(struct ldb_module *module) 643{ 644 /* TODO implement a local locking mechanism here */ 645 646 return LDB_SUCCESS; 647} 648 649static bool ildb_dn_is_special(struct ldb_request *req) 650{ 651 struct ldb_dn *dn = NULL; 652 653 switch (req->operation) { 654 case LDB_ADD: 655 dn = req->op.add.message->dn; 656 break; 657 case LDB_MODIFY: 658 dn = req->op.mod.message->dn; 659 break; 660 case LDB_DELETE: 661 dn = req->op.del.dn; 662 break; 663 case LDB_RENAME: 664 dn = req->op.rename.olddn; 665 break; 666 default: 667 break; 668 } 669 670 if (dn && ldb_dn_is_special(dn)) { 671 return true; 672 } 673 return false; 674} 675 676static int ildb_handle_request(struct ldb_module *module, struct ldb_request *req) 677{ 678 struct ldb_context *ldb; 679 struct ildb_private *ildb; 680 struct ildb_context *ac; 681 struct tevent_timer *te; 682 int ret; 683 684 ildb = talloc_get_type(ldb_module_get_private(module), struct ildb_private); 685 ldb = ldb_module_get_ctx(module); 686 687 if (req->starttime == 0 || req->timeout == 0) { 688 ldb_set_errstring(ldb, "Invalid timeout settings"); 689 return LDB_ERR_TIME_LIMIT_EXCEEDED; 690 } 691 692 ac = talloc_zero(req, struct ildb_context); 693 if (ac == NULL) { 694 ldb_set_errstring(ldb, "Out of Memory"); 695 return LDB_ERR_OPERATIONS_ERROR; 696 } 697 698 ac->module = module; 699 ac->req = req; 700 ac->ildb = ildb; 701 702 if (ildb_dn_is_special(req)) { 703 704 te = tevent_add_timer(ac->ildb->event_ctx, 705 ac, timeval_zero(), 706 ildb_auto_done_callback, ac); 707 if (NULL == te) { 708 return LDB_ERR_OPERATIONS_ERROR; 709 } 710 711 return LDB_SUCCESS; 712 } 713 714 switch (ac->req->operation) { 715 case LDB_SEARCH: 716 ret = ildb_search(ac); 717 break; 718 case LDB_ADD: 719 ret = ildb_add(ac); 720 break; 721 case LDB_MODIFY: 722 ret = ildb_modify(ac); 723 break; 724 case LDB_DELETE: 725 ret = ildb_delete(ac); 726 break; 727 case LDB_RENAME: 728 ret = ildb_rename(ac); 729 break; 730 default: 731 /* no other op supported */ 732 ret = LDB_ERR_OPERATIONS_ERROR; 733 break; 734 } 735 736 return ret; 737} 738 739static const struct ldb_module_ops ildb_ops = { 740 .name = "ldap", 741 .search = ildb_handle_request, 742 .add = ildb_handle_request, 743 .modify = ildb_handle_request, 744 .del = ildb_handle_request, 745 .rename = ildb_handle_request, 746/* .request = ildb_handle_request, */ 747 .start_transaction = ildb_start_trans, 748 .end_transaction = ildb_end_trans, 749 .del_transaction = ildb_del_trans, 750}; 751 752/* 753 connect to the database 754*/ 755static int ildb_connect(struct ldb_context *ldb, const char *url, 756 unsigned int flags, const char *options[], 757 struct ldb_module **_module) 758{ 759 struct ldb_module *module; 760 struct ildb_private *ildb; 761 NTSTATUS status; 762 struct cli_credentials *creds; 763 struct loadparm_context *lp_ctx; 764 765 module = ldb_module_new(ldb, ldb, "ldb_ildap backend", &ildb_ops); 766 if (!module) return -1; 767 768 ildb = talloc(module, struct ildb_private); 769 if (!ildb) { 770 ldb_oom(ldb); 771 goto failed; 772 } 773 ldb_module_set_private(module, ildb); 774 775 ildb->event_ctx = ldb_get_event_context(ldb); 776 777 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"), 778 struct loadparm_context); 779 780 ildb->ldap = ldap4_new_connection(ildb, lp_ctx, 781 ildb->event_ctx); 782 if (!ildb->ldap) { 783 ldb_oom(ldb); 784 goto failed; 785 } 786 787 if (flags & LDB_FLG_RECONNECT) { 788 ldap_set_reconn_params(ildb->ldap, 10); 789 } 790 791 status = ldap_connect(ildb->ldap, url); 792 if (!NT_STATUS_IS_OK(status)) { 793 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to ldap URL '%s' - %s", 794 url, ldap_errstr(ildb->ldap, module, status)); 795 goto failed; 796 } 797 798 /* caller can optionally setup credentials using the opaque token 'credentials' */ 799 creds = talloc_get_type(ldb_get_opaque(ldb, "credentials"), struct cli_credentials); 800 if (creds == NULL) { 801 struct auth_session_info *session_info = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info); 802 if (session_info) { 803 creds = session_info->credentials; 804 } 805 } 806 807 if (creds != NULL && cli_credentials_authentication_requested(creds)) { 808 const char *bind_dn = cli_credentials_get_bind_dn(creds); 809 if (bind_dn) { 810 const char *password = cli_credentials_get_password(creds); 811 status = ldap_bind_simple(ildb->ldap, bind_dn, password); 812 if (!NT_STATUS_IS_OK(status)) { 813 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s", 814 ldap_errstr(ildb->ldap, module, status)); 815 goto failed; 816 } 817 } else { 818 status = ldap_bind_sasl(ildb->ldap, creds, lp_ctx); 819 if (!NT_STATUS_IS_OK(status)) { 820 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s", 821 ldap_errstr(ildb->ldap, module, status)); 822 goto failed; 823 } 824 } 825 } 826 827 *_module = module; 828 return 0; 829 830failed: 831 talloc_free(module); 832 return -1; 833} 834 835_PUBLIC_ const struct ldb_backend_ops ldb_ldap_backend_ops = { 836 .name = "ldap", 837 .connect_fn = ildb_connect 838}; 839 840_PUBLIC_ const struct ldb_backend_ops ldb_ldapi_backend_ops = { 841 .name = "ldapi", 842 .connect_fn = ildb_connect 843}; 844 845_PUBLIC_ const struct ldb_backend_ops ldb_ldaps_backend_ops = { 846 .name = "ldaps", 847 .connect_fn = ildb_connect 848}; 849 850