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