r9789: Patch from Volker that fixes the build on AIX.
[Samba/aatanasov.git] / source / lib / ldb / modules / ldb_map.c
blobc5ddcc7e131aaba691961619e7f2bc9b92182436
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 "lib/ldb/include/ldb.h"
27 #include "lib/ldb/include/ldb_private.h"
28 #include "lib/ldb/modules/ldb_map.h"
30 /* TODO:
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'
39 - add/modify
40 - split up ldb_message into fallback and mapped parts if is_mappable
41 - search:
42 - search local one for not isMapped entries
43 - remove remote attributes from ldb_parse_tree
44 - search remote one
45 - per record, search local one for additional data (by dn)
46 - test if (full expression) is now true
47 - delete
48 - delete both
49 - rename
50 - rename locally and remotely
53 static struct ldb_val map_convert_local_dn(struct ldb_map_context *map,
54 TALLOC_CTX *ctx,
55 const struct ldb_val *val);
56 static struct ldb_val map_convert_remote_dn(struct ldb_map_context *map,
57 TALLOC_CTX *ctx,
58 const struct ldb_val *val);
59 static struct ldb_val map_convert_local_objectclass(struct ldb_map_context *map,
60 TALLOC_CTX *ctx,
61 const struct ldb_val *val);
62 static struct ldb_val map_convert_remote_objectclass(struct ldb_map_context *map,
63 TALLOC_CTX *ctx,
64 const struct ldb_val *val);
66 static const struct ldb_map_attribute builtin_attribute_maps[] = {
68 .local_name = "dn",
69 .type = MAP_CONVERT,
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",
76 .type = MAP_CONVERT,
77 .u.convert.remote_name = "objectclass",
78 .u.convert.convert_local = map_convert_local_objectclass,
79 .u.convert.convert_remote = map_convert_remote_objectclass,
82 .local_name = NULL,
86 struct map_private {
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)
98 int i;
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];
104 return NULL;
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 BOOL map_is_mappable(struct ldb_map_context *privdat, const struct ldb_message *msg)
111 int i;
112 struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
114 /* No objectClass... */
115 if (el == NULL) {
116 return False;
119 for (i = 0; i < el->num_values; i++) {
120 if (map_find_objectclass_local(privdat, (char *)el->values[i].data))
121 return True;
124 return False;
127 /* find an attribute by the local name */
128 static const struct ldb_map_attribute *map_find_attr_local(struct ldb_map_context *privdat, const char *attr)
130 int i;
132 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
133 if (!ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr))
134 return &privdat->attribute_maps[i];
137 return NULL;
140 /* find an attribute by the remote name */
141 static const struct ldb_map_attribute *map_find_attr_remote(struct ldb_map_context *privdat, const char *attr)
143 int i;
145 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
146 if (privdat->attribute_maps[i].type == MAP_IGNORE)
147 continue;
149 if (privdat->attribute_maps[i].type == MAP_GENERATE)
150 continue;
152 if (privdat->attribute_maps[i].type == MAP_KEEP &&
153 ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr) == 0)
154 return &privdat->attribute_maps[i];
156 if ((privdat->attribute_maps[i].type == MAP_RENAME ||
157 privdat->attribute_maps[i].type == MAP_CONVERT) &&
158 ldb_attr_cmp(privdat->attribute_maps[i].u.rename.remote_name, attr) == 0)
159 return &privdat->attribute_maps[i];
163 return NULL;
166 static struct ldb_parse_tree *ldb_map_parse_tree(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_parse_tree *tree)
168 int i;
169 const struct ldb_map_attribute *attr;
170 struct ldb_parse_tree *new_tree;
171 enum ldb_map_attr_type map_type;
172 struct ldb_val value, newvalue;
173 struct ldb_map_context *privdat = map_get_privdat(module);
175 if (tree == NULL)
176 return NULL;
179 /* Find attr in question and:
180 * - if it has a convert_operator function, run that
181 * - otherwise, replace attr name with required[0] */
183 if (tree->operation == LDB_OP_AND ||
184 tree->operation == LDB_OP_OR) {
186 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
187 new_tree->u.list.elements = talloc_array(new_tree, struct ldb_parse_tree *, tree->u.list.num_elements);
188 new_tree->u.list.num_elements = 0;
189 for (i = 0; i < tree->u.list.num_elements; i++) {
190 struct ldb_parse_tree *child = ldb_map_parse_tree(module, new_tree, tree->u.list.elements[i]);
192 if (child) {
193 new_tree->u.list.elements[i] = child;
194 new_tree->u.list.num_elements++;
198 return new_tree;
201 if (tree->operation == LDB_OP_NOT) {
202 struct ldb_parse_tree *child;
204 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
205 child = ldb_map_parse_tree(module, new_tree, tree->u.isnot.child);
207 if (!child) {
208 talloc_free(new_tree);
209 return NULL;
212 new_tree->u.isnot.child = child;
213 return new_tree;
216 /* tree->operation is LDB_OP_EQUALITY, LDB_OP_SUBSTRING, LDB_OP_GREATER,
217 * LDB_OP_LESS, LDB_OP_APPROX, LDB_OP_PRESENT or LDB_OP_EXTENDED
219 * (all have attr as the first element)
222 attr = map_find_attr_local(privdat, tree->u.equality.attr);
224 if (!attr) {
225 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s', leaving as is\n", tree->u.equality.attr);
226 map_type = MAP_KEEP;
227 } else {
228 map_type = attr->type;
231 if (attr && attr->convert_operator) {
232 /* Run convert_operator */
233 return attr->convert_operator(privdat, module, tree);
236 if (map_type == MAP_IGNORE) {
237 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Search on ignored attribute '%s'\n", tree->u.equality.attr);
238 return NULL;
241 if (map_type == MAP_GENERATE) {
242 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);
243 return NULL;
246 if (tree->operation == LDB_OP_EQUALITY) {
247 value = tree->u.equality.value;
248 } else if (tree->operation == LDB_OP_LESS || tree->operation == LDB_OP_GREATER ||
249 tree->operation == LDB_OP_APPROX) {
250 value = tree->u.comparison.value;
251 } else if (tree->operation == LDB_OP_EXTENDED) {
252 value = tree->u.extended.value;
255 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
257 if (map_type == MAP_KEEP) {
258 new_tree->u.equality.attr = talloc_strdup(new_tree, tree->u.equality.attr);
259 } else { /* MAP_RENAME / MAP_CONVERT */
260 new_tree->u.equality.attr = talloc_strdup(new_tree, attr->u.rename.remote_name);
263 if (new_tree->operation == LDB_OP_PRESENT)
264 return new_tree;
266 if (new_tree->operation == LDB_OP_SUBSTRING) {
267 new_tree->u.substring.chunks = NULL; /* FIXME! */
268 return new_tree;
271 if (map_type == MAP_CONVERT) {
272 newvalue = attr->u.convert.convert_local(privdat, new_tree, &value);
273 } else {
274 newvalue = ldb_val_dup(new_tree, &value);
277 if (new_tree->operation == LDB_OP_EQUALITY) {
278 new_tree->u.equality.value = newvalue;
279 } else if (new_tree->operation == LDB_OP_LESS || new_tree->operation == LDB_OP_GREATER ||
280 new_tree->operation == LDB_OP_APPROX) {
281 new_tree->u.comparison.value = newvalue;
282 } else if (new_tree->operation == LDB_OP_EXTENDED) {
283 new_tree->u.extended.value = newvalue;
284 new_tree->u.extended.rule_id = talloc_strdup(new_tree, tree->u.extended.rule_id);
287 return new_tree;
290 /* Remote DN -> Local DN */
291 static struct ldb_dn *map_remote_dn(struct ldb_map_context *privdat, TALLOC_CTX *ctx, const struct ldb_dn *dn)
293 struct ldb_dn *newdn;
294 int i;
296 if (dn == NULL)
297 return NULL;
299 newdn = talloc_memdup(ctx, dn, sizeof(*dn));
300 if (!newdn)
301 return NULL;
303 newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
305 if (!newdn->components)
306 return NULL;
308 /* For each rdn, map the attribute name and possibly the
309 * complete rdn */
311 for (i = 0; i < dn->comp_num; i++) {
312 const struct ldb_map_attribute *attr = map_find_attr_remote(privdat, dn->components[i].name);
313 enum ldb_map_attr_type map_type;
315 /* Unknown attribute - leave this dn as is and hope the best... */
316 if (!attr) map_type = MAP_KEEP;
317 else map_type = attr->type;
319 switch (map_type) {
320 case MAP_IGNORE:
321 case MAP_GENERATE:
322 DEBUG(0, ("Local MAP_IGNORE or MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name));
323 talloc_free(newdn);
324 return NULL;
326 case MAP_KEEP:
327 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
328 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
329 break;
331 case MAP_CONVERT:
332 newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
333 newdn->components[i].value = attr->u.convert.convert_remote(privdat, ctx, &dn->components[i].value);
334 break;
336 case MAP_RENAME:
337 newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
338 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
339 break;
342 return newdn;
345 /* Local DN -> Remote DN */
346 static struct ldb_dn *map_local_dn(struct ldb_map_context *privdat, TALLOC_CTX *ctx, const struct ldb_dn *dn)
348 struct ldb_dn *newdn;
349 int i;
351 if (dn == NULL)
352 return NULL;
354 newdn = talloc_memdup(ctx, dn, sizeof(*dn));
355 if (!newdn)
356 return NULL;
358 newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num);
360 if (!newdn->components)
361 return NULL;
363 /* For each rdn, map the attribute name and possibly the
364 * complete rdn using an equality convert_operator call */
366 for (i = 0; i < dn->comp_num; i++) {
367 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, dn->components[i].name);
368 enum ldb_map_attr_type map_type;
370 /* Unknown attribute - leave this dn as is and hope the best... */
371 if (!attr) map_type = MAP_KEEP; else map_type = attr->type;
373 switch (map_type)
375 case MAP_IGNORE:
376 case MAP_GENERATE:
377 DEBUG(0, ("Local MAP_IGNORE/MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name));
378 talloc_free(newdn);
379 return NULL;
381 case MAP_CONVERT:
382 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.convert.remote_name);
383 newdn->components[i].value = attr->u.convert.convert_local(privdat, newdn->components, &dn->components[i].value);
384 break;
386 case MAP_RENAME:
387 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.rename.remote_name);
388 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
389 break;
391 case MAP_KEEP:
392 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
393 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
394 continue;
398 return newdn;
401 /* Loop over ldb_map_attribute array and add remote_names */
402 static const char **ldb_map_attrs(struct ldb_module *module, const char *const attrs[])
404 int i;
405 const char **ret;
406 int ar_size = 0, last_element = 0;
407 struct ldb_map_context *privdat = map_get_privdat(module);
409 if (attrs == NULL)
410 return NULL;
412 /* Start with good guess of number of elements */
413 for (i = 0; attrs[i]; i++);
415 ret = talloc_array(module, const char *, i);
416 ar_size = i;
418 for (i = 0; attrs[i]; i++) {
419 int j;
420 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
421 enum ldb_map_attr_type map_type;
423 if (!attr) {
424 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Local attribute '%s' does not have a definition!\n", attrs[i]);
425 map_type = MAP_IGNORE;
426 } else map_type = attr->type;
428 switch (map_type)
430 case MAP_IGNORE: break;
431 case MAP_KEEP:
432 if (last_element >= ar_size) {
433 ret = talloc_realloc(module, ret, const char *, ar_size+1);
434 ar_size++;
436 ret[last_element] = attr->local_name;
437 last_element++;
438 break;
440 case MAP_RENAME:
441 case MAP_CONVERT:
442 if (last_element >= ar_size) {
443 ret = talloc_realloc(module, ret, const char *, ar_size+1);
444 ar_size++;
446 ret[last_element] = attr->u.rename.remote_name;
447 last_element++;
448 break;
450 case MAP_GENERATE:
451 /* Add remote_names[] for this attribute to the list of
452 * attributes to request from the remote server */
453 for (j = 0; attr->u.generate.remote_names[j]; j++) {
454 if (last_element >= ar_size) {
455 ret = talloc_realloc(module, ret, const char *, ar_size+1);
456 ar_size++;
458 ret[last_element] = attr->u.generate.remote_names[j];
459 last_element++;
461 break;
465 if (last_element >= ar_size) {
466 ret = talloc_realloc(module, ret, const char *, ar_size+1);
467 ar_size++;
470 ret[last_element] = NULL;
472 return ret;
475 static const char **available_local_attributes(struct ldb_module *module, const struct ldb_message *msg)
477 struct ldb_map_context *privdat = map_get_privdat(module);
478 int i, j;
479 int count = 0;
480 const char **ret = talloc_array(module, const char *, 1);
482 ret[0] = NULL;
484 for (i = 0; privdat->attribute_maps[i].local_name; i++) {
485 BOOL avail = False;
486 const struct ldb_map_attribute *attr = &privdat->attribute_maps[i];
488 /* If all remote attributes for this attribute are present, add the
489 * local one to the list */
491 switch (attr->type) {
492 case MAP_IGNORE: break;
493 case MAP_KEEP:
494 avail = (ldb_msg_find_ldb_val(msg, attr->local_name) != NULL);
495 break;
497 case MAP_RENAME:
498 case MAP_CONVERT:
499 avail = (ldb_msg_find_ldb_val(msg, attr->u.rename.remote_name) != NULL);
500 break;
502 case MAP_GENERATE:
503 avail = True;
504 for (j = 0; attr->u.generate.remote_names[j]; j++) {
505 avail &= (ldb_msg_find_ldb_val(msg, attr->u.generate.remote_names[j]) != NULL);
507 break;
510 if (!avail)
511 continue;
513 ret = talloc_realloc(module, ret, const char *, count+2);
514 ret[count] = attr->local_name;
515 ret[count+1] = NULL;
516 count++;
519 return ret;
522 /* Used for search */
523 static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, const char * const*attrs, const struct ldb_message *mi)
525 int i, j;
526 struct ldb_message *msg = talloc_zero(module, struct ldb_message);
527 struct ldb_message_element *elm, *oldelm;
528 struct ldb_map_context *privdat = map_get_privdat(module);
529 const char **newattrs = NULL;
531 msg->dn = map_remote_dn(privdat, module, mi->dn);
533 ldb_msg_add_string(module->ldb, msg, "mappedFromDn", ldb_dn_linearize(msg, mi->dn));
535 /* Loop over attrs, find in ldb_map_attribute array and
536 * run generate() */
538 if (attrs == NULL) {
539 /* Generate list of the local attributes that /can/ be generated
540 * using the specific remote attributes */
542 attrs = newattrs = available_local_attributes(module, mi);
545 for (i = 0; attrs[i]; i++) {
546 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
547 enum ldb_map_attr_type map_type;
549 if (!attr) {
550 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s' when generating incoming message\n", attrs[i]);
551 map_type = MAP_IGNORE;
552 } else map_type = attr->type;
554 switch (map_type) {
555 case MAP_IGNORE:break;
556 case MAP_RENAME:
557 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
558 if (!oldelm) continue;
560 elm = talloc(msg, struct ldb_message_element);
561 elm->name = talloc_strdup(elm, attr->local_name);
562 elm->num_values = oldelm->num_values;
563 elm->values = talloc_reference(elm, oldelm->values);
565 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
566 break;
568 case MAP_CONVERT:
569 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
570 if (!oldelm) continue;
572 elm = talloc(msg, struct ldb_message_element);
573 elm->name = talloc_strdup(elm, attr->local_name);
574 elm->num_values = oldelm->num_values;
575 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
577 for (j = 0; j < oldelm->num_values; j++)
578 elm->values[j] = attr->u.convert.convert_remote(privdat, elm, &oldelm->values[j]);
580 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
581 break;
583 case MAP_KEEP:
584 oldelm = ldb_msg_find_element(mi, attr->local_name);
585 if (!oldelm) continue;
587 elm = talloc(msg, struct ldb_message_element);
589 elm->num_values = oldelm->num_values;
590 elm->values = talloc_reference(elm, oldelm->values);
591 elm->name = talloc_strdup(elm, oldelm->name);
593 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
594 break;
596 case MAP_GENERATE:
597 elm = attr->u.generate.generate_local(privdat, msg, attr->local_name, mi);
598 if (!elm) continue;
600 ldb_msg_add(module->ldb, msg, elm, elm->flags);
601 break;
602 default:
603 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Unknown attr->type for %s", attr->local_name);
604 break;
608 talloc_free(newattrs);
610 return msg;
613 /* Used for add, modify */
614 static int ldb_map_message_outgoing(struct ldb_module *module, const struct ldb_message *mo, struct ldb_message **fb, struct ldb_message **mp)
616 struct ldb_map_context *privdat = map_get_privdat(module);
617 struct ldb_message *msg = talloc_zero(module, struct ldb_message);
618 struct ldb_message_element *elm;
619 int i,j;
621 *fb = talloc_zero(module, struct ldb_message);
622 (*fb)->dn = talloc_reference(*fb, mo->dn);
624 *mp = msg;
626 msg->private_data = mo->private_data;
628 msg->dn = map_local_dn(privdat, module, mo->dn);
630 /* Loop over mi and call generate_remote for each attribute */
631 for (i = 0; i < mo->num_elements; i++) {
632 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, mo->elements[i].name);
633 enum ldb_map_attr_type map_type;
635 if (!attr) {
636 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Undefined local attribute '%s', ignoring\n", mo->elements[i].name);
637 map_type = MAP_IGNORE;
638 continue;
639 } else map_type = attr->type;
641 switch (map_type) {
642 case MAP_IGNORE: /* Add to fallback message */
643 elm = talloc(*fb, struct ldb_message_element);
645 elm->num_values = mo->elements[i].num_values;
646 elm->values = talloc_reference(elm, mo->elements[i].values);
647 elm->name = talloc_strdup(elm, mo->elements[i].name);
649 ldb_msg_add(module->ldb, *fb, elm, mo->elements[i].flags);
650 break;
651 case MAP_RENAME:
652 elm = talloc(msg, struct ldb_message_element);
654 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
655 elm->num_values = mo->elements[i].num_values;
656 elm->values = talloc_reference(elm, mo->elements[i].values);
658 ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags);
659 break;
661 case MAP_CONVERT:
662 elm = talloc(msg, struct ldb_message_element);
664 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
665 elm->num_values = mo->elements[i].num_values;
666 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
668 for (j = 0; j < elm->num_values; j++) {
669 elm->values[j] = attr->u.convert.convert_local(privdat, msg, &mo->elements[i].values[j]);
672 ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags);
673 break;
675 case MAP_KEEP:
676 elm = talloc(msg, struct ldb_message_element);
678 elm->num_values = mo->elements[i].num_values;
679 elm->values = talloc_reference(elm, mo->elements[i].values);
680 elm->name = talloc_strdup(elm, mo->elements[i].name);
682 ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags);
683 break;
685 case MAP_GENERATE:
686 attr->u.generate.generate_remote(privdat, attr->local_name, mo, msg);
687 break;
691 return 0;
696 rename a record
698 static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
700 struct ldb_map_context *privdat = map_get_privdat(module);
701 struct ldb_dn *n_olddn, *n_newdn;
702 int ret;
704 ret = ldb_next_rename_record(module, olddn, newdn);
706 n_olddn = map_local_dn(privdat, module, olddn);
707 n_newdn = map_local_dn(privdat, module, newdn);
709 ret = ldb_rename(privdat->mapped_ldb, n_olddn, n_newdn);
711 talloc_free(n_olddn);
712 talloc_free(n_newdn);
714 return ret;
718 delete a record
720 static int map_delete(struct ldb_module *module, const struct ldb_dn *dn)
722 struct ldb_map_context *privdat = map_get_privdat(module);
723 struct ldb_dn *newdn;
724 int ret;
726 ret = ldb_next_delete_record(module, dn);
728 newdn = map_local_dn(privdat, module, dn);
730 ret = ldb_delete(privdat->mapped_ldb, newdn);
732 talloc_free(newdn);
734 return ret;
737 /* search fallback database */
738 static int map_search_bytree_fb(struct ldb_module *module, const struct ldb_dn *base,
739 enum ldb_scope scope, struct ldb_parse_tree *tree,
740 const char * const *attrs, struct ldb_message ***res)
742 int ret;
743 struct ldb_parse_tree t_and, t_not, t_present, *childs[2];
745 t_present.operation = LDB_OP_PRESENT;
746 t_present.u.present.attr = talloc_strdup(NULL, "isMapped");
748 t_not.operation = LDB_OP_NOT;
749 t_not.u.isnot.child = &t_present;
751 childs[0] = &t_not;
752 childs[1] = tree;
753 t_and.operation = LDB_OP_AND;
754 t_and.u.list.num_elements = 2;
755 t_and.u.list.elements = childs;
757 ret = ldb_next_search_bytree(module, base, scope, &t_and, attrs, res);
759 talloc_free(t_present.u.present.attr);
761 return ret;
764 static int map_search_bytree_mp(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)
768 struct ldb_parse_tree *new_tree;
769 struct ldb_dn *new_base;
770 struct ldb_message **newres;
771 const char **newattrs;
772 int mpret, ret;
773 struct ldb_map_context *privdat = map_get_privdat(module);
774 int i;
776 /*- search mapped database */
778 new_tree = ldb_map_parse_tree(module, module, tree);
779 newattrs = ldb_map_attrs(module, attrs);
780 new_base = map_local_dn(privdat, module, base);
782 mpret = ldb_search_bytree(privdat->mapped_ldb, new_base, scope, new_tree, newattrs, &newres);
784 talloc_free(new_base);
785 talloc_free(new_tree);
786 talloc_free(newattrs);
788 if (mpret == -1) {
789 struct map_private *map_private = module->private_data;
790 map_private->last_err_string = ldb_errstring(privdat->mapped_ldb);
791 return -1;
795 - per returned record, search fallback database for additional data (by dn)
796 - test if (full expression) is now true
799 *res = talloc_array(module, struct ldb_message *, mpret);
801 ret = 0;
803 for (i = 0; i < mpret; i++) {
804 struct ldb_message *merged = ldb_map_message_incoming(module, attrs, newres[i]);
805 struct ldb_message **extrares = NULL;
806 int extraret;
808 /* Merge with additional data from local database */
809 extraret = ldb_next_search(module, merged->dn, LDB_SCOPE_BASE, "", NULL, &extrares);
811 if (extraret == -1) {
812 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error searching for extra data!\n");
813 } else if (extraret > 1) {
814 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "More than one result for extra data!\n");
815 talloc_free(newres);
816 return -1;
817 } else if (extraret == 0) {
818 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "No extra data found for remote DN");
821 if (extraret == 1) {
822 int j;
823 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Extra data found for remote DN");
824 for (j = 0; j < extrares[0]->num_elements; j++) {
825 ldb_msg_add(module->ldb, merged, &(extrares[0]->elements[j]), extrares[0]->elements[j].flags);
828 ldb_msg_add_string(module->ldb, merged, "extraMapped", "TRUE");
829 } else {
830 ldb_msg_add_string(module->ldb, merged, "extraMapped", "FALSE");
833 if (ldb_match_msg(module->ldb, merged, tree, base, scope)) {
834 (*res)[ret] = merged;
835 ret++;
836 } else {
837 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Discarded merged message because it did not match");
841 talloc_free(newres);
843 return ret;
848 search for matching records using a ldb_parse_tree
850 static int map_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
851 enum ldb_scope scope, struct ldb_parse_tree *tree,
852 const char * const *attrs, struct ldb_message ***res)
854 struct ldb_message **fbres, **mpres;
855 int i;
856 int ret_fb, ret_mp;
858 ret_fb = map_search_bytree_fb(module, base, scope, tree, attrs, &fbres);
859 if (ret_fb == -1)
860 return -1;
862 ret_mp = map_search_bytree_mp(module, base, scope, tree, attrs, &mpres);
863 if (ret_mp == -1) {
864 return -1;
867 /* Merge results */
868 *res = talloc_array(module, struct ldb_message *, ret_fb + ret_mp);
870 for (i = 0; i < ret_fb; i++) (*res)[i] = fbres[i];
871 for (i = 0; i < ret_mp; i++) (*res)[ret_fb+i] = mpres[i];
873 return ret_fb + ret_mp;
876 search for matching records
878 static int map_search(struct ldb_module *module, const struct ldb_dn *base,
879 enum ldb_scope scope, const char *expression,
880 const char * const *attrs, struct ldb_message ***res)
882 struct map_private *map = module->private_data;
883 struct ldb_parse_tree *tree;
884 int ret;
886 tree = ldb_parse_tree(NULL, expression);
887 if (tree == NULL) {
888 map->last_err_string = "expression parse failed";
889 return -1;
892 ret = map_search_bytree(module, base, scope, tree, attrs, res);
893 talloc_free(tree);
894 return ret;
898 add a record
900 static int map_add(struct ldb_module *module, const struct ldb_message *msg)
902 int ret;
903 struct ldb_map_context *privdat = map_get_privdat(module);
904 struct ldb_message *fb, *mp;
906 if (!map_is_mappable(privdat, msg)) {
907 return ldb_next_add_record(module, msg);
910 if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1)
911 return -1;
913 ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
915 ret = ldb_next_add_record(module, fb);
916 if (ret == -1) {
917 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding fallback record failed");
918 return -1;
921 ret = ldb_add(privdat->mapped_ldb, mp);
922 if (ret == -1) {
923 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding mapped record failed");
924 return -1;
927 talloc_free(fb);
928 talloc_free(mp);
930 return ret;
935 modify a record
937 static int map_modify(struct ldb_module *module, const struct ldb_message *msg)
939 struct ldb_map_context *privdat = map_get_privdat(module);
940 struct ldb_message *fb, *mp;
941 int ret;
943 if (!map_is_mappable(privdat, msg))
944 return ldb_next_modify_record(module, msg);
947 if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1)
948 return -1;
950 ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
952 ret = ldb_next_modify_record(module, fb);
954 ret = ldb_modify(privdat->mapped_ldb, mp);
956 talloc_free(fb);
957 talloc_free(mp);
959 return ret;
962 static int map_lock(struct ldb_module *module, const char *lockname)
964 return ldb_next_named_lock(module, lockname);
967 static int map_unlock(struct ldb_module *module, const char *lockname)
969 return ldb_next_named_unlock(module, lockname);
973 return extended error information
975 static const char *map_errstring(struct ldb_module *module)
977 struct map_private *map = module->private_data;
979 if (map->last_err_string)
980 return map->last_err_string;
982 return ldb_next_errstring(module);
985 static const struct ldb_module_ops map_ops = {
986 .name = "map",
987 .search = map_search,
988 .search_bytree = map_search_bytree,
989 .add_record = map_add,
990 .modify_record = map_modify,
991 .delete_record = map_delete,
992 .rename_record = map_rename,
993 .named_lock = map_lock,
994 .named_unlock = map_unlock,
995 .errstring = map_errstring
998 static char *map_find_url(struct ldb_context *ldb, const char *name)
1000 const char * const attrs[] = { "@MAP_URL" , NULL};
1001 struct ldb_message **msg = NULL;
1002 struct ldb_dn *mods;
1003 char *url;
1004 int ret;
1006 mods = ldb_dn_string_compose(ldb, NULL, "@MAP=%s", name);
1007 if (mods == NULL) {
1008 ldb_debug(ldb, LDB_DEBUG_ERROR, "Can't construct DN");
1009 return NULL;
1012 ret = ldb_search(ldb, mods, LDB_SCOPE_BASE, "", attrs, &msg);
1013 talloc_free(mods);
1014 if (ret < 1) {
1015 ldb_debug(ldb, LDB_DEBUG_ERROR, "Not enough results found looking for @MAP");
1016 return NULL;
1019 url = talloc_strdup(ldb, ldb_msg_find_string(msg[0], "@MAP_URL", NULL));
1021 talloc_free(msg);
1023 return url;
1026 /* the init function */
1027 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)
1029 int i, j;
1030 struct ldb_module *ctx;
1031 struct map_private *data;
1032 char *url;
1034 ctx = talloc(ldb, struct ldb_module);
1035 if (!ctx)
1036 return NULL;
1038 data = talloc(ctx, struct map_private);
1039 if (!data) {
1040 talloc_free(ctx);
1041 return NULL;
1044 data->context.mapped_ldb = ldb_init(data);
1045 url = map_find_url(ldb, name);
1047 if (!url) {
1048 ldb_debug(ldb, LDB_DEBUG_FATAL, "@MAP=%s not set!\n", name);
1049 return NULL;
1052 if (ldb_connect(data->context.mapped_ldb, url, 0, NULL) != 0) {
1053 ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to open mapped database for %s at '%s'\n", name, url);
1054 return NULL;
1057 talloc_free(url);
1059 data->last_err_string = NULL;
1061 /* Get list of attribute maps */
1062 j = 0;
1063 data->context.attribute_maps = NULL;
1065 for (i = 0; attrs[i].local_name; i++) {
1066 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1067 data->context.attribute_maps[j] = attrs[i];
1068 j++;
1071 for (i = 0; builtin_attribute_maps[i].local_name; i++) {
1072 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1073 data->context.attribute_maps[j] = builtin_attribute_maps[i];
1074 j++;
1077 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1078 ZERO_STRUCT(data->context.attribute_maps[j].local_name);
1080 data->context.objectclass_maps = ocls;
1081 ctx->private_data = data;
1082 ctx->ldb = ldb;
1083 ctx->prev = ctx->next = NULL;
1084 ctx->ops = &map_ops;
1086 return ctx;
1089 static struct ldb_val map_convert_local_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1091 struct ldb_dn *dn, *newdn;;
1092 struct ldb_val *newval;
1094 dn = ldb_dn_explode(ctx, (char *)val->data);
1096 newdn = map_local_dn(map, ctx, dn);
1098 talloc_free(dn);
1100 newval = talloc(ctx, struct ldb_val);
1101 newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1102 newval->length = strlen((char *)newval->data);
1104 talloc_free(newdn);
1106 return *newval;
1109 static struct ldb_val map_convert_remote_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1111 struct ldb_dn *dn, *newdn;;
1112 struct ldb_val *newval;
1114 dn = ldb_dn_explode(ctx, (char *)val->data);
1116 newdn = map_remote_dn(map, ctx, dn);
1118 talloc_free(dn);
1120 newval = talloc(ctx, struct ldb_val);
1121 newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1122 newval->length = strlen((char *)newval->data);
1124 talloc_free(newdn);
1126 return *newval;
1129 static struct ldb_val map_convert_local_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1131 int i;
1133 for (i = 0; map->objectclass_maps[i].local_name; i++) {
1134 if (!strcmp(map->objectclass_maps[i].local_name, (char *)val->data)) {
1135 struct ldb_val newval;
1136 newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].remote_name);
1137 newval.length = strlen((char *)newval.data);
1139 return ldb_val_dup(ctx, &newval);
1143 return ldb_val_dup(ctx, val);
1146 static struct ldb_val map_convert_remote_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1148 int i;
1150 for (i = 0; map->objectclass_maps[i].remote_name; i++) {
1151 if (!strcmp(map->objectclass_maps[i].remote_name, (char *)val->data)) {
1152 struct ldb_val newval;
1153 newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].local_name);
1154 newval.length = strlen((char *)newval.data);
1156 return ldb_val_dup(ctx, &newval);
1160 return ldb_val_dup(ctx, val);