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