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