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 * - 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 struct ldb_val map_convert_local_dn(struct ldb_module *map,
55 const struct ldb_val *val);
56 static struct ldb_val map_convert_remote_dn(struct ldb_module *map,
58 const struct ldb_val *val);
59 static struct ldb_val map_convert_local_objectclass(struct ldb_module *map,
61 const struct ldb_val *val);
62 static struct ldb_val map_convert_remote_objectclass(struct ldb_module *map,
64 const struct ldb_val *val);
66 static const struct ldb_map_attribute builtin_attribute_maps[] = {
70 .u.convert.remote_name = "dn",
71 .u.convert.convert_local = map_convert_local_dn,
72 .u.convert.convert_remote = map_convert_remote_dn,
75 .local_name = "objectclass",
77 .u.convert.remote_name = "objectclass",
78 .u.convert.convert_local = map_convert_local_objectclass,
79 .u.convert.convert_remote = map_convert_remote_objectclass,
87 struct ldb_map_context context;
88 const char *last_err_string;
91 static struct ldb_map_context *map_get_privdat(struct ldb_module *module)
93 return &((struct map_private *)module->private_data)->context;
96 static const struct ldb_map_objectclass *map_find_objectclass_local(struct ldb_map_context *privdat, const char *name)
99 for (i = 0; privdat->objectclass_maps[i].local_name; i++) {
100 if (!ldb_attr_cmp(privdat->objectclass_maps[i].local_name, name))
101 return &privdat->objectclass_maps[i];
107 /* Decide whether a add/modify should be pushed to the
108 * remote LDAP server. We currently only do this if we see an objectClass we know */
109 static int map_is_mappable(struct ldb_map_context *privdat, const struct ldb_message *msg)
112 struct ldb_message_element *el;
114 if (ldb_dn_is_special(msg->dn))
117 el = ldb_msg_find_element(msg, "objectClass");
119 /* No objectClass... */
124 for (i = 0; i < el->num_values; i++) {
125 if (map_find_objectclass_local(privdat, (char *)el->values[i].data))
132 /* find an attribute by the local name */
133 static const struct ldb_map_attribute *map_find_attr_local(struct ldb_map_context *privdat, const char *attr)
137 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
138 if (!ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr))
139 return &privdat->attribute_maps[i];
145 /* find an attribute by the remote name */
146 static const struct ldb_map_attribute *map_find_attr_remote(struct ldb_map_context *privdat, const char *attr)
150 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
151 if (privdat->attribute_maps[i].type == MAP_IGNORE)
154 if (privdat->attribute_maps[i].type == MAP_GENERATE)
157 if (privdat->attribute_maps[i].type == MAP_KEEP &&
158 ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr) == 0)
159 return &privdat->attribute_maps[i];
161 if ((privdat->attribute_maps[i].type == MAP_RENAME ||
162 privdat->attribute_maps[i].type == MAP_CONVERT) &&
163 ldb_attr_cmp(privdat->attribute_maps[i].u.rename.remote_name, attr) == 0)
164 return &privdat->attribute_maps[i];
171 static struct ldb_parse_tree *ldb_map_parse_tree(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_parse_tree *tree)
174 const struct ldb_map_attribute *attr;
175 struct ldb_parse_tree *new_tree;
176 enum ldb_map_attr_type map_type;
177 struct ldb_val value, newvalue;
178 struct ldb_map_context *privdat = map_get_privdat(module);
184 /* Find attr in question and:
185 * - if it has a convert_operator function, run that
186 * - otherwise, replace attr name with required[0] */
188 if (tree->operation == LDB_OP_AND ||
189 tree->operation == LDB_OP_OR) {
191 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
192 new_tree->u.list.elements = talloc_array(new_tree, struct ldb_parse_tree *, tree->u.list.num_elements);
193 new_tree->u.list.num_elements = 0;
194 for (i = 0; i < tree->u.list.num_elements; i++) {
195 struct ldb_parse_tree *child = ldb_map_parse_tree(module, new_tree, tree->u.list.elements[i]);
198 new_tree->u.list.elements[i] = child;
199 new_tree->u.list.num_elements++;
206 if (tree->operation == LDB_OP_NOT) {
207 struct ldb_parse_tree *child;
209 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
210 child = ldb_map_parse_tree(module, new_tree, tree->u.isnot.child);
213 talloc_free(new_tree);
217 new_tree->u.isnot.child = child;
221 /* tree->operation is LDB_OP_EQUALITY, LDB_OP_SUBSTRING, LDB_OP_GREATER,
222 * LDB_OP_LESS, LDB_OP_APPROX, LDB_OP_PRESENT or LDB_OP_EXTENDED
224 * (all have attr as the first element)
227 attr = map_find_attr_local(privdat, tree->u.equality.attr);
230 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Unable to find local attribute '%s', removing from parse tree\n", tree->u.equality.attr);
231 map_type = MAP_IGNORE;
233 map_type = attr->type;
236 if (attr && attr->convert_operator) {
237 /* Run convert_operator */
238 return attr->convert_operator(privdat, module, tree);
241 if (map_type == MAP_IGNORE) {
242 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Not mapping search on ignored attribute '%s'\n", tree->u.equality.attr);
246 if (map_type == MAP_GENERATE) {
247 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);
251 if (tree->operation == LDB_OP_EQUALITY) {
252 value = tree->u.equality.value;
253 } else if (tree->operation == LDB_OP_LESS || tree->operation == LDB_OP_GREATER ||
254 tree->operation == LDB_OP_APPROX) {
255 value = tree->u.comparison.value;
256 } else if (tree->operation == LDB_OP_EXTENDED) {
257 value = tree->u.extended.value;
260 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
262 if (map_type == MAP_KEEP) {
263 new_tree->u.equality.attr = talloc_strdup(new_tree, tree->u.equality.attr);
264 } else { /* MAP_RENAME / MAP_CONVERT */
265 new_tree->u.equality.attr = talloc_strdup(new_tree, attr->u.rename.remote_name);
268 if (new_tree->operation == LDB_OP_PRESENT)
271 if (new_tree->operation == LDB_OP_SUBSTRING) {
272 new_tree->u.substring.chunks = NULL; /* FIXME! */
276 if (map_type == MAP_CONVERT) {
277 newvalue = attr->u.convert.convert_local(module, new_tree, &value);
279 newvalue = ldb_val_dup(new_tree, &value);
282 if (new_tree->operation == LDB_OP_EQUALITY) {
283 new_tree->u.equality.value = newvalue;
284 } else if (new_tree->operation == LDB_OP_LESS || new_tree->operation == LDB_OP_GREATER ||
285 new_tree->operation == LDB_OP_APPROX) {
286 new_tree->u.comparison.value = newvalue;
287 } else if (new_tree->operation == LDB_OP_EXTENDED) {
288 new_tree->u.extended.value = newvalue;
289 new_tree->u.extended.rule_id = talloc_strdup(new_tree, tree->u.extended.rule_id);
295 /* Remote DN -> Local DN */
296 static struct ldb_dn *map_remote_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_dn *dn)
298 struct ldb_dn *newdn;
304 newdn = talloc_memdup(ctx, dn, sizeof(*dn));
308 newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
310 if (!newdn->components)
313 /* For each rdn, map the attribute name and possibly the
316 for (i = 0; i < dn->comp_num; i++) {
317 const struct ldb_map_attribute *attr = map_find_attr_remote(module->private_data, dn->components[i].name);
318 enum ldb_map_attr_type map_type;
320 /* Unknown attribute - leave this dn as is and hope the best... */
321 if (!attr) map_type = MAP_KEEP;
322 else map_type = attr->type;
327 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Local MAP_IGNORE or MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name);
332 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
333 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
337 newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
338 newdn->components[i].value = attr->u.convert.convert_remote(module, ctx, &dn->components[i].value);
342 newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
343 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
350 /* Local DN -> Remote DN */
351 static struct ldb_dn *map_local_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_dn *dn)
353 struct ldb_dn *newdn;
359 newdn = talloc_memdup(ctx, dn, sizeof(*dn));
363 newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
365 if (!newdn->components)
368 /* For each rdn, map the attribute name and possibly the
369 * complete rdn using an equality convert_operator call */
371 for (i = 0; i < dn->comp_num; i++) {
372 const struct ldb_map_attribute *attr = map_find_attr_local(module->private_data, dn->components[i].name);
373 enum ldb_map_attr_type map_type;
375 /* Unknown attribute - leave this dn as is and hope the best... */
376 if (!attr) map_type = MAP_KEEP; else map_type = attr->type;
382 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Local MAP_IGNORE/MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name);
387 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.convert.remote_name);
388 newdn->components[i].value = attr->u.convert.convert_local(module, newdn->components, &dn->components[i].value);
392 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.rename.remote_name);
393 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
397 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
398 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
406 /* Loop over ldb_map_attribute array and add remote_names */
407 static const char **ldb_map_attrs(struct ldb_module *module, const char *const attrs[])
411 int ar_size = 0, last_element = 0;
412 struct ldb_map_context *privdat = map_get_privdat(module);
417 /* Start with good guess of number of elements */
418 for (i = 0; attrs[i]; i++);
420 ret = talloc_array(module, const char *, i);
423 for (i = 0; attrs[i]; i++) {
425 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
426 enum ldb_map_attr_type map_type;
429 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Local attribute '%s' does not have a definition!\n", attrs[i]);
430 map_type = MAP_IGNORE;
431 } else map_type = attr->type;
435 case MAP_IGNORE: break;
437 if (last_element >= ar_size) {
438 ret = talloc_realloc(module, ret, const char *, ar_size+1);
441 ret[last_element] = attr->local_name;
447 if (last_element >= ar_size) {
448 ret = talloc_realloc(module, ret, const char *, ar_size+1);
451 ret[last_element] = attr->u.rename.remote_name;
456 /* Add remote_names[] for this attribute to the list of
457 * attributes to request from the remote server */
458 for (j = 0; attr->u.generate.remote_names[j]; j++) {
459 if (last_element >= ar_size) {
460 ret = talloc_realloc(module, ret, const char *, ar_size+1);
463 ret[last_element] = attr->u.generate.remote_names[j];
470 if (last_element >= ar_size) {
471 ret = talloc_realloc(module, ret, const char *, ar_size+1);
475 ret[last_element] = NULL;
480 static const char **available_local_attributes(struct ldb_module *module, const struct ldb_message *msg)
482 struct ldb_map_context *privdat = map_get_privdat(module);
485 const char **ret = talloc_array(module, const char *, 1);
489 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
491 const struct ldb_map_attribute *attr = &privdat->attribute_maps[i];
493 /* If all remote attributes for this attribute are present, add the
494 * local one to the list */
496 switch (attr->type) {
497 case MAP_IGNORE: break;
499 avail = (ldb_msg_find_ldb_val(msg, attr->local_name) != NULL);
504 avail = (ldb_msg_find_ldb_val(msg, attr->u.rename.remote_name) != NULL);
509 for (j = 0; attr->u.generate.remote_names[j]; j++) {
510 avail &= (ldb_msg_find_ldb_val(msg, attr->u.generate.remote_names[j]) != NULL);
518 ret = talloc_realloc(module, ret, const char *, count+2);
519 ret[count] = attr->local_name;
527 /* Used for search */
528 static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, const char * const*attrs, const struct ldb_message *mi)
531 struct ldb_message *msg = talloc_zero(module, struct ldb_message);
532 struct ldb_message_element *elm, *oldelm;
533 struct ldb_map_context *privdat = map_get_privdat(module);
534 const char **newattrs = NULL;
536 msg->dn = map_remote_dn(module, module, mi->dn);
538 ldb_msg_add_string(module->ldb, msg, "mappedFromDn", ldb_dn_linearize(msg, mi->dn));
540 /* Loop over attrs, find in ldb_map_attribute array and
544 /* Generate list of the local attributes that /can/ be generated
545 * using the specific remote attributes */
547 attrs = newattrs = available_local_attributes(module, mi);
550 for (i = 0; attrs[i]; i++) {
551 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
552 enum ldb_map_attr_type map_type;
555 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s' when generating incoming message\n", attrs[i]);
556 map_type = MAP_IGNORE;
557 } else map_type = attr->type;
560 case MAP_IGNORE:break;
562 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Renaming remote attribute %s to %s", attr->u.rename.remote_name, attr->local_name);
563 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
567 elm = talloc(msg, struct ldb_message_element);
568 elm->name = talloc_strdup(elm, attr->local_name);
569 elm->num_values = oldelm->num_values;
570 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
571 for (j = 0; j < oldelm->num_values; j++)
572 elm->values[j] = ldb_val_dup(elm, &oldelm->values[j]);
574 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
578 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Converting remote attribute %s to %s", attr->u.rename.remote_name, attr->local_name);
579 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
583 elm = talloc(msg, struct ldb_message_element);
584 elm->name = talloc_strdup(elm, attr->local_name);
585 elm->num_values = oldelm->num_values;
586 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
588 for (j = 0; j < oldelm->num_values; j++)
589 elm->values[j] = attr->u.convert.convert_remote(module, elm, &oldelm->values[j]);
591 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
595 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Keeping remote attribute %s", attr->local_name);
596 oldelm = ldb_msg_find_element(mi, attr->local_name);
597 if (!oldelm) continue;
599 elm = talloc(msg, struct ldb_message_element);
601 elm->num_values = oldelm->num_values;
602 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
603 for (j = 0; j < oldelm->num_values; j++)
604 elm->values[j] = ldb_val_dup(elm, &oldelm->values[j]);
606 elm->name = talloc_strdup(elm, oldelm->name);
608 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
612 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Generating local attribute %s", attr->local_name);
613 elm = attr->u.generate.generate_local(module, msg, attr->local_name, mi);
616 ldb_msg_add(module->ldb, msg, elm, elm->flags);
619 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Unknown attr->type for %s", attr->local_name);
624 talloc_free(newattrs);
629 /* Used for add, modify */
630 static int ldb_map_message_outgoing(struct ldb_module *module, const struct ldb_message *mo, struct ldb_message **fb, struct ldb_message **mp)
632 struct ldb_map_context *privdat = map_get_privdat(module);
633 struct ldb_message_element *elm;
636 *fb = talloc_zero(module, struct ldb_message);
637 (*fb)->dn = talloc_reference(*fb, mo->dn);
639 *mp = talloc_zero(module, struct ldb_message);
640 (*mp)->dn = map_local_dn(module, module, mo->dn);
642 /* Loop over mi and call generate_remote for each attribute */
643 for (i = 0; i < mo->num_elements; i++) {
644 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, mo->elements[i].name);
645 enum ldb_map_attr_type map_type;
648 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Undefined local attribute '%s', ignoring\n", mo->elements[i].name);
649 map_type = MAP_IGNORE;
651 } else map_type = attr->type;
654 case MAP_IGNORE: /* Add to fallback message */
655 elm = talloc(*fb, struct ldb_message_element);
657 elm->num_values = mo->elements[i].num_values;
658 elm->values = talloc_reference(elm, mo->elements[i].values);
659 elm->name = talloc_strdup(elm, mo->elements[i].name);
661 ldb_msg_add(module->ldb, *fb, elm, mo->elements[i].flags);
664 elm = talloc(*mp, struct ldb_message_element);
666 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
667 elm->num_values = mo->elements[i].num_values;
668 elm->values = talloc_reference(elm, mo->elements[i].values);
670 ldb_msg_add(module->ldb, *mp, elm, mo->elements[i].flags);
674 elm = talloc(*mp, struct ldb_message_element);
676 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
677 elm->num_values = mo->elements[i].num_values;
678 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
680 for (j = 0; j < elm->num_values; j++) {
681 elm->values[j] = attr->u.convert.convert_local(module, *mp, &mo->elements[i].values[j]);
684 ldb_msg_add(module->ldb, *mp, elm, mo->elements[i].flags);
688 elm = talloc(*mp, struct ldb_message_element);
690 elm->num_values = mo->elements[i].num_values;
691 elm->values = talloc_reference(elm, mo->elements[i].values);
692 elm->name = talloc_strdup(elm, mo->elements[i].name);
694 ldb_msg_add(module->ldb, *mp, elm, mo->elements[i].flags);
698 attr->u.generate.generate_remote(module, attr->local_name, mo, *mp);
703 if ((*fb)->num_elements == 0) {
704 /* No elements, discard.. */
708 ldb_msg_add_string(module->ldb, *fb, "isMapped", "TRUE");
711 if ((*mp)->num_elements == 0) {
712 /* No elements, discard.. */
724 static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
726 struct ldb_map_context *privdat = map_get_privdat(module);
727 struct ldb_dn *n_olddn, *n_newdn;
730 ret = ldb_next_rename_record(module, olddn, newdn);
732 n_olddn = map_local_dn(module, module, olddn);
733 n_newdn = map_local_dn(module, module, newdn);
735 ret = ldb_rename(privdat->mapped_ldb, n_olddn, n_newdn);
737 talloc_free(n_olddn);
738 talloc_free(n_newdn);
746 static int map_delete(struct ldb_module *module, const struct ldb_dn *dn)
748 struct ldb_map_context *privdat = map_get_privdat(module);
749 struct ldb_dn *newdn;
752 ret = ldb_next_delete_record(module, dn);
754 newdn = map_local_dn(module, module, dn);
756 ret = ldb_delete(privdat->mapped_ldb, newdn);
763 /* search fallback database */
764 static int map_search_bytree_fb(struct ldb_module *module, const struct ldb_dn *base,
765 enum ldb_scope scope, struct ldb_parse_tree *tree,
766 const char * const *attrs, struct ldb_message ***res)
769 struct ldb_parse_tree t_and, t_not, t_present, *childs[2];
771 t_present.operation = LDB_OP_PRESENT;
772 t_present.u.present.attr = talloc_strdup(NULL, "isMapped");
774 t_not.operation = LDB_OP_NOT;
775 t_not.u.isnot.child = &t_present;
779 t_and.operation = LDB_OP_AND;
780 t_and.u.list.num_elements = 2;
781 t_and.u.list.elements = childs;
783 ret = ldb_next_search_bytree(module, base, scope, &t_and, attrs, res);
785 talloc_free(t_present.u.present.attr);
790 /* Search in the database against which we are mapping */
791 static int map_search_bytree_mp(struct ldb_module *module, const struct ldb_dn *base,
792 enum ldb_scope scope, struct ldb_parse_tree *tree,
793 const char * const *attrs, struct ldb_message ***res)
795 struct ldb_parse_tree *new_tree;
796 struct ldb_dn *new_base;
797 struct ldb_message **newres;
798 const char **newattrs;
800 struct ldb_map_context *privdat = map_get_privdat(module);
803 /*- search mapped database */
805 new_tree = ldb_map_parse_tree(module, module, tree);
806 if (new_tree == NULL) {
807 /* All attributes used in the parse tree are
808 * local, apparently. Fall back to enumerating the complete remote
809 * database... Rather a slow search then no results. */
810 new_tree = talloc_zero(module, struct ldb_parse_tree);
811 new_tree->operation = LDB_OP_PRESENT;
812 new_tree->u.present.attr = talloc_strdup(new_tree, "dn");
816 newattrs = ldb_map_attrs(module, attrs);
817 new_base = map_local_dn(module, module, base);
819 mpret = ldb_search_bytree(privdat->mapped_ldb, new_base, scope, new_tree, newattrs, &newres);
821 talloc_free(new_base);
822 talloc_free(new_tree);
823 talloc_free(newattrs);
826 struct map_private *map_private = module->private_data;
827 map_private->last_err_string = ldb_errstring(privdat->mapped_ldb);
832 - per returned record, search fallback database for additional data (by dn)
833 - test if (full expression) is now true
836 *res = talloc_array(module, struct ldb_message *, mpret);
840 for (i = 0; i < mpret; i++) {
841 struct ldb_message *merged;
842 struct ldb_message **extrares = NULL;
845 /* Always get special DN's from the fallback database */
846 if (ldb_dn_is_special(newres[i]->dn))
849 merged = ldb_map_message_incoming(module, attrs, newres[i]);
851 /* Merge with additional data from local database */
852 extraret = ldb_next_search(module, merged->dn, LDB_SCOPE_BASE, "", NULL, &extrares);
854 if (extraret == -1) {
855 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error searching for extra data!\n");
856 } else if (extraret > 1) {
857 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "More than one result for extra data!\n");
860 } else if (extraret == 0) {
861 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "No extra data found for remote DN: %s", ldb_dn_linearize(merged, merged->dn));
866 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Extra data found for remote DN: %s", ldb_dn_linearize(merged, merged->dn));
867 for (j = 0; j < extrares[0]->num_elements; j++) {
868 ldb_msg_add(module->ldb, merged, &(extrares[0]->elements[j]), extrares[0]->elements[j].flags);
871 ldb_msg_add_string(module->ldb, merged, "extraMapped", "TRUE");
873 ldb_msg_add_string(module->ldb, merged, "extraMapped", "FALSE");
876 if (ldb_match_msg(module->ldb, merged, tree, base, scope) != 0) {
877 (*res)[ret] = merged;
880 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Discarded merged message because it did not match");
891 search for matching records using a ldb_parse_tree
893 static int map_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
894 enum ldb_scope scope, struct ldb_parse_tree *tree,
895 const char * const *attrs, struct ldb_message ***res)
897 struct ldb_message **fbres, **mpres;
901 ret_fb = map_search_bytree_fb(module, base, scope, tree, attrs, &fbres);
905 /* special dn's are never mapped.. */
906 if (ldb_dn_is_special(base)) {
911 ret_mp = map_search_bytree_mp(module, base, scope, tree, attrs, &mpres);
917 *res = talloc_array(module, struct ldb_message *, ret_fb + ret_mp);
919 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Merging %d mapped and %d fallback messages", ret_mp, ret_fb);
921 for (i = 0; i < ret_fb; i++) (*res)[i] = fbres[i];
922 for (i = 0; i < ret_mp; i++) (*res)[ret_fb+i] = mpres[i];
924 return ret_fb + ret_mp;
927 search for matching records
929 static int map_search(struct ldb_module *module, const struct ldb_dn *base,
930 enum ldb_scope scope, const char *expression,
931 const char * const *attrs, struct ldb_message ***res)
933 struct map_private *map = module->private_data;
934 struct ldb_parse_tree *tree;
937 tree = ldb_parse_tree(NULL, expression);
939 map->last_err_string = "expression parse failed";
943 ret = map_search_bytree(module, base, scope, tree, attrs, res);
951 static int map_add(struct ldb_module *module, const struct ldb_message *msg)
954 struct ldb_map_context *privdat = map_get_privdat(module);
955 struct ldb_message *fb, *mp;
957 if (!map_is_mappable(privdat, msg)) {
958 return ldb_next_add_record(module, msg);
961 if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1)
965 ret = ldb_next_add_record(module, fb);
967 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding fallback record failed");
975 ret = ldb_add(privdat->mapped_ldb, mp);
977 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding mapped record failed");
991 static int map_modify(struct ldb_module *module, const struct ldb_message *msg)
993 struct ldb_map_context *privdat = map_get_privdat(module);
994 struct ldb_message *fb, *mp;
997 if (!map_is_mappable(privdat, msg))
998 return ldb_next_modify_record(module, msg);
1001 if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1)
1005 ret = ldb_next_modify_record(module, fb);
1010 ret = ldb_modify(privdat->mapped_ldb, mp);
1017 static int map_lock(struct ldb_module *module, const char *lockname)
1019 return ldb_next_named_lock(module, lockname);
1022 static int map_unlock(struct ldb_module *module, const char *lockname)
1024 return ldb_next_named_unlock(module, lockname);
1028 return extended error information
1030 static const char *map_errstring(struct ldb_module *module)
1032 struct map_private *map = module->private_data;
1034 if (map->last_err_string)
1035 return map->last_err_string;
1037 return ldb_next_errstring(module);
1040 static const struct ldb_module_ops map_ops = {
1042 .search = map_search,
1043 .search_bytree = map_search_bytree,
1044 .add_record = map_add,
1045 .modify_record = map_modify,
1046 .delete_record = map_delete,
1047 .rename_record = map_rename,
1048 .named_lock = map_lock,
1049 .named_unlock = map_unlock,
1050 .errstring = map_errstring
1053 static char *map_find_url(struct ldb_context *ldb, const char *name)
1055 const char * const attrs[] = { "@MAP_URL" , NULL};
1056 struct ldb_message **msg = NULL;
1057 struct ldb_dn *mods;
1061 mods = ldb_dn_string_compose(ldb, NULL, "@MAP=%s", name);
1063 ldb_debug(ldb, LDB_DEBUG_ERROR, "Can't construct DN");
1067 ret = ldb_search(ldb, mods, LDB_SCOPE_BASE, "", attrs, &msg);
1070 ldb_debug(ldb, LDB_DEBUG_ERROR, "Not enough results found looking for @MAP");
1074 url = talloc_strdup(ldb, ldb_msg_find_string(msg[0], "@MAP_URL", NULL));
1081 /* the init function */
1082 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)
1085 struct ldb_module *ctx;
1086 struct map_private *data;
1089 ctx = talloc(ldb, struct ldb_module);
1093 data = talloc(ctx, struct map_private);
1099 data->context.mapped_ldb = ldb_init(data);
1100 ldb_set_debug(data->context.mapped_ldb, ldb->debug_ops.debug, ldb->debug_ops.context);
1101 url = map_find_url(ldb, name);
1104 ldb_debug(ldb, LDB_DEBUG_FATAL, "@MAP=%s not set!\n", name);
1108 if (ldb_connect(data->context.mapped_ldb, url, 0, NULL) != 0) {
1109 ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to open mapped database for %s at '%s'\n", name, url);
1115 data->last_err_string = NULL;
1117 /* Get list of attribute maps */
1119 data->context.attribute_maps = NULL;
1121 for (i = 0; attrs[i].local_name; i++) {
1122 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1123 data->context.attribute_maps[j] = attrs[i];
1127 for (i = 0; builtin_attribute_maps[i].local_name; i++) {
1128 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1129 data->context.attribute_maps[j] = builtin_attribute_maps[i];
1133 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1134 memset(&data->context.attribute_maps[j], 0, sizeof(struct ldb_map_attribute));
1136 data->context.objectclass_maps = ocls;
1137 ctx->private_data = data;
1139 ctx->prev = ctx->next = NULL;
1140 ctx->ops = &map_ops;
1145 static struct ldb_val map_convert_local_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1147 struct ldb_dn *dn, *newdn;;
1148 struct ldb_val *newval;
1150 dn = ldb_dn_explode(ctx, (char *)val->data);
1152 newdn = map_local_dn(module, ctx, dn);
1156 newval = talloc(ctx, struct ldb_val);
1157 newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1158 newval->length = strlen((char *)newval->data);
1165 static struct ldb_val map_convert_remote_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1167 struct ldb_dn *dn, *newdn;;
1168 struct ldb_val *newval;
1170 dn = ldb_dn_explode(ctx, (char *)val->data);
1172 newdn = map_remote_dn(module, ctx, dn);
1176 newval = talloc(ctx, struct ldb_val);
1177 newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1178 newval->length = strlen((char *)newval->data);
1185 static struct ldb_val map_convert_local_objectclass(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1188 struct ldb_map_context *map = module->private_data;
1190 for (i = 0; map->objectclass_maps[i].local_name; i++) {
1191 if (!strcmp(map->objectclass_maps[i].local_name, (char *)val->data)) {
1192 struct ldb_val newval;
1193 newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].remote_name);
1194 newval.length = strlen((char *)newval.data);
1196 return ldb_val_dup(ctx, &newval);
1200 return ldb_val_dup(ctx, val);
1203 static struct ldb_val map_convert_remote_objectclass(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1206 struct ldb_map_context *map = module->private_data;
1208 for (i = 0; map->objectclass_maps[i].remote_name; i++) {
1209 if (!strcmp(map->objectclass_maps[i].remote_name, (char *)val->data)) {
1210 struct ldb_val newval;
1211 newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].local_name);
1212 newval.length = strlen((char *)newval.data);
1214 return ldb_val_dup(ctx, &newval);
1218 return ldb_val_dup(ctx, val);