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