2 ldb database library - ildap backend
4 Copyright (C) Andrew Tridgell 2005
5 Copyright (C) Simo Sorce 2008
7 ** NOTE! The following LGPL license applies to the ldb
8 ** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
28 * Component: ldb ildap backend
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
34 * Author: Andrew Tridgell
38 * - description: make the module use asyncronous calls
45 #include "ldb_includes.h"
47 #include "lib/events/events.h"
48 #include "libcli/ldap/ldap.h"
49 #include "libcli/ldap/ldap_client.h"
50 #include "auth/auth.h"
51 #include "auth/credentials/credentials.h"
52 #include "param/param.h"
55 struct ldap_connection *ldap;
56 struct ldb_module *module;
60 struct ildb_private *ildb;
61 struct ldb_handle *handle;
62 struct ldap_request *req;
64 int (*callback)(struct ldb_context *, void *, struct ldb_reply *);
68 convert a ldb_message structure to a list of ldap_mod structures
69 ready for ildap_add() or ildap_modify()
71 static struct ldap_mod **ildb_msg_to_mods(void *mem_ctx, int *num_mods,
72 const struct ldb_message *msg,
75 struct ldap_mod **mods;
79 /* allocate maximum number of elements needed */
80 mods = talloc_array(mem_ctx, struct ldap_mod *, msg->num_elements+1);
87 for (i = 0; i < msg->num_elements; i++) {
88 const struct ldb_message_element *el = &msg->elements[i];
90 mods[n] = talloc(mods, struct ldap_mod);
96 mods[n]->attrib = *el;
98 switch (el->flags & LDB_FLAG_MOD_MASK) {
99 case LDB_FLAG_MOD_ADD:
100 mods[n]->type = LDAP_MODIFY_ADD;
102 case LDB_FLAG_MOD_DELETE:
103 mods[n]->type = LDAP_MODIFY_DELETE;
105 case LDB_FLAG_MOD_REPLACE:
106 mods[n]->type = LDAP_MODIFY_REPLACE;
123 map an ildap NTSTATUS to a ldb error code
125 static int ildb_map_error(struct ildb_private *ildb, NTSTATUS status)
127 TALLOC_CTX *mem_ctx = talloc_new(ildb);
128 if (NT_STATUS_IS_OK(status)) {
132 ldb_oom(ildb->module->ldb);
133 return LDB_ERR_OPERATIONS_ERROR;
135 ldb_set_errstring(ildb->module->ldb,
136 ldap_errstr(ildb->ldap, mem_ctx, status));
137 talloc_free(mem_ctx);
138 if (NT_STATUS_IS_LDAP(status)) {
139 return NT_STATUS_LDAP_CODE(status);
141 return LDB_ERR_OPERATIONS_ERROR;
144 static void ildb_request_timeout(struct event_context *ev,
145 struct timed_event *te,
146 struct timeval t, void *private_data)
148 struct ildb_context *ac;
149 struct ldb_handle *handle = ac->handle;
151 ac = talloc_get_type(private_data, struct ildb_context);
153 if (ac->req->state == LDAP_REQUEST_PENDING) {
154 DLIST_REMOVE(ac->req->conn->pending, ac->req);
157 handle->status = LDB_ERR_TIME_LIMIT_EXCEEDED;
162 static void ildb_callback(struct ldap_request *req)
164 struct ildb_context *ac;
165 struct ldb_handle *handle = ac->handle;
166 struct ildb_private *ildb = ac->ildb;
170 ac =talloc_get_type(req->async.private_data, struct ildb_context);
171 handle->status = LDB_SUCCESS;
173 if (!NT_STATUS_IS_OK(req->status)) {
174 handle->status = ildb_map_error(ildb, req->status);
178 if (req->num_replies < 1) {
179 handle->status = LDB_ERR_OPERATIONS_ERROR;
185 case LDAP_TAG_ModifyRequest:
186 if (req->replies[0]->type != LDAP_TAG_ModifyResponse) {
187 handle->status = LDB_ERR_PROTOCOL_ERROR;
190 status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
191 handle->status = ildb_map_error(ildb, status);
192 if (ac->callback && handle->status == LDB_SUCCESS) {
193 /* FIXME: build a corresponding ares to pass on */
194 handle->status = ac->callback(ac->ildb->module->ldb, ac->context, NULL);
196 handle->state = LDB_ASYNC_DONE;
199 case LDAP_TAG_AddRequest:
200 if (req->replies[0]->type != LDAP_TAG_AddResponse) {
201 handle->status = LDB_ERR_PROTOCOL_ERROR;
204 status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
205 handle->status = ildb_map_error(ildb, status);
206 if (ac->callback && handle->status == LDB_SUCCESS) {
207 /* FIXME: build a corresponding ares to pass on */
208 handle->status = ac->callback(ac->ildb->module->ldb, ac->context, NULL);
210 handle->state = LDB_ASYNC_DONE;
213 case LDAP_TAG_DelRequest:
214 if (req->replies[0]->type != LDAP_TAG_DelResponse) {
215 handle->status = LDB_ERR_PROTOCOL_ERROR;
218 status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
219 handle->status = ildb_map_error(ildb, status);
220 if (ac->callback && handle->status == LDB_SUCCESS) {
221 /* FIXME: build a corresponding ares to pass on */
222 handle->status = ac->callback(ac->ildb->module->ldb, ac->context, NULL);
224 handle->state = LDB_ASYNC_DONE;
227 case LDAP_TAG_ModifyDNRequest:
228 if (req->replies[0]->type != LDAP_TAG_ModifyDNResponse) {
229 handle->status = LDB_ERR_PROTOCOL_ERROR;
232 status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
233 handle->status = ildb_map_error(ildb, status);
234 if (ac->callback && handle->status == LDB_SUCCESS) {
235 /* FIXME: build a corresponding ares to pass on */
236 handle->status = ac->callback(ac->ildb->module->ldb, ac->context, NULL);
238 handle->state = LDB_ASYNC_DONE;
241 case LDAP_TAG_SearchRequest:
242 /* loop over all messages */
243 for (i = 0; i < req->num_replies; i++) {
244 struct ldap_SearchResEntry *search;
245 struct ldb_reply *ares = NULL;
246 struct ldap_message *msg;
249 ares = talloc_zero(ac, struct ldb_reply);
251 handle->status = LDB_ERR_OPERATIONS_ERROR;
255 msg = req->replies[i];
258 case LDAP_TAG_SearchResultDone:
260 status = ldap_check_response(req->conn, &msg->r.GeneralResult);
261 if (!NT_STATUS_IS_OK(status)) {
262 handle->status = ildb_map_error(ildb, status);
266 ares->controls = talloc_move(ares, &msg->controls);
267 if (msg->r.SearchResultDone.resultcode) {
268 if (msg->r.SearchResultDone.errormessage) {
269 ldb_set_errstring(ac->ildb->module->ldb, msg->r.SearchResultDone.errormessage);
273 handle->status = msg->r.SearchResultDone.resultcode;
274 handle->state = LDB_ASYNC_DONE;
275 ares->type = LDB_REPLY_DONE;
278 case LDAP_TAG_SearchResultEntry:
281 ares->message = ldb_msg_new(ares);
282 if (!ares->message) {
283 handle->status = LDB_ERR_OPERATIONS_ERROR;
287 search = &(msg->r.SearchResultEntry);
289 ares->message->dn = ldb_dn_new(ares->message, ac->ildb->module->ldb, search->dn);
290 if ( ! ldb_dn_validate(ares->message->dn)) {
291 handle->status = LDB_ERR_OPERATIONS_ERROR;
294 ares->message->num_elements = search->num_attributes;
295 ares->message->elements = talloc_move(ares->message,
296 &search->attributes);
298 handle->status = LDB_SUCCESS;
299 handle->state = LDB_ASYNC_PENDING;
300 ares->type = LDB_REPLY_ENTRY;
303 case LDAP_TAG_SearchResultReference:
305 ares->referral = talloc_strdup(ares, msg->r.SearchResultReference.referral);
307 handle->status = LDB_SUCCESS;
308 handle->state = LDB_ASYNC_PENDING;
309 ares->type = LDB_REPLY_REFERRAL;
313 /* TAG not handled, fail ! */
314 handle->status = LDB_ERR_PROTOCOL_ERROR;
318 ret = ac->callback(ac->ildb->module->ldb, ac->context, ares);
320 handle->status = ret;
324 talloc_free(req->replies);
326 req->num_replies = 0;
331 handle->status = LDB_ERR_PROTOCOL_ERROR;
336 static struct ildb_context *init_ildb_handle(struct ildb_private *ildb,
337 struct ldb_request *req)
339 struct ildb_context *ildb_ac;
340 struct ldb_handle *h;
342 h = talloc_zero(req, struct ldb_handle);
344 ldb_set_errstring(ildb->module->ldb, "Out of Memory");
348 h->module = ildb->module;
350 ildb_ac = talloc(h, struct ildb_context);
351 if (ildb_ac == NULL) {
352 ldb_set_errstring(ildb->module->ldb, "Out of Memory");
357 h->private_data = ildb_ac;
359 h->state = LDB_ASYNC_INIT;
360 h->status = LDB_SUCCESS;
362 ildb_ac->ildb = ildb;
364 ildb_ac->context = req->context;
365 ildb_ac->callback = req->callback;
371 static int ildb_request_send(struct ildb_private *ildb, struct ldap_message *msg, struct ldb_request *r)
373 struct ildb_context *ildb_ac = init_ildb_handle(ildb, r);
374 struct ldap_request *req;
377 return LDB_ERR_OPERATIONS_ERROR;
380 req = ldap_request_send(ildb->ldap, msg);
382 ldb_set_errstring(ildb->module->ldb, "async send request failed");
383 return LDB_ERR_OPERATIONS_ERROR;
385 ildb_ac->req = talloc_steal(ildb_ac, req);
388 ldb_set_errstring(ildb->module->ldb, "connection to remote LDAP server dropped?");
389 return LDB_ERR_OPERATIONS_ERROR;
392 talloc_free(req->time_event);
393 req->time_event = NULL;
395 req->time_event = event_add_timed(req->conn->event.event_ctx, ildb_ac,
396 timeval_current_ofs(r->timeout, 0),
397 ildb_request_timeout, ildb_ac);
400 req->async.fn = ildb_callback;
401 req->async.private_data = ildb_ac;
406 static int ildb_request_noop(struct ildb_private *ildb, struct ldb_request *req)
408 struct ildb_context *ildb_ac = init_ildb_handle(ildb, req);
409 int ret = LDB_SUCCESS;
412 return LDB_ERR_OPERATIONS_ERROR;
415 if (ildb_ac->callback) {
416 ret = ildb_ac->callback(ildb->module->ldb, ildb_ac->context, NULL);
418 ildb_ac->handle->state = LDB_ASYNC_DONE;
423 search for matching records using an asynchronous function
425 static int ildb_search(struct ldb_module *module, struct ldb_request *req)
427 struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
428 struct ldap_message *msg;
433 if (!req->callback || !req->context) {
434 ldb_set_errstring(module->ldb, "Async interface called with NULL callback function or NULL context");
435 return LDB_ERR_OPERATIONS_ERROR;
438 if (req->op.search.tree == NULL) {
439 ldb_set_errstring(module->ldb, "Invalid expression parse tree");
440 return LDB_ERR_OPERATIONS_ERROR;
443 msg = new_ldap_message(req);
445 ldb_set_errstring(module->ldb, "Out of Memory");
446 return LDB_ERR_OPERATIONS_ERROR;
449 msg->type = LDAP_TAG_SearchRequest;
451 if (req->op.search.base == NULL) {
452 msg->r.SearchRequest.basedn = talloc_strdup(msg, "");
454 msg->r.SearchRequest.basedn = ldb_dn_alloc_linearized(msg, req->op.search.base);
456 if (msg->r.SearchRequest.basedn == NULL) {
457 ldb_set_errstring(module->ldb, "Unable to determine baseDN");
459 return LDB_ERR_OPERATIONS_ERROR;
462 if (req->op.search.scope == LDB_SCOPE_DEFAULT) {
463 msg->r.SearchRequest.scope = LDB_SCOPE_SUBTREE;
465 msg->r.SearchRequest.scope = req->op.search.scope;
468 msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
469 msg->r.SearchRequest.timelimit = 0;
470 msg->r.SearchRequest.sizelimit = 0;
471 msg->r.SearchRequest.attributesonly = 0;
472 msg->r.SearchRequest.tree = discard_const(req->op.search.tree);
474 for (n = 0; req->op.search.attrs && req->op.search.attrs[n]; n++) /* noop */ ;
475 msg->r.SearchRequest.num_attributes = n;
476 msg->r.SearchRequest.attributes = discard_const(req->op.search.attrs);
477 msg->controls = req->controls;
479 return ildb_request_send(ildb, msg, req);
485 static int ildb_add(struct ldb_module *module, struct ldb_request *req)
487 struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
488 struct ldap_message *msg;
489 struct ldap_mod **mods;
494 /* ignore ltdb specials */
495 if (ldb_dn_is_special(req->op.add.message->dn)) {
496 return ildb_request_noop(ildb, req);
499 msg = new_ldap_message(req);
501 return LDB_ERR_OPERATIONS_ERROR;
504 msg->type = LDAP_TAG_AddRequest;
506 msg->r.AddRequest.dn = ldb_dn_alloc_linearized(msg, req->op.add.message->dn);
507 if (msg->r.AddRequest.dn == NULL) {
509 return LDB_ERR_INVALID_DN_SYNTAX;
512 mods = ildb_msg_to_mods(msg, &n, req->op.add.message, 0);
515 return LDB_ERR_OPERATIONS_ERROR;
518 msg->r.AddRequest.num_attributes = n;
519 msg->r.AddRequest.attributes = talloc_array(msg, struct ldb_message_element, n);
520 if (msg->r.AddRequest.attributes == NULL) {
522 return LDB_ERR_OPERATIONS_ERROR;
525 for (i = 0; i < n; i++) {
526 msg->r.AddRequest.attributes[i] = mods[i]->attrib;
529 return ildb_request_send(ildb, msg, req);
535 static int ildb_modify(struct ldb_module *module, struct ldb_request *req)
537 struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
538 struct ldap_message *msg;
539 struct ldap_mod **mods;
544 /* ignore ltdb specials */
545 if (ldb_dn_is_special(req->op.mod.message->dn)) {
546 return ildb_request_noop(ildb, req);
549 msg = new_ldap_message(req);
551 return LDB_ERR_OPERATIONS_ERROR;
554 msg->type = LDAP_TAG_ModifyRequest;
556 msg->r.ModifyRequest.dn = ldb_dn_alloc_linearized(msg, req->op.mod.message->dn);
557 if (msg->r.ModifyRequest.dn == NULL) {
559 return LDB_ERR_INVALID_DN_SYNTAX;
562 mods = ildb_msg_to_mods(msg, &n, req->op.mod.message, 1);
565 return LDB_ERR_OPERATIONS_ERROR;
568 msg->r.ModifyRequest.num_mods = n;
569 msg->r.ModifyRequest.mods = talloc_array(msg, struct ldap_mod, n);
570 if (msg->r.ModifyRequest.mods == NULL) {
572 return LDB_ERR_OPERATIONS_ERROR;
575 for (i = 0; i < n; i++) {
576 msg->r.ModifyRequest.mods[i] = *mods[i];
579 return ildb_request_send(ildb, msg, req);
585 static int ildb_delete(struct ldb_module *module, struct ldb_request *req)
587 struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
588 struct ldap_message *msg;
592 /* ignore ltdb specials */
593 if (ldb_dn_is_special(req->op.del.dn)) {
594 return ildb_request_noop(ildb, req);
597 msg = new_ldap_message(req);
599 return LDB_ERR_OPERATIONS_ERROR;
602 msg->type = LDAP_TAG_DelRequest;
604 msg->r.DelRequest.dn = ldb_dn_alloc_linearized(msg, req->op.del.dn);
605 if (msg->r.DelRequest.dn == NULL) {
607 return LDB_ERR_INVALID_DN_SYNTAX;
610 return ildb_request_send(ildb, msg, req);
616 static int ildb_rename(struct ldb_module *module, struct ldb_request *req)
618 struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
619 struct ldap_message *msg;
623 /* ignore ltdb specials */
624 if (ldb_dn_is_special(req->op.rename.olddn) || ldb_dn_is_special(req->op.rename.newdn)) {
625 return ildb_request_noop(ildb, req);
628 msg = new_ldap_message(req);
630 return LDB_ERR_OPERATIONS_ERROR;
633 msg->type = LDAP_TAG_ModifyDNRequest;
634 msg->r.ModifyDNRequest.dn = ldb_dn_alloc_linearized(msg, req->op.rename.olddn);
635 if (msg->r.ModifyDNRequest.dn == NULL) {
637 return LDB_ERR_INVALID_DN_SYNTAX;
640 msg->r.ModifyDNRequest.newrdn =
641 talloc_asprintf(msg, "%s=%s",
642 ldb_dn_get_rdn_name(req->op.rename.newdn),
643 ldb_dn_escape_value(msg, *ldb_dn_get_rdn_val(req->op.rename.newdn)));
644 if (msg->r.ModifyDNRequest.newrdn == NULL) {
646 return LDB_ERR_OPERATIONS_ERROR;
649 msg->r.ModifyDNRequest.newsuperior =
650 ldb_dn_alloc_linearized(msg, ldb_dn_get_parent(msg, req->op.rename.newdn));
651 if (msg->r.ModifyDNRequest.newsuperior == NULL) {
653 return LDB_ERR_INVALID_DN_SYNTAX;
656 msg->r.ModifyDNRequest.deleteolddn = true;
658 return ildb_request_send(ildb, msg, req);
661 static int ildb_start_trans(struct ldb_module *module)
663 /* TODO implement a local locking mechanism here */
668 static int ildb_end_trans(struct ldb_module *module)
670 /* TODO implement a local transaction mechanism here */
675 static int ildb_del_trans(struct ldb_module *module)
677 /* TODO implement a local locking mechanism here */
682 static int ildb_request(struct ldb_module *module, struct ldb_request *req)
684 return LDB_ERR_OPERATIONS_ERROR;
687 static int ildb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
689 struct ildb_context *ac = talloc_get_type(handle->private_data, struct ildb_context);
691 if (handle->state == LDB_ASYNC_DONE) {
692 return handle->status;
696 return LDB_ERR_OPERATIONS_ERROR;
699 handle->state = LDB_ASYNC_INIT;
703 if (event_loop_once(ac->req->conn->event.event_ctx) != 0) {
704 return LDB_ERR_OTHER;
708 while (handle->status == LDB_SUCCESS && handle->state != LDB_ASYNC_DONE) {
709 if (event_loop_once(ac->req->conn->event.event_ctx) != 0) {
710 return LDB_ERR_OTHER;
715 return LDB_ERR_OPERATIONS_ERROR;
718 return handle->status;
721 static const struct ldb_module_ops ildb_ops = {
723 .search = ildb_search,
725 .modify = ildb_modify,
727 .rename = ildb_rename,
728 .request = ildb_request,
729 .start_transaction = ildb_start_trans,
730 .end_transaction = ildb_end_trans,
731 .del_transaction = ildb_del_trans,
736 connect to the database
738 static int ildb_connect(struct ldb_context *ldb, const char *url,
739 unsigned int flags, const char *options[],
740 struct ldb_module **_module)
742 struct ldb_module *module;
743 struct ildb_private *ildb;
745 struct cli_credentials *creds;
746 struct event_context *event_ctx;
748 module = talloc(ldb, struct ldb_module);
753 talloc_set_name_const(module, "ldb_ildap backend");
755 module->prev = module->next = NULL;
756 module->private_data = NULL;
757 module->ops = &ildb_ops;
759 ildb = talloc(module, struct ildb_private);
764 module->private_data = ildb;
765 ildb->module = module;
767 event_ctx = ldb_get_event_context(ldb);
769 ildb->ldap = ldap4_new_connection(ildb, ldb_get_opaque(ldb, "loadparm"),
776 if (flags & LDB_FLG_RECONNECT) {
777 ldap_set_reconn_params(ildb->ldap, 10);
780 status = ldap_connect(ildb->ldap, url);
781 if (!NT_STATUS_IS_OK(status)) {
782 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to ldap URL '%s' - %s\n",
783 url, ldap_errstr(ildb->ldap, module, status));
787 /* caller can optionally setup credentials using the opaque token 'credentials' */
788 creds = talloc_get_type(ldb_get_opaque(ldb, "credentials"), struct cli_credentials);
790 struct auth_session_info *session_info = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
792 creds = session_info->credentials;
796 if (creds != NULL && cli_credentials_authentication_requested(creds)) {
797 const char *bind_dn = cli_credentials_get_bind_dn(creds);
799 const char *password = cli_credentials_get_password(creds);
800 status = ldap_bind_simple(ildb->ldap, bind_dn, password);
801 if (!NT_STATUS_IS_OK(status)) {
802 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s\n",
803 ldap_errstr(ildb->ldap, module, status));
807 status = ldap_bind_sasl(ildb->ldap, creds, ldb_get_opaque(ldb, "loadparm"));
808 if (!NT_STATUS_IS_OK(status)) {
809 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s\n",
810 ldap_errstr(ildb->ldap, module, status));
824 _PUBLIC_ const struct ldb_backend_ops ldb_ldap_backend_ops = {
826 .connect_fn = ildb_connect
829 _PUBLIC_ const struct ldb_backend_ops ldb_ldapi_backend_ops = {
831 .connect_fn = ildb_connect
834 _PUBLIC_ const struct ldb_backend_ops ldb_ldaps_backend_ops = {
836 .connect_fn = ildb_connect