Added control copying for message types other than ldb_search.
[abartlet/samba.git/.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         msg->controls = req->controls;
517
518         return ildb_request_send(ac, msg);
519 }
520
521 /*
522   modify a record
523 */
524 static int ildb_modify(struct ildb_context *ac)
525 {
526         struct ldb_request *req = ac->req;
527         struct ldap_message *msg;
528         struct ldap_mod **mods;
529         int i,n;
530
531         msg = new_ldap_message(req);
532         if (msg == NULL) {
533                 return LDB_ERR_OPERATIONS_ERROR;
534         }
535
536         msg->type = LDAP_TAG_ModifyRequest;
537
538         msg->r.ModifyRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.mod.message->dn, 0);
539         if (msg->r.ModifyRequest.dn == NULL) {
540                 talloc_free(msg);
541                 return LDB_ERR_INVALID_DN_SYNTAX;
542         }
543
544         mods = ildb_msg_to_mods(msg, &n, req->op.mod.message, 1);
545         if (mods == NULL) {
546                 talloc_free(msg);
547                 return LDB_ERR_OPERATIONS_ERROR;
548         }
549
550         msg->r.ModifyRequest.num_mods = n;
551         msg->r.ModifyRequest.mods = talloc_array(msg, struct ldap_mod, n);
552         if (msg->r.ModifyRequest.mods == NULL) {
553                 talloc_free(msg);
554                 return LDB_ERR_OPERATIONS_ERROR;
555         }
556
557         for (i = 0; i < n; i++) {
558                 msg->r.ModifyRequest.mods[i] = *mods[i];
559         }
560         msg->controls = req->controls;
561         return ildb_request_send(ac, msg);
562 }
563
564 /*
565   delete a record
566 */
567 static int ildb_delete(struct ildb_context *ac)
568 {
569         struct ldb_request *req = ac->req;
570         struct ldap_message *msg;
571
572         msg = new_ldap_message(req);
573         if (msg == NULL) {
574                 return LDB_ERR_OPERATIONS_ERROR;
575         }
576
577         msg->type = LDAP_TAG_DelRequest;
578
579         msg->r.DelRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.del.dn, 0);
580         if (msg->r.DelRequest.dn == NULL) {
581                 talloc_free(msg);
582                 return LDB_ERR_INVALID_DN_SYNTAX;
583         }
584         msg->controls = req->controls;
585
586         return ildb_request_send(ac, msg);
587 }
588
589 /*
590   rename a record
591 */
592 static int ildb_rename(struct ildb_context *ac)
593 {
594         struct ldb_request *req = ac->req;
595         struct ldap_message *msg;
596         const char *rdn_name;
597         const struct ldb_val *rdn_val;
598
599         msg = new_ldap_message(req);
600         if (msg == NULL) {
601                 return LDB_ERR_OPERATIONS_ERROR;
602         }
603
604         msg->type = LDAP_TAG_ModifyDNRequest;
605         msg->r.ModifyDNRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.rename.olddn, 0);
606         if (msg->r.ModifyDNRequest.dn == NULL) {
607                 talloc_free(msg);
608                 return LDB_ERR_INVALID_DN_SYNTAX;
609         }
610
611         rdn_name = ldb_dn_get_rdn_name(req->op.rename.newdn);
612         rdn_val = ldb_dn_get_rdn_val(req->op.rename.newdn);
613
614         if ((rdn_name != NULL) && (rdn_val != NULL)) {
615                 msg->r.ModifyDNRequest.newrdn =
616                         talloc_asprintf(msg, "%s=%s", rdn_name,
617                                 ldb_dn_escape_value(msg, *rdn_val));
618         } else {
619                 msg->r.ModifyDNRequest.newrdn = talloc_strdup(msg, "");
620         }
621         if (msg->r.ModifyDNRequest.newrdn == NULL) {
622                 talloc_free(msg);
623                 return LDB_ERR_OPERATIONS_ERROR;
624         }
625
626         msg->r.ModifyDNRequest.newsuperior =
627                 ldb_dn_alloc_linearized(msg, ldb_dn_get_parent(msg, req->op.rename.newdn));
628         if (msg->r.ModifyDNRequest.newsuperior == NULL) {
629                 talloc_free(msg);
630                 return LDB_ERR_INVALID_DN_SYNTAX;
631         }
632
633         msg->r.ModifyDNRequest.deleteolddn = true;
634         msg->controls = req->controls;
635
636         return ildb_request_send(ac, msg);
637 }
638
639 static int ildb_start_trans(struct ldb_module *module)
640 {
641         /* TODO implement a local locking mechanism here */
642
643         return LDB_SUCCESS;
644 }
645
646 static int ildb_end_trans(struct ldb_module *module)
647 {
648         /* TODO implement a local transaction mechanism here */
649
650         return LDB_SUCCESS;
651 }
652
653 static int ildb_del_trans(struct ldb_module *module)
654 {
655         /* TODO implement a local locking mechanism here */
656
657         return LDB_SUCCESS;
658 }
659
660 static bool ildb_dn_is_special(struct ldb_request *req)
661 {
662         struct ldb_dn *dn = NULL;
663
664         switch (req->operation) {
665         case LDB_ADD:
666                 dn = req->op.add.message->dn;
667                 break;
668         case LDB_MODIFY:
669                 dn = req->op.mod.message->dn;
670                 break;
671         case LDB_DELETE:
672                 dn = req->op.del.dn;
673                 break;
674         case LDB_RENAME:
675                 dn = req->op.rename.olddn;
676                 break;
677         default:
678                 break;
679         }
680
681         if (dn && ldb_dn_is_special(dn)) {
682                 return true;
683         }
684         return false;
685 }
686
687 static int ildb_handle_request(struct ldb_module *module, struct ldb_request *req)
688 {
689         struct ldb_context *ldb;
690         struct ildb_private *ildb;
691         struct ildb_context *ac;
692         struct tevent_timer *te;
693         int ret;
694
695         ildb = talloc_get_type(ldb_module_get_private(module), struct ildb_private);
696         ldb = ldb_module_get_ctx(module);
697
698         if (req->starttime == 0 || req->timeout == 0) {
699                 ldb_set_errstring(ldb, "Invalid timeout settings");
700                 return LDB_ERR_TIME_LIMIT_EXCEEDED;
701         }
702
703         ac = talloc_zero(req, struct ildb_context);
704         if (ac == NULL) {
705                 ldb_set_errstring(ldb, "Out of Memory");
706                 return LDB_ERR_OPERATIONS_ERROR;
707         }
708
709         ac->module = module;
710         ac->req = req;
711         ac->ildb = ildb;
712
713         if (ildb_dn_is_special(req)) {
714
715                 te = tevent_add_timer(ac->ildb->event_ctx,
716                                       ac, timeval_zero(),
717                                       ildb_auto_done_callback, ac);
718                 if (NULL == te) {
719                         return LDB_ERR_OPERATIONS_ERROR;
720                 }
721
722                 return LDB_SUCCESS;
723         }
724
725         switch (ac->req->operation) {
726         case LDB_SEARCH:
727                 ret = ildb_search(ac);
728                 break;
729         case LDB_ADD:
730                 ret = ildb_add(ac);
731                 break;
732         case LDB_MODIFY:
733                 ret = ildb_modify(ac);
734                 break;
735         case LDB_DELETE:
736                 ret = ildb_delete(ac);
737                 break;
738         case LDB_RENAME:
739                 ret = ildb_rename(ac);
740                 break;
741         default:
742                 /* no other op supported */
743                 ret = LDB_ERR_OPERATIONS_ERROR;
744                 break;
745         }
746
747         return ret;
748 }
749
750 static const struct ldb_module_ops ildb_ops = {
751         .name              = "ldap",
752         .search            = ildb_handle_request,
753         .add               = ildb_handle_request,
754         .modify            = ildb_handle_request,
755         .del               = ildb_handle_request,
756         .rename            = ildb_handle_request,
757 /*      .request           = ildb_handle_request, */
758         .start_transaction = ildb_start_trans,
759         .end_transaction   = ildb_end_trans,
760         .del_transaction   = ildb_del_trans,
761 };
762
763 /*
764   connect to the database
765 */
766 static int ildb_connect(struct ldb_context *ldb, const char *url,
767                         unsigned int flags, const char *options[],
768                         struct ldb_module **_module)
769 {
770         struct ldb_module *module;
771         struct ildb_private *ildb;
772         NTSTATUS status;
773         struct cli_credentials *creds;
774         struct loadparm_context *lp_ctx;
775
776         module = ldb_module_new(ldb, ldb, "ldb_ildap backend", &ildb_ops);
777         if (!module) return LDB_ERR_OPERATIONS_ERROR;
778
779         ildb = talloc(module, struct ildb_private);
780         if (!ildb) {
781                 ldb_oom(ldb);
782                 goto failed;
783         }
784         ldb_module_set_private(module, ildb);
785
786         ildb->event_ctx = ldb_get_event_context(ldb);
787
788         lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
789                                  struct loadparm_context);
790
791         ildb->ldap = ldap4_new_connection(ildb, lp_ctx,
792                                           ildb->event_ctx);
793         if (!ildb->ldap) {
794                 ldb_oom(ldb);
795                 goto failed;
796         }
797
798         if (flags & LDB_FLG_RECONNECT) {
799                 ldap_set_reconn_params(ildb->ldap, 10);
800         }
801
802         status = ldap_connect(ildb->ldap, url);
803         if (!NT_STATUS_IS_OK(status)) {
804                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to ldap URL '%s' - %s",
805                           url, ldap_errstr(ildb->ldap, module, status));
806                 goto failed;
807         }
808
809         /* caller can optionally setup credentials using the opaque token 'credentials' */
810         creds = talloc_get_type(ldb_get_opaque(ldb, "credentials"), struct cli_credentials);
811         if (creds == NULL) {
812                 struct auth_session_info *session_info = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
813                 if (session_info) {
814                         creds = session_info->credentials;
815                 }
816         }
817
818         if (creds != NULL && cli_credentials_authentication_requested(creds)) {
819                 const char *bind_dn = cli_credentials_get_bind_dn(creds);
820                 if (bind_dn) {
821                         const char *password = cli_credentials_get_password(creds);
822                         status = ldap_bind_simple(ildb->ldap, bind_dn, password);
823                         if (!NT_STATUS_IS_OK(status)) {
824                                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s",
825                                           ldap_errstr(ildb->ldap, module, status));
826                                 goto failed;
827                         }
828                 } else {
829                         status = ldap_bind_sasl(ildb->ldap, creds, lp_ctx);
830                         if (!NT_STATUS_IS_OK(status)) {
831                                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s",
832                                           ldap_errstr(ildb->ldap, module, status));
833                                 goto failed;
834                         }
835                 }
836         }
837
838         *_module = module;
839         return LDB_SUCCESS;
840
841 failed:
842         talloc_free(module);
843         return LDB_ERR_OPERATIONS_ERROR;
844 }
845
846 _PUBLIC_ const struct ldb_backend_ops ldb_ldap_backend_ops = {
847         .name = "ldap",
848         .connect_fn = ildb_connect
849 };
850
851 _PUBLIC_ const struct ldb_backend_ops ldb_ldapi_backend_ops = {
852         .name = "ldapi",
853         .connect_fn = ildb_connect
854 };
855
856 _PUBLIC_ const struct ldb_backend_ops ldb_ldaps_backend_ops = {
857         .name = "ldaps",
858         .connect_fn = ildb_connect
859 };
860