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