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