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