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/includes.h"
28 #include "ldb/modules/ldb_map.h"
31 - special attribute 'isMapped'
33 - split up ldb_message into fallback and mapped parts if is_mappable
35 - search local one for not isMapped entries
36 - remove remote attributes from ldb_parse_tree
38 - per record, search local one for additional data (by dn)
39 - test if (full expression) is now true
43 - rename locally and remotely
46 static struct ldb_val map_convert_local_dn(struct ldb_module *map,
48 const struct ldb_val *val);
49 static struct ldb_val map_convert_remote_dn(struct ldb_module *map,
51 const struct ldb_val *val);
52 static struct ldb_val map_convert_local_objectclass(struct ldb_module *map,
54 const struct ldb_val *val);
55 static struct ldb_val map_convert_remote_objectclass(struct ldb_module *map,
57 const struct ldb_val *val);
59 static const struct ldb_map_attribute builtin_attribute_maps[] = {
66 .convert_local = map_convert_local_dn,
67 .convert_remote = map_convert_remote_dn,
72 .local_name = "objectclass",
76 .remote_name = "objectclass",
77 .convert_local = map_convert_local_objectclass,
78 .convert_remote = map_convert_remote_objectclass,
87 static const struct ldb_map_objectclass *map_find_objectclass_remote(struct ldb_map_context *privdat, const char *name)
90 for (i = 0; privdat->objectclass_maps[i].remote_name; i++) {
91 if (!ldb_attr_cmp(privdat->objectclass_maps[i].remote_name, name))
92 return &privdat->objectclass_maps[i];
99 struct ldb_map_context context;
102 static struct ldb_map_context *map_get_privdat(struct ldb_module *module)
104 return &((struct map_private *)module->private_data)->context;
107 /* Check whether the given attribute can fit into the specified
108 * message, obeying objectClass restrictions */
109 static int map_msg_valid_attr(struct ldb_module *module, const struct ldb_message *msg, const char *attr)
111 struct ldb_map_context *map = module->private_data;
113 struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
116 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Can't find objectClass");
120 for (i = 0; i < el->num_values; i++) {
121 const struct ldb_map_objectclass *class = map_find_objectclass_remote(map, (char *)el->values[i].data);
126 for (j = 0; class->musts[j]; j++) {
127 if (!ldb_attr_cmp(class->musts[j], attr))
131 for (j = 0; class->mays[j]; j++) {
132 if (!ldb_attr_cmp(class->mays[j], attr))
141 /* find an attribute by the local name */
142 static const struct ldb_map_attribute *map_find_attr_local(struct ldb_map_context *privdat, const char *attr)
146 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
147 if (!ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr))
148 return &privdat->attribute_maps[i];
154 /* Check if a given attribute can be created by doing mapping from a local attribute to a remote one */
155 static int map_msg_can_map_attr(struct ldb_module *module, const struct ldb_message *msg, const char *attr_name)
157 struct ldb_map_context *privdat = module->private_data;
160 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
161 switch (privdat->attribute_maps[i].type) {
162 case MAP_IGNORE: /* No remote name at all */
165 if (ldb_attr_cmp(attr_name, privdat->attribute_maps[i].local_name) == 0)
170 if (ldb_attr_cmp(attr_name, privdat->attribute_maps[i].u.rename.remote_name) == 0)
174 for (j = 0; privdat->attribute_maps[i].u.generate.remote_names[j]; j++) {
175 if (ldb_attr_cmp(attr_name, privdat->attribute_maps[i].u.generate.remote_names[j]) == 0)
186 if (ldb_msg_find_element(msg, privdat->attribute_maps[i].local_name))
194 /* find an attribute by the remote name */
195 static const struct ldb_map_attribute *map_find_attr_remote(struct ldb_map_context *privdat, const char *attr)
199 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
200 if (privdat->attribute_maps[i].type == MAP_IGNORE)
203 if (privdat->attribute_maps[i].type == MAP_GENERATE)
206 if (privdat->attribute_maps[i].type == MAP_KEEP &&
207 ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr) == 0)
208 return &privdat->attribute_maps[i];
210 if ((privdat->attribute_maps[i].type == MAP_RENAME ||
211 privdat->attribute_maps[i].type == MAP_CONVERT) &&
212 ldb_attr_cmp(privdat->attribute_maps[i].u.rename.remote_name, attr) == 0)
213 return &privdat->attribute_maps[i];
220 static struct ldb_parse_tree *ldb_map_parse_tree(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_parse_tree *tree)
223 const struct ldb_map_attribute *attr;
224 struct ldb_parse_tree *new_tree;
225 enum ldb_map_attr_type map_type;
226 struct ldb_val value, newvalue;
227 struct ldb_map_context *privdat = map_get_privdat(module);
233 /* Find attr in question and:
234 * - if it has a convert_operator function, run that
235 * - otherwise, replace attr name with required[0] */
237 if (tree->operation == LDB_OP_AND ||
238 tree->operation == LDB_OP_OR) {
240 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
241 new_tree->u.list.elements = talloc_array(new_tree, struct ldb_parse_tree *, tree->u.list.num_elements);
242 new_tree->u.list.num_elements = 0;
243 for (i = 0; i < tree->u.list.num_elements; i++) {
244 struct ldb_parse_tree *child = ldb_map_parse_tree(module, new_tree, tree->u.list.elements[i]);
247 new_tree->u.list.elements[i] = child;
248 new_tree->u.list.num_elements++;
255 if (tree->operation == LDB_OP_NOT) {
256 struct ldb_parse_tree *child;
258 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
259 child = ldb_map_parse_tree(module, new_tree, tree->u.isnot.child);
262 talloc_free(new_tree);
266 new_tree->u.isnot.child = child;
270 /* tree->operation is LDB_OP_EQUALITY, LDB_OP_SUBSTRING, LDB_OP_GREATER,
271 * LDB_OP_LESS, LDB_OP_APPROX, LDB_OP_PRESENT or LDB_OP_EXTENDED
273 * (all have attr as the first element)
276 attr = map_find_attr_local(privdat, tree->u.equality.attr);
279 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Unable to find local attribute '%s', removing from parse tree\n", tree->u.equality.attr);
280 map_type = MAP_IGNORE;
282 map_type = attr->type;
285 if (attr && attr->convert_operator) {
286 /* Run convert_operator */
287 return attr->convert_operator(privdat, module, tree);
290 if (map_type == MAP_IGNORE) {
291 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Not mapping search on ignored attribute '%s'\n", tree->u.equality.attr);
295 if (map_type == MAP_GENERATE) {
296 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);
300 if (tree->operation == LDB_OP_EQUALITY) {
301 value = tree->u.equality.value;
302 } else if (tree->operation == LDB_OP_LESS || tree->operation == LDB_OP_GREATER ||
303 tree->operation == LDB_OP_APPROX) {
304 value = tree->u.comparison.value;
305 } else if (tree->operation == LDB_OP_EXTENDED) {
306 value = tree->u.extended.value;
309 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
311 if (map_type == MAP_KEEP) {
312 new_tree->u.equality.attr = talloc_strdup(new_tree, tree->u.equality.attr);
313 } else { /* MAP_RENAME / MAP_CONVERT */
314 new_tree->u.equality.attr = talloc_strdup(new_tree, attr->u.rename.remote_name);
317 if (new_tree->operation == LDB_OP_PRESENT)
320 if (new_tree->operation == LDB_OP_SUBSTRING) {
321 new_tree->u.substring.chunks = NULL; /* FIXME! */
325 if (map_type == MAP_CONVERT) {
326 if (!attr->u.convert.convert_local)
328 newvalue = attr->u.convert.convert_local(module, new_tree, &value);
330 newvalue = ldb_val_dup(new_tree, &value);
333 if (new_tree->operation == LDB_OP_EQUALITY) {
334 new_tree->u.equality.value = newvalue;
335 } else if (new_tree->operation == LDB_OP_LESS || new_tree->operation == LDB_OP_GREATER ||
336 new_tree->operation == LDB_OP_APPROX) {
337 new_tree->u.comparison.value = newvalue;
338 } else if (new_tree->operation == LDB_OP_EXTENDED) {
339 new_tree->u.extended.value = newvalue;
340 new_tree->u.extended.rule_id = talloc_strdup(new_tree, tree->u.extended.rule_id);
346 /* Remote DN -> Local DN */
347 static struct ldb_dn *map_remote_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_dn *dn)
349 struct ldb_dn *newdn;
355 newdn = talloc_memdup(ctx, dn, sizeof(*dn));
359 newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
361 if (!newdn->components)
364 /* For each rdn, map the attribute name and possibly the
367 for (i = 0; i < dn->comp_num; i++) {
368 const struct ldb_map_attribute *attr = map_find_attr_remote(module->private_data, dn->components[i].name);
369 enum ldb_map_attr_type map_type;
371 /* Unknown attribute - leave this dn as is and hope the best... */
372 if (!attr) map_type = MAP_KEEP;
373 else map_type = attr->type;
378 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Local MAP_IGNORE or MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name);
383 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
384 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
388 newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
389 newdn->components[i].value = attr->u.convert.convert_remote(module, ctx, &dn->components[i].value);
393 newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
394 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
401 /* Local DN -> Remote DN */
402 static struct ldb_dn *map_local_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_dn *dn)
404 struct ldb_dn *newdn;
410 newdn = talloc_memdup(ctx, dn, sizeof(*dn));
414 newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
416 if (!newdn->components)
419 /* For each rdn, map the attribute name and possibly the
420 * complete rdn using an equality convert_operator call */
422 for (i = 0; i < dn->comp_num; i++) {
423 const struct ldb_map_attribute *attr = map_find_attr_local(module->private_data, dn->components[i].name);
424 enum ldb_map_attr_type map_type;
426 /* Unknown attribute - leave this dn as is and hope the best... */
427 if (!attr) map_type = MAP_KEEP; else map_type = attr->type;
433 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Local MAP_IGNORE/MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name);
438 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.convert.remote_name);
439 if (attr->u.convert.convert_local == NULL) {
440 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "convert_local not set for attribute '%s' used in DN!", dn->components[i].name);
444 newdn->components[i].value = attr->u.convert.convert_local(module, newdn->components, &dn->components[i].value);
448 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.rename.remote_name);
449 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
453 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
454 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
462 /* Loop over ldb_map_attribute array and add remote_names */
463 static const char **ldb_map_attrs(struct ldb_module *module, const char *const attrs[])
467 int ar_size = 0, last_element = 0;
468 struct ldb_map_context *privdat = map_get_privdat(module);
473 /* Start with good guess of number of elements */
474 for (i = 0; attrs[i]; i++);
476 ret = talloc_array(module, const char *, i);
479 for (i = 0; attrs[i]; i++) {
481 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
482 enum ldb_map_attr_type map_type;
485 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Local attribute '%s' does not have a definition!\n", attrs[i]);
486 map_type = MAP_IGNORE;
487 } else map_type = attr->type;
491 case MAP_IGNORE: break;
493 if (last_element >= ar_size) {
494 ret = talloc_realloc(module, ret, const char *, ar_size+1);
497 ret[last_element] = attr->local_name;
503 if (last_element >= ar_size) {
504 ret = talloc_realloc(module, ret, const char *, ar_size+1);
507 ret[last_element] = attr->u.rename.remote_name;
512 /* Add remote_names[] for this attribute to the list of
513 * attributes to request from the remote server */
514 for (j = 0; attr->u.generate.remote_names[j]; j++) {
515 if (last_element >= ar_size) {
516 ret = talloc_realloc(module, ret, const char *, ar_size+1);
519 ret[last_element] = attr->u.generate.remote_names[j];
526 if (last_element >= ar_size) {
527 ret = talloc_realloc(module, ret, const char *, ar_size+1);
531 ret[last_element] = NULL;
536 static const char **available_local_attributes(struct ldb_module *module, const struct ldb_message *msg)
538 struct ldb_map_context *privdat = map_get_privdat(module);
541 const char **ret = talloc_array(module, const char *, 1);
545 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
547 const struct ldb_map_attribute *attr = &privdat->attribute_maps[i];
549 /* If all remote attributes for this attribute are present, add the
550 * local one to the list */
552 switch (attr->type) {
553 case MAP_IGNORE: break;
555 avail = (ldb_msg_find_ldb_val(msg, attr->local_name) != NULL);
560 avail = (ldb_msg_find_ldb_val(msg, attr->u.rename.remote_name) != NULL);
565 for (j = 0; attr->u.generate.remote_names[j]; j++) {
566 avail &= (BOOL)(ldb_msg_find_ldb_val(msg, attr->u.generate.remote_names[j]) != NULL);
574 ret = talloc_realloc(module, ret, const char *, count+2);
575 ret[count] = attr->local_name;
583 /* Used for search */
584 static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, const char * const*attrs, const struct ldb_message *mi)
587 struct ldb_message *msg = talloc_zero(module, struct ldb_message);
588 struct ldb_message_element *elm, *oldelm;
589 struct ldb_map_context *privdat = map_get_privdat(module);
590 const char **newattrs = NULL;
592 msg->dn = map_remote_dn(module, module, mi->dn);
594 /* Loop over attrs, find in ldb_map_attribute array and
598 /* Generate list of the local attributes that /can/ be generated
599 * using the specific remote attributes */
601 attrs = newattrs = available_local_attributes(module, mi);
604 for (i = 0; attrs[i]; i++) {
605 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
606 enum ldb_map_attr_type map_type;
609 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s' when generating incoming message\n", attrs[i]);
610 map_type = MAP_IGNORE;
611 } else map_type = attr->type;
614 case MAP_IGNORE:break;
616 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Renaming remote attribute %s to %s", attr->u.rename.remote_name, attr->local_name);
617 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
621 elm = talloc(msg, struct ldb_message_element);
622 elm->name = talloc_strdup(elm, attr->local_name);
623 elm->num_values = oldelm->num_values;
624 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
625 for (j = 0; j < oldelm->num_values; j++)
626 elm->values[j] = ldb_val_dup(elm, &oldelm->values[j]);
628 ldb_msg_add(msg, elm, oldelm->flags);
632 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Converting remote attribute %s to %s", attr->u.rename.remote_name, attr->local_name);
633 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
637 elm = talloc(msg, struct ldb_message_element);
638 elm->name = talloc_strdup(elm, attr->local_name);
639 elm->num_values = oldelm->num_values;
640 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
642 for (j = 0; j < oldelm->num_values; j++)
643 elm->values[j] = attr->u.convert.convert_remote(module, elm, &oldelm->values[j]);
645 ldb_msg_add(msg, elm, oldelm->flags);
649 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Keeping remote attribute %s", attr->local_name);
650 oldelm = ldb_msg_find_element(mi, attr->local_name);
651 if (!oldelm) continue;
653 elm = talloc(msg, struct ldb_message_element);
655 elm->num_values = oldelm->num_values;
656 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
657 for (j = 0; j < oldelm->num_values; j++)
658 elm->values[j] = ldb_val_dup(elm, &oldelm->values[j]);
660 elm->name = talloc_strdup(elm, oldelm->name);
662 ldb_msg_add(msg, elm, oldelm->flags);
666 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Generating local attribute %s", attr->local_name);
667 if (!attr->u.generate.generate_local)
670 elm = attr->u.generate.generate_local(module, msg, attr->local_name, mi);
674 ldb_msg_add(msg, elm, elm->flags);
677 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Unknown attr->type for %s", attr->local_name);
682 talloc_free(newattrs);
690 static int map_rename(struct ldb_module *module, struct ldb_request *req)
692 const struct ldb_dn *olddn = req->op.rename.olddn;
693 const struct ldb_dn *newdn = req->op.rename.newdn;
694 struct ldb_map_context *privdat = map_get_privdat(module);
695 struct ldb_dn *n_olddn, *n_newdn;
698 n_olddn = map_local_dn(module, module, olddn);
699 n_newdn = map_local_dn(module, module, newdn);
701 ret = ldb_rename(privdat->mapped_ldb, n_olddn, n_newdn);
703 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Mapped record renamed");
704 ldb_next_request(module, req);
706 ret = ldb_next_request(module, req);
709 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record renamed");
714 talloc_free(n_olddn);
715 talloc_free(n_newdn);
723 static int map_delete(struct ldb_module *module, struct ldb_request *req)
725 const struct ldb_dn *dn = req->op.del.dn;
726 struct ldb_map_context *privdat = map_get_privdat(module);
727 struct ldb_dn *newdn;
730 newdn = map_local_dn(module, module, dn);
732 ret = ldb_delete(privdat->mapped_ldb, newdn);
734 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Mapped record deleted");
736 ret = ldb_next_request(module, req);
738 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record deleted");
742 req->op.del.dn = newdn;
743 ret = ldb_next_request(module, req);
751 /* search fallback database */
752 static int map_search_fb(struct ldb_module *module, struct ldb_request *req)
754 struct ldb_parse_tree *tree = req->op.search.tree;
755 struct ldb_parse_tree t_and, t_not, t_present, *childs[2];
759 t_present.operation = LDB_OP_PRESENT;
760 ismapped = talloc_strdup(module, "isMapped");
761 t_present.u.present.attr = ismapped;
763 t_not.operation = LDB_OP_NOT;
764 t_not.u.isnot.child = &t_present;
768 t_and.operation = LDB_OP_AND;
769 t_and.u.list.num_elements = 2;
770 t_and.u.list.elements = childs;
772 req->op.search.tree = &t_and;
773 ret = ldb_next_request(module, req);
774 req->op.search.tree = tree;
776 talloc_free(ismapped);
781 /* Search in the database against which we are mapping */
782 static int map_search_mp(struct ldb_module *module, struct ldb_request *req)
784 const struct ldb_dn *base = req->op.search.base;
785 enum ldb_scope scope = req->op.search.scope;
786 struct ldb_parse_tree *tree = req->op.search.tree;
787 const char * const *attrs = req->op.search.attrs;
788 struct ldb_result *res;
789 struct ldb_request new_req;
790 struct ldb_parse_tree *new_tree;
791 struct ldb_dn *new_base;
792 struct ldb_result *newres;
793 const char **newattrs;
795 struct ldb_map_context *privdat = map_get_privdat(module);
798 /*- search mapped database */
800 new_tree = ldb_map_parse_tree(module, module, tree);
801 if (new_tree == NULL) {
802 /* All attributes used in the parse tree are
803 * local, apparently. Fall back to enumerating the complete remote
804 * database... Rather a slow search then no results. */
805 new_tree = talloc_zero(module, struct ldb_parse_tree);
806 new_tree->operation = LDB_OP_PRESENT;
807 new_tree->u.present.attr = talloc_strdup(new_tree, "dn");
811 newattrs = ldb_map_attrs(module, attrs);
812 new_base = map_local_dn(module, module, base);
814 memset((char *)&(new_req), 0, sizeof(new_req));
815 new_req.operation = LDB_SEARCH;
816 new_req.op.search.base = new_base;
817 new_req.op.search.scope = scope;
818 new_req.op.search.tree = new_tree;
819 new_req.op.search.attrs = newattrs;
821 mpret = ldb_request(privdat->mapped_ldb, req);
823 newres = new_req.op.search.res;
825 talloc_free(new_base);
826 talloc_free(new_tree);
827 talloc_free(newattrs);
829 if (mpret != LDB_SUCCESS) {
830 ldb_set_errstring(module->ldb, ldb_errstring(privdat->mapped_ldb));
835 - per returned record, search fallback database for additional data (by dn)
836 - test if (full expression) is now true
839 res = talloc(module, struct ldb_result);
840 req->op.search.res = res;
841 res->msgs = talloc_array(module, struct ldb_message *, newres->count);
842 res->count = newres->count;
846 for (i = 0; i < mpret; i++) {
847 struct ldb_request mergereq;
848 struct ldb_message *merged;
849 struct ldb_result *extrares = NULL;
852 /* Always get special DN's from the fallback database */
853 if (ldb_dn_is_special(newres->msgs[i]->dn))
856 merged = ldb_map_message_incoming(module, attrs, newres->msgs[i]);
858 /* Merge with additional data from fallback database */
859 memset((char *)&(mergereq), 0, sizeof(mergereq)); /* zero off the request structure */
860 mergereq.operation = LDB_SEARCH;
861 mergereq.op.search.base = merged->dn;
862 mergereq.op.search.scope = LDB_SCOPE_BASE;
863 mergereq.op.search.tree = ldb_parse_tree(module, "");
864 mergereq.op.search.attrs = NULL;
866 extraret = ldb_next_request(module, &mergereq);
868 extrares = mergereq.op.search.res;
870 if (extraret == -1) {
871 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error searching for extra data!\n");
872 } else if (extraret > 1) {
873 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "More than one result for extra data!\n");
876 } else if (extraret == 0) {
877 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "No extra data found for remote DN: %s", ldb_dn_linearize(merged, merged->dn));
882 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Extra data found for remote DN: %s", ldb_dn_linearize(merged, merged->dn));
883 for (j = 0; j < extrares->msgs[0]->num_elements; j++) {
884 ldb_msg_add(merged, &(extrares->msgs[0]->elements[j]), extrares->msgs[0]->elements[j].flags);
888 if (ldb_match_msg(module->ldb, merged, tree, base, scope) != 0) {
889 res->msgs[ret] = merged;
892 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Discarded merged message because it did not match");
904 search for matching records using a ldb_parse_tree
906 static int map_search_bytree(struct ldb_module *module, struct ldb_request *req)
908 const struct ldb_dn *base = req->op.search.base;
909 struct ldb_result *fbres, *mpres, *res;
912 ret = map_search_fb(module, req);
913 if (ret != LDB_SUCCESS)
916 /* special dn's are never mapped.. */
917 if (ldb_dn_is_special(base)) {
921 fbres = req->op.search.res;
923 ret = map_search_mp(module, req);
924 if (ret != LDB_SUCCESS) {
928 mpres = req->op.search.res;
931 res = talloc(module, struct ldb_result);
932 res->msgs = talloc_array(res, struct ldb_message *, fbres->count + mpres->count);
934 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Merging %d mapped and %d fallback messages", mpres->count, fbres->count);
936 for (i = 0; i < fbres->count; i++) {
937 res->msgs[i] = talloc_steal(res->msgs, fbres->msgs[i]);
939 for (i = 0; i < mpres->count; i++) {
940 res->msgs[fbres->count + i] = talloc_steal(res->msgs, mpres->msgs[i]);
943 res->count = fbres->count + mpres->count;
947 static int msg_contains_objectclass(const struct ldb_message *msg, const char *name)
949 struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
952 for (i = 0; i < el->num_values; i++) {
953 if (ldb_attr_cmp((char *)el->values[i].data, name) == 0) {
964 static int map_add(struct ldb_module *module, struct ldb_request *req)
966 const struct ldb_message *msg = req->op.add.message;
967 struct ldb_map_context *privdat = map_get_privdat(module);
968 struct ldb_message *fb, *mp;
969 struct ldb_message_element *ocs;
973 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add");
975 if (ldb_dn_is_special(msg->dn)) {
976 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add: Added fallback record");
977 return ldb_next_request(module, req);
980 mp = talloc_zero(module, struct ldb_message);
981 mp->dn = map_local_dn(module, mp, msg->dn);
983 fb = talloc_zero(module, struct ldb_message);
984 fb->dn = talloc_reference(fb, msg->dn);
986 /* We add objectClass, so 'top' should be no problem */
987 ldb_msg_add_string(mp, "objectClass", "top");
989 /* make a list of remote objectclasses that can be used
990 * given the attributes that are available and add to
992 for (i = 0; privdat->objectclass_maps[i].local_name; i++) {
993 int j, has_musts, has_baseclasses;
995 /* Add this objectClass to the list if all musts are present */
996 for (j = 0; privdat->objectclass_maps[i].musts[j]; j++) {
997 if (!map_msg_can_map_attr(module, msg, privdat->objectclass_maps[i].musts[j])) {
998 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "map_add: Not adding objectClass %s because it is not possible to create remote attribute %s", privdat->objectclass_maps[i].local_name, privdat->objectclass_maps[i].musts[j]);
1003 has_musts = (privdat->objectclass_maps[i].musts[j] == NULL);
1005 /* Check if base classes are present as well */
1006 for (j = 0; privdat->objectclass_maps[i].base_classes[j]; j++) {
1007 if (!msg_contains_objectclass(mp, privdat->objectclass_maps[i].base_classes[j])) {
1008 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "map_add: Not adding objectClass %s of missing base class %s", privdat->objectclass_maps[i].local_name, privdat->objectclass_maps[i].base_classes[j]);
1013 has_baseclasses = (privdat->objectclass_maps[i].base_classes[j] == NULL);
1015 /* Apparently, it contains all required elements */
1016 if (has_musts && has_baseclasses) {
1017 ldb_msg_add_string(mp, "objectClass", privdat->objectclass_maps[i].remote_name);
1018 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "map_add: Adding objectClass %s", privdat->objectclass_maps[i].remote_name);
1022 ocs = ldb_msg_find_element(mp, "objectClass");
1023 if (ocs->num_values == 1) { /* Only top */
1024 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add: Added fallback record");
1025 return ldb_next_request(module, req);
1029 * - try to map as much attributes as possible where allowed and add them to mp_msg
1030 * - add other attributes to fb_msg
1032 for (i = 0; i < msg->num_elements; i++) {
1033 const struct ldb_map_attribute *attr;
1034 struct ldb_message_element *elm = NULL;
1038 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0)
1041 /* Loop over all attribute_maps with msg->elements[i].name as local_name */
1042 for (k = 0; privdat->attribute_maps[k].local_name; k++) {
1043 if (ldb_attr_cmp(msg->elements[i].name, privdat->attribute_maps[k].local_name) != 0)
1046 attr = &privdat->attribute_maps[k];
1048 /* Decide whether or not we need to map or fallback */
1049 switch (attr->type) {
1051 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Generating from %s", attr->local_name);
1052 attr->u.generate.generate_remote(module, attr->local_name, msg, mp, fb);
1056 if (!map_msg_valid_attr(module, mp, attr->local_name))
1059 case MAP_IGNORE: continue;
1062 if (!map_msg_valid_attr(module, mp, attr->u.rename.remote_name))
1067 switch (attr->type) {
1069 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Keeping %s", attr->local_name);
1070 elm = talloc(fb, struct ldb_message_element);
1072 elm->num_values = msg->elements[i].num_values;
1073 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
1075 for (j = 0; j < elm->num_values; j++) {
1076 elm->values[j] = ldb_val_dup(elm, &msg->elements[i].values[j]);
1079 elm->name = talloc_strdup(elm, msg->elements[i].name);
1083 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Renaming %s -> %s", attr->local_name, attr->u.rename.remote_name);
1084 elm = talloc(mp, struct ldb_message_element);
1086 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
1087 elm->num_values = msg->elements[i].num_values;
1088 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
1090 for (j = 0; j < elm->num_values; j++) {
1091 elm->values[j] = ldb_val_dup(elm, &msg->elements[i].values[j]);
1096 if (attr->u.convert.convert_local == NULL)
1098 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Converting %s -> %s", attr->local_name, attr->u.convert.remote_name);
1099 elm = talloc(mp, struct ldb_message_element);
1101 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
1102 elm->num_values = msg->elements[i].num_values;
1103 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
1105 for (j = 0; j < elm->num_values; j++) {
1106 elm->values[j] = attr->u.convert.convert_local(module, mp, &msg->elements[i].values[j]);
1113 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "This line should never be reached");
1117 ldb_msg_add(mp, elm, 0);
1122 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback storing %s", msg->elements[i].name);
1123 elm = talloc(fb, struct ldb_message_element);
1125 elm->num_values = msg->elements[i].num_values;
1126 elm->values = talloc_reference(elm, msg->elements[i].values);
1127 elm->name = talloc_strdup(elm, msg->elements[i].name);
1129 ldb_msg_add(fb, elm, 0);
1133 ret = ldb_add(privdat->mapped_ldb, mp);
1135 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Adding mapped record failed: %s", ldb_errstring(privdat->mapped_ldb));
1139 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add: Added mapped record");
1141 ldb_msg_add_string(fb, "isMapped", "TRUE");
1143 req->op.add.message = fb;
1144 ret = ldb_next_request(module, req);
1145 req->op.add.message = msg;
1147 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Adding fallback record failed: %s", ldb_errstring(module->ldb));
1161 static int map_modify(struct ldb_module *module, struct ldb_request *req)
1163 const struct ldb_message *msg = req->op.mod.message;
1164 struct ldb_map_context *privdat = map_get_privdat(module);
1165 struct ldb_message *fb, *mp;
1166 struct ldb_message_element *elm;
1170 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_modify");
1172 if (ldb_dn_is_special(msg->dn))
1173 return ldb_next_request(module, req);
1175 fb = talloc_zero(module, struct ldb_message);
1176 fb->dn = talloc_reference(fb, msg->dn);
1178 mp = talloc_zero(module, struct ldb_message);
1179 mp->dn = map_local_dn(module, mp, msg->dn);
1181 /* Loop over mi and call generate_remote for each attribute */
1182 for (i = 0; i < msg->num_elements; i++) {
1183 const struct ldb_map_attribute *attr;
1187 if (ldb_attr_cmp(msg->elements[i].name, "isMapped") == 0)
1190 for (k = 0; privdat->attribute_maps[k].local_name; k++)
1192 if (ldb_attr_cmp(privdat->attribute_maps[k].local_name, msg->elements[i].name) != 0)
1195 attr = &privdat->attribute_maps[k];
1197 switch (attr->type) {
1198 case MAP_IGNORE: continue;
1200 elm = talloc(mp, struct ldb_message_element);
1202 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
1203 elm->num_values = msg->elements[i].num_values;
1204 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
1205 for (j = 0; j < elm->num_values; j++) {
1206 elm->values[j] = msg->elements[i].values[j];
1209 ldb_msg_add(mp, elm, msg->elements[i].flags);
1214 if (!attr->u.convert.convert_local)
1216 elm = talloc(mp, struct ldb_message_element);
1218 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
1219 elm->num_values = msg->elements[i].num_values;
1220 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
1222 for (j = 0; j < elm->num_values; j++) {
1223 elm->values[j] = attr->u.convert.convert_local(module, mp, &msg->elements[i].values[j]);
1226 ldb_msg_add(mp, elm, msg->elements[i].flags);
1231 elm = talloc(mp, struct ldb_message_element);
1233 elm->num_values = msg->elements[i].num_values;
1234 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
1235 for (j = 0; j < elm->num_values; j++) {
1236 elm->values[j] = msg->elements[i].values[j];
1239 elm->name = talloc_strdup(elm, msg->elements[i].name);
1241 ldb_msg_add(mp, elm, msg->elements[i].flags);
1246 attr->u.generate.generate_remote(module, attr->local_name, msg, mp, fb);
1252 if (mapped == 0) {/* Add to fallback message */
1253 elm = talloc(fb, struct ldb_message_element);
1255 elm->num_values = msg->elements[i].num_values;
1256 elm->values = talloc_reference(elm, msg->elements[i].values);
1257 elm->name = talloc_strdup(elm, msg->elements[i].name);
1259 ldb_msg_add(fb, elm, msg->elements[i].flags);
1263 if (fb->num_elements > 0) {
1264 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Modifying fallback record with %d elements", fb->num_elements);
1265 req->op.mod.message = fb;
1266 fb_ret = ldb_next_request(module, req);
1268 ldb_msg_add_string(fb, "isMapped", "TRUE");
1269 req->operation = LDB_ADD;
1270 req->op.add.message = fb;
1271 fb_ret = ldb_next_request(module, req);
1272 req->operation = LDB_MODIFY;
1274 req->op.mod.message = msg;
1278 if (mp->num_elements > 0) {
1279 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Modifying mapped record with %d elements", mp->num_elements);
1280 mp_ret = ldb_modify(privdat->mapped_ldb, mp);
1284 return (mp_ret == -1 || fb_ret == -1)?-1:0;
1288 static int map_request(struct ldb_module *module, struct ldb_request *req)
1290 switch (req->operation) {
1293 return map_search_bytree(module, req);
1296 return map_add(module, req);
1299 return map_modify(module, req);
1302 return map_delete(module, req);
1305 return map_rename(module, req);
1308 return ldb_next_request(module, req);
1314 static const struct ldb_module_ops map_ops = {
1316 .request = map_request
1319 static char *map_find_url(struct ldb_context *ldb, const char *name)
1321 const char * const attrs[] = { "@MAP_URL" , NULL};
1322 struct ldb_result *result = NULL;
1323 struct ldb_dn *mods;
1327 mods = ldb_dn_string_compose(ldb, NULL, "@MAP=%s", name);
1329 ldb_debug(ldb, LDB_DEBUG_ERROR, "Can't construct DN");
1333 ret = ldb_search(ldb, mods, LDB_SCOPE_BASE, "", attrs, &result);
1335 if (ret != LDB_SUCCESS || result->count == 0) {
1336 ldb_debug(ldb, LDB_DEBUG_ERROR, "Not enough results found looking for @MAP");
1340 url = talloc_strdup(ldb, ldb_msg_find_string(result->msgs[0], "@MAP_URL", NULL));
1342 talloc_free(result);
1347 /* the init function */
1348 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)
1351 struct ldb_module *ctx;
1352 struct map_private *data;
1355 ctx = talloc(ldb, struct ldb_module);
1359 data = talloc(ctx, struct map_private);
1365 data->context.mapped_ldb = ldb_init(data);
1366 ldb_set_debug(data->context.mapped_ldb, ldb->debug_ops.debug, ldb->debug_ops.context);
1367 url = map_find_url(ldb, name);
1370 ldb_debug(ldb, LDB_DEBUG_FATAL, "@MAP=%s not set!\n", name);
1374 if (ldb_connect(data->context.mapped_ldb, url, 0, NULL) != 0) {
1375 ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to open mapped database for %s at '%s'\n", name, url);
1381 /* Get list of attribute maps */
1383 data->context.attribute_maps = NULL;
1385 for (i = 0; attrs[i].local_name; i++) {
1386 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1387 data->context.attribute_maps[j] = attrs[i];
1391 for (i = 0; builtin_attribute_maps[i].local_name; i++) {
1392 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1393 data->context.attribute_maps[j] = builtin_attribute_maps[i];
1397 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1398 memset(&data->context.attribute_maps[j], 0, sizeof(struct ldb_map_attribute));
1400 data->context.objectclass_maps = ocls;
1401 ctx->private_data = data;
1403 ctx->prev = ctx->next = NULL;
1404 ctx->ops = &map_ops;
1409 static struct ldb_val map_convert_local_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1411 struct ldb_dn *dn, *newdn;
1412 struct ldb_val *newval;
1414 dn = ldb_dn_explode(ctx, (char *)val->data);
1416 newdn = map_local_dn(module, ctx, dn);
1420 newval = talloc(ctx, struct ldb_val);
1421 newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1423 newval->length = strlen((char *)newval->data);
1433 static struct ldb_val map_convert_remote_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1435 struct ldb_dn *dn, *newdn;
1436 struct ldb_val *newval;
1438 dn = ldb_dn_explode(ctx, (char *)val->data);
1440 newdn = map_remote_dn(module, ctx, dn);
1444 newval = talloc(ctx, struct ldb_val);
1445 newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1447 newval->length = strlen((char *)newval->data);
1457 static struct ldb_val map_convert_local_objectclass(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1460 struct ldb_map_context *map = module->private_data;
1462 for (i = 0; map->objectclass_maps[i].local_name; i++) {
1463 if (!strcmp(map->objectclass_maps[i].local_name, (char *)val->data)) {
1464 struct ldb_val newval;
1465 newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].remote_name);
1466 newval.length = strlen((char *)newval.data);
1468 return ldb_val_dup(ctx, &newval);
1472 return ldb_val_dup(ctx, val);
1475 static struct ldb_val map_convert_remote_objectclass(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1478 struct ldb_map_context *map = module->private_data;
1480 for (i = 0; map->objectclass_maps[i].remote_name; i++) {
1481 if (!strcmp(map->objectclass_maps[i].remote_name, (char *)val->data)) {
1482 struct ldb_val newval;
1483 newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].local_name);
1484 newval.length = strlen((char *)newval.data);
1486 return ldb_val_dup(ctx, &newval);
1490 return ldb_val_dup(ctx, val);