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