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