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