Fix bug #9147 - winbind can't fetch user or group info from AD via LDAP
[Samba.git] / source3 / lib / ldb / modules / ldb_map_inbound.c
blob0508e724ab081e8a427e2dcbdb22975d4991e4f3
1 /*
2 ldb database mapping module
4 Copyright (C) Jelmer Vernooij 2005
5 Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
7 * NOTICE: this module is NOT released under the GNU LGPL license as
8 * other ldb code. This module is release under the GNU GPL v2 or
9 * later license.
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program 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
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "ldb/include/includes.h"
28 #include "ldb/modules/ldb_map.h"
29 #include "ldb/modules/ldb_map_private.h"
32 /* Mapping message elements
33 * ======================== */
35 /* Map a message element into the remote partition. */
36 static struct ldb_message_element *ldb_msg_el_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_message_element *old)
38 struct ldb_message_element *el;
39 int i;
41 el = talloc_zero(mem_ctx, struct ldb_message_element);
42 if (el == NULL) {
43 map_oom(module);
44 return NULL;
47 el->num_values = old->num_values;
48 el->values = talloc_array(el, struct ldb_val, el->num_values);
49 if (el->values == NULL) {
50 talloc_free(el);
51 map_oom(module);
52 return NULL;
55 el->name = map_attr_map_local(el, map, old->name);
57 for (i = 0; i < el->num_values; i++) {
58 el->values[i] = ldb_val_map_local(module, el->values, map, &old->values[i]);
61 return el;
64 /* Add a message element either to a local or to a remote message,
65 * depending on whether it goes into the local or remote partition. */
66 static int ldb_msg_el_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg, const char *attr_name, /* const char * const names[], */ const struct ldb_message_element *old)
68 const struct ldb_map_context *data = map_get_context(module);
69 const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name);
70 struct ldb_message_element *el=NULL;
72 /* Unknown attribute: ignore */
73 if (map == NULL) {
74 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
75 "Not mapping attribute '%s': no mapping found\n",
76 old->name);
77 goto local;
80 switch (map->type) {
81 case MAP_IGNORE:
82 goto local;
84 case MAP_CONVERT:
85 if (map->u.convert.convert_local == NULL) {
86 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
87 "Not mapping attribute '%s': "
88 "'convert_local' not set\n",
89 map->local_name);
90 goto local;
92 /* fall through */
93 case MAP_KEEP:
94 case MAP_RENAME:
95 el = ldb_msg_el_map_local(module, remote, map, old);
96 break;
98 case MAP_GENERATE:
99 if (map->u.generate.generate_remote == NULL) {
100 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
101 "Not mapping attribute '%s': "
102 "'generate_remote' not set\n",
103 map->local_name);
104 goto local;
107 /* TODO: if this attr requires context:
108 * make sure all context attrs are mappable (in 'names')
109 * make sure all context attrs have already been mapped?
110 * maybe postpone generation until they have been mapped?
113 map->u.generate.generate_remote(module, map->local_name, msg, remote, local);
114 return 0;
117 if (el == NULL) {
118 return -1;
121 return ldb_msg_add(remote, el, old->flags);
123 local:
124 el = talloc(local, struct ldb_message_element);
125 if (el == NULL) {
126 map_oom(module);
127 return -1;
130 *el = *old; /* copy the old element */
132 return ldb_msg_add(local, el, old->flags);
135 /* Mapping messages
136 * ================ */
138 /* Check whether a message will be (partially) mapped into the remote partition. */
139 static BOOL ldb_msg_check_remote(struct ldb_module *module, const struct ldb_message *msg)
141 const struct ldb_map_context *data = map_get_context(module);
142 BOOL ret;
143 int i;
145 for (i = 0; i < msg->num_elements; i++) {
146 ret = map_attr_check_remote(data, msg->elements[i].name);
147 if (ret) {
148 return ret;
152 return False;
155 /* Split message elements that stay in the local partition from those
156 * that are mapped into the remote partition. */
157 static int ldb_msg_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg)
159 /* const char * const names[]; */
160 int i, ret;
162 for (i = 0; i < msg->num_elements; i++) {
163 /* Skip 'IS_MAPPED' */
164 if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) {
165 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
166 "Skipping attribute '%s'\n",
167 msg->elements[i].name);
168 continue;
171 ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
172 if (ret) {
173 return ret;
177 return 0;
181 /* Inbound requests: add, modify, rename, delete
182 * ============================================= */
184 /* Add the remote record. */
185 int map_add_do_remote(struct ldb_handle *handle)
187 struct map_context *ac;
189 ac = talloc_get_type(handle->private_data, struct map_context);
191 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
193 ac->step = MAP_ADD_REMOTE;
195 handle->state = LDB_ASYNC_INIT;
196 handle->status = LDB_SUCCESS;
198 return ldb_next_remote_request(ac->module, ac->remote_req);
201 /* Add the local record. */
202 int map_add_do_local(struct ldb_handle *handle)
204 struct map_context *ac;
206 ac = talloc_get_type(handle->private_data, struct map_context);
208 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
210 ac->step = MAP_ADD_LOCAL;
212 handle->state = LDB_ASYNC_INIT;
213 handle->status = LDB_SUCCESS;
215 return ldb_next_request(ac->module, ac->local_req);
218 /* Add a record. */
219 int map_add(struct ldb_module *module, struct ldb_request *req)
221 const struct ldb_message *msg = req->op.add.message;
222 struct ldb_handle *h;
223 struct map_context *ac;
224 struct ldb_message *local, *remote;
225 const char *dn;
227 /* Do not manipulate our control entries */
228 if (ldb_dn_is_special(msg->dn)) {
229 return ldb_next_request(module, req);
232 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
233 if (!ldb_dn_check_local(module, msg->dn)) {
234 return ldb_next_request(module, req);
237 /* No mapping needed, fail */
238 if (!ldb_msg_check_remote(module, msg)) {
239 return LDB_ERR_OPERATIONS_ERROR;
242 /* Prepare context and handle */
243 h = map_init_handle(req, module);
244 if (h == NULL) {
245 return LDB_ERR_OPERATIONS_ERROR;
247 ac = talloc_get_type(h->private_data, struct map_context);
249 /* Prepare the local operation */
250 ac->local_req = talloc(ac, struct ldb_request);
251 if (ac->local_req == NULL) {
252 goto oom;
255 *(ac->local_req) = *req; /* copy the request */
257 ac->local_req->context = NULL;
258 ac->local_req->callback = NULL;
260 /* Prepare the remote operation */
261 ac->remote_req = talloc(ac, struct ldb_request);
262 if (ac->remote_req == NULL) {
263 goto oom;
266 *(ac->remote_req) = *req; /* copy the request */
268 ac->remote_req->context = NULL;
269 ac->remote_req->callback = NULL;
271 /* Prepare the local message */
272 local = ldb_msg_new(ac->local_req);
273 if (local == NULL) {
274 goto oom;
276 local->dn = msg->dn;
278 /* Prepare the remote message */
279 remote = ldb_msg_new(ac->remote_req);
280 if (remote == NULL) {
281 goto oom;
283 remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
285 /* Split local from remote message */
286 ldb_msg_partition(module, local, remote, msg);
287 ac->local_req->op.add.message = local;
288 ac->remote_req->op.add.message = remote;
290 if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
291 /* No local data or db, just run the remote request */
292 talloc_free(ac->local_req);
293 req->handle = h; /* return our own handle to deal with this call */
294 return map_add_do_remote(h);
297 /* Store remote DN in 'IS_MAPPED' */
298 /* TODO: use GUIDs here instead */
299 dn = ldb_dn_linearize(local, remote->dn);
300 if (ldb_msg_add_string(local, IS_MAPPED, dn) != 0) {
301 goto failed;
304 req->handle = h; /* return our own handle to deal with this call */
305 return map_add_do_local(h);
307 oom:
308 map_oom(module);
309 failed:
310 talloc_free(h);
311 return LDB_ERR_OPERATIONS_ERROR;
314 /* Modify the remote record. */
315 int map_modify_do_remote(struct ldb_handle *handle)
317 struct map_context *ac;
319 ac = talloc_get_type(handle->private_data, struct map_context);
321 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
323 ac->step = MAP_MODIFY_REMOTE;
325 handle->state = LDB_ASYNC_INIT;
326 handle->status = LDB_SUCCESS;
328 return ldb_next_remote_request(ac->module, ac->remote_req);
331 /* Modify the local record. */
332 int map_modify_do_local(struct ldb_handle *handle)
334 struct map_context *ac;
335 struct ldb_message *msg;
336 char *dn;
338 ac = talloc_get_type(handle->private_data, struct map_context);
340 if (ac->local_dn == NULL) {
341 /* No local record present, add it instead */
342 msg = discard_const_p(struct ldb_message, ac->local_req->op.mod.message);
344 /* Add local 'IS_MAPPED' */
345 /* TODO: use GUIDs here instead */
346 dn = ldb_dn_linearize(msg, ac->remote_req->op.mod.message->dn);
347 if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_ADD, NULL) != 0) {
348 return LDB_ERR_OPERATIONS_ERROR;
350 if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
351 return LDB_ERR_OPERATIONS_ERROR;
354 /* Turn request into 'add' */
355 ac->local_req->operation = LDB_ADD;
356 ac->local_req->op.add.message = msg;
357 /* TODO: Could I just leave msg in there? I think so,
358 * but it looks clearer this way. */
361 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
363 ac->step = MAP_MODIFY_LOCAL;
365 handle->state = LDB_ASYNC_INIT;
366 handle->status = LDB_SUCCESS;
368 return ldb_next_request(ac->module, ac->local_req);
371 /* Modify a record. */
372 int map_modify(struct ldb_module *module, struct ldb_request *req)
374 const struct ldb_message *msg = req->op.mod.message;
375 struct ldb_handle *h;
376 struct map_context *ac;
377 struct ldb_message *local, *remote;
379 /* Do not manipulate our control entries */
380 if (ldb_dn_is_special(msg->dn)) {
381 return ldb_next_request(module, req);
384 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
385 if (!ldb_dn_check_local(module, msg->dn)) {
386 return ldb_next_request(module, req);
389 /* No mapping needed, skip to next module */
390 /* TODO: What if the remote part exists, the local doesn't,
391 * and this request wants to modify local data and thus
392 * add the local record? */
393 if (!ldb_msg_check_remote(module, msg)) {
394 return LDB_ERR_OPERATIONS_ERROR;
397 /* Prepare context and handle */
398 h = map_init_handle(req, module);
399 if (h == NULL) {
400 return LDB_ERR_OPERATIONS_ERROR;
402 ac = talloc_get_type(h->private_data, struct map_context);
404 /* Prepare the local operation */
405 ac->local_req = talloc(ac, struct ldb_request);
406 if (ac->local_req == NULL) {
407 goto oom;
410 *(ac->local_req) = *req; /* copy the request */
412 ac->local_req->context = NULL;
413 ac->local_req->callback = NULL;
415 /* Prepare the remote operation */
416 ac->remote_req = talloc(ac, struct ldb_request);
417 if (ac->remote_req == NULL) {
418 goto oom;
421 *(ac->remote_req) = *req; /* copy the request */
423 ac->remote_req->context = NULL;
424 ac->remote_req->callback = NULL;
426 /* Prepare the local message */
427 local = ldb_msg_new(ac->local_req);
428 if (local == NULL) {
429 goto oom;
431 local->dn = msg->dn;
433 /* Prepare the remote message */
434 remote = ldb_msg_new(ac->remote_req);
435 if (remote == NULL) {
436 goto oom;
438 remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
440 /* Split local from remote message */
441 ldb_msg_partition(module, local, remote, msg);
442 ac->local_req->op.mod.message = local;
443 ac->remote_req->op.mod.message = remote;
445 if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
446 /* No local data or db, just run the remote request */
447 talloc_free(ac->local_req);
448 req->handle = h; /* return our own handle to deal with this call */
449 return map_modify_do_remote(h);
452 /* prepare the search operation */
453 ac->search_req = map_search_self_req(ac, msg->dn);
454 if (ac->search_req == NULL) {
455 goto failed;
458 ac->step = MAP_SEARCH_SELF_MODIFY;
460 req->handle = h; /* return our own handle to deal with this call */
461 return ldb_next_request(module, ac->search_req);
463 oom:
464 map_oom(module);
465 failed:
466 talloc_free(h);
467 return LDB_ERR_OPERATIONS_ERROR;
470 /* Delete the remote record. */
471 int map_delete_do_remote(struct ldb_handle *handle)
473 struct map_context *ac;
475 ac = talloc_get_type(handle->private_data, struct map_context);
477 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
479 ac->step = MAP_DELETE_REMOTE;
481 handle->state = LDB_ASYNC_INIT;
482 handle->status = LDB_SUCCESS;
484 return ldb_next_remote_request(ac->module, ac->remote_req);
487 /* Delete the local record. */
488 int map_delete_do_local(struct ldb_handle *handle)
490 struct map_context *ac;
492 ac = talloc_get_type(handle->private_data, struct map_context);
494 /* No local record, continue remotely */
495 if (ac->local_dn == NULL) {
496 return map_delete_do_remote(handle);
499 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
501 ac->step = MAP_DELETE_LOCAL;
503 handle->state = LDB_ASYNC_INIT;
504 handle->status = LDB_SUCCESS;
506 return ldb_next_request(ac->module, ac->local_req);
509 /* Delete a record. */
510 int map_delete(struct ldb_module *module, struct ldb_request *req)
512 struct ldb_handle *h;
513 struct map_context *ac;
515 /* Do not manipulate our control entries */
516 if (ldb_dn_is_special(req->op.del.dn)) {
517 return ldb_next_request(module, req);
520 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
521 if (!ldb_dn_check_local(module, req->op.del.dn)) {
522 return ldb_next_request(module, req);
525 /* Prepare context and handle */
526 h = map_init_handle(req, module);
527 if (h == NULL) {
528 return LDB_ERR_OPERATIONS_ERROR;
530 ac = talloc_get_type(h->private_data, struct map_context);
532 /* Prepare the local operation */
533 ac->local_req = talloc(ac, struct ldb_request);
534 if (ac->local_req == NULL) {
535 goto oom;
538 *(ac->local_req) = *req; /* copy the request */
539 ac->local_req->op.del.dn = req->op.del.dn;
541 ac->local_req->context = NULL;
542 ac->local_req->callback = NULL;
544 /* Prepare the remote operation */
545 ac->remote_req = talloc(ac, struct ldb_request);
546 if (ac->remote_req == NULL) {
547 goto oom;
550 *(ac->remote_req) = *req; /* copy the request */
551 ac->remote_req->op.del.dn = ldb_dn_map_local(module, ac->remote_req, req->op.del.dn);
553 /* No local db, just run the remote request */
554 if (!map_check_local_db(ac->module)) {
555 req->handle = h; /* return our own handle to deal with this call */
556 return map_delete_do_remote(h);
559 ac->remote_req->context = NULL;
560 ac->remote_req->callback = NULL;
562 /* Prepare the search operation */
563 ac->search_req = map_search_self_req(ac, req->op.del.dn);
564 if (ac->search_req == NULL) {
565 goto failed;
568 req->handle = h; /* return our own handle to deal with this call */
570 ac->step = MAP_SEARCH_SELF_DELETE;
572 return ldb_next_request(module, ac->search_req);
574 oom:
575 map_oom(module);
576 failed:
577 talloc_free(h);
578 return LDB_ERR_OPERATIONS_ERROR;
581 /* Rename the remote record. */
582 int map_rename_do_remote(struct ldb_handle *handle)
584 struct map_context *ac;
586 ac = talloc_get_type(handle->private_data, struct map_context);
588 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
590 ac->step = MAP_RENAME_REMOTE;
592 handle->state = LDB_ASYNC_INIT;
593 handle->status = LDB_SUCCESS;
595 return ldb_next_remote_request(ac->module, ac->remote_req);
598 /* Update the local 'IS_MAPPED' attribute. */
599 int map_rename_do_fixup(struct ldb_handle *handle)
601 struct map_context *ac;
603 ac = talloc_get_type(handle->private_data, struct map_context);
605 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req);
607 ac->step = MAP_RENAME_FIXUP;
609 handle->state = LDB_ASYNC_INIT;
610 handle->status = LDB_SUCCESS;
612 return ldb_next_request(ac->module, ac->down_req);
615 /* Rename the local record. */
616 int map_rename_do_local(struct ldb_handle *handle)
618 struct map_context *ac;
620 ac = talloc_get_type(handle->private_data, struct map_context);
622 /* No local record, continue remotely */
623 if (ac->local_dn == NULL) {
624 return map_rename_do_remote(handle);
627 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
629 ac->step = MAP_RENAME_LOCAL;
631 handle->state = LDB_ASYNC_INIT;
632 handle->status = LDB_SUCCESS;
634 return ldb_next_request(ac->module, ac->local_req);
637 /* Rename a record. */
638 int map_rename(struct ldb_module *module, struct ldb_request *req)
640 struct ldb_handle *h;
641 struct map_context *ac;
643 /* Do not manipulate our control entries */
644 if (ldb_dn_is_special(req->op.rename.olddn)) {
645 return ldb_next_request(module, req);
648 /* No mapping requested (perhaps no DN mapping specified), skip to next module */
649 if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
650 (!ldb_dn_check_local(module, req->op.rename.newdn))) {
651 return ldb_next_request(module, req);
654 /* Rename into/out of the mapped partition requested, bail out */
655 if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
656 !ldb_dn_check_local(module, req->op.rename.newdn)) {
657 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
660 /* Prepare context and handle */
661 h = map_init_handle(req, module);
662 if (h == NULL) {
663 return LDB_ERR_OPERATIONS_ERROR;
665 ac = talloc_get_type(h->private_data, struct map_context);
667 /* Prepare the local operation */
668 ac->local_req = talloc(ac, struct ldb_request);
669 if (ac->local_req == NULL) {
670 goto oom;
673 *(ac->local_req) = *req; /* copy the request */
674 ac->local_req->op.rename.olddn = req->op.rename.olddn;
675 ac->local_req->op.rename.newdn = req->op.rename.newdn;
677 ac->local_req->context = NULL;
678 ac->local_req->callback = NULL;
680 /* Prepare the remote operation */
681 ac->remote_req = talloc(ac, struct ldb_request);
682 if (ac->remote_req == NULL) {
683 goto oom;
686 *(ac->remote_req) = *req; /* copy the request */
687 ac->remote_req->op.rename.olddn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.olddn);
688 ac->remote_req->op.rename.newdn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.newdn);
690 ac->remote_req->context = NULL;
691 ac->remote_req->callback = NULL;
693 /* No local db, just run the remote request */
694 if (!map_check_local_db(ac->module)) {
695 req->handle = h; /* return our own handle to deal with this call */
696 return map_rename_do_remote(h);
699 /* Prepare the fixup operation */
700 /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
701 ac->down_req = map_build_fixup_req(ac, req->op.rename.newdn, ac->remote_req->op.rename.newdn);
702 if (ac->down_req == NULL) {
703 goto failed;
706 /* Prepare the search operation */
707 ac->search_req = map_search_self_req(ac, req->op.rename.olddn);
708 if (ac->search_req == NULL) {
709 goto failed;
712 req->handle = h; /* return our own handle to deal with this call */
714 ac->step = MAP_SEARCH_SELF_RENAME;
716 return ldb_next_request(module, ac->search_req);
718 oom:
719 map_oom(module);
720 failed:
721 talloc_free(h);
722 return LDB_ERR_OPERATIONS_ERROR;