samba-tool: add `samba-tool domain kds root_key list`
[samba.git] / lib / ldb-samba / ldb_ildap.c
blob37ef185fbbfd1dd82f39070b831c21ce1d39d23e
1 /*
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
9 ** under the LGPL
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/>.
26 * Name: ldb_ildap
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
36 * Modifications:
38 * - description: make the module use asynchronous calls
39 * date: Feb 2006
40 * author: Simo Sorce
43 #include "includes.h"
44 #include "ldb_module.h"
45 #include "util/dlinklist.h"
47 #include "libcli/ldap/libcli_ldap.h"
48 #include "libcli/ldap/ldap_client.h"
49 #include "auth/auth.h"
50 #include "auth/credentials/credentials.h"
51 #include "dsdb/common/util.h"
53 struct ildb_private {
54 struct ldap_connection *ldap;
55 struct tevent_context *event_ctx;
58 struct ildb_context {
59 struct ldb_module *module;
60 struct ldb_request *req;
62 struct ildb_private *ildb;
63 struct ldap_request *ireq;
65 /* indicate we are already processing
66 * the ldap_request in ildb_callback() */
67 bool in_ildb_callback;
69 bool done;
71 struct ildb_destructor_ctx *dc;
74 static void ildb_request_done(struct ildb_context *ctx,
75 struct ldb_control **ctrls, int error)
77 struct ldb_context *ldb;
78 struct ldb_reply *ares;
80 ldb = ldb_module_get_ctx(ctx->module);
82 ctx->done = true;
84 if (ctx->req == NULL) {
85 /* if the req has been freed already just return */
86 return;
89 ares = talloc_zero(ctx->req, struct ldb_reply);
90 if (!ares) {
91 ldb_oom(ldb);
92 ctx->req->callback(ctx->req, NULL);
93 return;
95 ares->type = LDB_REPLY_DONE;
96 ares->controls = talloc_steal(ares, ctrls);
97 ares->error = error;
99 ctx->req->callback(ctx->req, ares);
102 static void ildb_auto_done_callback(struct tevent_context *ev,
103 struct tevent_timer *te,
104 struct timeval t,
105 void *private_data)
107 struct ildb_context *ac;
109 ac = talloc_get_type(private_data, struct ildb_context);
110 ildb_request_done(ac, NULL, LDB_SUCCESS);
114 convert a ldb_message structure to a list of ldap_mod structures
115 ready for ildap_add() or ildap_modify()
117 static struct ldap_mod **ildb_msg_to_mods(void *mem_ctx, unsigned int *num_mods,
118 const struct ldb_message *msg,
119 int use_flags)
121 struct ldap_mod **mods;
122 unsigned int i;
123 unsigned int n = 0;
125 /* allocate maximum number of elements needed */
126 mods = talloc_array(mem_ctx, struct ldap_mod *, msg->num_elements+1);
127 if (!mods) {
128 errno = ENOMEM;
129 return NULL;
131 mods[0] = NULL;
133 for (i = 0; i < msg->num_elements; i++) {
134 const struct ldb_message_element *el = &msg->elements[i];
136 mods[n] = talloc(mods, struct ldap_mod);
137 if (!mods[n]) {
138 goto failed;
140 mods[n + 1] = NULL;
141 mods[n]->type = 0;
142 mods[n]->attrib = *el;
143 if (use_flags) {
144 switch (el->flags & LDB_FLAG_MOD_MASK) {
145 case LDB_FLAG_MOD_ADD:
146 mods[n]->type = LDAP_MODIFY_ADD;
147 break;
148 case LDB_FLAG_MOD_DELETE:
149 mods[n]->type = LDAP_MODIFY_DELETE;
150 break;
151 case LDB_FLAG_MOD_REPLACE:
152 mods[n]->type = LDAP_MODIFY_REPLACE;
153 break;
156 n++;
159 *num_mods = n;
160 return mods;
162 failed:
163 talloc_free(mods);
164 return NULL;
169 map an ildap NTSTATUS to a ldb error code
171 static int ildb_map_error(struct ldb_module *module, NTSTATUS status)
173 struct ildb_private *ildb;
174 struct ldb_context *ldb;
175 TALLOC_CTX *mem_ctx;
177 ildb = talloc_get_type(ldb_module_get_private(module), struct ildb_private);
178 ldb = ldb_module_get_ctx(module);
180 if (NT_STATUS_IS_OK(status)) {
181 return LDB_SUCCESS;
184 mem_ctx = talloc_new(ildb);
185 if (!mem_ctx) {
186 ldb_oom(ldb);
187 return LDB_ERR_OPERATIONS_ERROR;
189 ldb_set_errstring(ldb,
190 ldap_errstr(ildb->ldap, mem_ctx, status));
191 talloc_free(mem_ctx);
192 if (NT_STATUS_IS_LDAP(status)) {
193 return NT_STATUS_LDAP_CODE(status);
195 return LDB_ERR_OPERATIONS_ERROR;
198 static void ildb_request_timeout(struct tevent_context *ev, struct tevent_timer *te,
199 struct timeval t, void *private_data)
201 struct ildb_context *ac = talloc_get_type(private_data, struct ildb_context);
203 if (ac->ireq->state == LDAP_REQUEST_PENDING) {
204 DLIST_REMOVE(ac->ireq->conn->pending, ac->ireq);
207 ildb_request_done(ac, NULL, LDB_ERR_TIME_LIMIT_EXCEEDED);
210 static void ildb_callback(struct ldap_request *req)
212 struct ldb_context *ldb;
213 struct ildb_context *ac;
214 NTSTATUS status;
215 struct ldap_SearchResEntry *search;
216 struct ldap_message *msg;
217 struct ldb_control **controls;
218 struct ldb_message *ldbmsg;
219 char *referral;
220 bool callback_failed;
221 bool request_done;
222 int ret;
223 int i;
225 ac = talloc_get_type(req->async.private_data, struct ildb_context);
226 ldb = ldb_module_get_ctx(ac->module);
227 callback_failed = false;
228 request_done = false;
229 controls = NULL;
231 /* check if we are already processing this request */
232 if (ac->in_ildb_callback) {
233 return;
235 /* mark the request as being in process */
236 ac->in_ildb_callback = true;
238 if (!NT_STATUS_IS_OK(req->status)) {
239 ret = ildb_map_error(ac->module, req->status);
240 ildb_request_done(ac, NULL, ret);
241 return;
244 if (req->num_replies < 1) {
245 ret = LDB_ERR_OPERATIONS_ERROR;
246 ildb_request_done(ac, NULL, ret);
247 return;
250 switch (req->type) {
252 case LDAP_TAG_ModifyRequest:
253 if (req->replies[0]->type != LDAP_TAG_ModifyResponse) {
254 ret = LDB_ERR_PROTOCOL_ERROR;
255 break;
257 status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult);
258 ret = ildb_map_error(ac->module, status);
259 request_done = true;
260 break;
262 case LDAP_TAG_AddRequest:
263 if (req->replies[0]->type != LDAP_TAG_AddResponse) {
264 ret = LDB_ERR_PROTOCOL_ERROR;
265 return;
267 status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult);
268 ret = ildb_map_error(ac->module, status);
269 request_done = true;
270 break;
272 case LDAP_TAG_DelRequest:
273 if (req->replies[0]->type != LDAP_TAG_DelResponse) {
274 ret = LDB_ERR_PROTOCOL_ERROR;
275 return;
277 status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult);
278 ret = ildb_map_error(ac->module, status);
279 request_done = true;
280 break;
282 case LDAP_TAG_ModifyDNRequest:
283 if (req->replies[0]->type != LDAP_TAG_ModifyDNResponse) {
284 ret = LDB_ERR_PROTOCOL_ERROR;
285 return;
287 status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult);
288 ret = ildb_map_error(ac->module, status);
289 request_done = true;
290 break;
292 case LDAP_TAG_SearchRequest:
293 /* loop over all messages */
294 ret = LDB_SUCCESS;
295 for (i = 0; i < req->num_replies; i++) {
297 msg = req->replies[i];
298 switch (msg->type) {
300 case LDAP_TAG_SearchResultDone:
302 status = ldap_check_response(ac->ireq->conn, &msg->r.GeneralResult);
303 if (!NT_STATUS_IS_OK(status)) {
304 ret = ildb_map_error(ac->module, status);
305 break;
308 controls = talloc_steal(ac, msg->controls);
309 if (msg->r.SearchResultDone.resultcode) {
310 if (msg->r.SearchResultDone.errormessage) {
311 ldb_set_errstring(ldb, msg->r.SearchResultDone.errormessage);
315 ret = msg->r.SearchResultDone.resultcode;
316 request_done = true;
317 break;
319 case LDAP_TAG_SearchResultEntry:
321 ldbmsg = ldb_msg_new(ac);
322 if (!ldbmsg) {
323 ret = LDB_ERR_OPERATIONS_ERROR;
324 break;
327 search = &(msg->r.SearchResultEntry);
329 ldbmsg->dn = ldb_dn_new(ldbmsg, ldb, search->dn);
330 if ( ! ldb_dn_validate(ldbmsg->dn)) {
331 ret = LDB_ERR_OPERATIONS_ERROR;
332 break;
334 ldbmsg->num_elements = search->num_attributes;
335 ldbmsg->elements = talloc_move(ldbmsg, &search->attributes);
337 controls = talloc_steal(ac, msg->controls);
339 ret = ldb_module_send_entry(ac->req, ldbmsg, controls);
340 if (ret != LDB_SUCCESS) {
341 callback_failed = true;
344 break;
346 case LDAP_TAG_SearchResultReference:
348 referral = talloc_strdup(ac, msg->r.SearchResultReference.referral);
350 ret = ldb_module_send_referral(ac->req, referral);
351 if (ret != LDB_SUCCESS) {
352 callback_failed = true;
355 break;
357 default:
358 /* TAG not handled, fail ! */
359 ret = LDB_ERR_PROTOCOL_ERROR;
360 break;
363 if (ret != LDB_SUCCESS) {
364 break;
368 talloc_free(req->replies);
369 req->replies = NULL;
370 req->num_replies = 0;
372 break;
374 case LDAP_TAG_ExtendedRequest: {
376 struct ldap_ExtendedResponse *ext_response = NULL;
377 struct ldb_reply *ares = NULL;
379 if (req->replies[0]->type != LDAP_TAG_ExtendedResponse) {
380 ret = LDB_ERR_PROTOCOL_ERROR;
381 return;
383 ext_response = &req->replies[0]->r.ExtendedResponse;
385 status = ldap_check_response(ac->ireq->conn,
386 &req->replies[0]->r.GeneralResult);
387 if (!NT_STATUS_IS_OK(status)) {
388 ret = ildb_map_error(ac->module, status);
389 request_done = true;
390 break;
393 ares = talloc_zero(req, struct ldb_reply);
394 if (ares == NULL) {
395 ret = LDB_ERR_OPERATIONS_ERROR;
396 request_done = true;
397 break;
400 ares->type = LDB_REPLY_DONE;
402 ares->response = talloc_zero(ares, struct ldb_extended);
403 if (ares->response == NULL) {
404 ret = LDB_ERR_OPERATIONS_ERROR;
405 request_done = true;
406 break;
409 ares->response->oid =
410 talloc_strdup(ares->response, ext_response->oid);
411 if (ares->response->oid == NULL) {
412 ret = LDB_ERR_OPERATIONS_ERROR;
413 request_done = true;
414 break;
417 if (ext_response->value != NULL) {
418 ares->response->data =
419 talloc_memdup(ares->response,
420 ext_response->value->data,
421 ext_response->value->length);
422 if (ares->response->data == NULL) {
423 ret = LDB_ERR_OPERATIONS_ERROR;
424 request_done = true;
425 break;
429 ares->controls = talloc_move(ares, &req->replies[0]->controls);
431 ac->req->callback(ac->req, ares);
432 return;
435 default:
436 ret = LDB_ERR_PROTOCOL_ERROR;
437 break;
440 if (ret != LDB_SUCCESS) {
442 /* if the callback failed the caller will have freed the
443 * request. Just return and don't try to use it */
444 if ( ! callback_failed) {
445 request_done = true;
449 /* mark the request as not being in progress */
450 ac->in_ildb_callback = false;
452 if (request_done) {
453 ildb_request_done(ac, controls, ret);
456 return;
459 static int ildb_request_send(struct ildb_context *ac, struct ldap_message *msg)
461 struct ldb_context *ldb;
462 struct ldap_request *req;
464 if (!ac) {
465 return LDB_ERR_OPERATIONS_ERROR;
468 ldb = ldb_module_get_ctx(ac->module);
470 ldb_request_set_state(ac->req, LDB_ASYNC_PENDING);
472 req = ldap_request_send(ac->ildb->ldap, msg);
473 if (req == NULL) {
474 ldb_set_errstring(ldb, "async send request failed");
475 return LDB_ERR_OPERATIONS_ERROR;
477 ac->ireq = talloc_reparent(ac->ildb->ldap, ac, req);
479 if (!ac->ireq->conn) {
480 ldb_set_errstring(ldb, "connection to remote LDAP server dropped?");
481 return LDB_ERR_OPERATIONS_ERROR;
484 TALLOC_FREE(req->time_event);
485 if (ac->req->timeout > 0) {
486 struct timeval tv = {
487 .tv_sec = ac->req->starttime + ac->req->timeout,
490 req->time_event = tevent_add_timer(ac->ildb->event_ctx, ac, tv,
491 ildb_request_timeout, ac);
494 req->async.fn = ildb_callback;
495 req->async.private_data = ac;
497 return LDB_SUCCESS;
501 search for matching records using an asynchronous function
503 static int ildb_search(struct ildb_context *ac)
505 struct ldb_context *ldb;
506 struct ldb_request *req = ac->req;
507 struct ldap_message *msg;
508 int n;
510 ldb = ldb_module_get_ctx(ac->module);
512 if (!req->callback || !req->context) {
513 ldb_set_errstring(ldb, "Async interface called with NULL callback function or NULL context");
514 return LDB_ERR_OPERATIONS_ERROR;
517 if (req->op.search.tree == NULL) {
518 ldb_set_errstring(ldb, "Invalid expression parse tree");
519 return LDB_ERR_OPERATIONS_ERROR;
522 msg = new_ldap_message(req);
523 if (msg == NULL) {
524 ldb_set_errstring(ldb, "Out of Memory");
525 return LDB_ERR_OPERATIONS_ERROR;
528 msg->type = LDAP_TAG_SearchRequest;
530 if (req->op.search.base == NULL) {
531 msg->r.SearchRequest.basedn = talloc_strdup(msg, "");
532 } else {
533 msg->r.SearchRequest.basedn = ldb_dn_get_extended_linearized(msg, req->op.search.base, 0);
535 if (msg->r.SearchRequest.basedn == NULL) {
536 ldb_set_errstring(ldb, "Unable to determine baseDN");
537 talloc_free(msg);
538 return LDB_ERR_OPERATIONS_ERROR;
541 switch (req->op.search.scope) {
542 case LDB_SCOPE_DEFAULT:
543 case LDB_SCOPE_SUBTREE:
544 msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_SUB;
545 break;
546 case LDB_SCOPE_BASE:
547 msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
548 break;
549 case LDB_SCOPE_ONELEVEL:
550 msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_SINGLE;
551 break;
554 msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
555 msg->r.SearchRequest.timelimit = 0;
556 msg->r.SearchRequest.sizelimit = 0;
557 msg->r.SearchRequest.attributesonly = 0;
558 msg->r.SearchRequest.tree = discard_const(req->op.search.tree);
560 for (n = 0; req->op.search.attrs && req->op.search.attrs[n]; n++) /* noop */ ;
561 msg->r.SearchRequest.num_attributes = n;
562 msg->r.SearchRequest.attributes = req->op.search.attrs;
563 msg->controls = req->controls;
565 return ildb_request_send(ac, msg);
569 add a record
571 static int ildb_add(struct ildb_context *ac)
573 struct ldb_request *req = ac->req;
574 struct ldap_message *msg;
575 struct ldap_mod **mods;
576 unsigned int i,n;
578 msg = new_ldap_message(req);
579 if (msg == NULL) {
580 return LDB_ERR_OPERATIONS_ERROR;
583 msg->type = LDAP_TAG_AddRequest;
585 msg->r.AddRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.add.message->dn, 0);
586 if (msg->r.AddRequest.dn == NULL) {
587 talloc_free(msg);
588 return LDB_ERR_INVALID_DN_SYNTAX;
591 mods = ildb_msg_to_mods(msg, &n, req->op.add.message, 0);
592 if (mods == NULL) {
593 talloc_free(msg);
594 return LDB_ERR_OPERATIONS_ERROR;
597 msg->r.AddRequest.num_attributes = n;
598 msg->r.AddRequest.attributes = talloc_array(msg, struct ldb_message_element, n);
599 if (msg->r.AddRequest.attributes == NULL) {
600 talloc_free(msg);
601 return LDB_ERR_OPERATIONS_ERROR;
604 for (i = 0; i < n; i++) {
605 msg->r.AddRequest.attributes[i] = mods[i]->attrib;
607 msg->controls = req->controls;
609 return ildb_request_send(ac, msg);
613 modify a record
615 static int ildb_modify(struct ildb_context *ac)
617 struct ldb_request *req = ac->req;
618 struct ldap_message *msg;
619 struct ldap_mod **mods;
620 unsigned int i,n;
622 msg = new_ldap_message(req);
623 if (msg == NULL) {
624 return LDB_ERR_OPERATIONS_ERROR;
627 msg->type = LDAP_TAG_ModifyRequest;
629 msg->r.ModifyRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.mod.message->dn, 0);
630 if (msg->r.ModifyRequest.dn == NULL) {
631 talloc_free(msg);
632 return LDB_ERR_INVALID_DN_SYNTAX;
635 mods = ildb_msg_to_mods(msg, &n, req->op.mod.message, 1);
636 if (mods == NULL) {
637 talloc_free(msg);
638 return LDB_ERR_OPERATIONS_ERROR;
641 msg->r.ModifyRequest.num_mods = n;
642 msg->r.ModifyRequest.mods = talloc_array(msg, struct ldap_mod, n);
643 if (msg->r.ModifyRequest.mods == NULL) {
644 talloc_free(msg);
645 return LDB_ERR_OPERATIONS_ERROR;
648 for (i = 0; i < n; i++) {
649 msg->r.ModifyRequest.mods[i] = *mods[i];
651 msg->controls = req->controls;
652 return ildb_request_send(ac, msg);
656 delete a record
658 static int ildb_delete(struct ildb_context *ac)
660 struct ldb_request *req = ac->req;
661 struct ldap_message *msg;
663 msg = new_ldap_message(req);
664 if (msg == NULL) {
665 return LDB_ERR_OPERATIONS_ERROR;
668 msg->type = LDAP_TAG_DelRequest;
670 msg->r.DelRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.del.dn, 0);
671 if (msg->r.DelRequest.dn == NULL) {
672 talloc_free(msg);
673 return LDB_ERR_INVALID_DN_SYNTAX;
675 msg->controls = req->controls;
677 return ildb_request_send(ac, msg);
681 rename a record
683 static int ildb_rename(struct ildb_context *ac)
685 struct ldb_request *req = ac->req;
686 struct ldap_message *msg;
687 const char *rdn_name;
688 const struct ldb_val *rdn_val;
690 msg = new_ldap_message(req);
691 if (msg == NULL) {
692 return LDB_ERR_OPERATIONS_ERROR;
695 msg->type = LDAP_TAG_ModifyDNRequest;
696 msg->r.ModifyDNRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.rename.olddn, 0);
697 if (msg->r.ModifyDNRequest.dn == NULL) {
698 talloc_free(msg);
699 return LDB_ERR_INVALID_DN_SYNTAX;
702 rdn_name = ldb_dn_get_rdn_name(req->op.rename.newdn);
703 rdn_val = ldb_dn_get_rdn_val(req->op.rename.newdn);
705 if ((rdn_name != NULL) && (rdn_val != NULL)) {
706 msg->r.ModifyDNRequest.newrdn =
707 talloc_asprintf(msg, "%s=%s", rdn_name,
708 rdn_val->length > 0 ? ldb_dn_escape_value(msg, *rdn_val) : "");
709 } else {
710 msg->r.ModifyDNRequest.newrdn = talloc_strdup(msg, "");
712 if (msg->r.ModifyDNRequest.newrdn == NULL) {
713 talloc_free(msg);
714 return LDB_ERR_OPERATIONS_ERROR;
717 msg->r.ModifyDNRequest.newsuperior =
718 ldb_dn_alloc_linearized(msg, ldb_dn_get_parent(msg, req->op.rename.newdn));
719 if (msg->r.ModifyDNRequest.newsuperior == NULL) {
720 talloc_free(msg);
721 return LDB_ERR_INVALID_DN_SYNTAX;
724 msg->r.ModifyDNRequest.deleteolddn = true;
725 msg->controls = req->controls;
727 return ildb_request_send(ac, msg);
731 * Issue an extended operation
733 static int ildb_extended(struct ildb_context *ac)
735 struct ldb_request *req = ac->req;
736 struct ldb_extended *extended_req = NULL;
737 struct ldap_message *msg = NULL;
738 DATA_BLOB *value = NULL;
740 if (req->operation != LDB_EXTENDED) {
741 return LDB_ERR_OPERATIONS_ERROR;
743 extended_req = &req->op.extended;
745 msg = new_ldap_message(req);
746 if (msg == NULL) {
747 goto nomem;
750 if (extended_req->data != NULL) {
751 value = talloc(req, DATA_BLOB);
752 if (value == NULL) {
753 goto nomem;
755 *value = data_blob_talloc(value,
756 extended_req->data,
757 talloc_get_size(extended_req->data));
758 if (value->data == NULL) {
759 goto nomem;
763 *msg = (struct ldap_message){
764 .type = LDAP_TAG_ExtendedRequest,
765 .r.ExtendedRequest.oid = extended_req->oid,
766 .r.ExtendedRequest.value = value,
767 .controls = req->controls,
770 return ildb_request_send(ac, msg);
771 nomem:
772 TALLOC_FREE(msg);
773 return LDB_ERR_OPERATIONS_ERROR;
776 static int ildb_start_trans(struct ldb_module *module)
778 /* TODO implement a local locking mechanism here */
780 return LDB_SUCCESS;
783 static int ildb_end_trans(struct ldb_module *module)
785 /* TODO implement a local transaction mechanism here */
787 return LDB_SUCCESS;
790 static int ildb_del_trans(struct ldb_module *module)
792 /* TODO implement a local locking mechanism here */
794 return LDB_SUCCESS;
797 static bool ildb_dn_is_special(struct ldb_request *req)
799 struct ldb_dn *dn = NULL;
801 switch (req->operation) {
802 case LDB_SEARCH:
803 dn = req->op.search.base;
804 break;
805 case LDB_ADD:
806 dn = req->op.add.message->dn;
807 break;
808 case LDB_MODIFY:
809 dn = req->op.mod.message->dn;
810 break;
811 case LDB_DELETE:
812 dn = req->op.del.dn;
813 break;
814 case LDB_RENAME:
815 dn = req->op.rename.olddn;
816 break;
817 default:
818 break;
821 if (dn && ldb_dn_is_special(dn)) {
822 return true;
824 return false;
827 static int ildb_handle_request(struct ldb_module *module, struct ldb_request *req)
829 struct ldb_context *ldb;
830 struct ildb_private *ildb;
831 struct ildb_context *ac;
832 struct tevent_timer *te;
833 int ret;
835 ildb = talloc_get_type(ldb_module_get_private(module), struct ildb_private);
836 ldb = ldb_module_get_ctx(module);
838 if (req->starttime == 0 || req->timeout == 0) {
839 ldb_set_errstring(ldb, "Invalid timeout settings");
840 return LDB_ERR_TIME_LIMIT_EXCEEDED;
843 ac = talloc_zero(req, struct ildb_context);
844 if (ac == NULL) {
845 ldb_set_errstring(ldb, "Out of Memory");
846 return LDB_ERR_OPERATIONS_ERROR;
849 ac->module = module;
850 ac->req = req;
851 ac->ildb = ildb;
853 if (ildb_dn_is_special(req)) {
855 te = tevent_add_timer(ac->ildb->event_ctx,
856 ac, timeval_zero(),
857 ildb_auto_done_callback, ac);
858 if (NULL == te) {
859 return LDB_ERR_OPERATIONS_ERROR;
862 return LDB_SUCCESS;
865 switch (ac->req->operation) {
866 case LDB_SEARCH:
867 ret = ildb_search(ac);
868 break;
869 case LDB_ADD:
870 ret = ildb_add(ac);
871 break;
872 case LDB_MODIFY:
873 ret = ildb_modify(ac);
874 break;
875 case LDB_DELETE:
876 ret = ildb_delete(ac);
877 break;
878 case LDB_RENAME:
879 ret = ildb_rename(ac);
880 break;
881 case LDB_EXTENDED:
882 ret = ildb_extended(ac);
883 break;
884 default:
885 /* no other op supported */
886 ret = LDB_ERR_PROTOCOL_ERROR;
887 break;
890 return ret;
893 static const struct ldb_module_ops ildb_ops = {
894 .name = "ldap",
895 .search = ildb_handle_request,
896 .add = ildb_handle_request,
897 .modify = ildb_handle_request,
898 .del = ildb_handle_request,
899 .rename = ildb_handle_request,
900 .extended = ildb_handle_request,
901 /* .request = ildb_handle_request, */
902 .start_transaction = ildb_start_trans,
903 .end_transaction = ildb_end_trans,
904 .del_transaction = ildb_del_trans,
908 connect to the database
910 static int ildb_connect(struct ldb_context *ldb, const char *url,
911 unsigned int flags, const char *options[],
912 struct ldb_module **_module)
914 struct ldb_module *module;
915 struct ildb_private *ildb;
916 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
917 struct cli_credentials *creds;
918 struct loadparm_context *lp_ctx;
920 module = ldb_module_new(ldb, ldb, "ldb_ildap backend", &ildb_ops);
921 if (!module) return LDB_ERR_OPERATIONS_ERROR;
923 ildb = talloc(module, struct ildb_private);
924 if (!ildb) {
925 ldb_oom(ldb);
926 goto failed;
928 ldb_module_set_private(module, ildb);
930 ildb->event_ctx = ldb_get_event_context(ldb);
932 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
933 struct loadparm_context);
935 ildb->ldap = ldap4_new_connection(ildb, lp_ctx,
936 ildb->event_ctx);
937 if (!ildb->ldap) {
938 ldb_oom(ldb);
939 goto failed;
942 if (flags & LDB_FLG_RECONNECT) {
943 ldap_set_reconn_params(ildb->ldap, 10);
946 status = ldap_connect(ildb->ldap, url);
947 if (!NT_STATUS_IS_OK(status)) {
948 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to ldap URL '%s' - %s",
949 url, ldap_errstr(ildb->ldap, module, status));
950 goto failed;
953 /* caller can optionally setup credentials using the opaque token 'credentials' */
954 creds = talloc_get_type(ldb_get_opaque(ldb, "credentials"), struct cli_credentials);
955 if (creds == NULL) {
956 struct auth_session_info *session_info = talloc_get_type(
957 ldb_get_opaque(ldb, DSDB_SESSION_INFO),
958 struct auth_session_info);
959 if (session_info) {
960 creds = session_info->credentials;
964 if (creds != NULL && cli_credentials_authentication_requested(creds)) {
965 const char *bind_dn = cli_credentials_get_bind_dn(creds);
966 if (bind_dn) {
967 const char *password = cli_credentials_get_password(creds);
968 status = ldap_bind_simple(ildb->ldap, bind_dn, password);
969 if (!NT_STATUS_IS_OK(status)) {
970 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s",
971 ldap_errstr(ildb->ldap, module, status));
972 goto failed;
974 } else {
975 status = ldap_bind_sasl(ildb->ldap, creds, lp_ctx);
976 if (!NT_STATUS_IS_OK(status)) {
977 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s",
978 ldap_errstr(ildb->ldap, module, status));
979 goto failed;
984 *_module = module;
985 return LDB_SUCCESS;
987 failed:
988 if (ildb != NULL && ildb->ldap != NULL) {
989 ldb_set_errstring(ldb, ldap_errstr(ildb->ldap, module, status));
991 talloc_free(module);
992 if (NT_STATUS_IS_LDAP(status)) {
993 return NT_STATUS_LDAP_CODE(status);
995 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)
996 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
997 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
998 || NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
999 return LDB_ERR_INVALID_CREDENTIALS;
1001 return LDB_ERR_OPERATIONS_ERROR;
1005 initialise the module
1007 _PUBLIC_ int ldb_ildap_init(const char *ldb_version)
1009 int ret, i;
1010 const char *names[] = { "ldap", "ldaps", "ldapi", NULL };
1011 for (i=0; names[i]; i++) {
1012 ret = ldb_register_backend(names[i], ildb_connect, true);
1013 if (ret != LDB_SUCCESS) {
1014 return ret;
1017 return LDB_SUCCESS;