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