Line data Source code
1 : /*
2 : ldb database library
3 :
4 : Copyright (C) Andrew Tridgell 2004
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 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_ldap
27 : *
28 : * Component: ldb ldap backend
29 : *
30 : * Description: core files for LDAP backend
31 : *
32 : * Author: Andrew Tridgell
33 : *
34 : * Modifications:
35 : *
36 : * - description: make the module use asynchronous calls
37 : * date: Feb 2006
38 : * author: Simo Sorce
39 : */
40 :
41 : #include "replace.h"
42 : #include "system/filesys.h"
43 : #include "system/time.h"
44 : #include "ldb_module.h"
45 : #include "ldb_private.h"
46 :
47 : #define LDAP_DEPRECATED 1
48 : #include <ldap.h>
49 :
50 : struct lldb_private {
51 : LDAP *ldap;
52 : };
53 :
54 : struct lldb_context {
55 : struct ldb_module *module;
56 : struct ldb_request *req;
57 :
58 : struct lldb_private *lldb;
59 :
60 : struct ldb_control **controls;
61 : int msgid;
62 : };
63 :
64 0 : static int lldb_ldap_to_ldb(int err) {
65 : /* Ldap errors and ldb errors are defined to the same values */
66 0 : return err;
67 : }
68 :
69 : /*
70 : convert a ldb_message structure to a list of LDAPMod structures
71 : ready for ldap_add() or ldap_modify()
72 : */
73 0 : static LDAPMod **lldb_msg_to_mods(void *mem_ctx, const struct ldb_message *msg, int use_flags)
74 : {
75 0 : LDAPMod **mods;
76 0 : unsigned int i, j;
77 0 : int num_mods = 0;
78 :
79 : /* allocate maximum number of elements needed */
80 0 : mods = talloc_array(mem_ctx, LDAPMod *, msg->num_elements+1);
81 0 : if (!mods) {
82 0 : errno = ENOMEM;
83 0 : return NULL;
84 : }
85 0 : mods[0] = NULL;
86 :
87 0 : for (i=0;i<msg->num_elements;i++) {
88 0 : const struct ldb_message_element *el = &msg->elements[i];
89 :
90 0 : mods[num_mods] = talloc(mods, LDAPMod);
91 0 : if (!mods[num_mods]) {
92 0 : goto failed;
93 : }
94 0 : mods[num_mods+1] = NULL;
95 0 : mods[num_mods]->mod_op = LDAP_MOD_BVALUES;
96 0 : if (use_flags) {
97 0 : switch (el->flags & LDB_FLAG_MOD_MASK) {
98 0 : case LDB_FLAG_MOD_ADD:
99 0 : mods[num_mods]->mod_op |= LDAP_MOD_ADD;
100 0 : break;
101 0 : case LDB_FLAG_MOD_DELETE:
102 0 : mods[num_mods]->mod_op |= LDAP_MOD_DELETE;
103 0 : break;
104 0 : case LDB_FLAG_MOD_REPLACE:
105 0 : mods[num_mods]->mod_op |= LDAP_MOD_REPLACE;
106 0 : break;
107 : }
108 : }
109 0 : mods[num_mods]->mod_type = discard_const_p(char, el->name);
110 0 : mods[num_mods]->mod_vals.modv_bvals = talloc_array(mods[num_mods],
111 : struct berval *,
112 : 1+el->num_values);
113 0 : if (!mods[num_mods]->mod_vals.modv_bvals) {
114 0 : goto failed;
115 : }
116 :
117 0 : for (j=0;j<el->num_values;j++) {
118 0 : mods[num_mods]->mod_vals.modv_bvals[j] = talloc(mods[num_mods]->mod_vals.modv_bvals,
119 : struct berval);
120 0 : if (!mods[num_mods]->mod_vals.modv_bvals[j]) {
121 0 : goto failed;
122 : }
123 0 : mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = (char *)el->values[j].data;
124 0 : mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length;
125 : }
126 0 : mods[num_mods]->mod_vals.modv_bvals[j] = NULL;
127 0 : num_mods++;
128 : }
129 :
130 0 : return mods;
131 :
132 0 : failed:
133 0 : talloc_free(mods);
134 0 : return NULL;
135 : }
136 :
137 : /*
138 : add a single set of ldap message values to a ldb_message
139 : */
140 1 : static int lldb_add_msg_attr(struct ldb_context *ldb,
141 : struct ldb_message *msg,
142 : const char *attr, struct berval **bval)
143 : {
144 1 : int count, i, ret;
145 1 : struct ldb_message_element *el;
146 :
147 1 : count = ldap_count_values_len(bval);
148 :
149 1 : if (count <= 0) {
150 0 : return -1;
151 : }
152 :
153 1 : ret = ldb_msg_add_empty(msg, attr, 0, &el);
154 1 : if (ret != LDB_SUCCESS) {
155 0 : errno = ENOMEM;
156 0 : return -1;
157 : }
158 :
159 1 : el->values = talloc_array(msg->elements, struct ldb_val, count);
160 1 : if (!el->values) {
161 0 : errno = ENOMEM;
162 0 : return -1;
163 : }
164 :
165 2 : for (i=0;i<count;i++) {
166 : /* we have to ensure this is null terminated so that
167 : ldb_msg_find_attr_as_string() can work */
168 1 : el->values[i].data = talloc_size(el->values, bval[i]->bv_len+1);
169 1 : if (!el->values[i].data) {
170 0 : errno = ENOMEM;
171 0 : return -1;
172 : }
173 1 : memcpy(el->values[i].data, bval[i]->bv_val, bval[i]->bv_len);
174 1 : el->values[i].data[bval[i]->bv_len] = 0;
175 1 : el->values[i].length = bval[i]->bv_len;
176 1 : el->num_values++;
177 : }
178 :
179 0 : return 0;
180 : }
181 :
182 : /*
183 : search for matching records
184 : */
185 0 : static int lldb_search(struct lldb_context *lldb_ac)
186 : {
187 0 : struct ldb_context *ldb;
188 0 : struct lldb_private *lldb = lldb_ac->lldb;
189 0 : struct ldb_module *module = lldb_ac->module;
190 0 : struct ldb_request *req = lldb_ac->req;
191 0 : struct timeval tv;
192 0 : int ldap_scope;
193 0 : char *search_base;
194 0 : char *expression;
195 0 : int ret;
196 :
197 0 : ldb = ldb_module_get_ctx(module);
198 :
199 0 : if (!req->callback || !req->context) {
200 0 : ldb_set_errstring(ldb, "Async interface called with NULL callback function or NULL context");
201 0 : return LDB_ERR_OPERATIONS_ERROR;
202 : }
203 :
204 0 : if (req->op.search.tree == NULL) {
205 0 : ldb_set_errstring(ldb, "Invalid expression parse tree");
206 0 : return LDB_ERR_OPERATIONS_ERROR;
207 : }
208 :
209 0 : if (req->controls != NULL) {
210 0 : ldb_debug(ldb, LDB_DEBUG_WARNING, "Controls are not yet supported by ldb_ldap backend!");
211 : }
212 :
213 0 : ldb_request_set_state(req, LDB_ASYNC_PENDING);
214 :
215 0 : search_base = ldb_dn_alloc_linearized(lldb_ac, req->op.search.base);
216 0 : if (req->op.search.base == NULL) {
217 0 : search_base = talloc_strdup(lldb_ac, "");
218 : }
219 0 : if (search_base == NULL) {
220 0 : return LDB_ERR_OPERATIONS_ERROR;
221 : }
222 :
223 0 : expression = ldb_filter_from_tree(lldb_ac, req->op.search.tree);
224 0 : if (expression == NULL) {
225 0 : return LDB_ERR_OPERATIONS_ERROR;
226 : }
227 :
228 0 : switch (req->op.search.scope) {
229 0 : case LDB_SCOPE_BASE:
230 0 : ldap_scope = LDAP_SCOPE_BASE;
231 0 : break;
232 0 : case LDB_SCOPE_ONELEVEL:
233 0 : ldap_scope = LDAP_SCOPE_ONELEVEL;
234 0 : break;
235 0 : default:
236 0 : ldap_scope = LDAP_SCOPE_SUBTREE;
237 0 : break;
238 : }
239 :
240 0 : tv.tv_sec = 0;
241 0 : tv.tv_usec = 0;
242 0 : if (req->timeout > 0) {
243 0 : tv.tv_sec = req->timeout;
244 : }
245 :
246 0 : ret = ldap_search_ext(lldb->ldap, search_base, ldap_scope,
247 : expression,
248 0 : discard_const_p(char *, req->op.search.attrs),
249 : 0,
250 : NULL,
251 : NULL,
252 : &tv,
253 : LDAP_NO_LIMIT,
254 : &lldb_ac->msgid);
255 :
256 0 : if (ret != LDAP_SUCCESS) {
257 0 : ldb_set_errstring(ldb, ldap_err2string(ret));
258 : }
259 :
260 0 : return lldb_ldap_to_ldb(ret);
261 : }
262 :
263 : /*
264 : add a record
265 : */
266 0 : static int lldb_add(struct lldb_context *lldb_ac)
267 : {
268 0 : struct ldb_context *ldb;
269 0 : struct lldb_private *lldb = lldb_ac->lldb;
270 0 : struct ldb_module *module = lldb_ac->module;
271 0 : struct ldb_request *req = lldb_ac->req;
272 0 : LDAPMod **mods;
273 0 : char *dn;
274 0 : int ret;
275 :
276 0 : ldb = ldb_module_get_ctx(module);
277 :
278 0 : ldb_request_set_state(req, LDB_ASYNC_PENDING);
279 :
280 0 : mods = lldb_msg_to_mods(lldb_ac, req->op.add.message, 0);
281 0 : if (mods == NULL) {
282 0 : return LDB_ERR_OPERATIONS_ERROR;
283 : }
284 :
285 0 : dn = ldb_dn_alloc_linearized(lldb_ac, req->op.add.message->dn);
286 0 : if (dn == NULL) {
287 0 : return LDB_ERR_OPERATIONS_ERROR;
288 : }
289 :
290 0 : ret = ldap_add_ext(lldb->ldap, dn, mods,
291 : NULL,
292 : NULL,
293 : &lldb_ac->msgid);
294 :
295 0 : if (ret != LDAP_SUCCESS) {
296 0 : ldb_set_errstring(ldb, ldap_err2string(ret));
297 : }
298 :
299 0 : return lldb_ldap_to_ldb(ret);
300 : }
301 :
302 : /*
303 : modify a record
304 : */
305 0 : static int lldb_modify(struct lldb_context *lldb_ac)
306 : {
307 0 : struct ldb_context *ldb;
308 0 : struct lldb_private *lldb = lldb_ac->lldb;
309 0 : struct ldb_module *module = lldb_ac->module;
310 0 : struct ldb_request *req = lldb_ac->req;
311 0 : LDAPMod **mods;
312 0 : char *dn;
313 0 : int ret;
314 :
315 0 : ldb = ldb_module_get_ctx(module);
316 :
317 0 : ldb_request_set_state(req, LDB_ASYNC_PENDING);
318 :
319 0 : mods = lldb_msg_to_mods(lldb_ac, req->op.mod.message, 1);
320 0 : if (mods == NULL) {
321 0 : return LDB_ERR_OPERATIONS_ERROR;
322 : }
323 :
324 0 : dn = ldb_dn_alloc_linearized(lldb_ac, req->op.mod.message->dn);
325 0 : if (dn == NULL) {
326 0 : return LDB_ERR_OPERATIONS_ERROR;
327 : }
328 :
329 0 : ret = ldap_modify_ext(lldb->ldap, dn, mods,
330 : NULL,
331 : NULL,
332 : &lldb_ac->msgid);
333 :
334 0 : if (ret != LDAP_SUCCESS) {
335 0 : ldb_set_errstring(ldb, ldap_err2string(ret));
336 : }
337 :
338 0 : return lldb_ldap_to_ldb(ret);
339 : }
340 :
341 : /*
342 : delete a record
343 : */
344 0 : static int lldb_delete(struct lldb_context *lldb_ac)
345 : {
346 0 : struct ldb_context *ldb;
347 0 : struct lldb_private *lldb = lldb_ac->lldb;
348 0 : struct ldb_module *module = lldb_ac->module;
349 0 : struct ldb_request *req = lldb_ac->req;
350 0 : char *dnstr;
351 0 : int ret;
352 :
353 0 : ldb = ldb_module_get_ctx(module);
354 :
355 0 : ldb_request_set_state(req, LDB_ASYNC_PENDING);
356 :
357 0 : dnstr = ldb_dn_alloc_linearized(lldb_ac, req->op.del.dn);
358 :
359 0 : ret = ldap_delete_ext(lldb->ldap, dnstr,
360 : NULL,
361 : NULL,
362 : &lldb_ac->msgid);
363 :
364 0 : if (ret != LDAP_SUCCESS) {
365 0 : ldb_set_errstring(ldb, ldap_err2string(ret));
366 : }
367 :
368 0 : return lldb_ldap_to_ldb(ret);
369 : }
370 :
371 : /*
372 : rename a record
373 : */
374 0 : static int lldb_rename(struct lldb_context *lldb_ac)
375 : {
376 0 : struct ldb_context *ldb;
377 0 : struct lldb_private *lldb = lldb_ac->lldb;
378 0 : struct ldb_module *module = lldb_ac->module;
379 0 : struct ldb_request *req = lldb_ac->req;
380 0 : const char *rdn_name;
381 0 : const struct ldb_val *rdn_val;
382 0 : char *old_dn;
383 0 : char *newrdn;
384 0 : char *parentdn;
385 0 : int ret;
386 :
387 0 : ldb = ldb_module_get_ctx(module);
388 :
389 0 : ldb_request_set_state(req, LDB_ASYNC_PENDING);
390 :
391 0 : old_dn = ldb_dn_alloc_linearized(lldb_ac, req->op.rename.olddn);
392 0 : if (old_dn == NULL) {
393 0 : return LDB_ERR_OPERATIONS_ERROR;
394 : }
395 :
396 0 : rdn_name = ldb_dn_get_rdn_name(req->op.rename.newdn);
397 0 : rdn_val = ldb_dn_get_rdn_val(req->op.rename.newdn);
398 :
399 0 : if ((rdn_name != NULL) && (rdn_val != NULL)) {
400 0 : newrdn = talloc_asprintf(lldb_ac, "%s=%s", rdn_name,
401 0 : rdn_val->length > 0 ? ldb_dn_escape_value(lldb_ac, *rdn_val) : "");
402 : } else {
403 0 : newrdn = talloc_strdup(lldb_ac, "");
404 : }
405 0 : if (!newrdn) {
406 0 : return LDB_ERR_OPERATIONS_ERROR;
407 : }
408 :
409 0 : parentdn = ldb_dn_alloc_linearized(lldb_ac, ldb_dn_get_parent(lldb_ac, req->op.rename.newdn));
410 0 : if (!parentdn) {
411 0 : return LDB_ERR_OPERATIONS_ERROR;
412 : }
413 :
414 0 : ret = ldap_rename(lldb->ldap, old_dn, newrdn, parentdn,
415 : 1, NULL, NULL,
416 : &lldb_ac->msgid);
417 :
418 0 : if (ret != LDAP_SUCCESS) {
419 0 : ldb_set_errstring(ldb, ldap_err2string(ret));
420 : }
421 :
422 0 : return lldb_ldap_to_ldb(ret);
423 : }
424 :
425 0 : static int lldb_start_trans(struct ldb_module *module)
426 : {
427 : /* TODO implement a local transaction mechanism here */
428 :
429 0 : return LDB_SUCCESS;
430 : }
431 :
432 0 : static int lldb_end_trans(struct ldb_module *module)
433 : {
434 : /* TODO implement a local transaction mechanism here */
435 :
436 0 : return LDB_SUCCESS;
437 : }
438 :
439 0 : static int lldb_del_trans(struct ldb_module *module)
440 : {
441 : /* TODO implement a local transaction mechanism here */
442 :
443 0 : return LDB_SUCCESS;
444 : }
445 :
446 0 : static void lldb_request_done(struct lldb_context *ac,
447 : struct ldb_control **ctrls, int error)
448 : {
449 0 : struct ldb_request *req;
450 0 : struct ldb_reply *ares;
451 :
452 0 : req = ac->req;
453 :
454 0 : ares = talloc_zero(req, struct ldb_reply);
455 0 : if (!ares) {
456 0 : ldb_oom(ldb_module_get_ctx(ac->module));
457 0 : req->callback(req, NULL);
458 0 : return;
459 : }
460 0 : ares->type = LDB_REPLY_DONE;
461 0 : ares->controls = talloc_steal(ares, ctrls);
462 0 : ares->error = error;
463 :
464 0 : req->callback(req, ares);
465 : }
466 :
467 : /* return false if the request is still in progress
468 : * return true if the request is completed
469 : */
470 0 : static bool lldb_parse_result(struct lldb_context *ac, LDAPMessage *result)
471 : {
472 0 : struct ldb_context *ldb;
473 0 : struct lldb_private *lldb = ac->lldb;
474 0 : LDAPControl **serverctrlsp = NULL;
475 0 : char **referralsp = NULL;
476 0 : char *matcheddnp = NULL;
477 0 : char *errmsgp = NULL;
478 0 : LDAPMessage *msg;
479 0 : int type;
480 0 : struct ldb_message *ldbmsg = NULL;
481 0 : char *referral;
482 0 : bool callback_failed;
483 0 : bool request_done;
484 0 : bool lret;
485 0 : unsigned int i;
486 0 : int ret;
487 :
488 0 : ldb = ldb_module_get_ctx(ac->module);
489 :
490 0 : type = ldap_msgtype(result);
491 0 : callback_failed = false;
492 0 : request_done = false;
493 :
494 0 : switch (type) {
495 0 : case LDAP_RES_SEARCH_ENTRY:
496 :
497 0 : msg = ldap_first_entry(lldb->ldap, result);
498 0 : if (msg != NULL) {
499 0 : BerElement *berptr = NULL;
500 0 : char *attr, *dn;
501 :
502 0 : ldbmsg = ldb_msg_new(ac);
503 0 : if (!ldbmsg) {
504 0 : ldb_oom(ldb);
505 0 : ret = LDB_ERR_OPERATIONS_ERROR;
506 0 : break;
507 : }
508 :
509 0 : dn = ldap_get_dn(lldb->ldap, msg);
510 0 : if (!dn) {
511 0 : ldb_oom(ldb);
512 0 : talloc_free(ldbmsg);
513 0 : ret = LDB_ERR_OPERATIONS_ERROR;
514 0 : break;
515 : }
516 0 : ldbmsg->dn = ldb_dn_new(ldbmsg, ldb, dn);
517 0 : if ( ! ldb_dn_validate(ldbmsg->dn)) {
518 0 : ldb_asprintf_errstring(ldb, "Invalid DN '%s' in reply", dn);
519 0 : talloc_free(ldbmsg);
520 0 : ret = LDB_ERR_OPERATIONS_ERROR;
521 0 : ldap_memfree(dn);
522 0 : break;
523 : }
524 0 : ldap_memfree(dn);
525 : /* loop over all attributes */
526 0 : for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr);
527 0 : attr;
528 0 : attr=ldap_next_attribute(lldb->ldap, msg, berptr)) {
529 0 : struct berval **bval;
530 0 : bval = ldap_get_values_len(lldb->ldap, msg, attr);
531 :
532 0 : if (bval) {
533 0 : lldb_add_msg_attr(ldb, ldbmsg, attr, bval);
534 0 : ldap_value_free_len(bval);
535 : }
536 : }
537 0 : if (berptr) ber_free(berptr, 0);
538 :
539 0 : ret = ldb_module_send_entry(ac->req, ldbmsg, NULL /* controls not yet supported */);
540 0 : if (ret != LDB_SUCCESS) {
541 0 : ldb_asprintf_errstring(ldb, "entry send failed: %s",
542 : ldb_errstring(ldb));
543 0 : callback_failed = true;
544 : }
545 : } else {
546 0 : ret = LDB_ERR_OPERATIONS_ERROR;
547 : }
548 0 : break;
549 :
550 0 : case LDAP_RES_SEARCH_REFERENCE:
551 :
552 0 : ret = ldap_parse_reference(lldb->ldap, result,
553 : &referralsp, &serverctrlsp, 0);
554 0 : if (ret != LDAP_SUCCESS) {
555 0 : ldb_asprintf_errstring(ldb, "ldap reference parse error: %s : %s",
556 : ldap_err2string(ret), errmsgp);
557 0 : ret = LDB_ERR_OPERATIONS_ERROR;
558 0 : break;
559 : }
560 0 : if (referralsp == NULL) {
561 0 : ldb_asprintf_errstring(ldb, "empty ldap referrals list");
562 0 : ret = LDB_ERR_PROTOCOL_ERROR;
563 0 : break;
564 : }
565 :
566 0 : for (i = 0; referralsp[i]; i++) {
567 0 : referral = talloc_strdup(ac, referralsp[i]);
568 :
569 0 : ret = ldb_module_send_referral(ac->req, referral);
570 0 : if (ret != LDB_SUCCESS) {
571 0 : ldb_asprintf_errstring(ldb, "referral send failed: %s",
572 : ldb_errstring(ldb));
573 0 : callback_failed = true;
574 0 : break;
575 : }
576 : }
577 0 : break;
578 :
579 0 : case LDAP_RES_SEARCH_RESULT:
580 : case LDAP_RES_MODIFY:
581 : case LDAP_RES_ADD:
582 : case LDAP_RES_DELETE:
583 : case LDAP_RES_MODDN:
584 :
585 0 : if (ldap_parse_result(lldb->ldap, result, &ret,
586 : &matcheddnp, &errmsgp,
587 : &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) {
588 0 : ret = LDB_ERR_OPERATIONS_ERROR;
589 : }
590 0 : if (ret != LDB_SUCCESS) {
591 0 : ldb_asprintf_errstring(ldb, "ldap parse error for type %d: %s : %s",
592 : type, ldap_err2string(ret), errmsgp);
593 0 : break;
594 : }
595 :
596 0 : if (serverctrlsp != NULL) {
597 : /* FIXME: transform the LDAPControl list into an ldb_control one */
598 0 : ac->controls = NULL;
599 : }
600 :
601 0 : request_done = true;
602 0 : break;
603 :
604 0 : default:
605 0 : ldb_asprintf_errstring(ldb, "unknown ldap return type: %d", type);
606 0 : ret = LDB_ERR_PROTOCOL_ERROR;
607 0 : break;
608 : }
609 :
610 0 : if (ret != LDB_SUCCESS) {
611 :
612 : /* if the callback failed the caller will have freed the
613 : * request. Just return and don't try to use it */
614 0 : if (callback_failed) {
615 :
616 : /* tell lldb_wait to remove the request from the
617 : * queue */
618 0 : lret = true;
619 0 : goto free_and_return;
620 : }
621 :
622 0 : request_done = true;
623 : }
624 :
625 0 : if (request_done) {
626 0 : lldb_request_done(ac, ac->controls, ret);
627 0 : lret = true;
628 0 : goto free_and_return;
629 : }
630 :
631 0 : lret = false;
632 :
633 0 : free_and_return:
634 :
635 0 : if (matcheddnp) ldap_memfree(matcheddnp);
636 0 : if (errmsgp && *errmsgp) {
637 0 : ldb_set_errstring(ldb, errmsgp);
638 : }
639 0 : if (errmsgp) {
640 0 : ldap_memfree(errmsgp);
641 : }
642 0 : if (referralsp) ldap_value_free(referralsp);
643 0 : if (serverctrlsp) ldap_controls_free(serverctrlsp);
644 :
645 0 : ldap_msgfree(result);
646 :
647 0 : return lret;
648 : }
649 :
650 0 : static void lldb_timeout(struct tevent_context *ev,
651 : struct tevent_timer *te,
652 : struct timeval t,
653 : void *private_data)
654 : {
655 0 : struct lldb_context *ac;
656 0 : ac = talloc_get_type(private_data, struct lldb_context);
657 :
658 0 : lldb_request_done(ac, NULL, LDB_ERR_TIME_LIMIT_EXCEEDED);
659 0 : }
660 :
661 0 : static void lldb_callback(struct tevent_context *ev,
662 : struct tevent_timer *te,
663 : struct timeval t,
664 : void *private_data)
665 : {
666 0 : struct lldb_context *ac;
667 0 : struct tevent_timer *lte;
668 0 : struct timeval tv;
669 0 : LDAPMessage *result;
670 0 : int lret;
671 :
672 0 : ac = talloc_get_type(private_data, struct lldb_context);
673 :
674 0 : if (!ac->msgid) {
675 0 : lldb_request_done(ac, NULL, LDB_ERR_OPERATIONS_ERROR);
676 0 : return;
677 : }
678 :
679 0 : tv.tv_sec = 0;
680 0 : tv.tv_usec = 0;
681 0 : lret = ldap_result(ac->lldb->ldap, ac->msgid, 0, &tv, &result);
682 0 : if (lret == 0) {
683 0 : goto respin;
684 : }
685 0 : if (lret == -1) {
686 0 : lldb_request_done(ac, NULL, LDB_ERR_OPERATIONS_ERROR);
687 0 : return;
688 : }
689 :
690 0 : if ( ! lldb_parse_result(ac, result)) {
691 0 : goto respin;
692 : }
693 :
694 0 : return;
695 :
696 0 : respin:
697 0 : tv.tv_sec = 0;
698 0 : tv.tv_usec = 100;
699 0 : lte = tevent_add_timer(ev, ac, tv, lldb_callback, ac);
700 0 : if (NULL == lte) {
701 0 : lldb_request_done(ac, NULL, LDB_ERR_OPERATIONS_ERROR);
702 : }
703 : }
704 :
705 0 : static bool lldb_dn_is_special(struct ldb_request *req)
706 : {
707 0 : struct ldb_dn *dn = NULL;
708 :
709 0 : switch (req->operation) {
710 0 : case LDB_ADD:
711 0 : dn = req->op.add.message->dn;
712 0 : break;
713 0 : case LDB_MODIFY:
714 0 : dn = req->op.mod.message->dn;
715 0 : break;
716 0 : case LDB_DELETE:
717 0 : dn = req->op.del.dn;
718 0 : break;
719 0 : case LDB_RENAME:
720 0 : dn = req->op.rename.olddn;
721 0 : break;
722 0 : default:
723 0 : break;
724 : }
725 :
726 0 : if (dn && ldb_dn_is_special(dn)) {
727 0 : return true;
728 : }
729 0 : return false;
730 : }
731 :
732 0 : static void lldb_auto_done_callback(struct tevent_context *ev,
733 : struct tevent_timer *te,
734 : struct timeval t,
735 : void *private_data)
736 : {
737 0 : struct lldb_context *ac;
738 :
739 0 : ac = talloc_get_type(private_data, struct lldb_context);
740 0 : lldb_request_done(ac, NULL, LDB_SUCCESS);
741 0 : }
742 :
743 0 : static int lldb_handle_request(struct ldb_module *module, struct ldb_request *req)
744 : {
745 0 : struct ldb_context *ldb;
746 0 : struct lldb_private *lldb;
747 0 : struct lldb_context *ac;
748 0 : struct tevent_context *ev;
749 0 : struct tevent_timer *te;
750 0 : struct timeval tv;
751 0 : int ret;
752 :
753 0 : lldb = talloc_get_type(ldb_module_get_private(module), struct lldb_private);
754 0 : ldb = ldb_module_get_ctx(module);
755 :
756 0 : if (req->starttime == 0 || req->timeout == 0) {
757 0 : ldb_set_errstring(ldb, "Invalid timeout settings");
758 0 : return LDB_ERR_TIME_LIMIT_EXCEEDED;
759 : }
760 :
761 0 : ev = ldb_get_event_context(ldb);
762 0 : if (NULL == ev) {
763 0 : return LDB_ERR_OPERATIONS_ERROR;
764 : }
765 :
766 0 : ac = talloc_zero(ldb, struct lldb_context);
767 0 : if (ac == NULL) {
768 0 : ldb_set_errstring(ldb, "Out of Memory");
769 0 : return LDB_ERR_OPERATIONS_ERROR;
770 : }
771 :
772 0 : ac->module = module;
773 0 : ac->req = req;
774 0 : ac->lldb = lldb;
775 0 : ac->msgid = 0;
776 :
777 0 : if (lldb_dn_is_special(req)) {
778 0 : tv.tv_sec = 0;
779 0 : tv.tv_usec = 0;
780 0 : te = tevent_add_timer(ev, ac, tv,
781 : lldb_auto_done_callback, ac);
782 0 : if (NULL == te) {
783 0 : return LDB_ERR_OPERATIONS_ERROR;
784 : }
785 :
786 0 : return LDB_SUCCESS;
787 : }
788 :
789 0 : switch (ac->req->operation) {
790 0 : case LDB_SEARCH:
791 0 : ret = lldb_search(ac);
792 0 : break;
793 0 : case LDB_ADD:
794 0 : ret = lldb_add(ac);
795 0 : break;
796 0 : case LDB_MODIFY:
797 0 : ret = lldb_modify(ac);
798 0 : break;
799 0 : case LDB_DELETE:
800 0 : ret = lldb_delete(ac);
801 0 : break;
802 0 : case LDB_RENAME:
803 0 : ret = lldb_rename(ac);
804 0 : break;
805 0 : default:
806 : /* no other op supported */
807 0 : ret = LDB_ERR_PROTOCOL_ERROR;
808 0 : break;
809 : }
810 :
811 0 : if (ret != LDB_SUCCESS) {
812 0 : lldb_request_done(ac, NULL, ret);
813 0 : return ret;
814 : }
815 :
816 0 : tv.tv_sec = 0;
817 0 : tv.tv_usec = 0;
818 0 : te = tevent_add_timer(ev, ac, tv, lldb_callback, ac);
819 0 : if (NULL == te) {
820 0 : return LDB_ERR_OPERATIONS_ERROR;
821 : }
822 :
823 0 : if (req->timeout > 0) {
824 0 : tv.tv_sec = req->starttime + req->timeout;
825 0 : tv.tv_usec = 0;
826 0 : te = tevent_add_timer(ev, ac, tv, lldb_timeout, ac);
827 0 : if (NULL == te) {
828 0 : return LDB_ERR_OPERATIONS_ERROR;
829 : }
830 : }
831 :
832 0 : return LDB_SUCCESS;
833 : }
834 :
835 : static const struct ldb_module_ops lldb_ops = {
836 : .name = "ldap",
837 : .search = lldb_handle_request,
838 : .add = lldb_handle_request,
839 : .modify = lldb_handle_request,
840 : .del = lldb_handle_request,
841 : .rename = lldb_handle_request,
842 : .request = lldb_handle_request,
843 : .start_transaction = lldb_start_trans,
844 : .end_transaction = lldb_end_trans,
845 : .del_transaction = lldb_del_trans,
846 : };
847 :
848 :
849 0 : static int lldb_destructor(struct lldb_private *lldb)
850 : {
851 0 : ldap_unbind(lldb->ldap);
852 0 : return 0;
853 : }
854 :
855 :
856 : /*
857 : optionally perform a bind
858 : */
859 0 : static int lldb_bind(struct ldb_module *module,
860 : const char *options[])
861 : {
862 0 : const char *bind_mechanism;
863 0 : struct lldb_private *lldb;
864 0 : struct ldb_context *ldb = ldb_module_get_ctx(module);
865 0 : int ret;
866 :
867 0 : bind_mechanism = ldb_options_find(ldb, options, "bindMech");
868 0 : if (bind_mechanism == NULL) {
869 : /* no bind wanted */
870 0 : return LDB_SUCCESS;
871 : }
872 :
873 0 : lldb = talloc_get_type(ldb_module_get_private(module), struct lldb_private);
874 :
875 0 : if (strcmp(bind_mechanism, "simple") == 0) {
876 0 : const char *bind_id, *bind_secret;
877 :
878 0 : bind_id = ldb_options_find(ldb, options, "bindID");
879 0 : bind_secret = ldb_options_find(ldb, options, "bindSecret");
880 0 : if (bind_id == NULL || bind_secret == NULL) {
881 0 : ldb_asprintf_errstring(ldb, "simple bind requires bindID and bindSecret");
882 0 : return LDB_ERR_OPERATIONS_ERROR;
883 : }
884 :
885 0 : ret = ldap_simple_bind_s(lldb->ldap, bind_id, bind_secret);
886 0 : if (ret != LDAP_SUCCESS) {
887 0 : ldb_asprintf_errstring(ldb, "bind failed: %s", ldap_err2string(ret));
888 0 : return ret;
889 : }
890 0 : return LDB_SUCCESS;
891 : }
892 :
893 0 : ldb_asprintf_errstring(ldb, "bind failed: unknown mechanism %s", bind_mechanism);
894 0 : return LDB_ERR_INAPPROPRIATE_AUTHENTICATION;
895 : }
896 :
897 : /*
898 : connect to the database
899 : */
900 0 : static int lldb_connect(struct ldb_context *ldb,
901 : const char *url,
902 : unsigned int flags,
903 : const char *options[],
904 : struct ldb_module **_module)
905 : {
906 0 : struct ldb_module *module;
907 0 : struct lldb_private *lldb;
908 0 : int version = 3;
909 0 : int ret;
910 :
911 0 : module = ldb_module_new(ldb, ldb, "ldb_ldap backend", &lldb_ops);
912 0 : if (!module) return LDB_ERR_OPERATIONS_ERROR;
913 :
914 0 : lldb = talloc_zero(module, struct lldb_private);
915 0 : if (!lldb) {
916 0 : ldb_oom(ldb);
917 0 : goto failed;
918 : }
919 0 : ldb_module_set_private(module, lldb);
920 :
921 0 : ret = ldap_initialize(&lldb->ldap, url);
922 0 : if (ret != LDAP_SUCCESS) {
923 0 : ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_initialize failed for URL '%s' - %s",
924 : url, ldap_err2string(ret));
925 0 : goto failed;
926 : }
927 :
928 0 : talloc_set_destructor(lldb, lldb_destructor);
929 :
930 0 : ret = ldap_set_option(lldb->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
931 0 : if (ret != LDAP_SUCCESS) {
932 0 : ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_set_option failed - %s",
933 : ldap_err2string(ret));
934 0 : goto failed;
935 : }
936 :
937 0 : *_module = module;
938 :
939 0 : ret = lldb_bind(module, options);
940 0 : if (ret != LDB_SUCCESS) {
941 0 : goto failed;
942 : }
943 :
944 :
945 0 : return LDB_SUCCESS;
946 :
947 0 : failed:
948 0 : talloc_free(module);
949 0 : return LDB_ERR_OPERATIONS_ERROR;
950 : }
951 :
952 : /*
953 : initialise the module
954 : */
955 6067 : int ldb_ldap_init(const char *version)
956 : {
957 444 : int ret, i;
958 6067 : const char *names[] = { "ldap", "ldaps", "ldapi", NULL };
959 6067 : LDB_MODULE_CHECK_VERSION(version);
960 24268 : for (i=0; names[i]; i++) {
961 18201 : ret = ldb_register_backend(names[i], lldb_connect, false);
962 18201 : if (ret != LDB_SUCCESS) {
963 0 : return ret;
964 : }
965 : }
966 5623 : return LDB_SUCCESS;
967 : }
|