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 "lib/ldb/include/ldb.h"
27 #include "lib/ldb/include/ldb_private.h"
28 #include "lib/ldb/modules/ldb_map.h"
31 * - objectclass hint in ldb_map_attribute
32 * for use when multiple remote attributes (independant of each other)
33 * map to one local attribute. E.g.: (uid, gidNumber) -> unixName
34 * (use MAP_GENERATE instead ?)
38 - special attribute 'isMapped'
40 - split up ldb_message into fallback and mapped parts if is_mappable
42 - search local one for not isMapped entries
43 - remove remote attributes from ldb_parse_tree
45 - per record, search local one for additional data (by dn)
46 - test if (full expression) is now true
50 - rename locally and remotely
53 static const struct ldb_map_attribute builtin_attribute_maps[];
56 struct ldb_map_context context;
57 const char *last_err_string;
60 static struct ldb_map_context *map_get_privdat(struct ldb_module *module)
62 return &((struct map_private *)module->private_data)->context;
65 static const struct ldb_map_objectclass *map_find_objectclass_local(struct ldb_map_context *privdat, const char *name)
68 for (i = 0; privdat->objectclass_maps[i].local_name; i++) {
69 if (!ldb_attr_cmp(privdat->objectclass_maps[i].local_name, name))
70 return &privdat->objectclass_maps[i];
76 /* Decide whether a add/modify should be pushed to the
77 * remote LDAP server. We currently only do this if we see an objectClass we know */
78 static BOOL map_is_mappable(struct ldb_map_context *privdat, const struct ldb_message *msg)
81 struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
83 /* No objectClass... */
88 for (i = 0; i < el->num_values; i++) {
89 if (map_find_objectclass_local(privdat, (char *)el->values[i].data))
96 /* find an attribute by the local name */
97 static const struct ldb_map_attribute *map_find_attr_local(struct ldb_map_context *privdat, const char *attr)
101 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
102 if (!ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr))
103 return &privdat->attribute_maps[i];
109 /* find an attribute by the remote name */
110 static const struct ldb_map_attribute *map_find_attr_remote(struct ldb_map_context *privdat, const char *attr)
114 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
115 if (privdat->attribute_maps[i].type == MAP_IGNORE)
118 if (privdat->attribute_maps[i].type == MAP_GENERATE)
121 if (privdat->attribute_maps[i].type == MAP_KEEP &&
122 ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr) == 0)
123 return &privdat->attribute_maps[i];
125 if ((privdat->attribute_maps[i].type == MAP_RENAME ||
126 privdat->attribute_maps[i].type == MAP_CONVERT) &&
127 ldb_attr_cmp(privdat->attribute_maps[i].u.rename.remote_name, attr) == 0)
128 return &privdat->attribute_maps[i];
135 static struct ldb_parse_tree *ldb_map_parse_tree(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_parse_tree *tree)
138 const struct ldb_map_attribute *attr;
139 struct ldb_parse_tree *new_tree;
140 enum ldb_map_attr_type map_type;
141 struct ldb_val value, newvalue;
142 struct ldb_map_context *privdat = map_get_privdat(module);
148 /* Find attr in question and:
149 * - if it has a convert_operator function, run that
150 * - otherwise, replace attr name with required[0] */
152 if (tree->operation == LDB_OP_AND ||
153 tree->operation == LDB_OP_OR) {
155 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
156 new_tree->u.list.elements = talloc_array(new_tree, struct ldb_parse_tree *, tree->u.list.num_elements);
157 new_tree->u.list.num_elements = 0;
158 for (i = 0; i < tree->u.list.num_elements; i++) {
159 struct ldb_parse_tree *child = ldb_map_parse_tree(module, new_tree, tree->u.list.elements[i]);
162 new_tree->u.list.elements[i] = child;
163 new_tree->u.list.num_elements++;
170 if (tree->operation == LDB_OP_NOT) {
171 struct ldb_parse_tree *child;
173 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
174 child = ldb_map_parse_tree(module, new_tree, tree->u.isnot.child);
177 talloc_free(new_tree);
181 new_tree->u.isnot.child = child;
185 /* tree->operation is LDB_OP_EQUALITY, LDB_OP_SUBSTRING, LDB_OP_GREATER,
186 * LDB_OP_LESS, LDB_OP_APPROX, LDB_OP_PRESENT or LDB_OP_EXTENDED
188 * (all have attr as the first element)
191 attr = map_find_attr_local(privdat, tree->u.equality.attr);
194 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s', leaving as is\n", tree->u.equality.attr);
197 map_type = attr->type;
200 if (attr && attr->convert_operator) {
201 /* Run convert_operator */
202 return attr->convert_operator(privdat, module, tree);
205 if (map_type == MAP_IGNORE) {
206 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Search on ignored attribute '%s'\n", tree->u.equality.attr);
210 if (map_type == MAP_GENERATE) {
211 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);
215 if (tree->operation == LDB_OP_EQUALITY) {
216 value = tree->u.equality.value;
217 } else if (tree->operation == LDB_OP_LESS || tree->operation == LDB_OP_GREATER ||
218 tree->operation == LDB_OP_APPROX) {
219 value = tree->u.comparison.value;
220 } else if (tree->operation == LDB_OP_EXTENDED) {
221 value = tree->u.extended.value;
224 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
226 if (map_type == MAP_KEEP) {
227 new_tree->u.equality.attr = talloc_strdup(new_tree, tree->u.equality.attr);
228 } else { /* MAP_RENAME / MAP_CONVERT */
229 new_tree->u.equality.attr = talloc_strdup(new_tree, attr->u.rename.remote_name);
232 if (new_tree->operation == LDB_OP_PRESENT)
235 if (new_tree->operation == LDB_OP_SUBSTRING) {
236 new_tree->u.substring.chunks = NULL; /* FIXME! */
240 if (map_type == MAP_CONVERT) {
241 newvalue = attr->u.convert.convert_local(privdat, new_tree, &value);
243 newvalue = ldb_val_dup(new_tree, &value);
246 if (new_tree->operation == LDB_OP_EQUALITY) {
247 new_tree->u.equality.value = newvalue;
248 } else if (new_tree->operation == LDB_OP_LESS || new_tree->operation == LDB_OP_GREATER ||
249 new_tree->operation == LDB_OP_APPROX) {
250 new_tree->u.comparison.value = newvalue;
251 } else if (new_tree->operation == LDB_OP_EXTENDED) {
252 new_tree->u.extended.value = newvalue;
253 new_tree->u.extended.rule_id = talloc_strdup(new_tree, tree->u.extended.rule_id);
259 /* Remote DN -> Local DN */
260 static struct ldb_dn *map_remote_dn(struct ldb_map_context *privdat, TALLOC_CTX *ctx, const struct ldb_dn *dn)
262 struct ldb_dn *newdn;
268 newdn = talloc_memdup(ctx, dn, sizeof(*dn));
272 newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
274 if (!newdn->components)
277 /* For each rdn, map the attribute name and possibly the
280 for (i = 0; i < dn->comp_num; i++) {
281 const struct ldb_map_attribute *attr = map_find_attr_remote(privdat, dn->components[i].name);
282 enum ldb_map_attr_type map_type;
284 /* Unknown attribute - leave this dn as is and hope the best... */
285 if (!attr) map_type = MAP_KEEP;
286 else map_type = attr->type;
291 DEBUG(0, ("Local MAP_IGNORE or MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name));
296 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
297 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
301 newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
302 newdn->components[i].value = attr->u.convert.convert_remote(privdat, ctx, &dn->components[i].value);
306 newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
307 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
314 /* Local DN -> Remote DN */
315 static struct ldb_dn *map_local_dn(struct ldb_map_context *privdat, TALLOC_CTX *ctx, const struct ldb_dn *dn)
317 struct ldb_dn *newdn;
323 newdn = talloc_memdup(ctx, dn, sizeof(*dn));
327 newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
329 if (!newdn->components)
332 /* For each rdn, map the attribute name and possibly the
333 * complete rdn using an equality convert_operator call */
335 for (i = 0; i < dn->comp_num; i++) {
336 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, dn->components[i].name);
337 enum ldb_map_attr_type map_type;
339 /* Unknown attribute - leave this dn as is and hope the best... */
340 if (!attr) map_type = MAP_KEEP; else map_type = attr->type;
346 DEBUG(0, ("Local MAP_IGNORE/MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name));
351 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.convert.remote_name);
352 newdn->components[i].value = attr->u.convert.convert_local(privdat, newdn->components, &dn->components[i].value);
356 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.rename.remote_name);
357 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
361 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
362 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
370 /* Loop over ldb_map_attribute array and add remote_names */
371 static const char **ldb_map_attrs(struct ldb_module *module, const char *const attrs[])
375 int ar_size = 0, last_element = 0;
376 struct ldb_map_context *privdat = map_get_privdat(module);
381 /* Start with good guess of number of elements */
382 for (i = 0; attrs[i]; i++);
384 ret = talloc_array(module, const char *, i);
387 for (i = 0; attrs[i]; i++) {
389 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
390 enum ldb_map_attr_type map_type;
393 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Local attribute '%s' does not have a definition!\n", attrs[i]);
394 map_type = MAP_IGNORE;
395 } else map_type = attr->type;
399 case MAP_IGNORE: break;
401 if (last_element >= ar_size) {
402 ret = talloc_realloc(module, ret, const char *, ar_size+1);
405 ret[last_element] = attr->local_name;
411 if (last_element >= ar_size) {
412 ret = talloc_realloc(module, ret, const char *, ar_size+1);
415 ret[last_element] = attr->u.rename.remote_name;
420 /* Add remote_names[] for this attribute to the list of
421 * attributes to request from the remote server */
422 for (j = 0; attr->u.generate.remote_names[j]; j++) {
423 if (last_element >= ar_size) {
424 ret = talloc_realloc(module, ret, const char *, ar_size+1);
427 ret[last_element] = attr->u.generate.remote_names[j];
434 if (last_element >= ar_size) {
435 ret = talloc_realloc(module, ret, const char *, ar_size+1);
439 ret[last_element] = NULL;
444 static const char **available_local_attributes(struct ldb_module *module, const struct ldb_message *msg)
446 struct ldb_map_context *privdat = map_get_privdat(module);
449 const char **ret = talloc_array(module, const char *, 1);
453 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
455 const struct ldb_map_attribute *attr = &privdat->attribute_maps[i];
457 /* If all remote attributes for this attribute are present, add the
458 * local one to the list */
460 switch (attr->type) {
461 case MAP_IGNORE: break;
463 avail = (ldb_msg_find_ldb_val(msg, attr->local_name) != NULL);
468 avail = (ldb_msg_find_ldb_val(msg, attr->u.rename.remote_name) != NULL);
473 for (j = 0; attr->u.generate.remote_names[j]; j++) {
474 avail &= (ldb_msg_find_ldb_val(msg, attr->u.generate.remote_names[j]) != NULL);
482 ret = talloc_realloc(module, ret, const char *, count+2);
483 ret[count] = attr->local_name;
491 /* Used for search */
492 static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, const char * const*attrs, const struct ldb_message *mi)
495 struct ldb_message *msg = talloc_zero(module, struct ldb_message);
496 struct ldb_message_element *elm, *oldelm;
497 struct ldb_map_context *privdat = map_get_privdat(module);
498 const char **newattrs = NULL;
500 msg->dn = map_remote_dn(privdat, module, mi->dn);
502 ldb_msg_add_string(module->ldb, msg, "mappedFromDn", ldb_dn_linearize(msg, mi->dn));
504 /* Loop over attrs, find in ldb_map_attribute array and
508 /* Generate list of the local attributes that /can/ be generated
509 * using the specific remote attributes */
511 attrs = newattrs = available_local_attributes(module, mi);
514 for (i = 0; attrs[i]; i++) {
515 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
516 enum ldb_map_attr_type map_type;
519 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s' when generating incoming message\n", attrs[i]);
520 map_type = MAP_IGNORE;
521 } else map_type = attr->type;
524 case MAP_IGNORE:break;
526 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
527 if (!oldelm) continue;
529 elm = talloc(msg, struct ldb_message_element);
530 elm->name = talloc_strdup(elm, attr->local_name);
531 elm->num_values = oldelm->num_values;
532 elm->values = talloc_reference(elm, oldelm->values);
534 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
538 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
539 if (!oldelm) continue;
541 elm = talloc(msg, struct ldb_message_element);
542 elm->name = talloc_strdup(elm, attr->local_name);
543 elm->num_values = oldelm->num_values;
544 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
546 for (j = 0; j < oldelm->num_values; j++)
547 elm->values[j] = attr->u.convert.convert_remote(privdat, elm, &oldelm->values[j]);
549 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
553 oldelm = ldb_msg_find_element(mi, attr->local_name);
554 if (!oldelm) continue;
556 elm = talloc(msg, struct ldb_message_element);
558 elm->num_values = oldelm->num_values;
559 elm->values = talloc_reference(elm, oldelm->values);
560 elm->name = talloc_strdup(elm, oldelm->name);
562 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
566 elm = attr->u.generate.generate_local(privdat, msg, attr->local_name, mi);
569 ldb_msg_add(module->ldb, msg, elm, elm->flags);
572 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Unknown attr->type for %s", attr->local_name);
577 talloc_free(newattrs);
582 /* Used for add, modify */
583 static int ldb_map_message_outgoing(struct ldb_module *module, const struct ldb_message *mo, struct ldb_message **fb, struct ldb_message **mp)
585 struct ldb_map_context *privdat = map_get_privdat(module);
586 struct ldb_message *msg = talloc_zero(module, struct ldb_message);
587 struct ldb_message_element *elm;
590 *fb = talloc_zero(module, struct ldb_message);
591 (*fb)->dn = talloc_reference(*fb, mo->dn);
595 msg->private_data = mo->private_data;
597 msg->dn = map_local_dn(privdat, module, mo->dn);
599 /* Loop over mi and call generate_remote for each attribute */
600 for (i = 0; i < mo->num_elements; i++) {
601 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, mo->elements[i].name);
602 enum ldb_map_attr_type map_type;
605 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Undefined local attribute '%s', ignoring\n", mo->elements[i].name);
606 map_type = MAP_IGNORE;
608 } else map_type = attr->type;
611 case MAP_IGNORE: /* Add to fallback message */
612 elm = talloc(*fb, struct ldb_message_element);
614 elm->num_values = mo->elements[i].num_values;
615 elm->values = talloc_reference(elm, mo->elements[i].values);
616 elm->name = talloc_strdup(elm, mo->elements[i].name);
618 ldb_msg_add(module->ldb, *fb, elm, mo->elements[i].flags);
621 elm = talloc(msg, struct ldb_message_element);
623 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
624 elm->num_values = mo->elements[i].num_values;
625 elm->values = talloc_reference(elm, mo->elements[i].values);
627 ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags);
631 elm = talloc(msg, struct ldb_message_element);
633 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
634 elm->num_values = mo->elements[i].num_values;
635 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
637 for (j = 0; j < elm->num_values; j++) {
638 elm->values[j] = attr->u.convert.convert_local(privdat, msg, &mo->elements[i].values[j]);
641 ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags);
645 elm = talloc(msg, struct ldb_message_element);
647 elm->num_values = mo->elements[i].num_values;
648 elm->values = talloc_reference(elm, mo->elements[i].values);
649 elm->name = talloc_strdup(elm, mo->elements[i].name);
651 ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags);
655 attr->u.generate.generate_remote(privdat, attr->local_name, mo, msg);
667 static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
669 struct ldb_map_context *privdat = map_get_privdat(module);
670 struct ldb_dn *n_olddn, *n_newdn;
673 ret = ldb_next_rename_record(module, olddn, newdn);
675 n_olddn = map_local_dn(privdat, module, olddn);
676 n_newdn = map_local_dn(privdat, module, newdn);
678 ret = ldb_rename(privdat->mapped_ldb, n_olddn, n_newdn);
680 talloc_free(n_olddn);
681 talloc_free(n_newdn);
689 static int map_delete(struct ldb_module *module, const struct ldb_dn *dn)
691 struct ldb_map_context *privdat = map_get_privdat(module);
692 struct ldb_dn *newdn;
695 ret = ldb_next_delete_record(module, dn);
697 newdn = map_local_dn(privdat, module, dn);
699 ret = ldb_delete(privdat->mapped_ldb, newdn);
706 /* search fallback database */
707 static int map_search_bytree_fb(struct ldb_module *module, const struct ldb_dn *base,
708 enum ldb_scope scope, struct ldb_parse_tree *tree,
709 const char * const *attrs, struct ldb_message ***res)
712 struct ldb_parse_tree t_and, t_not, t_present, *childs[2];
714 t_present.operation = LDB_OP_PRESENT;
715 t_present.u.present.attr = talloc_strdup(NULL, "isMapped");
717 t_not.operation = LDB_OP_NOT;
718 t_not.u.isnot.child = &t_present;
722 t_and.operation = LDB_OP_AND;
723 t_and.u.list.num_elements = 2;
724 t_and.u.list.elements = childs;
726 ret = ldb_next_search_bytree(module, base, scope, &t_and, attrs, res);
728 talloc_free(t_present.u.present.attr);
733 static int map_search_bytree_mp(struct ldb_module *module, const struct ldb_dn *base,
734 enum ldb_scope scope, struct ldb_parse_tree *tree,
735 const char * const *attrs, struct ldb_message ***res)
737 struct ldb_parse_tree *new_tree;
738 struct ldb_dn *new_base;
739 struct ldb_message **newres;
740 const char **newattrs;
742 struct ldb_map_context *privdat = map_get_privdat(module);
745 /*- search mapped database */
747 new_tree = ldb_map_parse_tree(module, module, tree);
748 newattrs = ldb_map_attrs(module, attrs);
749 new_base = map_local_dn(privdat, module, base);
751 mpret = ldb_search_bytree(privdat->mapped_ldb, new_base, scope, new_tree, newattrs, &newres);
753 talloc_free(new_base);
754 talloc_free(new_tree);
755 talloc_free(newattrs);
758 struct map_private *map_private = module->private_data;
759 map_private->last_err_string = ldb_errstring(privdat->mapped_ldb);
764 - per returned record, search fallback database for additional data (by dn)
765 - test if (full expression) is now true
768 *res = talloc_array(module, struct ldb_message *, mpret);
772 for (i = 0; i < mpret; i++) {
773 struct ldb_message *merged = ldb_map_message_incoming(module, attrs, newres[i]);
774 struct ldb_message **extrares = NULL;
777 /* Merge with additional data from local database */
778 extraret = ldb_next_search(module, merged->dn, LDB_SCOPE_BASE, "", NULL, &extrares);
780 if (extraret == -1) {
781 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error searching for extra data!\n");
782 } else if (extraret > 1) {
783 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "More than one result for extra data!\n");
786 } else if (extraret == 0) {
787 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "No extra data found for remote DN");
792 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Extra data found for remote DN");
793 for (j = 0; j < extrares[0]->num_elements; j++) {
794 ldb_msg_add(module->ldb, merged, &(extrares[0]->elements[j]), extrares[0]->elements[j].flags);
797 ldb_msg_add_string(module->ldb, merged, "extraMapped", "TRUE");
799 ldb_msg_add_string(module->ldb, merged, "extraMapped", "FALSE");
802 if (ldb_match_msg(module->ldb, merged, tree, base, scope)) {
803 (*res)[ret] = merged;
806 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Discarded merged message because it did not match");
817 search for matching records using a ldb_parse_tree
819 static int map_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
820 enum ldb_scope scope, struct ldb_parse_tree *tree,
821 const char * const *attrs, struct ldb_message ***res)
823 struct ldb_message **fbres, **mpres;
827 ret_fb = map_search_bytree_fb(module, base, scope, tree, attrs, &fbres);
831 ret_mp = map_search_bytree_mp(module, base, scope, tree, attrs, &mpres);
837 *res = talloc_array(module, struct ldb_message *, ret_fb + ret_mp);
839 for (i = 0; i < ret_fb; i++) (*res)[i] = fbres[i];
840 for (i = 0; i < ret_mp; i++) (*res)[ret_fb+i] = mpres[i];
842 return ret_fb + ret_mp;
845 search for matching records
847 static int map_search(struct ldb_module *module, const struct ldb_dn *base,
848 enum ldb_scope scope, const char *expression,
849 const char * const *attrs, struct ldb_message ***res)
851 struct map_private *map = module->private_data;
852 struct ldb_parse_tree *tree;
855 tree = ldb_parse_tree(NULL, expression);
857 map->last_err_string = "expression parse failed";
861 ret = map_search_bytree(module, base, scope, tree, attrs, res);
869 static int map_add(struct ldb_module *module, const struct ldb_message *msg)
872 struct ldb_map_context *privdat = map_get_privdat(module);
873 struct ldb_message *fb, *mp;
875 if (!map_is_mappable(privdat, msg)) {
876 return ldb_next_add_record(module, msg);
879 if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1)
882 ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
884 ret = ldb_next_add_record(module, fb);
886 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding fallback record failed");
890 ret = ldb_add(privdat->mapped_ldb, mp);
892 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding mapped record failed");
906 static int map_modify(struct ldb_module *module, const struct ldb_message *msg)
908 struct ldb_map_context *privdat = map_get_privdat(module);
909 struct ldb_message *fb, *mp;
912 if (!map_is_mappable(privdat, msg))
913 return ldb_next_modify_record(module, msg);
916 if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1)
919 ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
921 ret = ldb_next_modify_record(module, fb);
923 ret = ldb_modify(privdat->mapped_ldb, mp);
931 static int map_lock(struct ldb_module *module, const char *lockname)
933 return ldb_next_named_lock(module, lockname);
936 static int map_unlock(struct ldb_module *module, const char *lockname)
938 return ldb_next_named_unlock(module, lockname);
942 return extended error information
944 static const char *map_errstring(struct ldb_module *module)
946 struct map_private *map = module->private_data;
948 if (map->last_err_string)
949 return map->last_err_string;
951 return ldb_next_errstring(module);
954 static const struct ldb_module_ops map_ops = {
956 .search = map_search,
957 .search_bytree = map_search_bytree,
958 .add_record = map_add,
959 .modify_record = map_modify,
960 .delete_record = map_delete,
961 .rename_record = map_rename,
962 .named_lock = map_lock,
963 .named_unlock = map_unlock,
964 .errstring = map_errstring
967 static char *map_find_url(struct ldb_context *ldb, const char *name)
969 const char * const attrs[] = { "@MAP_URL" , NULL};
970 struct ldb_message **msg = NULL;
975 mods = ldb_dn_string_compose(ldb, NULL, "@MAP=%s", name);
977 ldb_debug(ldb, LDB_DEBUG_ERROR, "Can't construct DN");
981 ret = ldb_search(ldb, mods, LDB_SCOPE_BASE, "", attrs, &msg);
984 ldb_debug(ldb, LDB_DEBUG_ERROR, "Not enough results found looking for @MAP");
988 url = talloc_strdup(ldb, ldb_msg_find_string(msg[0], "@MAP_URL", NULL));
995 /* the init function */
996 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)
999 struct ldb_module *ctx;
1000 struct map_private *data;
1003 ctx = talloc(ldb, struct ldb_module);
1007 data = talloc(ctx, struct map_private);
1013 data->context.mapped_ldb = ldb_init(data);
1014 url = map_find_url(ldb, name);
1017 ldb_debug(ldb, LDB_DEBUG_FATAL, "@MAP=%s not set!\n", name);
1021 if (ldb_connect(data->context.mapped_ldb, url, 0, NULL) != 0) {
1022 ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to open mapped database for %s at '%s'\n", name, url);
1028 data->last_err_string = NULL;
1030 /* Get list of attribute maps */
1032 data->context.attribute_maps = NULL;
1034 for (i = 0; attrs[i].local_name; i++) {
1035 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1036 data->context.attribute_maps[j] = attrs[i];
1040 for (i = 0; builtin_attribute_maps[i].local_name; i++) {
1041 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1042 data->context.attribute_maps[j] = builtin_attribute_maps[i];
1046 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1047 ZERO_STRUCT(data->context.attribute_maps[j].local_name);
1049 data->context.objectclass_maps = ocls;
1050 ctx->private_data = data;
1052 ctx->prev = ctx->next = NULL;
1053 ctx->ops = &map_ops;
1058 static struct ldb_val map_convert_local_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1060 struct ldb_dn *dn, *newdn;;
1061 struct ldb_val *newval;
1063 dn = ldb_dn_explode(ctx, (char *)val->data);
1065 newdn = map_local_dn(map, ctx, dn);
1069 newval = talloc(ctx, struct ldb_val);
1070 newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1071 newval->length = strlen((char *)newval->data);
1078 static struct ldb_val map_convert_remote_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1080 struct ldb_dn *dn, *newdn;;
1081 struct ldb_val *newval;
1083 dn = ldb_dn_explode(ctx, (char *)val->data);
1085 newdn = map_remote_dn(map, ctx, dn);
1089 newval = talloc(ctx, struct ldb_val);
1090 newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1091 newval->length = strlen((char *)newval->data);
1098 static struct ldb_val map_convert_local_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1102 for (i = 0; map->objectclass_maps[i].local_name; i++) {
1103 if (!strcmp(map->objectclass_maps[i].local_name, (char *)val->data)) {
1104 struct ldb_val newval;
1105 newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].remote_name);
1106 newval.length = strlen((char *)newval.data);
1108 return ldb_val_dup(ctx, &newval);
1112 return ldb_val_dup(ctx, val);
1115 static struct ldb_val map_convert_remote_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1119 for (i = 0; map->objectclass_maps[i].remote_name; i++) {
1120 if (!strcmp(map->objectclass_maps[i].remote_name, (char *)val->data)) {
1121 struct ldb_val newval;
1122 newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].local_name);
1123 newval.length = strlen((char *)newval.data);
1125 return ldb_val_dup(ctx, &newval);
1129 return ldb_val_dup(ctx, val);
1132 static const struct ldb_map_attribute builtin_attribute_maps[] = {
1135 .type = MAP_CONVERT,
1136 .u.convert.remote_name = "dn",
1137 .u.convert.convert_local = map_convert_local_dn,
1138 .u.convert.convert_remote = map_convert_remote_dn,
1141 .local_name = "objectclass",
1142 .type = MAP_CONVERT,
1143 .u.convert.remote_name = "objectclass",
1144 .u.convert.convert_local = map_convert_local_objectclass,
1145 .u.convert.convert_remote = map_convert_remote_objectclass,