r16090: Fix standalone build after the rename of enum ldb_request_type in
[Samba.git] / source4 / lib / ldb / modules / ldb_map.c
blob4a21defc2b1620a8c8ab77db085bdc2a49cd3584
1 /*
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
8 ** under the LGPL
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
25 #include "includes.h"
26 #include "ldb/include/includes.h"
28 #include "ldb/modules/ldb_map.h"
31 - special attribute 'isMapped'
32 - add/modify
33 - split up ldb_message into fallback and mapped parts if is_mappable
34 - search:
35 - search local one for not isMapped entries
36 - remove remote attributes from ldb_parse_tree
37 - search remote one
38 - per record, search local one for additional data (by dn)
39 - test if (full expression) is now true
40 - delete
41 - delete both
42 - rename
43 - rename locally and remotely
46 static struct ldb_val map_convert_local_dn(struct ldb_module *map,
47 TALLOC_CTX *ctx,
48 const struct ldb_val *val);
49 static struct ldb_val map_convert_remote_dn(struct ldb_module *map,
50 TALLOC_CTX *ctx,
51 const struct ldb_val *val);
52 static struct ldb_val map_convert_local_objectclass(struct ldb_module *map,
53 TALLOC_CTX *ctx,
54 const struct ldb_val *val);
55 static struct ldb_val map_convert_remote_objectclass(struct ldb_module *map,
56 TALLOC_CTX *ctx,
57 const struct ldb_val *val);
59 static const struct ldb_map_attribute builtin_attribute_maps[] = {
61 .local_name = "dn",
62 .type = MAP_CONVERT,
63 .u = {
64 .convert = {
65 .remote_name = "dn",
66 .convert_local = map_convert_local_dn,
67 .convert_remote = map_convert_remote_dn,
72 .local_name = "objectclass",
73 .type = MAP_CONVERT,
74 .u = {
75 .convert = {
76 .remote_name = "objectclass",
77 .convert_local = map_convert_local_objectclass,
78 .convert_remote = map_convert_remote_objectclass,
83 .local_name = NULL,
87 static const struct ldb_map_objectclass *map_find_objectclass_remote(struct ldb_map_context *privdat, const char *name)
89 int i;
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];
95 return NULL;
98 struct map_private {
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;
112 int i, j;
113 struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
115 if (el == NULL) {
116 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Can't find objectClass");
117 return 0;
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);
123 if (!class)
124 continue;
126 for (j = 0; class->musts[j]; j++) {
127 if (!ldb_attr_cmp(class->musts[j], attr))
128 return 1;
131 for (j = 0; class->mays[j]; j++) {
132 if (!ldb_attr_cmp(class->mays[j], attr))
133 return 1;
137 return 0;
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)
144 int i;
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];
151 return NULL;
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;
158 int i,j;
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 */
163 continue;
164 case MAP_KEEP:
165 if (ldb_attr_cmp(attr_name, privdat->attribute_maps[i].local_name) == 0)
166 goto found;
167 break;
168 case MAP_RENAME:
169 case MAP_CONVERT:
170 if (ldb_attr_cmp(attr_name, privdat->attribute_maps[i].u.rename.remote_name) == 0)
171 goto found;
172 break;
173 case MAP_GENERATE:
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)
176 goto found;
178 break;
182 return 0;
184 found:
186 if (ldb_msg_find_element(msg, privdat->attribute_maps[i].local_name))
187 return 1;
189 return 0;
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)
197 int i;
199 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
200 if (privdat->attribute_maps[i].type == MAP_IGNORE)
201 continue;
203 if (privdat->attribute_maps[i].type == MAP_GENERATE)
204 continue;
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];
217 return NULL;
220 static struct ldb_parse_tree *ldb_map_parse_tree(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_parse_tree *tree)
222 int i;
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);
229 if (tree == NULL)
230 return NULL;
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]);
246 if (child) {
247 new_tree->u.list.elements[i] = child;
248 new_tree->u.list.num_elements++;
252 return new_tree;
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);
261 if (!child) {
262 talloc_free(new_tree);
263 return NULL;
266 new_tree->u.isnot.child = child;
267 return new_tree;
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);
278 if (!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;
281 } else {
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);
292 return NULL;
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);
297 return NULL;
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)
318 return new_tree;
320 if (new_tree->operation == LDB_OP_SUBSTRING) {
321 new_tree->u.substring.chunks = NULL; /* FIXME! */
322 return new_tree;
325 if (map_type == MAP_CONVERT) {
326 if (!attr->u.convert.convert_local)
327 return NULL;
328 newvalue = attr->u.convert.convert_local(module, new_tree, &value);
329 } else {
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);
343 return new_tree;
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;
350 int i;
352 if (dn == NULL)
353 return NULL;
355 newdn = talloc_memdup(ctx, dn, sizeof(*dn));
356 if (!newdn)
357 return NULL;
359 newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
361 if (!newdn->components)
362 return NULL;
364 /* For each rdn, map the attribute name and possibly the
365 * complete rdn */
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;
375 switch (map_type) {
376 case MAP_IGNORE:
377 case MAP_GENERATE:
378 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Local MAP_IGNORE or MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name);
379 talloc_free(newdn);
380 return NULL;
382 case MAP_KEEP:
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);
385 break;
387 case MAP_CONVERT:
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);
390 break;
392 case MAP_RENAME:
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);
395 break;
398 return newdn;
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;
405 int i;
407 if (dn == NULL)
408 return NULL;
410 newdn = talloc_memdup(ctx, dn, sizeof(*dn));
411 if (!newdn)
412 return NULL;
414 newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
416 if (!newdn->components)
417 return NULL;
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;
429 switch (map_type)
431 case MAP_IGNORE:
432 case MAP_GENERATE:
433 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Local MAP_IGNORE/MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name);
434 talloc_free(newdn);
435 return NULL;
437 case MAP_CONVERT:
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);
441 talloc_free(newdn);
442 return NULL;
444 newdn->components[i].value = attr->u.convert.convert_local(module, newdn->components, &dn->components[i].value);
445 break;
447 case MAP_RENAME:
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);
450 break;
452 case MAP_KEEP:
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);
455 continue;
459 return newdn;
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[])
465 int i;
466 const char **ret;
467 int ar_size = 0, last_element = 0;
468 struct ldb_map_context *privdat = map_get_privdat(module);
470 if (attrs == NULL)
471 return NULL;
473 /* Start with good guess of number of elements */
474 for (i = 0; attrs[i]; i++);
476 ret = talloc_array(module, const char *, i);
477 ar_size = i;
479 for (i = 0; attrs[i]; i++) {
480 int j;
481 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
482 enum ldb_map_attr_type map_type;
484 if (!attr) {
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;
489 switch (map_type)
491 case MAP_IGNORE: break;
492 case MAP_KEEP:
493 if (last_element >= ar_size) {
494 ret = talloc_realloc(module, ret, const char *, ar_size+1);
495 ar_size++;
497 ret[last_element] = attr->local_name;
498 last_element++;
499 break;
501 case MAP_RENAME:
502 case MAP_CONVERT:
503 if (last_element >= ar_size) {
504 ret = talloc_realloc(module, ret, const char *, ar_size+1);
505 ar_size++;
507 ret[last_element] = attr->u.rename.remote_name;
508 last_element++;
509 break;
511 case MAP_GENERATE:
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);
517 ar_size++;
519 ret[last_element] = attr->u.generate.remote_names[j];
520 last_element++;
522 break;
526 if (last_element >= ar_size) {
527 ret = talloc_realloc(module, ret, const char *, ar_size+1);
528 ar_size++;
531 ret[last_element] = NULL;
533 return ret;
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);
539 int i, j;
540 int count = 0;
541 const char **ret = talloc_array(module, const char *, 1);
543 ret[0] = NULL;
545 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
546 BOOL avail = False;
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;
554 case MAP_KEEP:
555 avail = (ldb_msg_find_ldb_val(msg, attr->local_name) != NULL);
556 break;
558 case MAP_RENAME:
559 case MAP_CONVERT:
560 avail = (ldb_msg_find_ldb_val(msg, attr->u.rename.remote_name) != NULL);
561 break;
563 case MAP_GENERATE:
564 avail = True;
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);
568 break;
571 if (!avail)
572 continue;
574 ret = talloc_realloc(module, ret, const char *, count+2);
575 ret[count] = attr->local_name;
576 ret[count+1] = NULL;
577 count++;
580 return ret;
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)
586 int i, j;
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
595 * run generate() */
597 if (attrs == NULL) {
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;
608 if (!attr) {
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;
613 switch (map_type) {
614 case MAP_IGNORE:break;
615 case MAP_RENAME:
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);
618 if (!oldelm)
619 continue;
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);
629 break;
631 case MAP_CONVERT:
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);
634 if (!oldelm)
635 continue;
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);
646 break;
648 case MAP_KEEP:
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);
663 break;
665 case MAP_GENERATE:
666 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Generating local attribute %s", attr->local_name);
667 if (!attr->u.generate.generate_local)
668 continue;
670 elm = attr->u.generate.generate_local(module, msg, attr->local_name, mi);
671 if (!elm)
672 continue;
674 ldb_msg_add(msg, elm, elm->flags);
675 break;
676 default:
677 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Unknown attr->type for %s", attr->local_name);
678 break;
682 talloc_free(newattrs);
684 return msg;
688 rename a record
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;
696 int ret;
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);
702 if (ret != -1) {
703 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Mapped record renamed");
704 ldb_next_request(module, req);
705 } else {
706 ret = ldb_next_request(module, req);
708 if (ret != -1) {
709 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record renamed");
714 talloc_free(n_olddn);
715 talloc_free(n_newdn);
717 return ret;
721 delete a record
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;
728 int ret;
730 newdn = map_local_dn(module, module, dn);
732 ret = ldb_delete(privdat->mapped_ldb, newdn);
733 if (ret != -1) {
734 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Mapped record deleted");
735 } else {
736 ret = ldb_next_request(module, req);
737 if (ret != -1) {
738 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record deleted");
742 req->op.del.dn = newdn;
743 ret = ldb_next_request(module, req);
744 req->op.del.dn = dn;
746 talloc_free(newdn);
748 return ret;
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];
756 int ret;
757 char *ismapped;
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;
766 childs[0] = &t_not;
767 childs[1] = tree;
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);
778 return ret;
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;
794 int mpret, ret;
795 struct ldb_map_context *privdat = map_get_privdat(module);
796 int i;
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");
808 return 0;
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, talloc_strdup(module, ldb_errstring(privdat->mapped_ldb)));
831 return mpret;
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;
844 ret = 0;
846 for (i = 0; i < mpret; i++) {
847 struct ldb_request mergereq;
848 struct ldb_message *merged;
849 struct ldb_result *extrares = NULL;
850 int extraret;
852 /* Always get special DN's from the fallback database */
853 if (ldb_dn_is_special(newres->msgs[i]->dn))
854 continue;
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");
874 talloc_free(newres);
875 return -1;
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));
880 if (extraret == 1) {
881 int j;
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;
890 ret++;
891 } else {
892 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Discarded merged message because it did not match");
896 talloc_free(newres);
898 res->count = ret;
899 return LDB_SUCCESS;
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;
910 int i, ret;
912 ret = map_search_fb(module, req);
913 if (ret != LDB_SUCCESS)
914 return ret;
916 /* special dn's are never mapped.. */
917 if (ldb_dn_is_special(base)) {
918 return ret;
921 fbres = req->op.search.res;
923 ret = map_search_mp(module, req);
924 if (ret != LDB_SUCCESS) {
925 return ret;
928 mpres = req->op.search.res;
930 /* Merge results */
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;
944 return LDB_SUCCESS;
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");
950 int i;
952 for (i = 0; i < el->num_values; i++) {
953 if (ldb_attr_cmp((char *)el->values[i].data, name) == 0) {
954 return 1;
958 return 0;
962 add a record
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;
970 int ret;
971 int i;
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
991 * mp_msg */
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]);
999 break;
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]);
1009 break;
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;
1035 int j, k;
1036 int mapped = 0;
1038 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0)
1039 continue;
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)
1044 continue;
1046 attr = &privdat->attribute_maps[k];
1048 /* Decide whether or not we need to map or fallback */
1049 switch (attr->type) {
1050 case MAP_GENERATE:
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);
1053 mapped++;
1054 continue;
1055 case MAP_KEEP:
1056 if (!map_msg_valid_attr(module, mp, attr->local_name))
1057 continue;
1058 break;
1059 case MAP_IGNORE: continue;
1060 case MAP_CONVERT:
1061 case MAP_RENAME:
1062 if (!map_msg_valid_attr(module, mp, attr->u.rename.remote_name))
1063 continue;
1064 break;
1067 switch (attr->type) {
1068 case MAP_KEEP:
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);
1080 break;
1082 case MAP_RENAME:
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]);
1093 break;
1095 case MAP_CONVERT:
1096 if (attr->u.convert.convert_local == NULL)
1097 continue;
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]);
1109 break;
1111 case MAP_GENERATE:
1112 case MAP_IGNORE:
1113 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "This line should never be reached");
1114 continue;
1117 ldb_msg_add(mp, elm, 0);
1118 mapped++;
1121 if (mapped == 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);
1134 if (ret == -1) {
1135 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Adding mapped record failed: %s", ldb_errstring(privdat->mapped_ldb));
1136 return -1;
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;
1146 if (ret == -1) {
1147 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Adding fallback record failed: %s", ldb_errstring(module->ldb));
1148 return -1;
1151 talloc_free(fb);
1152 talloc_free(mp);
1154 return ret;
1159 modify a record
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;
1167 int fb_ret, mp_ret;
1168 int i,j;
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;
1184 int k;
1185 int mapped = 0;
1187 if (ldb_attr_cmp(msg->elements[i].name, "isMapped") == 0)
1188 continue;
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)
1193 continue;
1195 attr = &privdat->attribute_maps[k];
1197 switch (attr->type) {
1198 case MAP_IGNORE: continue;
1199 case MAP_RENAME:
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);
1210 mapped++;
1211 continue;
1213 case MAP_CONVERT:
1214 if (!attr->u.convert.convert_local)
1215 continue;
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);
1227 mapped++;
1228 continue;
1230 case MAP_KEEP:
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);
1242 mapped++;
1243 continue;
1245 case MAP_GENERATE:
1246 attr->u.generate.generate_remote(module, attr->local_name, msg, mp, fb);
1247 mapped++;
1248 continue;
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);
1267 if (fb_ret == -1) {
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;
1275 } else fb_ret = 0;
1276 talloc_free(fb);
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);
1281 } else mp_ret = 0;
1282 talloc_free(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) {
1292 case LDB_SEARCH:
1293 return map_search_bytree(module, req);
1295 case LDB_ADD:
1296 return map_add(module, req);
1298 case LDB_MODIFY:
1299 return map_modify(module, req);
1301 case LDB_DELETE:
1302 return map_delete(module, req);
1304 case LDB_RENAME:
1305 return map_rename(module, req);
1307 default:
1308 return ldb_next_request(module, req);
1314 static const struct ldb_module_ops map_ops = {
1315 .name = "map",
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;
1324 char *url;
1325 int ret;
1327 mods = ldb_dn_string_compose(ldb, NULL, "@MAP=%s", name);
1328 if (mods == NULL) {
1329 ldb_debug(ldb, LDB_DEBUG_ERROR, "Can't construct DN");
1330 return NULL;
1333 ret = ldb_search(ldb, mods, LDB_SCOPE_BASE, "", attrs, &result);
1334 talloc_free(mods);
1335 if (ret != LDB_SUCCESS || result->count == 0) {
1336 ldb_debug(ldb, LDB_DEBUG_ERROR, "Not enough results found looking for @MAP");
1337 return NULL;
1340 url = talloc_strdup(ldb, ldb_msg_find_string(result->msgs[0], "@MAP_URL", NULL));
1342 talloc_free(result);
1344 return url;
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)
1350 int i, j;
1351 struct ldb_module *ctx;
1352 struct map_private *data;
1353 char *url;
1355 ctx = talloc(ldb, struct ldb_module);
1356 if (!ctx)
1357 return NULL;
1359 data = talloc(ctx, struct map_private);
1360 if (!data) {
1361 talloc_free(ctx);
1362 return NULL;
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);
1369 if (!url) {
1370 ldb_debug(ldb, LDB_DEBUG_FATAL, "@MAP=%s not set!\n", name);
1371 return NULL;
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);
1376 return NULL;
1379 talloc_free(url);
1381 /* Get list of attribute maps */
1382 j = 0;
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];
1388 j++;
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];
1394 j++;
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;
1402 ctx->ldb = ldb;
1403 ctx->prev = ctx->next = NULL;
1404 ctx->ops = &map_ops;
1406 return ctx;
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);
1418 talloc_free(dn);
1420 newval = talloc(ctx, struct ldb_val);
1421 newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1422 if (newval->data) {
1423 newval->length = strlen((char *)newval->data);
1424 } else {
1425 newval->length = 0;
1428 talloc_free(newdn);
1430 return *newval;
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);
1442 talloc_free(dn);
1444 newval = talloc(ctx, struct ldb_val);
1445 newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1446 if (newval->data) {
1447 newval->length = strlen((char *)newval->data);
1448 } else {
1449 newval->length = 0;
1452 talloc_free(newdn);
1454 return *newval;
1457 static struct ldb_val map_convert_local_objectclass(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1459 int i;
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)
1477 int i;
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);