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