Line data Source code
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 567890 : static void ildb_request_done(struct ildb_context *ctx,
75 : struct ldb_control **ctrls, int error)
76 : {
77 465 : struct ldb_context *ldb;
78 465 : struct ldb_reply *ares;
79 :
80 567890 : ldb = ldb_module_get_ctx(ctx->module);
81 :
82 567890 : ctx->done = true;
83 :
84 567890 : if (ctx->req == NULL) {
85 : /* if the req has been freed already just return */
86 0 : return;
87 : }
88 :
89 567890 : ares = talloc_zero(ctx->req, struct ldb_reply);
90 567890 : if (!ares) {
91 0 : ldb_oom(ldb);
92 0 : ctx->req->callback(ctx->req, NULL);
93 0 : return;
94 : }
95 567890 : ares->type = LDB_REPLY_DONE;
96 567890 : ares->controls = talloc_steal(ares, ctrls);
97 567890 : ares->error = error;
98 :
99 567890 : ctx->req->callback(ctx->req, ares);
100 : }
101 :
102 24 : 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 0 : struct ildb_context *ac;
108 :
109 24 : ac = talloc_get_type(private_data, struct ildb_context);
110 24 : ildb_request_done(ac, NULL, LDB_SUCCESS);
111 24 : }
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 154297 : 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 180 : struct ldap_mod **mods;
122 180 : unsigned int i;
123 154297 : unsigned int n = 0;
124 :
125 : /* allocate maximum number of elements needed */
126 154297 : mods = talloc_array(mem_ctx, struct ldap_mod *, msg->num_elements+1);
127 154297 : if (!mods) {
128 0 : errno = ENOMEM;
129 0 : return NULL;
130 : }
131 154297 : mods[0] = NULL;
132 :
133 453711 : for (i = 0; i < msg->num_elements; i++) {
134 299414 : const struct ldb_message_element *el = &msg->elements[i];
135 :
136 299414 : mods[n] = talloc(mods, struct ldap_mod);
137 299414 : if (!mods[n]) {
138 0 : goto failed;
139 : }
140 299414 : mods[n + 1] = NULL;
141 299414 : mods[n]->type = 0;
142 299414 : mods[n]->attrib = *el;
143 299414 : if (use_flags) {
144 113235 : switch (el->flags & LDB_FLAG_MOD_MASK) {
145 31686 : case LDB_FLAG_MOD_ADD:
146 31686 : mods[n]->type = LDAP_MODIFY_ADD;
147 31686 : break;
148 21509 : case LDB_FLAG_MOD_DELETE:
149 21509 : mods[n]->type = LDAP_MODIFY_DELETE;
150 21509 : break;
151 60026 : case LDB_FLAG_MOD_REPLACE:
152 60026 : mods[n]->type = LDAP_MODIFY_REPLACE;
153 60026 : break;
154 : }
155 : }
156 299090 : n++;
157 : }
158 :
159 154297 : *num_mods = n;
160 154297 : return mods;
161 :
162 0 : failed:
163 0 : talloc_free(mods);
164 0 : return NULL;
165 : }
166 :
167 :
168 : /*
169 : map an ildap NTSTATUS to a ldb error code
170 : */
171 238290 : static int ildb_map_error(struct ldb_module *module, NTSTATUS status)
172 : {
173 216 : struct ildb_private *ildb;
174 216 : struct ldb_context *ldb;
175 216 : TALLOC_CTX *mem_ctx;
176 :
177 238290 : ildb = talloc_get_type(ldb_module_get_private(module), struct ildb_private);
178 238290 : ldb = ldb_module_get_ctx(module);
179 :
180 238290 : if (NT_STATUS_IS_OK(status)) {
181 186396 : return LDB_SUCCESS;
182 : }
183 :
184 51678 : mem_ctx = talloc_new(ildb);
185 51678 : if (!mem_ctx) {
186 0 : ldb_oom(ldb);
187 0 : return LDB_ERR_OPERATIONS_ERROR;
188 : }
189 51678 : ldb_set_errstring(ldb,
190 : ldap_errstr(ildb->ldap, mem_ctx, status));
191 51678 : talloc_free(mem_ctx);
192 51678 : if (NT_STATUS_IS_LDAP(status)) {
193 51678 : return NT_STATUS_LDAP_CODE(status);
194 : }
195 0 : return LDB_ERR_OPERATIONS_ERROR;
196 : }
197 :
198 14 : static void ildb_request_timeout(struct tevent_context *ev, struct tevent_timer *te,
199 : struct timeval t, void *private_data)
200 : {
201 14 : struct ildb_context *ac = talloc_get_type(private_data, struct ildb_context);
202 :
203 14 : if (ac->ireq->state == LDAP_REQUEST_PENDING) {
204 14 : DLIST_REMOVE(ac->ireq->conn->pending, ac->ireq);
205 : }
206 :
207 14 : ildb_request_done(ac, NULL, LDB_ERR_TIME_LIMIT_EXCEEDED);
208 14 : }
209 :
210 1307246 : static void ildb_callback(struct ldap_request *req)
211 : {
212 750 : struct ldb_context *ldb;
213 750 : struct ildb_context *ac;
214 750 : NTSTATUS status;
215 750 : struct ldap_SearchResEntry *search;
216 750 : struct ldap_message *msg;
217 750 : struct ldb_control **controls;
218 750 : struct ldb_message *ldbmsg;
219 750 : char *referral;
220 750 : bool callback_failed;
221 750 : bool request_done;
222 750 : int ret;
223 750 : int i;
224 :
225 1307246 : ac = talloc_get_type(req->async.private_data, struct ildb_context);
226 1307246 : ldb = ldb_module_get_ctx(ac->module);
227 1307246 : callback_failed = false;
228 1307246 : request_done = false;
229 1307246 : controls = NULL;
230 :
231 : /* check if we are already processing this request */
232 1307246 : if (ac->in_ildb_callback) {
233 1 : return;
234 : }
235 : /* mark the request as being in process */
236 1307245 : ac->in_ildb_callback = true;
237 :
238 1307245 : if (!NT_STATUS_IS_OK(req->status)) {
239 0 : ret = ildb_map_error(ac->module, req->status);
240 0 : ildb_request_done(ac, NULL, ret);
241 0 : return;
242 : }
243 :
244 1307245 : if (req->num_replies < 1) {
245 0 : ret = LDB_ERR_OPERATIONS_ERROR;
246 0 : ildb_request_done(ac, NULL, ret);
247 0 : return;
248 : }
249 :
250 1307245 : switch (req->type) {
251 :
252 86586 : case LDAP_TAG_ModifyRequest:
253 86586 : if (req->replies[0]->type != LDAP_TAG_ModifyResponse) {
254 0 : ret = LDB_ERR_PROTOCOL_ERROR;
255 0 : break;
256 : }
257 86586 : status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult);
258 86586 : ret = ildb_map_error(ac->module, status);
259 86586 : request_done = true;
260 86586 : break;
261 :
262 67711 : case LDAP_TAG_AddRequest:
263 67711 : if (req->replies[0]->type != LDAP_TAG_AddResponse) {
264 750 : ret = LDB_ERR_PROTOCOL_ERROR;
265 0 : return;
266 : }
267 67711 : status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult);
268 67711 : ret = ildb_map_error(ac->module, status);
269 67711 : request_done = true;
270 67711 : break;
271 :
272 75000 : case LDAP_TAG_DelRequest:
273 75000 : if (req->replies[0]->type != LDAP_TAG_DelResponse) {
274 750 : ret = LDB_ERR_PROTOCOL_ERROR;
275 0 : return;
276 : }
277 75000 : status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult);
278 75000 : ret = ildb_map_error(ac->module, status);
279 75000 : request_done = true;
280 75000 : break;
281 :
282 384 : case LDAP_TAG_ModifyDNRequest:
283 384 : if (req->replies[0]->type != LDAP_TAG_ModifyDNResponse) {
284 750 : ret = LDB_ERR_PROTOCOL_ERROR;
285 0 : return;
286 : }
287 384 : status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult);
288 384 : ret = ildb_map_error(ac->module, status);
289 384 : request_done = true;
290 384 : break;
291 :
292 1076714 : case LDAP_TAG_SearchRequest:
293 : /* loop over all messages */
294 1076714 : ret = LDB_SUCCESS;
295 2146202 : for (i = 0; i < req->num_replies; i++) {
296 :
297 1077249 : msg = req->replies[i];
298 1077249 : switch (msg->type) {
299 :
300 337855 : case LDAP_TAG_SearchResultDone:
301 :
302 337855 : status = ldap_check_response(ac->ireq->conn, &msg->r.GeneralResult);
303 337855 : if (!NT_STATUS_IS_OK(status)) {
304 8294 : ret = ildb_map_error(ac->module, status);
305 8294 : break;
306 : }
307 :
308 329561 : controls = talloc_steal(ac, msg->controls);
309 329561 : if (msg->r.SearchResultDone.resultcode) {
310 0 : if (msg->r.SearchResultDone.errormessage) {
311 0 : ldb_set_errstring(ldb, msg->r.SearchResultDone.errormessage);
312 : }
313 : }
314 :
315 329561 : ret = msg->r.SearchResultDone.resultcode;
316 329561 : request_done = true;
317 329561 : break;
318 :
319 606225 : case LDAP_TAG_SearchResultEntry:
320 :
321 606225 : ldbmsg = ldb_msg_new(ac);
322 606225 : if (!ldbmsg) {
323 0 : ret = LDB_ERR_OPERATIONS_ERROR;
324 0 : break;
325 : }
326 :
327 606225 : search = &(msg->r.SearchResultEntry);
328 :
329 606225 : ldbmsg->dn = ldb_dn_new(ldbmsg, ldb, search->dn);
330 606225 : if ( ! ldb_dn_validate(ldbmsg->dn)) {
331 0 : ret = LDB_ERR_OPERATIONS_ERROR;
332 0 : break;
333 : }
334 606225 : ldbmsg->num_elements = search->num_attributes;
335 606225 : ldbmsg->elements = talloc_move(ldbmsg, &search->attributes);
336 :
337 606225 : controls = talloc_steal(ac, msg->controls);
338 :
339 606225 : ret = ldb_module_send_entry(ac->req, ldbmsg, controls);
340 606225 : if (ret != LDB_SUCCESS) {
341 0 : callback_failed = true;
342 : }
343 :
344 605976 : break;
345 :
346 133168 : case LDAP_TAG_SearchResultReference:
347 :
348 133168 : referral = talloc_strdup(ac, msg->r.SearchResultReference.referral);
349 :
350 133168 : ret = ldb_module_send_referral(ac->req, referral);
351 133168 : if (ret != LDB_SUCCESS) {
352 0 : callback_failed = true;
353 : }
354 :
355 133132 : break;
356 :
357 1 : default:
358 : /* TAG not handled, fail ! */
359 1 : ret = LDB_ERR_PROTOCOL_ERROR;
360 1 : break;
361 : }
362 :
363 1077249 : if (ret != LDB_SUCCESS) {
364 8295 : break;
365 : }
366 : }
367 :
368 1077248 : talloc_free(req->replies);
369 1077248 : req->replies = NULL;
370 1077248 : req->num_replies = 0;
371 :
372 1077248 : break;
373 :
374 316 : case LDAP_TAG_ExtendedRequest: {
375 :
376 316 : struct ldap_ExtendedResponse *ext_response = NULL;
377 316 : struct ldb_reply *ares = NULL;
378 :
379 316 : if (req->replies[0]->type != LDAP_TAG_ExtendedResponse) {
380 750 : ret = LDB_ERR_PROTOCOL_ERROR;
381 0 : return;
382 : }
383 316 : ext_response = &req->replies[0]->r.ExtendedResponse;
384 :
385 316 : status = ldap_check_response(ac->ireq->conn,
386 316 : &req->replies[0]->r.GeneralResult);
387 316 : if (!NT_STATUS_IS_OK(status)) {
388 315 : ret = ildb_map_error(ac->module, status);
389 315 : request_done = true;
390 315 : break;
391 : }
392 :
393 1 : ares = talloc_zero(req, struct ldb_reply);
394 1 : if (ares == NULL) {
395 0 : ret = LDB_ERR_OPERATIONS_ERROR;
396 0 : request_done = true;
397 0 : break;
398 : }
399 :
400 1 : ares->type = LDB_REPLY_DONE;
401 :
402 1 : ares->response = talloc_zero(ares, struct ldb_extended);
403 1 : if (ares->response == NULL) {
404 0 : ret = LDB_ERR_OPERATIONS_ERROR;
405 0 : request_done = true;
406 0 : break;
407 : }
408 :
409 2 : ares->response->oid =
410 1 : talloc_strdup(ares->response, ext_response->oid);
411 1 : if (ares->response->oid == NULL) {
412 0 : ret = LDB_ERR_OPERATIONS_ERROR;
413 0 : request_done = true;
414 0 : break;
415 : }
416 :
417 1 : if (ext_response->value != NULL) {
418 2 : ares->response->data =
419 1 : talloc_memdup(ares->response,
420 : ext_response->value->data,
421 : ext_response->value->length);
422 1 : if (ares->response->data == NULL) {
423 0 : ret = LDB_ERR_OPERATIONS_ERROR;
424 0 : request_done = true;
425 0 : break;
426 : }
427 : }
428 :
429 1 : ares->controls = talloc_move(ares, &req->replies[0]->controls);
430 :
431 1 : ac->req->callback(ac->req, ares);
432 1 : return;
433 : }
434 :
435 0 : default:
436 0 : ret = LDB_ERR_PROTOCOL_ERROR;
437 0 : break;
438 : }
439 :
440 1307244 : if (ret != LDB_SUCCESS) {
441 :
442 : /* if the callback failed the caller will have freed the
443 : * request. Just return and don't try to use it */
444 51679 : if ( ! callback_failed) {
445 51679 : request_done = true;
446 : }
447 : }
448 :
449 : /* mark the request as not being in progress */
450 1307244 : ac->in_ildb_callback = false;
451 :
452 1307244 : if (request_done) {
453 567852 : ildb_request_done(ac, controls, ret);
454 : }
455 :
456 1306494 : return;
457 : }
458 :
459 567932 : static int ildb_request_send(struct ildb_context *ac, struct ldap_message *msg)
460 : {
461 465 : struct ldb_context *ldb;
462 465 : struct ldap_request *req;
463 :
464 567932 : if (!ac) {
465 0 : return LDB_ERR_OPERATIONS_ERROR;
466 : }
467 :
468 567932 : ldb = ldb_module_get_ctx(ac->module);
469 :
470 567932 : ldb_request_set_state(ac->req, LDB_ASYNC_PENDING);
471 :
472 567932 : req = ldap_request_send(ac->ildb->ldap, msg);
473 567932 : if (req == NULL) {
474 0 : ldb_set_errstring(ldb, "async send request failed");
475 0 : return LDB_ERR_OPERATIONS_ERROR;
476 : }
477 567932 : ac->ireq = talloc_reparent(ac->ildb->ldap, ac, req);
478 :
479 567932 : if (!ac->ireq->conn) {
480 0 : ldb_set_errstring(ldb, "connection to remote LDAP server dropped?");
481 0 : return LDB_ERR_OPERATIONS_ERROR;
482 : }
483 :
484 567932 : TALLOC_FREE(req->time_event);
485 567932 : if (ac->req->timeout > 0) {
486 567867 : struct timeval tv = {
487 567867 : .tv_sec = ac->req->starttime + ac->req->timeout,
488 : };
489 :
490 567867 : req->time_event = tevent_add_timer(ac->ildb->event_ctx, ac, tv,
491 : ildb_request_timeout, ac);
492 : }
493 :
494 567932 : req->async.fn = ildb_callback;
495 567932 : req->async.private_data = ac;
496 :
497 567932 : return LDB_SUCCESS;
498 : }
499 :
500 : /*
501 : search for matching records using an asynchronous function
502 : */
503 337935 : static int ildb_search(struct ildb_context *ac)
504 : {
505 249 : struct ldb_context *ldb;
506 337935 : struct ldb_request *req = ac->req;
507 249 : struct ldap_message *msg;
508 249 : int n;
509 :
510 337935 : ldb = ldb_module_get_ctx(ac->module);
511 :
512 337935 : if (!req->callback || !req->context) {
513 0 : ldb_set_errstring(ldb, "Async interface called with NULL callback function or NULL context");
514 0 : return LDB_ERR_OPERATIONS_ERROR;
515 : }
516 :
517 337935 : if (req->op.search.tree == NULL) {
518 0 : ldb_set_errstring(ldb, "Invalid expression parse tree");
519 0 : return LDB_ERR_OPERATIONS_ERROR;
520 : }
521 :
522 337935 : msg = new_ldap_message(req);
523 337935 : if (msg == NULL) {
524 0 : ldb_set_errstring(ldb, "Out of Memory");
525 0 : return LDB_ERR_OPERATIONS_ERROR;
526 : }
527 :
528 337935 : msg->type = LDAP_TAG_SearchRequest;
529 :
530 337935 : if (req->op.search.base == NULL) {
531 0 : msg->r.SearchRequest.basedn = talloc_strdup(msg, "");
532 : } else {
533 337935 : msg->r.SearchRequest.basedn = ldb_dn_get_extended_linearized(msg, req->op.search.base, 0);
534 : }
535 337935 : if (msg->r.SearchRequest.basedn == NULL) {
536 0 : ldb_set_errstring(ldb, "Unable to determine baseDN");
537 0 : talloc_free(msg);
538 0 : return LDB_ERR_OPERATIONS_ERROR;
539 : }
540 :
541 337935 : switch (req->op.search.scope) {
542 88220 : case LDB_SCOPE_DEFAULT:
543 : case LDB_SCOPE_SUBTREE:
544 88220 : msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_SUB;
545 88220 : break;
546 171420 : case LDB_SCOPE_BASE:
547 171420 : msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
548 171420 : break;
549 78295 : case LDB_SCOPE_ONELEVEL:
550 78295 : msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_SINGLE;
551 78295 : break;
552 : }
553 :
554 337935 : msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
555 337935 : msg->r.SearchRequest.timelimit = 0;
556 337935 : msg->r.SearchRequest.sizelimit = 0;
557 337935 : msg->r.SearchRequest.attributesonly = 0;
558 337935 : msg->r.SearchRequest.tree = discard_const(req->op.search.tree);
559 :
560 931988 : for (n = 0; req->op.search.attrs && req->op.search.attrs[n]; n++) /* noop */ ;
561 337935 : msg->r.SearchRequest.num_attributes = n;
562 337935 : msg->r.SearchRequest.attributes = req->op.search.attrs;
563 337935 : msg->controls = req->controls;
564 :
565 337935 : return ildb_request_send(ac, msg);
566 : }
567 :
568 : /*
569 : add a record
570 : */
571 67711 : static int ildb_add(struct ildb_context *ac)
572 : {
573 67711 : struct ldb_request *req = ac->req;
574 36 : struct ldap_message *msg;
575 36 : struct ldap_mod **mods;
576 36 : unsigned int i,n;
577 :
578 67711 : msg = new_ldap_message(req);
579 67711 : if (msg == NULL) {
580 0 : return LDB_ERR_OPERATIONS_ERROR;
581 : }
582 :
583 67711 : msg->type = LDAP_TAG_AddRequest;
584 :
585 67711 : msg->r.AddRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.add.message->dn, 0);
586 67711 : if (msg->r.AddRequest.dn == NULL) {
587 0 : talloc_free(msg);
588 0 : return LDB_ERR_INVALID_DN_SYNTAX;
589 : }
590 :
591 67711 : mods = ildb_msg_to_mods(msg, &n, req->op.add.message, 0);
592 67711 : if (mods == NULL) {
593 0 : talloc_free(msg);
594 0 : return LDB_ERR_OPERATIONS_ERROR;
595 : }
596 :
597 67711 : msg->r.AddRequest.num_attributes = n;
598 67711 : msg->r.AddRequest.attributes = talloc_array(msg, struct ldb_message_element, n);
599 67711 : if (msg->r.AddRequest.attributes == NULL) {
600 0 : talloc_free(msg);
601 0 : return LDB_ERR_OPERATIONS_ERROR;
602 : }
603 :
604 253890 : for (i = 0; i < n; i++) {
605 186179 : msg->r.AddRequest.attributes[i] = mods[i]->attrib;
606 : }
607 67711 : msg->controls = req->controls;
608 :
609 67711 : return ildb_request_send(ac, msg);
610 : }
611 :
612 : /*
613 : modify a record
614 : */
615 86586 : static int ildb_modify(struct ildb_context *ac)
616 : {
617 86586 : struct ldb_request *req = ac->req;
618 144 : struct ldap_message *msg;
619 144 : struct ldap_mod **mods;
620 144 : unsigned int i,n;
621 :
622 86586 : msg = new_ldap_message(req);
623 86586 : if (msg == NULL) {
624 0 : return LDB_ERR_OPERATIONS_ERROR;
625 : }
626 :
627 86586 : msg->type = LDAP_TAG_ModifyRequest;
628 :
629 86586 : msg->r.ModifyRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.mod.message->dn, 0);
630 86586 : if (msg->r.ModifyRequest.dn == NULL) {
631 0 : talloc_free(msg);
632 0 : return LDB_ERR_INVALID_DN_SYNTAX;
633 : }
634 :
635 86586 : mods = ildb_msg_to_mods(msg, &n, req->op.mod.message, 1);
636 86586 : if (mods == NULL) {
637 0 : talloc_free(msg);
638 0 : return LDB_ERR_OPERATIONS_ERROR;
639 : }
640 :
641 86586 : msg->r.ModifyRequest.num_mods = n;
642 86586 : msg->r.ModifyRequest.mods = talloc_array(msg, struct ldap_mod, n);
643 86586 : if (msg->r.ModifyRequest.mods == NULL) {
644 0 : talloc_free(msg);
645 0 : return LDB_ERR_OPERATIONS_ERROR;
646 : }
647 :
648 199821 : for (i = 0; i < n; i++) {
649 113235 : msg->r.ModifyRequest.mods[i] = *mods[i];
650 : }
651 86586 : msg->controls = req->controls;
652 86586 : return ildb_request_send(ac, msg);
653 : }
654 :
655 : /*
656 : delete a record
657 : */
658 75000 : static int ildb_delete(struct ildb_context *ac)
659 : {
660 75000 : struct ldb_request *req = ac->req;
661 36 : struct ldap_message *msg;
662 :
663 75000 : msg = new_ldap_message(req);
664 75000 : if (msg == NULL) {
665 0 : return LDB_ERR_OPERATIONS_ERROR;
666 : }
667 :
668 75000 : msg->type = LDAP_TAG_DelRequest;
669 :
670 75000 : msg->r.DelRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.del.dn, 0);
671 75000 : if (msg->r.DelRequest.dn == NULL) {
672 0 : talloc_free(msg);
673 0 : return LDB_ERR_INVALID_DN_SYNTAX;
674 : }
675 75000 : msg->controls = req->controls;
676 :
677 75000 : return ildb_request_send(ac, msg);
678 : }
679 :
680 : /*
681 : rename a record
682 : */
683 384 : static int ildb_rename(struct ildb_context *ac)
684 : {
685 384 : struct ldb_request *req = ac->req;
686 0 : struct ldap_message *msg;
687 0 : const char *rdn_name;
688 0 : const struct ldb_val *rdn_val;
689 :
690 384 : msg = new_ldap_message(req);
691 384 : if (msg == NULL) {
692 0 : return LDB_ERR_OPERATIONS_ERROR;
693 : }
694 :
695 384 : msg->type = LDAP_TAG_ModifyDNRequest;
696 384 : msg->r.ModifyDNRequest.dn = ldb_dn_get_extended_linearized(msg, req->op.rename.olddn, 0);
697 384 : if (msg->r.ModifyDNRequest.dn == NULL) {
698 0 : talloc_free(msg);
699 0 : return LDB_ERR_INVALID_DN_SYNTAX;
700 : }
701 :
702 384 : rdn_name = ldb_dn_get_rdn_name(req->op.rename.newdn);
703 384 : rdn_val = ldb_dn_get_rdn_val(req->op.rename.newdn);
704 :
705 384 : if ((rdn_name != NULL) && (rdn_val != NULL)) {
706 384 : msg->r.ModifyDNRequest.newrdn =
707 384 : talloc_asprintf(msg, "%s=%s", rdn_name,
708 384 : rdn_val->length > 0 ? ldb_dn_escape_value(msg, *rdn_val) : "");
709 : } else {
710 0 : msg->r.ModifyDNRequest.newrdn = talloc_strdup(msg, "");
711 : }
712 384 : if (msg->r.ModifyDNRequest.newrdn == NULL) {
713 0 : talloc_free(msg);
714 0 : return LDB_ERR_OPERATIONS_ERROR;
715 : }
716 :
717 384 : msg->r.ModifyDNRequest.newsuperior =
718 384 : ldb_dn_alloc_linearized(msg, ldb_dn_get_parent(msg, req->op.rename.newdn));
719 384 : if (msg->r.ModifyDNRequest.newsuperior == NULL) {
720 0 : talloc_free(msg);
721 0 : return LDB_ERR_INVALID_DN_SYNTAX;
722 : }
723 :
724 384 : msg->r.ModifyDNRequest.deleteolddn = true;
725 384 : msg->controls = req->controls;
726 :
727 384 : return ildb_request_send(ac, msg);
728 : }
729 :
730 : /*
731 : * Issue an extended operation
732 : */
733 316 : static int ildb_extended(struct ildb_context *ac)
734 : {
735 316 : struct ldb_request *req = ac->req;
736 316 : struct ldb_extended *extended_req = NULL;
737 316 : struct ldap_message *msg = NULL;
738 316 : DATA_BLOB *value = NULL;
739 :
740 316 : if (req->operation != LDB_EXTENDED) {
741 0 : return LDB_ERR_OPERATIONS_ERROR;
742 : }
743 316 : extended_req = &req->op.extended;
744 :
745 316 : msg = new_ldap_message(req);
746 316 : if (msg == NULL) {
747 0 : goto nomem;
748 : }
749 :
750 316 : if (extended_req->data != NULL) {
751 315 : value = talloc(req, DATA_BLOB);
752 315 : if (value == NULL) {
753 0 : goto nomem;
754 : }
755 315 : *value = data_blob_talloc(value,
756 : extended_req->data,
757 : talloc_get_size(extended_req->data));
758 315 : if (value->data == NULL) {
759 0 : goto nomem;
760 : }
761 : }
762 :
763 316 : *msg = (struct ldap_message){
764 : .type = LDAP_TAG_ExtendedRequest,
765 316 : .r.ExtendedRequest.oid = extended_req->oid,
766 : .r.ExtendedRequest.value = value,
767 316 : .controls = req->controls,
768 : };
769 :
770 316 : return ildb_request_send(ac, msg);
771 0 : nomem:
772 0 : TALLOC_FREE(msg);
773 0 : return LDB_ERR_OPERATIONS_ERROR;
774 : }
775 :
776 197141 : static int ildb_start_trans(struct ldb_module *module)
777 : {
778 : /* TODO implement a local locking mechanism here */
779 :
780 197141 : return LDB_SUCCESS;
781 : }
782 :
783 154188 : static int ildb_end_trans(struct ldb_module *module)
784 : {
785 : /* TODO implement a local transaction mechanism here */
786 :
787 154188 : return LDB_SUCCESS;
788 : }
789 :
790 42951 : static int ildb_del_trans(struct ldb_module *module)
791 : {
792 : /* TODO implement a local locking mechanism here */
793 :
794 42951 : return LDB_SUCCESS;
795 : }
796 :
797 567956 : static bool ildb_dn_is_special(struct ldb_request *req)
798 : {
799 567956 : struct ldb_dn *dn = NULL;
800 :
801 567956 : switch (req->operation) {
802 337947 : case LDB_SEARCH:
803 337947 : dn = req->op.search.base;
804 337947 : break;
805 67723 : case LDB_ADD:
806 67723 : dn = req->op.add.message->dn;
807 67723 : break;
808 86586 : case LDB_MODIFY:
809 86586 : dn = req->op.mod.message->dn;
810 86586 : break;
811 75000 : case LDB_DELETE:
812 75000 : dn = req->op.del.dn;
813 75000 : break;
814 384 : case LDB_RENAME:
815 384 : dn = req->op.rename.olddn;
816 384 : break;
817 316 : default:
818 316 : break;
819 : }
820 :
821 567956 : if (dn && ldb_dn_is_special(dn)) {
822 24 : return true;
823 : }
824 567467 : return false;
825 : }
826 :
827 567956 : static int ildb_handle_request(struct ldb_module *module, struct ldb_request *req)
828 : {
829 465 : struct ldb_context *ldb;
830 465 : struct ildb_private *ildb;
831 465 : struct ildb_context *ac;
832 465 : struct tevent_timer *te;
833 465 : int ret;
834 :
835 567956 : ildb = talloc_get_type(ldb_module_get_private(module), struct ildb_private);
836 567956 : ldb = ldb_module_get_ctx(module);
837 :
838 567956 : if (req->starttime == 0 || req->timeout == 0) {
839 0 : ldb_set_errstring(ldb, "Invalid timeout settings");
840 0 : return LDB_ERR_TIME_LIMIT_EXCEEDED;
841 : }
842 :
843 567956 : ac = talloc_zero(req, struct ildb_context);
844 567956 : if (ac == NULL) {
845 0 : ldb_set_errstring(ldb, "Out of Memory");
846 0 : return LDB_ERR_OPERATIONS_ERROR;
847 : }
848 :
849 567956 : ac->module = module;
850 567956 : ac->req = req;
851 567956 : ac->ildb = ildb;
852 :
853 567956 : if (ildb_dn_is_special(req)) {
854 :
855 24 : te = tevent_add_timer(ac->ildb->event_ctx,
856 : ac, timeval_zero(),
857 : ildb_auto_done_callback, ac);
858 24 : if (NULL == te) {
859 0 : return LDB_ERR_OPERATIONS_ERROR;
860 : }
861 :
862 24 : return LDB_SUCCESS;
863 : }
864 :
865 567932 : switch (ac->req->operation) {
866 337935 : case LDB_SEARCH:
867 337935 : ret = ildb_search(ac);
868 337935 : break;
869 67711 : case LDB_ADD:
870 67711 : ret = ildb_add(ac);
871 67711 : break;
872 86586 : case LDB_MODIFY:
873 86586 : ret = ildb_modify(ac);
874 86586 : break;
875 75000 : case LDB_DELETE:
876 75000 : ret = ildb_delete(ac);
877 75000 : break;
878 384 : case LDB_RENAME:
879 384 : ret = ildb_rename(ac);
880 384 : break;
881 316 : case LDB_EXTENDED:
882 316 : ret = ildb_extended(ac);
883 316 : break;
884 0 : default:
885 : /* no other op supported */
886 0 : ret = LDB_ERR_PROTOCOL_ERROR;
887 0 : break;
888 : }
889 :
890 567467 : return ret;
891 : }
892 :
893 : static const struct ldb_module_ops ildb_ops = {
894 : .name = "ldap",
895 : .search = ildb_handle_request,
896 : .add = ildb_handle_request,
897 : .modify = ildb_handle_request,
898 : .del = ildb_handle_request,
899 : .rename = ildb_handle_request,
900 : .extended = ildb_handle_request,
901 : /* .request = ildb_handle_request, */
902 : .start_transaction = ildb_start_trans,
903 : .end_transaction = ildb_end_trans,
904 : .del_transaction = ildb_del_trans,
905 : };
906 :
907 : /*
908 : connect to the database
909 : */
910 26714 : static int ildb_connect(struct ldb_context *ldb, const char *url,
911 : unsigned int flags, const char *options[],
912 : struct ldb_module **_module)
913 : {
914 122 : struct ldb_module *module;
915 122 : struct ildb_private *ildb;
916 26714 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
917 122 : struct cli_credentials *creds;
918 122 : struct loadparm_context *lp_ctx;
919 :
920 26714 : module = ldb_module_new(ldb, ldb, "ldb_ildap backend", &ildb_ops);
921 26714 : if (!module) return LDB_ERR_OPERATIONS_ERROR;
922 :
923 26714 : ildb = talloc(module, struct ildb_private);
924 26714 : if (!ildb) {
925 0 : ldb_oom(ldb);
926 0 : goto failed;
927 : }
928 26714 : ldb_module_set_private(module, ildb);
929 :
930 26714 : ildb->event_ctx = ldb_get_event_context(ldb);
931 :
932 26714 : lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
933 : struct loadparm_context);
934 :
935 26714 : ildb->ldap = ldap4_new_connection(ildb, lp_ctx,
936 : ildb->event_ctx);
937 26714 : if (!ildb->ldap) {
938 0 : ldb_oom(ldb);
939 0 : goto failed;
940 : }
941 :
942 26714 : if (flags & LDB_FLG_RECONNECT) {
943 0 : ldap_set_reconn_params(ildb->ldap, 10);
944 : }
945 :
946 26714 : status = ldap_connect(ildb->ldap, url);
947 26714 : if (!NT_STATUS_IS_OK(status)) {
948 19 : ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to ldap URL '%s' - %s",
949 : url, ldap_errstr(ildb->ldap, module, status));
950 19 : goto failed;
951 : }
952 :
953 : /* caller can optionally setup credentials using the opaque token 'credentials' */
954 26695 : creds = talloc_get_type(ldb_get_opaque(ldb, "credentials"), struct cli_credentials);
955 26695 : if (creds == NULL) {
956 11 : struct auth_session_info *session_info = talloc_get_type(
957 : ldb_get_opaque(ldb, DSDB_SESSION_INFO),
958 : struct auth_session_info);
959 11 : if (session_info) {
960 8 : creds = session_info->credentials;
961 : }
962 : }
963 :
964 26695 : if (creds != NULL && cli_credentials_authentication_requested(creds)) {
965 26543 : const char *bind_dn = cli_credentials_get_bind_dn(creds);
966 26543 : if (bind_dn) {
967 442 : const char *password = cli_credentials_get_password(creds);
968 442 : status = ldap_bind_simple(ildb->ldap, bind_dn, password);
969 442 : if (!NT_STATUS_IS_OK(status)) {
970 124 : ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s",
971 : ldap_errstr(ildb->ldap, module, status));
972 124 : goto failed;
973 : }
974 : } else {
975 26101 : status = ldap_bind_sasl(ildb->ldap, creds, lp_ctx);
976 26101 : if (!NT_STATUS_IS_OK(status)) {
977 471 : ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s",
978 : ldap_errstr(ildb->ldap, module, status));
979 471 : goto failed;
980 : }
981 : }
982 : }
983 :
984 26100 : *_module = module;
985 26100 : return LDB_SUCCESS;
986 :
987 614 : failed:
988 614 : if (ildb != NULL && ildb->ldap != NULL) {
989 614 : ldb_set_errstring(ldb, ldap_errstr(ildb->ldap, module, status));
990 : }
991 614 : talloc_free(module);
992 614 : if (NT_STATUS_IS_LDAP(status)) {
993 323 : return NT_STATUS_LDAP_CODE(status);
994 : }
995 291 : if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)
996 291 : || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
997 291 : || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
998 136 : || NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
999 176 : return LDB_ERR_INVALID_CREDENTIALS;
1000 : }
1001 115 : return LDB_ERR_OPERATIONS_ERROR;
1002 : }
1003 :
1004 : /*
1005 : initialise the module
1006 : */
1007 6091 : _PUBLIC_ int ldb_ildap_init(const char *ldb_version)
1008 : {
1009 444 : int ret, i;
1010 6091 : const char *names[] = { "ldap", "ldaps", "ldapi", NULL };
1011 24364 : for (i=0; names[i]; i++) {
1012 18273 : ret = ldb_register_backend(names[i], ildb_connect, true);
1013 18273 : if (ret != LDB_SUCCESS) {
1014 0 : return ret;
1015 : }
1016 : }
1017 5647 : return LDB_SUCCESS;
1018 : }
|