791cc75dc1176cec82918093661c8711f823d170
[metze/samba/wip.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 "tevent.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 tevent_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 tevent_context *ev,
96                                     struct tevent_timer *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 tevent_context *ev, struct tevent_timer *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                                 controls = talloc_steal(ac, msg->controls);
315                                 
316                                 ret = ldb_module_send_entry(ac->req, ldbmsg, controls);
317                                 if (ret != LDB_SUCCESS) {
318                                         callback_failed = true;
319                                 }
320                                 break;
321
322                         case LDAP_TAG_SearchResultReference:
323
324                                 referral = talloc_strdup(ac, msg->r.SearchResultReference.referral);
325
326                                 ret = ldb_module_send_referral(ac->req, referral);
327                                 if (ret != LDB_SUCCESS) {
328                                         callback_failed = true;
329                                 }
330                                 break;
331
332                         default:
333                                 /* TAG not handled, fail ! */
334                                 ret = LDB_ERR_PROTOCOL_ERROR;
335                                 break;
336                         }
337
338                         if (ret != LDB_SUCCESS) {
339                                 break;
340                         }
341                 }
342
343                 talloc_free(req->replies);
344                 req->replies = NULL;
345                 req->num_replies = 0;
346
347                 break;
348
349         default:
350                 ret = LDB_ERR_PROTOCOL_ERROR;
351                 break;
352         }
353
354         if (ret != LDB_SUCCESS) {
355
356                 /* if the callback failed the caller will have freed the
357                  * request. Just return and don't try to use it */
358                 if ( ! callback_failed) {
359                         request_done = true;
360                 }
361         }
362
363         if (request_done) {
364                 ildb_request_done(ac, controls, ret);
365         }
366         return;
367 }
368
369 static int ildb_request_send(struct ildb_context *ac, struct ldap_message *msg)
370 {
371         struct ldap_request *req;
372
373         if (!ac) {
374                 return LDB_ERR_OPERATIONS_ERROR;
375         }
376
377         req = ldap_request_send(ac->ildb->ldap, msg);
378         if (req == NULL) {
379                 ldb_set_errstring(ac->module->ldb, "async send request failed");
380                 return LDB_ERR_OPERATIONS_ERROR;
381         }
382         ac->ireq = talloc_steal(ac, req);
383
384         if (!ac->ireq->conn) {
385                 ldb_set_errstring(ac->module->ldb, "connection to remote LDAP server dropped?");
386                 return LDB_ERR_OPERATIONS_ERROR;
387         }
388
389         talloc_free(req->time_event);
390         req->time_event = NULL;
391         if (ac->req->timeout) {
392                 req->time_event = tevent_add_timer(ac->ildb->event_ctx, ac,
393                                                    timeval_current_ofs(ac->req->timeout, 0),
394                                                    ildb_request_timeout, ac);
395         }
396
397         req->async.fn = ildb_callback;
398         req->async.private_data = ac;
399
400         return LDB_SUCCESS;
401 }
402
403 /*
404   search for matching records using an asynchronous function
405  */
406 static int ildb_search(struct ildb_context *ac)
407 {
408         struct ldb_request *req = ac->req;
409         struct ldap_message *msg;
410         int n;
411
412         if (!req->callback || !req->context) {
413                 ldb_set_errstring(ac->module->ldb, "Async interface called with NULL callback function or NULL context");
414                 return LDB_ERR_OPERATIONS_ERROR;
415         }
416
417         if (req->op.search.tree == NULL) {
418                 ldb_set_errstring(ac->module->ldb, "Invalid expression parse tree");
419                 return LDB_ERR_OPERATIONS_ERROR;
420         }
421
422         msg = new_ldap_message(req);
423         if (msg == NULL) {
424                 ldb_set_errstring(ac->module->ldb, "Out of Memory");
425                 return LDB_ERR_OPERATIONS_ERROR;
426         }
427
428         msg->type = LDAP_TAG_SearchRequest;
429
430         if (req->op.search.base == NULL) {
431                 msg->r.SearchRequest.basedn = talloc_strdup(msg, "");
432         } else {
433                 msg->r.SearchRequest.basedn  = ldb_dn_get_extended_linearized(msg, req->op.search.base, 0);
434         }
435         if (msg->r.SearchRequest.basedn == NULL) {
436                 ldb_set_errstring(ac->module->ldb, "Unable to determine baseDN");
437                 talloc_free(msg);
438                 return LDB_ERR_OPERATIONS_ERROR;
439         }
440
441         if (req->op.search.scope == LDB_SCOPE_DEFAULT) {
442                 msg->r.SearchRequest.scope = LDB_SCOPE_SUBTREE;
443         } else {
444                 msg->r.SearchRequest.scope = req->op.search.scope;
445         }
446
447         msg->r.SearchRequest.deref  = LDAP_DEREFERENCE_NEVER;
448         msg->r.SearchRequest.timelimit = 0;
449         msg->r.SearchRequest.sizelimit = 0;
450         msg->r.SearchRequest.attributesonly = 0;
451         msg->r.SearchRequest.tree = discard_const(req->op.search.tree);
452
453         for (n = 0; req->op.search.attrs && req->op.search.attrs[n]; n++) /* noop */ ;
454         msg->r.SearchRequest.num_attributes = n;
455         msg->r.SearchRequest.attributes = discard_const(req->op.search.attrs);
456         msg->controls = req->controls;
457
458         return ildb_request_send(ac, msg);
459 }
460
461 /*
462   add a record
463 */
464 static int ildb_add(struct ildb_context *ac)
465 {
466         struct ldb_request *req = ac->req;
467         struct ldap_message *msg;
468         struct ldap_mod **mods;
469         int i,n;
470
471         msg = new_ldap_message(req);
472         if (msg == NULL) {
473                 return LDB_ERR_OPERATIONS_ERROR;
474         }
475
476         msg->type = LDAP_TAG_AddRequest;
477
478         msg->r.AddRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.add.message->dn, 0);
479         if (msg->r.AddRequest.dn == NULL) {
480                 talloc_free(msg);
481                 return LDB_ERR_INVALID_DN_SYNTAX;
482         }
483
484         mods = ildb_msg_to_mods(msg, &n, req->op.add.message, 0);
485         if (mods == NULL) {
486                 talloc_free(msg);
487                 return LDB_ERR_OPERATIONS_ERROR;
488         }
489
490         msg->r.AddRequest.num_attributes = n;
491         msg->r.AddRequest.attributes = talloc_array(msg, struct ldb_message_element, n);
492         if (msg->r.AddRequest.attributes == NULL) {
493                 talloc_free(msg);
494                 return LDB_ERR_OPERATIONS_ERROR;
495         }
496
497         for (i = 0; i < n; i++) {
498                 msg->r.AddRequest.attributes[i] = mods[i]->attrib;
499         }
500
501         return ildb_request_send(ac, msg);
502 }
503
504 /*
505   modify a record
506 */
507 static int ildb_modify(struct ildb_context *ac)
508 {
509         struct ldb_request *req = ac->req;
510         struct ldap_message *msg;
511         struct ldap_mod **mods;
512         int i,n;
513
514         msg = new_ldap_message(req);
515         if (msg == NULL) {
516                 return LDB_ERR_OPERATIONS_ERROR;
517         }
518
519         msg->type = LDAP_TAG_ModifyRequest;
520
521         msg->r.ModifyRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.mod.message->dn, 0);
522         if (msg->r.ModifyRequest.dn == NULL) {
523                 talloc_free(msg);
524                 return LDB_ERR_INVALID_DN_SYNTAX;
525         }
526
527         mods = ildb_msg_to_mods(msg, &n, req->op.mod.message, 1);
528         if (mods == NULL) {
529                 talloc_free(msg);
530                 return LDB_ERR_OPERATIONS_ERROR;
531         }
532
533         msg->r.ModifyRequest.num_mods = n;
534         msg->r.ModifyRequest.mods = talloc_array(msg, struct ldap_mod, n);
535         if (msg->r.ModifyRequest.mods == NULL) {
536                 talloc_free(msg);
537                 return LDB_ERR_OPERATIONS_ERROR;
538         }
539
540         for (i = 0; i < n; i++) {
541                 msg->r.ModifyRequest.mods[i] = *mods[i];
542         }
543
544         return ildb_request_send(ac, msg);
545 }
546
547 /*
548   delete a record
549 */
550 static int ildb_delete(struct ildb_context *ac)
551 {
552         struct ldb_request *req = ac->req;
553         struct ldap_message *msg;
554
555         msg = new_ldap_message(req);
556         if (msg == NULL) {
557                 return LDB_ERR_OPERATIONS_ERROR;
558         }
559
560         msg->type = LDAP_TAG_DelRequest;
561
562         msg->r.DelRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.del.dn, 0);
563         if (msg->r.DelRequest.dn == NULL) {
564                 talloc_free(msg);
565                 return LDB_ERR_INVALID_DN_SYNTAX;
566         }
567
568         return ildb_request_send(ac, msg);
569 }
570
571 /*
572   rename a record
573 */
574 static int ildb_rename(struct ildb_context *ac)
575 {
576         struct ldb_request *req = ac->req;
577         struct ldap_message *msg;
578
579         msg = new_ldap_message(req);
580         if (msg == NULL) {
581                 return LDB_ERR_OPERATIONS_ERROR;
582         }
583
584         msg->type = LDAP_TAG_ModifyDNRequest;
585         msg->r.ModifyDNRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.rename.olddn, 0);
586         if (msg->r.ModifyDNRequest.dn == NULL) {
587                 talloc_free(msg);
588                 return LDB_ERR_INVALID_DN_SYNTAX;
589         }
590
591         msg->r.ModifyDNRequest.newrdn =
592                 talloc_asprintf(msg, "%s=%s",
593                                 ldb_dn_get_rdn_name(req->op.rename.newdn),
594                                 ldb_dn_escape_value(msg, *ldb_dn_get_rdn_val(req->op.rename.newdn)));
595         if (msg->r.ModifyDNRequest.newrdn == NULL) {
596                 talloc_free(msg);
597                 return LDB_ERR_OPERATIONS_ERROR;
598         }
599
600         msg->r.ModifyDNRequest.newsuperior =
601                 ldb_dn_alloc_linearized(msg, ldb_dn_get_parent(msg, req->op.rename.newdn));
602         if (msg->r.ModifyDNRequest.newsuperior == NULL) {
603                 talloc_free(msg);
604                 return LDB_ERR_INVALID_DN_SYNTAX;
605         }
606
607         msg->r.ModifyDNRequest.deleteolddn = true;
608
609         return ildb_request_send(ac, msg);
610 }
611
612 static int ildb_start_trans(struct ldb_module *module)
613 {
614         /* TODO implement a local locking mechanism here */
615
616         return LDB_SUCCESS;
617 }
618
619 static int ildb_end_trans(struct ldb_module *module)
620 {
621         /* TODO implement a local transaction mechanism here */
622
623         return LDB_SUCCESS;
624 }
625
626 static int ildb_del_trans(struct ldb_module *module)
627 {
628         /* TODO implement a local locking mechanism here */
629
630         return LDB_SUCCESS;
631 }
632
633 static bool ildb_dn_is_special(struct ldb_request *req)
634 {
635         struct ldb_dn *dn = NULL;
636
637         switch (req->operation) {
638         case LDB_ADD:
639                 dn = req->op.add.message->dn;
640                 break;
641         case LDB_MODIFY:
642                 dn = req->op.mod.message->dn;
643                 break;
644         case LDB_DELETE:
645                 dn = req->op.del.dn;
646                 break;
647         case LDB_RENAME:
648                 dn = req->op.rename.olddn;
649                 break;
650         default:
651                 break;
652         }
653
654         if (dn && ldb_dn_is_special(dn)) {
655                 return true;
656         }
657         return false;
658 }
659
660 static int ildb_handle_request(struct ldb_module *module, struct ldb_request *req)
661 {
662         struct ildb_private *ildb;
663         struct ildb_context *ac;
664         struct tevent_timer *te;
665         int ret;
666
667         ildb = talloc_get_type(module->private_data, struct ildb_private);
668
669         if (req->starttime == 0 || req->timeout == 0) {
670                 ldb_set_errstring(module->ldb, "Invalid timeout settings");
671                 return LDB_ERR_TIME_LIMIT_EXCEEDED;
672         }
673
674         ac = talloc_zero(req, struct ildb_context);
675         if (ac == NULL) {
676                 ldb_set_errstring(module->ldb, "Out of Memory");
677                 return LDB_ERR_OPERATIONS_ERROR;
678         }
679
680         ac->module = module;
681         ac->req = req;
682         ac->ildb = ildb;
683
684         if (ildb_dn_is_special(req)) {
685
686                 te = tevent_add_timer(ac->ildb->event_ctx,
687                                       ac, timeval_zero(),
688                                       ildb_auto_done_callback, ac);
689                 if (NULL == te) {
690                         return LDB_ERR_OPERATIONS_ERROR;
691                 }
692
693                 return LDB_SUCCESS;
694         }
695
696         switch (ac->req->operation) {
697         case LDB_SEARCH:
698                 ret = ildb_search(ac);
699                 break;
700         case LDB_ADD:
701                 ret = ildb_add(ac);
702                 break;
703         case LDB_MODIFY:
704                 ret = ildb_modify(ac);
705                 break;
706         case LDB_DELETE:
707                 ret = ildb_delete(ac);
708                 break;
709         case LDB_RENAME:
710                 ret = ildb_rename(ac);
711                 break;
712         default:
713                 /* no other op supported */
714                 ret = LDB_ERR_OPERATIONS_ERROR;
715                 break;
716         }
717
718         return ret;
719 }
720
721 static const struct ldb_module_ops ildb_ops = {
722         .name              = "ldap",
723         .search            = ildb_handle_request,
724         .add               = ildb_handle_request,
725         .modify            = ildb_handle_request,
726         .del               = ildb_handle_request,
727         .rename            = ildb_handle_request,
728 /*      .request           = ildb_handle_request, */
729         .start_transaction = ildb_start_trans,
730         .end_transaction   = ildb_end_trans,
731         .del_transaction   = ildb_del_trans,
732 };
733
734 /*
735   connect to the database
736 */
737 static int ildb_connect(struct ldb_context *ldb, const char *url,
738                         unsigned int flags, const char *options[],
739                         struct ldb_module **_module)
740 {
741         struct ldb_module *module;
742         struct ildb_private *ildb;
743         NTSTATUS status;
744         struct cli_credentials *creds;
745
746         module = talloc(ldb, struct ldb_module);
747         if (!module) {
748                 ldb_oom(ldb);
749                 return -1;
750         }
751         talloc_set_name_const(module, "ldb_ildap backend");
752         module->ldb             = ldb;
753         module->prev            = module->next = NULL;
754         module->ops             = &ildb_ops;
755
756         ildb = talloc(module, struct ildb_private);
757         if (!ildb) {
758                 ldb_oom(ldb);
759                 goto failed;
760         }
761         module->private_data    = ildb;
762
763         ildb->event_ctx = ldb_get_event_context(ldb);
764
765
766         ildb->ldap = ldap4_new_connection(ildb, ldb_get_opaque(ldb, "loadparm"),
767                                           ildb->event_ctx);
768         if (!ildb->ldap) {
769                 ldb_oom(ldb);
770                 goto failed;
771         }
772
773         if (flags & LDB_FLG_RECONNECT) {
774                 ldap_set_reconn_params(ildb->ldap, 10);
775         }
776
777         status = ldap_connect(ildb->ldap, url);
778         if (!NT_STATUS_IS_OK(status)) {
779                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to ldap URL '%s' - %s\n",
780                           url, ldap_errstr(ildb->ldap, module, status));
781                 goto failed;
782         }
783
784         /* caller can optionally setup credentials using the opaque token 'credentials' */
785         creds = talloc_get_type(ldb_get_opaque(ldb, "credentials"), struct cli_credentials);
786         if (creds == NULL) {
787                 struct auth_session_info *session_info = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
788                 if (session_info) {
789                         creds = session_info->credentials;
790                 }
791         }
792
793         if (creds != NULL && cli_credentials_authentication_requested(creds)) {
794                 const char *bind_dn = cli_credentials_get_bind_dn(creds);
795                 if (bind_dn) {
796                         const char *password = cli_credentials_get_password(creds);
797                         status = ldap_bind_simple(ildb->ldap, bind_dn, password);
798                         if (!NT_STATUS_IS_OK(status)) {
799                                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s\n",
800                                           ldap_errstr(ildb->ldap, module, status));
801                                 goto failed;
802                         }
803                 } else {
804                         status = ldap_bind_sasl(ildb->ldap, creds, ldb_get_opaque(ldb, "loadparm"));
805                         if (!NT_STATUS_IS_OK(status)) {
806                                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s\n",
807                                           ldap_errstr(ildb->ldap, module, status));
808                                 goto failed;
809                         }
810                 }
811         }
812
813         *_module = module;
814         return 0;
815
816 failed:
817         talloc_free(module);
818         return -1;
819 }
820
821 _PUBLIC_ const struct ldb_backend_ops ldb_ldap_backend_ops = {
822         .name = "ldap",
823         .connect_fn = ildb_connect
824 };
825
826 _PUBLIC_ const struct ldb_backend_ops ldb_ldapi_backend_ops = {
827         .name = "ldapi",
828         .connect_fn = ildb_connect
829 };
830
831 _PUBLIC_ const struct ldb_backend_ops ldb_ldaps_backend_ops = {
832         .name = "ldaps",
833         .connect_fn = ildb_connect
834 };
835