2 ldb database mapping module
4 Copyright (C) Jelmer Vernooij 2005
5 Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
6 Copyright (C) Simo Sorce 2008
8 ** NOTE! The following LGPL license applies to the ldb
9 ** library. This does NOT imply that all of Samba is released
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 3 of the License, or (at your option) any later version.
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public
23 License along with this library; if not, see <http://www.gnu.org/licenses/>.
30 * Component: ldb ldb_map module
32 * Description: Map portions of data into a different format on a
35 * Author: Jelmer Vernooij, Martin Kuehl
38 #include "ldb_module.h"
41 #include "ldb_map_private.h"
47 /* Description of the provided ldb requests:
48 - special attribute 'isMapped'
51 - if parse tree can be split
52 - search remote records w/ remote attrs and parse tree
54 - enumerate all remote records
55 - for each remote result
56 - map remote result to local message
59 - merge local into remote result
60 - run callback on merged result
62 - run callback on remote result
65 - split message into local and remote part
66 - if local message is not empty
67 - add isMapped to local message
72 - split message into local and remote part
73 - if local message is not empty
74 - add isMapped to local message
75 - search for local record
80 - modify remote record
83 - search for local record
86 - delete remote record
89 - search for local record
92 - modify local isMapped
93 - rename remote record
98 /* Private data structures
99 * ======================= */
101 /* Global private data */
102 /* Extract mappings from private data. */
103 const struct ldb_map_context *map_get_context(struct ldb_module *module)
105 const struct map_private *data = talloc_get_type(ldb_module_get_private(module), struct map_private);
106 return data->context;
109 /* Create a generic request context. */
110 struct map_context *map_init_context(struct ldb_module *module,
111 struct ldb_request *req)
113 struct ldb_context *ldb;
114 struct map_context *ac;
116 ldb = ldb_module_get_ctx(module);
118 ac = talloc_zero(req, struct map_context);
120 ldb_set_errstring(ldb, "Out of Memory");
130 /* Dealing with DNs for different partitions
131 * ========================================= */
133 /* Check whether any data should be stored in the local partition. */
134 bool map_check_local_db(struct ldb_module *module)
136 const struct ldb_map_context *data = map_get_context(module);
138 if (!data->remote_base_dn || !data->local_base_dn) {
145 /* Copy a DN with the base DN of the local partition. */
146 static struct ldb_dn *ldb_dn_rebase_local(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn)
148 struct ldb_dn *new_dn;
150 new_dn = ldb_dn_copy(mem_ctx, dn);
151 if ( ! ldb_dn_validate(new_dn)) {
156 /* may be we don't need to rebase at all */
157 if ( ! data->remote_base_dn || ! data->local_base_dn) {
161 if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->remote_base_dn))) {
166 if ( ! ldb_dn_add_base(new_dn, data->local_base_dn)) {
174 /* Copy a DN with the base DN of the remote partition. */
175 static struct ldb_dn *ldb_dn_rebase_remote(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn)
177 struct ldb_dn *new_dn;
179 new_dn = ldb_dn_copy(mem_ctx, dn);
180 if ( ! ldb_dn_validate(new_dn)) {
185 /* may be we don't need to rebase at all */
186 if ( ! data->remote_base_dn || ! data->local_base_dn) {
190 if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->local_base_dn))) {
195 if ( ! ldb_dn_add_base(new_dn, data->remote_base_dn)) {
203 /* Run a request and make sure it targets the remote partition. */
204 /* TODO: free old DNs and messages? */
205 int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request)
207 const struct ldb_map_context *data = map_get_context(module);
208 struct ldb_context *ldb;
209 struct ldb_message *msg;
211 ldb = ldb_module_get_ctx(module);
213 switch (request->operation) {
215 if (request->op.search.base) {
216 request->op.search.base = ldb_dn_rebase_remote(request, data, request->op.search.base);
218 request->op.search.base = data->remote_base_dn;
219 /* TODO: adjust scope? */
224 msg = ldb_msg_copy_shallow(request, request->op.add.message);
225 msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn);
226 request->op.add.message = msg;
230 msg = ldb_msg_copy_shallow(request, request->op.mod.message);
231 msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn);
232 request->op.mod.message = msg;
236 request->op.del.dn = ldb_dn_rebase_remote(request, data, request->op.del.dn);
240 request->op.rename.olddn = ldb_dn_rebase_remote(request, data, request->op.rename.olddn);
241 request->op.rename.newdn = ldb_dn_rebase_remote(request, data, request->op.rename.newdn);
245 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
246 "Invalid remote request!\n");
247 return LDB_ERR_OPERATIONS_ERROR;
250 return ldb_next_request(module, request);
254 /* Finding mappings for attributes and objectClasses
255 * ================================================= */
257 /* Find an objectClass mapping by the local name. */
258 static const struct ldb_map_objectclass *map_objectclass_find_local(const struct ldb_map_context *data, const char *name)
262 for (i = 0; data->objectclass_maps && data->objectclass_maps[i].local_name; i++) {
263 if (ldb_attr_cmp(data->objectclass_maps[i].local_name, name) == 0) {
264 return &data->objectclass_maps[i];
271 /* Find an objectClass mapping by the remote name. */
272 static const struct ldb_map_objectclass *map_objectclass_find_remote(const struct ldb_map_context *data, const char *name)
276 for (i = 0; data->objectclass_maps && data->objectclass_maps[i].remote_name; i++) {
277 if (ldb_attr_cmp(data->objectclass_maps[i].remote_name, name) == 0) {
278 return &data->objectclass_maps[i];
285 /* Find an attribute mapping by the local name. */
286 const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name)
290 for (i = 0; data->attribute_maps[i].local_name; i++) {
291 if (ldb_attr_cmp(data->attribute_maps[i].local_name, name) == 0) {
292 return &data->attribute_maps[i];
295 for (i = 0; data->attribute_maps[i].local_name; i++) {
296 if (ldb_attr_cmp(data->attribute_maps[i].local_name, "*") == 0) {
297 return &data->attribute_maps[i];
304 /* Find an attribute mapping by the remote name. */
305 const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name)
307 const struct ldb_map_attribute *map;
308 const struct ldb_map_attribute *wildcard = NULL;
311 for (i = 0; data->attribute_maps[i].local_name; i++) {
312 map = &data->attribute_maps[i];
313 if (ldb_attr_cmp(map->local_name, "*") == 0) {
314 wildcard = &data->attribute_maps[i];
322 if (ldb_attr_cmp(map->local_name, name) == 0) {
329 if (ldb_attr_cmp(map->u.rename.remote_name, name) == 0) {
335 for (j = 0; map->u.generate.remote_names && map->u.generate.remote_names[j]; j++) {
336 if (ldb_attr_cmp(map->u.generate.remote_names[j], name) == 0) {
344 /* We didn't find it, so return the wildcard record if one was configured */
349 /* Mapping attributes
350 * ================== */
352 /* Check whether an attribute will be mapped into the remote partition. */
353 bool map_attr_check_remote(const struct ldb_map_context *data, const char *attr)
355 const struct ldb_map_attribute *map = map_attr_find_local(data, attr);
360 if (map->type == MAP_IGNORE) {
367 /* Map an attribute name into the remote partition. */
368 const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr)
371 return talloc_strdup(mem_ctx, attr);
376 return talloc_strdup(mem_ctx, attr);
380 return talloc_strdup(mem_ctx, map->u.rename.remote_name);
387 /* Map an attribute name back into the local partition. */
388 const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr)
391 return talloc_strdup(mem_ctx, attr);
394 if (map->type == MAP_KEEP) {
395 return talloc_strdup(mem_ctx, attr);
398 return talloc_strdup(mem_ctx, map->local_name);
402 /* Merge two lists of attributes into a single one. */
403 int map_attrs_merge(struct ldb_module *module, void *mem_ctx,
404 const char ***attrs, const char * const *more_attrs)
408 for (i = 0; *attrs && (*attrs)[i]; i++) /* noop */ ;
409 for (j = 0; more_attrs && more_attrs[j]; j++) /* noop */ ;
411 *attrs = talloc_realloc(mem_ctx, *attrs, const char *, i+j+1);
412 if (*attrs == NULL) {
417 for (k = 0; k < j; k++) {
418 (*attrs)[i + k] = more_attrs[k];
421 (*attrs)[i+k] = NULL;
426 /* Mapping ldb values
427 * ================== */
429 /* Map an ldb value into the remote partition. */
430 struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx,
431 const struct ldb_map_attribute *map, const struct ldb_val *val)
433 if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_local)) {
434 return map->u.convert.convert_local(module, mem_ctx, val);
437 return ldb_val_dup(mem_ctx, val);
440 /* Map an ldb value back into the local partition. */
441 struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx,
442 const struct ldb_map_attribute *map, const struct ldb_val *val)
444 if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_remote)) {
445 return map->u.convert.convert_remote(module, mem_ctx, val);
448 return ldb_val_dup(mem_ctx, val);
455 /* Check whether a DN is below the local baseDN. */
456 bool ldb_dn_check_local(struct ldb_module *module, struct ldb_dn *dn)
458 const struct ldb_map_context *data = map_get_context(module);
460 if (!data->local_base_dn) {
464 return ldb_dn_compare_base(data->local_base_dn, dn) == 0;
467 /* Map a DN into the remote partition. */
468 struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
470 const struct ldb_map_context *data = map_get_context(module);
471 struct ldb_context *ldb;
472 struct ldb_dn *newdn;
473 const struct ldb_map_attribute *map;
474 enum ldb_map_attr_type map_type;
476 struct ldb_val value;
483 ldb = ldb_module_get_ctx(module);
485 newdn = ldb_dn_copy(mem_ctx, dn);
491 /* For each RDN, map the component name and possibly the value */
492 for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) {
493 map = map_attr_find_local(data, ldb_dn_get_component_name(dn, i));
495 /* Unknown attribute - leave this RDN as is and hope the best... */
499 map_type = map->type;
505 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
506 "MAP_IGNORE/MAP_GENERATE attribute '%s' "
507 "used in DN!\n", ldb_dn_get_component_name(dn, i));
511 if (map->u.convert.convert_local == NULL) {
512 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
513 "'convert_local' not set for attribute '%s' "
514 "used in DN!\n", ldb_dn_get_component_name(dn, i));
520 name = map_attr_map_local(newdn, map, ldb_dn_get_component_name(dn, i));
521 if (name == NULL) goto failed;
523 value = ldb_val_map_local(module, newdn, map, ldb_dn_get_component_val(dn, i));
524 if (value.data == NULL) goto failed;
526 ret = ldb_dn_set_component(newdn, i, name, value);
527 if (ret != LDB_SUCCESS) {
542 /* Map a DN into the local partition. */
543 struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
545 const struct ldb_map_context *data = map_get_context(module);
546 struct ldb_context *ldb;
547 struct ldb_dn *newdn;
548 const struct ldb_map_attribute *map;
549 enum ldb_map_attr_type map_type;
551 struct ldb_val value;
558 ldb = ldb_module_get_ctx(module);
560 newdn = ldb_dn_copy(mem_ctx, dn);
566 /* For each RDN, map the component name and possibly the value */
567 for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) {
568 map = map_attr_find_remote(data, ldb_dn_get_component_name(dn, i));
570 /* Unknown attribute - leave this RDN as is and hope the best... */
574 map_type = map->type;
580 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
581 "MAP_IGNORE/MAP_GENERATE attribute '%s' "
582 "used in DN!\n", ldb_dn_get_component_name(dn, i));
586 if (map->u.convert.convert_remote == NULL) {
587 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
588 "'convert_remote' not set for attribute '%s' "
589 "used in DN!\n", ldb_dn_get_component_name(dn, i));
595 name = map_attr_map_remote(newdn, map, ldb_dn_get_component_name(dn, i));
596 if (name == NULL) goto failed;
598 value = ldb_val_map_remote(module, newdn, map, ldb_dn_get_component_val(dn, i));
599 if (value.data == NULL) goto failed;
601 ret = ldb_dn_set_component(newdn, i, name, value);
602 if (ret != LDB_SUCCESS) {
617 /* Map a DN and its base into the local partition. */
618 /* TODO: This should not be required with GUIDs. */
619 struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
621 const struct ldb_map_context *data = map_get_context(module);
622 struct ldb_dn *dn1, *dn2;
624 dn1 = ldb_dn_rebase_local(mem_ctx, data, dn);
625 dn2 = ldb_dn_map_remote(module, mem_ctx, dn1);
632 /* Converting DNs and objectClasses (as ldb values)
633 * ================================================ */
635 /* Map a DN contained in an ldb value into the remote partition. */
636 static struct ldb_val ldb_dn_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
638 struct ldb_context *ldb;
639 struct ldb_dn *dn, *newdn;
640 struct ldb_val newval;
642 ldb = ldb_module_get_ctx(module);
644 dn = ldb_dn_from_ldb_val(mem_ctx, ldb, val);
645 if (! ldb_dn_validate(dn)) {
651 newdn = ldb_dn_map_local(module, mem_ctx, dn);
655 newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn);
657 newval.length = strlen((char *)newval.data);
664 /* Map a DN contained in an ldb value into the local partition. */
665 static struct ldb_val ldb_dn_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
667 struct ldb_context *ldb;
668 struct ldb_dn *dn, *newdn;
669 struct ldb_val newval;
671 ldb = ldb_module_get_ctx(module);
673 dn = ldb_dn_from_ldb_val(mem_ctx, ldb, val);
674 if (! ldb_dn_validate(dn)) {
680 newdn = ldb_dn_map_remote(module, mem_ctx, dn);
684 newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn);
686 newval.length = strlen((char *)newval.data);
693 /* Map an objectClass into the remote partition. */
694 static struct ldb_val map_objectclass_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
696 const struct ldb_map_context *data = map_get_context(module);
697 const char *name = (char *)val->data;
698 const struct ldb_map_objectclass *map = map_objectclass_find_local(data, name);
699 struct ldb_val newval;
702 newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->remote_name);
703 newval.length = strlen((char *)newval.data);
707 return ldb_val_dup(mem_ctx, val);
710 /* Generate a remote message with a mapped objectClass. */
711 static void map_objectclass_generate_remote(struct ldb_module *module, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local)
713 const struct ldb_map_context *data = map_get_context(module);
714 struct ldb_context *ldb;
715 struct ldb_message_element *el, *oc;
717 bool found_extensibleObject = false;
720 ldb = ldb_module_get_ctx(module);
722 /* Find old local objectClass */
723 oc = ldb_msg_find_element(old, "objectClass");
728 /* Prepare new element */
729 el = talloc_zero(remote, struct ldb_message_element);
732 return; /* TODO: fail? */
735 /* Copy local objectClass element, reverse space for an extra value */
736 el->num_values = oc->num_values + 1;
737 el->values = talloc_array(el, struct ldb_val, el->num_values);
738 if (el->values == NULL) {
741 return; /* TODO: fail? */
744 /* Copy local element name "objectClass" */
745 el->name = talloc_strdup(el, local_attr);
747 /* Convert all local objectClasses */
748 for (i = 0; i < el->num_values - 1; i++) {
749 el->values[i] = map_objectclass_convert_local(module, el->values, &oc->values[i]);
750 if (ldb_attr_cmp((char *)el->values[i].data, data->add_objectclass) == 0) {
751 found_extensibleObject = true;
755 if (!found_extensibleObject) {
756 val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass);
757 val.length = strlen((char *)val.data);
759 /* Append additional objectClass data->add_objectclass */
765 /* Add new objectClass to remote message */
766 ldb_msg_add(remote, el, 0);
769 /* Map an objectClass into the local partition. */
770 static struct ldb_val map_objectclass_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
772 const struct ldb_map_context *data = map_get_context(module);
773 const char *name = (char *)val->data;
774 const struct ldb_map_objectclass *map = map_objectclass_find_remote(data, name);
775 struct ldb_val newval;
778 newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->local_name);
779 newval.length = strlen((char *)newval.data);
783 return ldb_val_dup(mem_ctx, val);
786 /* Generate a local message with a mapped objectClass. */
787 static struct ldb_message_element *map_objectclass_generate_local(struct ldb_module *module, void *mem_ctx, const char *local_attr, const struct ldb_message *remote)
789 const struct ldb_map_context *data = map_get_context(module);
790 struct ldb_context *ldb;
791 struct ldb_message_element *el, *oc;
795 ldb = ldb_module_get_ctx(module);
797 /* Find old remote objectClass */
798 oc = ldb_msg_find_element(remote, "objectClass");
803 /* Prepare new element */
804 el = talloc_zero(mem_ctx, struct ldb_message_element);
810 /* Copy remote objectClass element */
811 el->num_values = oc->num_values;
812 el->values = talloc_array(el, struct ldb_val, el->num_values);
813 if (el->values == NULL) {
819 /* Copy remote element name "objectClass" */
820 el->name = talloc_strdup(el, local_attr);
822 /* Convert all remote objectClasses */
823 for (i = 0; i < el->num_values; i++) {
824 el->values[i] = map_objectclass_convert_remote(module, el->values, &oc->values[i]);
827 val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass);
828 val.length = strlen((char *)val.data);
830 /* Remove last value if it was the string in data->add_objectclass (eg samba4top, extensibleObject) */
831 if (ldb_val_equal_exact(&val, &el->values[i-1])) {
833 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values);
834 if (el->values == NULL) {
844 static const struct ldb_map_attribute objectclass_convert_map = {
845 .local_name = "objectClass",
849 .remote_name = "objectClass",
850 .convert_local = map_objectclass_convert_local,
851 .convert_remote = map_objectclass_convert_remote,
857 /* Mappings for searches on objectClass= assuming a one-to-one
858 * mapping. Needed because this is a generate operator for the
860 static int map_objectclass_convert_operator(struct ldb_module *module, void *mem_ctx,
861 struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
864 return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, &objectclass_convert_map);
867 /* Auxiliary request construction
868 * ============================== */
870 /* Build a request to search a record by its DN. */
871 struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_map_callback_t callback)
873 const struct ldb_parse_tree *search_tree;
874 struct ldb_context *ldb;
875 struct ldb_request *req;
878 ldb = ldb_module_get_ctx(ac->module);
883 search_tree = ldb_parse_tree(ac, NULL);
884 if (search_tree == NULL) {
889 ret = ldb_build_search_req_ex(&req, ldb, ac,
895 if (ret != LDB_SUCCESS) {
902 /* Build a request to update the 'IS_MAPPED' attribute */
903 struct ldb_request *map_build_fixup_req(struct map_context *ac,
904 struct ldb_dn *olddn,
905 struct ldb_dn *newdn,
907 ldb_map_callback_t callback)
909 struct ldb_context *ldb;
910 struct ldb_request *req;
911 struct ldb_message *msg;
915 ldb = ldb_module_get_ctx(ac->module);
917 /* Prepare message */
918 msg = ldb_msg_new(ac);
924 /* Update local 'IS_MAPPED' to the new remote DN */
925 msg->dn = ldb_dn_copy(msg, olddn);
926 dn = ldb_dn_alloc_linearized(msg, newdn);
927 if ( ! dn || ! ldb_dn_validate(msg->dn)) {
930 if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
933 if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
937 /* Prepare request */
938 ret = ldb_build_mod_req(&req, ldb,
942 if (ret != LDB_SUCCESS) {
945 talloc_steal(req, msg);
953 /* Module initialization
954 * ===================== */
957 /* Builtin mappings for DNs and objectClasses */
958 static const struct ldb_map_attribute builtin_attribute_maps[] = {
965 .convert_local = ldb_dn_convert_local,
966 .convert_remote = ldb_dn_convert_remote,
975 static const struct ldb_map_attribute objectclass_attribute_map = {
976 .local_name = "objectClass",
977 .type = MAP_GENERATE,
978 .convert_operator = map_objectclass_convert_operator,
981 .remote_names = { "objectClass", NULL },
982 .generate_local = map_objectclass_generate_local,
983 .generate_remote = map_objectclass_generate_remote,
989 /* Find the special 'MAP_DN_NAME' record and store local and remote
990 * base DNs in private data. */
991 static int map_init_dns(struct ldb_module *module, struct ldb_map_context *data, const char *name)
993 static const char * const attrs[] = { MAP_DN_FROM, MAP_DN_TO, NULL };
994 struct ldb_context *ldb;
996 struct ldb_message *msg;
997 struct ldb_result *res;
1001 data->local_base_dn = NULL;
1002 data->remote_base_dn = NULL;
1006 ldb = ldb_module_get_ctx(module);
1008 dn = ldb_dn_new_fmt(data, ldb, "%s=%s", MAP_DN_NAME, name);
1009 if ( ! ldb_dn_validate(dn)) {
1010 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
1011 "Failed to construct '%s' DN!\n", MAP_DN_NAME);
1012 return LDB_ERR_OPERATIONS_ERROR;
1015 ret = ldb_search(ldb, data, &res, dn, LDB_SCOPE_BASE, attrs, NULL);
1017 if (ret != LDB_SUCCESS) {
1020 if (res->count == 0) {
1021 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
1022 "No results for '%s=%s'!\n", MAP_DN_NAME, name);
1024 return LDB_ERR_CONSTRAINT_VIOLATION;
1026 if (res->count > 1) {
1027 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
1028 "Too many results for '%s=%s'!\n", MAP_DN_NAME, name);
1030 return LDB_ERR_CONSTRAINT_VIOLATION;
1034 data->local_base_dn = ldb_msg_find_attr_as_dn(ldb, data, msg, MAP_DN_FROM);
1035 data->remote_base_dn = ldb_msg_find_attr_as_dn(ldb, data, msg, MAP_DN_TO);
1041 /* Store attribute maps and objectClass maps in private data. */
1042 static int map_init_maps(struct ldb_module *module, struct ldb_map_context *data,
1043 const struct ldb_map_attribute *attrs,
1044 const struct ldb_map_objectclass *ocls,
1045 const char * const *wildcard_attributes)
1050 /* Count specified attribute maps */
1051 for (i = 0; attrs[i].local_name; i++) /* noop */ ;
1052 /* Count built-in attribute maps */
1053 for (j = 0; builtin_attribute_maps[j].local_name; j++) /* noop */ ;
1055 /* Store list of attribute maps */
1056 data->attribute_maps = talloc_array(data, struct ldb_map_attribute, i+j+2);
1057 if (data->attribute_maps == NULL) {
1059 return LDB_ERR_OPERATIONS_ERROR;
1062 /* Specified ones go first */
1063 for (i = 0; attrs[i].local_name; i++) {
1064 data->attribute_maps[last] = attrs[i];
1068 /* Built-in ones go last */
1069 for (i = 0; builtin_attribute_maps[i].local_name; i++) {
1070 data->attribute_maps[last] = builtin_attribute_maps[i];
1074 if (data->add_objectclass) {
1075 /* ObjectClass one is very last, if required */
1076 data->attribute_maps[last] = objectclass_attribute_map;
1079 data->attribute_maps[last] = objectclass_convert_map;
1083 /* Ensure 'local_name == NULL' for the last entry */
1084 memset(&data->attribute_maps[last], 0, sizeof(struct ldb_map_attribute));
1086 /* Store list of objectClass maps */
1087 data->objectclass_maps = ocls;
1089 data->wildcard_attributes = wildcard_attributes;
1094 /* Initialize global private data. */
1095 _PUBLIC_ int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs,
1096 const struct ldb_map_objectclass *ocls,
1097 const char * const *wildcard_attributes,
1098 const char *add_objectclass,
1101 struct map_private *data;
1104 /* Prepare private data */
1105 data = talloc_zero(module, struct map_private);
1108 return LDB_ERR_OPERATIONS_ERROR;
1111 ldb_module_set_private(module, data);
1113 data->context = talloc_zero(data, struct ldb_map_context);
1114 if (!data->context) {
1116 return LDB_ERR_OPERATIONS_ERROR;
1119 /* Store local and remote baseDNs */
1120 ret = map_init_dns(module, data->context, name);
1121 if (ret != LDB_SUCCESS) {
1126 data->context->add_objectclass = add_objectclass;
1128 /* Store list of attribute and objectClass maps */
1129 ret = map_init_maps(module, data->context, attrs, ocls, wildcard_attributes);
1130 if (ret != LDB_SUCCESS) {