2 ldb database library - map backend
4 Copyright (C) Jelmer Vernooij 2005
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "ldb/include/ldb.h"
27 #include "ldb/include/ldb_private.h"
28 #include "ldb/modules/ldb_map.h"
31 * - per remote objectclass:
40 - special attribute 'isMapped'
42 - split up ldb_message into fallback and mapped parts if is_mappable
44 - search local one for not isMapped entries
45 - remove remote attributes from ldb_parse_tree
47 - per record, search local one for additional data (by dn)
48 - test if (full expression) is now true
52 - rename locally and remotely
55 static struct ldb_val map_convert_local_dn(struct ldb_module *map,
57 const struct ldb_val *val);
58 static struct ldb_val map_convert_remote_dn(struct ldb_module *map,
60 const struct ldb_val *val);
61 static struct ldb_val map_convert_local_objectclass(struct ldb_module *map,
63 const struct ldb_val *val);
64 static struct ldb_val map_convert_remote_objectclass(struct ldb_module *map,
66 const struct ldb_val *val);
68 static const struct ldb_map_attribute builtin_attribute_maps[] = {
75 .convert_local = map_convert_local_dn,
76 .convert_remote = map_convert_remote_dn,
81 .local_name = "objectclass",
85 .remote_name = "objectclass",
86 .convert_local = map_convert_local_objectclass,
87 .convert_remote = map_convert_remote_objectclass,
96 static const struct ldb_map_objectclass *map_find_objectclass_remote(struct ldb_map_context *privdat, const char *name)
99 for (i = 0; privdat->objectclass_maps[i].remote_name; i++) {
100 if (!ldb_attr_cmp(privdat->objectclass_maps[i].remote_name, name))
101 return &privdat->objectclass_maps[i];
108 struct ldb_map_context context;
109 const char *last_err_string;
112 static struct ldb_map_context *map_get_privdat(struct ldb_module *module)
114 return &((struct map_private *)module->private_data)->context;
117 /* Check whether the given attribute can fit into the specified
118 * message, obeying objectClass restrictions */
119 static int map_msg_valid_attr(struct ldb_module *module, const struct ldb_message *msg, const char *attr)
121 struct ldb_map_context *map = module->private_data;
123 struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
126 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Can't find objectClass");
130 for (i = 0; i < el->num_values; i++) {
131 const struct ldb_map_objectclass *class = map_find_objectclass_remote(map, (char *)el->values[i].data);
136 for (j = 0; class->musts[j]; j++) {
137 if (!ldb_attr_cmp(class->musts[j], attr))
141 for (j = 0; class->mays[j]; j++) {
142 if (!ldb_attr_cmp(class->mays[j], attr))
151 /* find an attribute by the local name */
152 static const struct ldb_map_attribute *map_find_attr_local(struct ldb_map_context *privdat, const char *attr)
156 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
157 if (!ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr))
158 return &privdat->attribute_maps[i];
164 /* Check if a given attribute can be created by doing mapping from a local attribute to a remote one */
165 static int map_msg_can_map_attr(struct ldb_module *module, const struct ldb_message *msg, const char *attr_name)
167 struct ldb_map_context *map = module->private_data;
170 for (i = 0; i < msg->num_elements; i++) {
171 const struct ldb_map_attribute *attr = map_find_attr_local(map, msg->elements[i].name);
176 switch (attr->type) {
177 case MAP_IGNORE: continue;
179 if (ldb_attr_cmp(attr->local_name, attr_name) == 0) return 1;
183 if (ldb_attr_cmp(attr->u.rename.remote_name, attr_name) == 0) return 1;
186 for (j = 0; attr->u.generate.remote_names[j]; j++) {
187 if (ldb_attr_cmp(attr->u.generate.remote_names[j], attr_name) == 0) return 1;
198 /* find an attribute by the remote name */
199 static const struct ldb_map_attribute *map_find_attr_remote(struct ldb_map_context *privdat, const char *attr)
203 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
204 if (privdat->attribute_maps[i].type == MAP_IGNORE)
207 if (privdat->attribute_maps[i].type == MAP_GENERATE)
210 if (privdat->attribute_maps[i].type == MAP_KEEP &&
211 ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr) == 0)
212 return &privdat->attribute_maps[i];
214 if ((privdat->attribute_maps[i].type == MAP_RENAME ||
215 privdat->attribute_maps[i].type == MAP_CONVERT) &&
216 ldb_attr_cmp(privdat->attribute_maps[i].u.rename.remote_name, attr) == 0)
217 return &privdat->attribute_maps[i];
224 static struct ldb_parse_tree *ldb_map_parse_tree(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_parse_tree *tree)
227 const struct ldb_map_attribute *attr;
228 struct ldb_parse_tree *new_tree;
229 enum ldb_map_attr_type map_type;
230 struct ldb_val value, newvalue;
231 struct ldb_map_context *privdat = map_get_privdat(module);
237 /* Find attr in question and:
238 * - if it has a convert_operator function, run that
239 * - otherwise, replace attr name with required[0] */
241 if (tree->operation == LDB_OP_AND ||
242 tree->operation == LDB_OP_OR) {
244 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
245 new_tree->u.list.elements = talloc_array(new_tree, struct ldb_parse_tree *, tree->u.list.num_elements);
246 new_tree->u.list.num_elements = 0;
247 for (i = 0; i < tree->u.list.num_elements; i++) {
248 struct ldb_parse_tree *child = ldb_map_parse_tree(module, new_tree, tree->u.list.elements[i]);
251 new_tree->u.list.elements[i] = child;
252 new_tree->u.list.num_elements++;
259 if (tree->operation == LDB_OP_NOT) {
260 struct ldb_parse_tree *child;
262 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
263 child = ldb_map_parse_tree(module, new_tree, tree->u.isnot.child);
266 talloc_free(new_tree);
270 new_tree->u.isnot.child = child;
274 /* tree->operation is LDB_OP_EQUALITY, LDB_OP_SUBSTRING, LDB_OP_GREATER,
275 * LDB_OP_LESS, LDB_OP_APPROX, LDB_OP_PRESENT or LDB_OP_EXTENDED
277 * (all have attr as the first element)
280 attr = map_find_attr_local(privdat, tree->u.equality.attr);
283 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Unable to find local attribute '%s', removing from parse tree\n", tree->u.equality.attr);
284 map_type = MAP_IGNORE;
286 map_type = attr->type;
289 if (attr && attr->convert_operator) {
290 /* Run convert_operator */
291 return attr->convert_operator(privdat, module, tree);
294 if (map_type == MAP_IGNORE) {
295 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Not mapping search on ignored attribute '%s'\n", tree->u.equality.attr);
299 if (map_type == MAP_GENERATE) {
300 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Can't do conversion for MAP_GENERATE in map_parse_tree without convert_operator for '%s'\n", tree->u.equality.attr);
304 if (tree->operation == LDB_OP_EQUALITY) {
305 value = tree->u.equality.value;
306 } else if (tree->operation == LDB_OP_LESS || tree->operation == LDB_OP_GREATER ||
307 tree->operation == LDB_OP_APPROX) {
308 value = tree->u.comparison.value;
309 } else if (tree->operation == LDB_OP_EXTENDED) {
310 value = tree->u.extended.value;
313 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
315 if (map_type == MAP_KEEP) {
316 new_tree->u.equality.attr = talloc_strdup(new_tree, tree->u.equality.attr);
317 } else { /* MAP_RENAME / MAP_CONVERT */
318 new_tree->u.equality.attr = talloc_strdup(new_tree, attr->u.rename.remote_name);
321 if (new_tree->operation == LDB_OP_PRESENT)
324 if (new_tree->operation == LDB_OP_SUBSTRING) {
325 new_tree->u.substring.chunks = NULL; /* FIXME! */
329 if (map_type == MAP_CONVERT) {
330 newvalue = attr->u.convert.convert_local(module, new_tree, &value);
332 newvalue = ldb_val_dup(new_tree, &value);
335 if (new_tree->operation == LDB_OP_EQUALITY) {
336 new_tree->u.equality.value = newvalue;
337 } else if (new_tree->operation == LDB_OP_LESS || new_tree->operation == LDB_OP_GREATER ||
338 new_tree->operation == LDB_OP_APPROX) {
339 new_tree->u.comparison.value = newvalue;
340 } else if (new_tree->operation == LDB_OP_EXTENDED) {
341 new_tree->u.extended.value = newvalue;
342 new_tree->u.extended.rule_id = talloc_strdup(new_tree, tree->u.extended.rule_id);
348 /* Remote DN -> Local DN */
349 static struct ldb_dn *map_remote_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_dn *dn)
351 struct ldb_dn *newdn;
357 newdn = talloc_memdup(ctx, dn, sizeof(*dn));
361 newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
363 if (!newdn->components)
366 /* For each rdn, map the attribute name and possibly the
369 for (i = 0; i < dn->comp_num; i++) {
370 const struct ldb_map_attribute *attr = map_find_attr_remote(module->private_data, dn->components[i].name);
371 enum ldb_map_attr_type map_type;
373 /* Unknown attribute - leave this dn as is and hope the best... */
374 if (!attr) map_type = MAP_KEEP;
375 else map_type = attr->type;
380 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Local MAP_IGNORE or MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name);
385 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
386 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
390 newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
391 newdn->components[i].value = attr->u.convert.convert_remote(module, ctx, &dn->components[i].value);
395 newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
396 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
403 /* Local DN -> Remote DN */
404 static struct ldb_dn *map_local_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_dn *dn)
406 struct ldb_dn *newdn;
412 newdn = talloc_memdup(ctx, dn, sizeof(*dn));
416 newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
418 if (!newdn->components)
421 /* For each rdn, map the attribute name and possibly the
422 * complete rdn using an equality convert_operator call */
424 for (i = 0; i < dn->comp_num; i++) {
425 const struct ldb_map_attribute *attr = map_find_attr_local(module->private_data, dn->components[i].name);
426 enum ldb_map_attr_type map_type;
428 /* Unknown attribute - leave this dn as is and hope the best... */
429 if (!attr) map_type = MAP_KEEP; else map_type = attr->type;
435 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Local MAP_IGNORE/MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name);
440 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.convert.remote_name);
441 newdn->components[i].value = attr->u.convert.convert_local(module, newdn->components, &dn->components[i].value);
445 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.rename.remote_name);
446 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
450 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
451 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
459 /* Loop over ldb_map_attribute array and add remote_names */
460 static const char **ldb_map_attrs(struct ldb_module *module, const char *const attrs[])
464 int ar_size = 0, last_element = 0;
465 struct ldb_map_context *privdat = map_get_privdat(module);
470 /* Start with good guess of number of elements */
471 for (i = 0; attrs[i]; i++);
473 ret = talloc_array(module, const char *, i);
476 for (i = 0; attrs[i]; i++) {
478 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
479 enum ldb_map_attr_type map_type;
482 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Local attribute '%s' does not have a definition!\n", attrs[i]);
483 map_type = MAP_IGNORE;
484 } else map_type = attr->type;
488 case MAP_IGNORE: break;
490 if (last_element >= ar_size) {
491 ret = talloc_realloc(module, ret, const char *, ar_size+1);
494 ret[last_element] = attr->local_name;
500 if (last_element >= ar_size) {
501 ret = talloc_realloc(module, ret, const char *, ar_size+1);
504 ret[last_element] = attr->u.rename.remote_name;
509 /* Add remote_names[] for this attribute to the list of
510 * attributes to request from the remote server */
511 for (j = 0; attr->u.generate.remote_names[j]; j++) {
512 if (last_element >= ar_size) {
513 ret = talloc_realloc(module, ret, const char *, ar_size+1);
516 ret[last_element] = attr->u.generate.remote_names[j];
523 if (last_element >= ar_size) {
524 ret = talloc_realloc(module, ret, const char *, ar_size+1);
528 ret[last_element] = NULL;
533 static const char **available_local_attributes(struct ldb_module *module, const struct ldb_message *msg)
535 struct ldb_map_context *privdat = map_get_privdat(module);
538 const char **ret = talloc_array(module, const char *, 1);
542 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
544 const struct ldb_map_attribute *attr = &privdat->attribute_maps[i];
546 /* If all remote attributes for this attribute are present, add the
547 * local one to the list */
549 switch (attr->type) {
550 case MAP_IGNORE: break;
552 avail = (ldb_msg_find_ldb_val(msg, attr->local_name) != NULL);
557 avail = (ldb_msg_find_ldb_val(msg, attr->u.rename.remote_name) != NULL);
562 for (j = 0; attr->u.generate.remote_names[j]; j++) {
563 avail &= (ldb_msg_find_ldb_val(msg, attr->u.generate.remote_names[j]) != NULL);
571 ret = talloc_realloc(module, ret, const char *, count+2);
572 ret[count] = attr->local_name;
580 /* Used for search */
581 static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, const char * const*attrs, const struct ldb_message *mi)
584 struct ldb_message *msg = talloc_zero(module, struct ldb_message);
585 struct ldb_message_element *elm, *oldelm;
586 struct ldb_map_context *privdat = map_get_privdat(module);
587 const char **newattrs = NULL;
589 msg->dn = map_remote_dn(module, module, mi->dn);
591 /* Loop over attrs, find in ldb_map_attribute array and
595 /* Generate list of the local attributes that /can/ be generated
596 * using the specific remote attributes */
598 attrs = newattrs = available_local_attributes(module, mi);
601 for (i = 0; attrs[i]; i++) {
602 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
603 enum ldb_map_attr_type map_type;
606 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s' when generating incoming message\n", attrs[i]);
607 map_type = MAP_IGNORE;
608 } else map_type = attr->type;
611 case MAP_IGNORE:break;
613 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Renaming remote attribute %s to %s", attr->u.rename.remote_name, attr->local_name);
614 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
618 elm = talloc(msg, struct ldb_message_element);
619 elm->name = talloc_strdup(elm, attr->local_name);
620 elm->num_values = oldelm->num_values;
621 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
622 for (j = 0; j < oldelm->num_values; j++)
623 elm->values[j] = ldb_val_dup(elm, &oldelm->values[j]);
625 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
629 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Converting remote attribute %s to %s", attr->u.rename.remote_name, attr->local_name);
630 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
634 elm = talloc(msg, struct ldb_message_element);
635 elm->name = talloc_strdup(elm, attr->local_name);
636 elm->num_values = oldelm->num_values;
637 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
639 for (j = 0; j < oldelm->num_values; j++)
640 elm->values[j] = attr->u.convert.convert_remote(module, elm, &oldelm->values[j]);
642 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
646 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Keeping remote attribute %s", attr->local_name);
647 oldelm = ldb_msg_find_element(mi, attr->local_name);
648 if (!oldelm) continue;
650 elm = talloc(msg, struct ldb_message_element);
652 elm->num_values = oldelm->num_values;
653 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
654 for (j = 0; j < oldelm->num_values; j++)
655 elm->values[j] = ldb_val_dup(elm, &oldelm->values[j]);
657 elm->name = talloc_strdup(elm, oldelm->name);
659 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
663 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Generating local attribute %s", attr->local_name);
664 elm = attr->u.generate.generate_local(module, msg, attr->local_name, mi);
667 ldb_msg_add(module->ldb, msg, elm, elm->flags);
670 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Unknown attr->type for %s", attr->local_name);
675 talloc_free(newattrs);
683 static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
685 struct ldb_map_context *privdat = map_get_privdat(module);
686 struct ldb_dn *n_olddn, *n_newdn;
689 fb_ret = ldb_next_rename_record(module, olddn, newdn);
692 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record renamed");
696 n_olddn = map_local_dn(module, module, olddn);
697 n_newdn = map_local_dn(module, module, newdn);
699 mp_ret = ldb_rename(privdat->mapped_ldb, n_olddn, n_newdn);
701 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Mapped record renamed");
704 ldb_next_rename_record(module, olddn, newdn);
706 talloc_free(n_olddn);
707 talloc_free(n_newdn);
715 static int map_delete(struct ldb_module *module, const struct ldb_dn *dn)
717 struct ldb_map_context *privdat = map_get_privdat(module);
718 struct ldb_dn *newdn;
721 fb_ret = ldb_next_delete_record(module, dn);
723 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record deleted");
727 newdn = map_local_dn(module, module, dn);
729 mp_ret = ldb_delete(privdat->mapped_ldb, newdn);
731 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Mapped record deleted");
734 ldb_next_delete_record(module, newdn);
741 /* search fallback database */
742 static int map_search_bytree_fb(struct ldb_module *module, const struct ldb_dn *base,
743 enum ldb_scope scope, struct ldb_parse_tree *tree,
744 const char * const *attrs, struct ldb_message ***res)
747 struct ldb_parse_tree t_and, t_not, t_present, *childs[2];
749 t_present.operation = LDB_OP_PRESENT;
750 t_present.u.present.attr = talloc_strdup(NULL, "isMapped");
752 t_not.operation = LDB_OP_NOT;
753 t_not.u.isnot.child = &t_present;
757 t_and.operation = LDB_OP_AND;
758 t_and.u.list.num_elements = 2;
759 t_and.u.list.elements = childs;
761 ret = ldb_next_search_bytree(module, base, scope, &t_and, attrs, res);
763 talloc_free(t_present.u.present.attr);
768 /* Search in the database against which we are mapping */
769 static int map_search_bytree_mp(struct ldb_module *module, const struct ldb_dn *base,
770 enum ldb_scope scope, struct ldb_parse_tree *tree,
771 const char * const *attrs, struct ldb_message ***res)
773 struct ldb_parse_tree *new_tree;
774 struct ldb_dn *new_base;
775 struct ldb_message **newres;
776 const char **newattrs;
778 struct ldb_map_context *privdat = map_get_privdat(module);
781 /*- search mapped database */
783 new_tree = ldb_map_parse_tree(module, module, tree);
784 if (new_tree == NULL) {
785 /* All attributes used in the parse tree are
786 * local, apparently. Fall back to enumerating the complete remote
787 * database... Rather a slow search then no results. */
788 new_tree = talloc_zero(module, struct ldb_parse_tree);
789 new_tree->operation = LDB_OP_PRESENT;
790 new_tree->u.present.attr = talloc_strdup(new_tree, "dn");
794 newattrs = ldb_map_attrs(module, attrs);
795 new_base = map_local_dn(module, module, base);
797 mpret = ldb_search_bytree(privdat->mapped_ldb, new_base, scope, new_tree, newattrs, &newres);
799 talloc_free(new_base);
800 talloc_free(new_tree);
801 talloc_free(newattrs);
804 struct map_private *map_private = module->private_data;
805 map_private->last_err_string = ldb_errstring(privdat->mapped_ldb);
810 - per returned record, search fallback database for additional data (by dn)
811 - test if (full expression) is now true
814 *res = talloc_array(module, struct ldb_message *, mpret);
818 for (i = 0; i < mpret; i++) {
819 struct ldb_message *merged;
820 struct ldb_message **extrares = NULL;
823 /* Always get special DN's from the fallback database */
824 if (ldb_dn_is_special(newres[i]->dn))
827 merged = ldb_map_message_incoming(module, attrs, newres[i]);
829 /* Merge with additional data from fallback database */
830 extraret = ldb_next_search(module, merged->dn, LDB_SCOPE_BASE, "", NULL, &extrares);
832 if (extraret == -1) {
833 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error searching for extra data!\n");
834 } else if (extraret > 1) {
835 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "More than one result for extra data!\n");
838 } else if (extraret == 0) {
839 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "No extra data found for remote DN: %s", ldb_dn_linearize(merged, merged->dn));
844 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Extra data found for remote DN: %s", ldb_dn_linearize(merged, merged->dn));
845 for (j = 0; j < extrares[0]->num_elements; j++) {
846 ldb_msg_add(module->ldb, merged, &(extrares[0]->elements[j]), extrares[0]->elements[j].flags);
850 if (ldb_match_msg(module->ldb, merged, tree, base, scope) != 0) {
851 (*res)[ret] = merged;
854 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Discarded merged message because it did not match");
865 search for matching records using a ldb_parse_tree
867 static int map_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
868 enum ldb_scope scope, struct ldb_parse_tree *tree,
869 const char * const *attrs, struct ldb_message ***res)
871 struct ldb_message **fbres, **mpres;
875 ret_fb = map_search_bytree_fb(module, base, scope, tree, attrs, &fbres);
879 /* special dn's are never mapped.. */
880 if (ldb_dn_is_special(base)) {
885 ret_mp = map_search_bytree_mp(module, base, scope, tree, attrs, &mpres);
891 *res = talloc_array(module, struct ldb_message *, ret_fb + ret_mp);
893 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Merging %d mapped and %d fallback messages", ret_mp, ret_fb);
895 for (i = 0; i < ret_fb; i++) (*res)[i] = fbres[i];
896 for (i = 0; i < ret_mp; i++) (*res)[ret_fb+i] = mpres[i];
898 return ret_fb + ret_mp;
901 search for matching records
903 static int map_search(struct ldb_module *module, const struct ldb_dn *base,
904 enum ldb_scope scope, const char *expression,
905 const char * const *attrs, struct ldb_message ***res)
907 struct map_private *map = module->private_data;
908 struct ldb_parse_tree *tree;
911 tree = ldb_parse_tree(NULL, expression);
913 map->last_err_string = "expression parse failed";
917 ret = map_search_bytree(module, base, scope, tree, attrs, res);
922 static int msg_contains_objectclass(const struct ldb_message *msg, const char *name)
924 struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
927 for (i = 0; i < el->num_values; i++) {
928 if (ldb_attr_cmp((char *)el->values[i].data, name) == 0) {
939 static int map_add(struct ldb_module *module, const struct ldb_message *msg)
942 struct ldb_map_context *privdat = map_get_privdat(module);
943 struct ldb_message *fb, *mp;
944 struct ldb_message_element *ocs;
947 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add");
949 if (ldb_dn_is_special(msg->dn)) {
950 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add: Added fallback record");
951 return ldb_next_add_record(module, msg);
954 mp = talloc_zero(module, struct ldb_message);
955 mp->dn = map_local_dn(module, mp, msg->dn);
957 fb = talloc_zero(module, struct ldb_message);
958 fb->dn = talloc_reference(fb, msg->dn);
960 /* We add objectClass, so 'top' should be no problem */
961 ldb_msg_add_string(module->ldb, mp, "objectClass", "top");
963 /* make a list of remote objectclasses that can be used
964 * given the attributes that are available and add to
966 for (i = 0; privdat->objectclass_maps[i].local_name; i++) {
967 int j, has_musts, has_baseclasses;
969 /* Add this objectClass to the list if all musts are present */
970 for (j = 0; privdat->objectclass_maps[i].musts[j]; j++) {
971 if (!map_msg_can_map_attr(module, msg, privdat->objectclass_maps[i].musts[j]))
975 has_musts = (privdat->objectclass_maps[i].musts[j] == NULL);
977 /* Check if base classes are present as well */
978 for (j = 0; privdat->objectclass_maps[i].base_classes[j]; j++) {
979 if (!msg_contains_objectclass(mp, privdat->objectclass_maps[i].base_classes[j]))
983 has_baseclasses = (privdat->objectclass_maps[i].base_classes[j] == NULL);
985 /* Apparently, it contains all required elements */
986 if (has_musts && has_baseclasses) {
987 ldb_msg_add_string(module->ldb, mp, "objectClass", privdat->objectclass_maps[i].remote_name);
991 ocs = ldb_msg_find_element(mp, "objectClass");
992 if (ocs->num_values == 1) { /* Only top */
993 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add: Added fallback record");
994 return ldb_next_add_record(module, msg);
998 * - try to map as much attributes as possible where allowed and add them to mp_msg
999 * - add other attributes to fb_msg
1001 for (i = 0; i < msg->num_elements; i++) {
1002 const struct ldb_map_attribute *attr;
1003 struct ldb_message_element *elm;
1004 enum ldb_map_attr_type map_type;
1008 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0)
1011 attr = map_find_attr_local(privdat, msg->elements[i].name);
1014 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Undefined local attribute '%s', ignoring\n", msg->elements[i].name);
1015 map_type = MAP_IGNORE;
1016 } else map_type = attr->type;
1018 /* Decide whether or not we need to map or fallback */
1021 attr->u.generate.generate_remote(module, attr->local_name, msg, mp, fb);
1024 mapped = map_msg_valid_attr(module, mp, attr->local_name);
1025 case MAP_IGNORE: mapped = 0; break;
1027 case MAP_RENAME: mapped = map_msg_valid_attr(module, mp, attr->u.rename.remote_name);
1034 elm = talloc(fb, struct ldb_message_element);
1036 elm->num_values = msg->elements[i].num_values;
1037 elm->values = talloc_reference(elm, msg->elements[i].values);
1038 elm->name = talloc_strdup(elm, msg->elements[i].name);
1042 elm = talloc(mp, struct ldb_message_element);
1044 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
1045 elm->num_values = msg->elements[i].num_values;
1046 elm->values = talloc_reference(elm, msg->elements[i].values);
1050 elm = talloc(mp, struct ldb_message_element);
1052 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
1053 elm->num_values = msg->elements[i].num_values;
1054 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
1056 for (j = 0; j < elm->num_values; j++) {
1057 elm->values[j] = attr->u.convert.convert_local(module, mp, &msg->elements[i].values[j]);
1060 mapped = map_msg_valid_attr(module, mp, attr->u.convert.remote_name);
1066 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "This line should never be reached");
1069 ldb_msg_add(module->ldb, mp, elm, 0);
1071 elm = talloc(fb, struct ldb_message_element);
1073 elm->num_values = msg->elements[i].num_values;
1074 elm->values = talloc_reference(elm, msg->elements[i].values);
1075 elm->name = talloc_strdup(elm, msg->elements[i].name);
1077 ldb_msg_add(module->ldb, fb, elm, 0);
1081 ret = ldb_add(privdat->mapped_ldb, mp);
1083 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Adding mapped record failed: %s", ldb_errstring(privdat->mapped_ldb));
1087 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add: Added mapped record");
1089 ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
1090 ret = ldb_next_add_record(module, fb);
1092 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Adding fallback record failed: %s", ldb_next_errstring(module));
1106 static int map_modify(struct ldb_module *module, const struct ldb_message *msg)
1108 struct ldb_map_context *privdat = map_get_privdat(module);
1109 struct ldb_message *fb, *mp;
1110 struct ldb_message_element *elm;
1114 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_modify");
1116 if (ldb_dn_is_special(msg->dn))
1117 return ldb_next_modify_record(module, msg);
1119 fb = talloc_zero(module, struct ldb_message);
1120 fb->dn = talloc_reference(fb, msg->dn);
1122 mp = talloc_zero(module, struct ldb_message);
1123 mp->dn = map_local_dn(module, mp, msg->dn);
1125 /* Loop over mi and call generate_remote for each attribute */
1126 for (i = 0; i < msg->num_elements; i++) {
1127 const struct ldb_map_attribute *attr;
1128 enum ldb_map_attr_type map_type;
1130 if (ldb_attr_cmp(msg->elements[i].name, "isMapped") == 0)
1133 attr = map_find_attr_local(privdat, msg->elements[i].name);
1136 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Undefined local attribute '%s', ignoring\n", msg->elements[i].name);
1137 map_type = MAP_IGNORE;
1138 } else map_type = attr->type;
1141 case MAP_IGNORE: /* Add to fallback message */
1142 elm = talloc(fb, struct ldb_message_element);
1144 elm->num_values = msg->elements[i].num_values;
1145 elm->values = talloc_reference(elm, msg->elements[i].values);
1146 elm->name = talloc_strdup(elm, msg->elements[i].name);
1148 ldb_msg_add(module->ldb, fb, elm, msg->elements[i].flags);
1151 elm = talloc(mp, struct ldb_message_element);
1153 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
1154 elm->num_values = msg->elements[i].num_values;
1155 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
1156 for (j = 0; j < elm->num_values; j++) {
1157 elm->values[j] = msg->elements[i].values[j];
1160 ldb_msg_add(module->ldb, mp, elm, msg->elements[i].flags);
1164 elm = talloc(mp, struct ldb_message_element);
1166 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
1167 elm->num_values = msg->elements[i].num_values;
1168 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
1170 for (j = 0; j < elm->num_values; j++) {
1171 elm->values[j] = attr->u.convert.convert_local(module, mp, &msg->elements[i].values[j]);
1174 ldb_msg_add(module->ldb, mp, elm, msg->elements[i].flags);
1178 elm = talloc(mp, struct ldb_message_element);
1180 elm->num_values = msg->elements[i].num_values;
1181 elm->values = talloc_reference(elm, msg->elements[i].values);
1182 elm->name = talloc_strdup(elm, msg->elements[i].name);
1184 ldb_msg_add(module->ldb, mp, elm, msg->elements[i].flags);
1188 attr->u.generate.generate_remote(module, attr->local_name, msg, mp, fb);
1193 if (fb->num_elements > 0) {
1194 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Modifying fallback record with %d elements", fb->num_elements);
1195 fb_ret = ldb_next_modify_record(module, fb);
1197 ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
1198 fb_ret = ldb_next_add_record(module, fb);
1203 if (mp->num_elements > 0) {
1204 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Modifying mapped record with %d elements", mp->num_elements);
1205 mp_ret = ldb_modify(privdat->mapped_ldb, mp);
1209 return (mp_ret == -1 || fb_ret == -1)?-1:0;
1212 static int map_lock(struct ldb_module *module, const char *lockname)
1214 return ldb_next_named_lock(module, lockname);
1217 static int map_unlock(struct ldb_module *module, const char *lockname)
1219 return ldb_next_named_unlock(module, lockname);
1223 return extended error information
1225 static const char *map_errstring(struct ldb_module *module)
1227 struct map_private *map = module->private_data;
1229 if (map->last_err_string)
1230 return map->last_err_string;
1232 return ldb_next_errstring(module);
1235 static const struct ldb_module_ops map_ops = {
1237 .search = map_search,
1238 .search_bytree = map_search_bytree,
1239 .add_record = map_add,
1240 .modify_record = map_modify,
1241 .delete_record = map_delete,
1242 .rename_record = map_rename,
1243 .named_lock = map_lock,
1244 .named_unlock = map_unlock,
1245 .errstring = map_errstring
1248 static char *map_find_url(struct ldb_context *ldb, const char *name)
1250 const char * const attrs[] = { "@MAP_URL" , NULL};
1251 struct ldb_message **msg = NULL;
1252 struct ldb_dn *mods;
1256 mods = ldb_dn_string_compose(ldb, NULL, "@MAP=%s", name);
1258 ldb_debug(ldb, LDB_DEBUG_ERROR, "Can't construct DN");
1262 ret = ldb_search(ldb, mods, LDB_SCOPE_BASE, "", attrs, &msg);
1265 ldb_debug(ldb, LDB_DEBUG_ERROR, "Not enough results found looking for @MAP");
1269 url = talloc_strdup(ldb, ldb_msg_find_string(msg[0], "@MAP_URL", NULL));
1276 /* the init function */
1277 struct ldb_module *ldb_map_init(struct ldb_context *ldb, const struct ldb_map_attribute *attrs, const struct ldb_map_objectclass *ocls, const char *name)
1280 struct ldb_module *ctx;
1281 struct map_private *data;
1284 ctx = talloc(ldb, struct ldb_module);
1288 data = talloc(ctx, struct map_private);
1294 data->context.mapped_ldb = ldb_init(data);
1295 ldb_set_debug(data->context.mapped_ldb, ldb->debug_ops.debug, ldb->debug_ops.context);
1296 url = map_find_url(ldb, name);
1299 ldb_debug(ldb, LDB_DEBUG_FATAL, "@MAP=%s not set!\n", name);
1303 if (ldb_connect(data->context.mapped_ldb, url, 0, NULL) != 0) {
1304 ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to open mapped database for %s at '%s'\n", name, url);
1310 data->last_err_string = NULL;
1312 /* Get list of attribute maps */
1314 data->context.attribute_maps = NULL;
1316 for (i = 0; attrs[i].local_name; i++) {
1317 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1318 data->context.attribute_maps[j] = attrs[i];
1322 for (i = 0; builtin_attribute_maps[i].local_name; i++) {
1323 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1324 data->context.attribute_maps[j] = builtin_attribute_maps[i];
1328 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1329 memset(&data->context.attribute_maps[j], 0, sizeof(struct ldb_map_attribute));
1331 data->context.objectclass_maps = ocls;
1332 ctx->private_data = data;
1334 ctx->prev = ctx->next = NULL;
1335 ctx->ops = &map_ops;
1340 static struct ldb_val map_convert_local_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1342 struct ldb_dn *dn, *newdn;
1343 struct ldb_val *newval;
1345 dn = ldb_dn_explode(ctx, (char *)val->data);
1347 newdn = map_local_dn(module, ctx, dn);
1351 newval = talloc(ctx, struct ldb_val);
1352 newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1353 newval->length = strlen((char *)newval->data);
1360 static struct ldb_val map_convert_remote_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1362 struct ldb_dn *dn, *newdn;
1363 struct ldb_val *newval;
1365 dn = ldb_dn_explode(ctx, (char *)val->data);
1367 newdn = map_remote_dn(module, ctx, dn);
1371 newval = talloc(ctx, struct ldb_val);
1372 newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1373 newval->length = strlen((char *)newval->data);
1380 static struct ldb_val map_convert_local_objectclass(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1383 struct ldb_map_context *map = module->private_data;
1385 for (i = 0; map->objectclass_maps[i].local_name; i++) {
1386 if (!strcmp(map->objectclass_maps[i].local_name, (char *)val->data)) {
1387 struct ldb_val newval;
1388 newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].remote_name);
1389 newval.length = strlen((char *)newval.data);
1391 return ldb_val_dup(ctx, &newval);
1395 return ldb_val_dup(ctx, val);
1398 static struct ldb_val map_convert_remote_objectclass(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1401 struct ldb_map_context *map = module->private_data;
1403 for (i = 0; map->objectclass_maps[i].remote_name; i++) {
1404 if (!strcmp(map->objectclass_maps[i].remote_name, (char *)val->data)) {
1405 struct ldb_val newval;
1406 newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].local_name);
1407 newval.length = strlen((char *)newval.data);
1409 return ldb_val_dup(ctx, &newval);
1413 return ldb_val_dup(ctx, val);