2 ldb database library - map backend
4 Copyright (C) Jelmer Vernooij 2005
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "lib/ldb/include/ldb.h"
27 #include "lib/ldb/include/ldb_private.h"
28 #include "lib/ldb/modules/ldb_map.h"
31 * - objectclass hint in ldb_map_attribute
32 * for use when multiple remote attributes (independant of each other)
33 * map to one local attribute. E.g.: (uid, gidNumber) -> unixName
34 * (use MAP_GENERATE instead ?)
38 - special attribute 'isMapped'
40 - split up ldb_message into fallback and mapped parts if is_mappable
42 - search local one for not isMapped entries
43 - remove remote attributes from ldb_parse_tree
45 - per record, search local one for additional data (by dn)
46 - test if (full expression) is now true
50 - rename locally and remotely
53 static struct ldb_val
map_convert_local_dn(struct ldb_map_context
*map
,
55 const struct ldb_val
*val
);
56 static struct ldb_val
map_convert_remote_dn(struct ldb_map_context
*map
,
58 const struct ldb_val
*val
);
59 static struct ldb_val
map_convert_local_objectclass(struct ldb_map_context
*map
,
61 const struct ldb_val
*val
);
62 static struct ldb_val
map_convert_remote_objectclass(struct ldb_map_context
*map
,
64 const struct ldb_val
*val
);
66 static const struct ldb_map_attribute builtin_attribute_maps
[] = {
70 .u
.convert
.remote_name
= "dn",
71 .u
.convert
.convert_local
= map_convert_local_dn
,
72 .u
.convert
.convert_remote
= map_convert_remote_dn
,
75 .local_name
= "objectclass",
77 .u
.convert
.remote_name
= "objectclass",
78 .u
.convert
.convert_local
= map_convert_local_objectclass
,
79 .u
.convert
.convert_remote
= map_convert_remote_objectclass
,
87 struct ldb_map_context context
;
88 const char *last_err_string
;
91 static struct ldb_map_context
*map_get_privdat(struct ldb_module
*module
)
93 return &((struct map_private
*)module
->private_data
)->context
;
96 static const struct ldb_map_objectclass
*map_find_objectclass_local(struct ldb_map_context
*privdat
, const char *name
)
99 for (i
= 0; privdat
->objectclass_maps
[i
].local_name
; i
++) {
100 if (!ldb_attr_cmp(privdat
->objectclass_maps
[i
].local_name
, name
))
101 return &privdat
->objectclass_maps
[i
];
107 /* Decide whether a add/modify should be pushed to the
108 * remote LDAP server. We currently only do this if we see an objectClass we know */
109 static BOOL
map_is_mappable(struct ldb_map_context
*privdat
, const struct ldb_message
*msg
)
112 struct ldb_message_element
*el
= ldb_msg_find_element(msg
, "objectClass");
114 /* No objectClass... */
119 for (i
= 0; i
< el
->num_values
; i
++) {
120 if (map_find_objectclass_local(privdat
, (char *)el
->values
[i
].data
))
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
)
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
];
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
)
145 for (i
= 0; privdat
->attribute_maps
[i
].local_name
; i
++) {
146 if (privdat
->attribute_maps
[i
].type
== MAP_IGNORE
)
149 if (privdat
->attribute_maps
[i
].type
== MAP_GENERATE
)
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
];
166 static struct ldb_parse_tree
*ldb_map_parse_tree(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_parse_tree
*tree
)
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
);
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
]);
193 new_tree
->u
.list
.elements
[i
] = child
;
194 new_tree
->u
.list
.num_elements
++;
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
);
208 talloc_free(new_tree
);
212 new_tree
->u
.isnot
.child
= child
;
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
);
225 ldb_debug(module
->ldb
, LDB_DEBUG_WARNING
, "Unable to find local attribute '%s', leaving as is\n", tree
->u
.equality
.attr
);
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
);
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
);
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
)
266 if (new_tree
->operation
== LDB_OP_SUBSTRING
) {
267 new_tree
->u
.substring
.chunks
= NULL
; /* FIXME! */
271 if (map_type
== MAP_CONVERT
) {
272 newvalue
= attr
->u
.convert
.convert_local(privdat
, new_tree
, &value
);
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
);
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
;
299 newdn
= talloc_memdup(ctx
, dn
, sizeof(*dn
));
303 newdn
->components
= talloc_array(newdn
, struct ldb_dn_component
, newdn
->comp_num
);
305 if (!newdn
->components
)
308 /* For each rdn, map the attribute name and possibly the
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
;
322 DEBUG(0, ("Local MAP_IGNORE or MAP_GENERATE attribute '%s' used in DN!", dn
->components
[i
].name
));
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
);
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
);
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
);
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
;
354 newdn
= talloc_memdup(ctx
, dn
, sizeof(*dn
));
358 newdn
->components
= talloc_array(newdn
, struct ldb_dn_component
, newdn
->comp_num
);
360 if (!newdn
->components
)
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
;
377 DEBUG(0, ("Local MAP_IGNORE/MAP_GENERATE attribute '%s' used in DN!", dn
->components
[i
].name
));
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
);
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
);
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
);
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
[])
406 int ar_size
= 0, last_element
= 0;
407 struct ldb_map_context
*privdat
= map_get_privdat(module
);
412 /* Start with good guess of number of elements */
413 for (i
= 0; attrs
[i
]; i
++);
415 ret
= talloc_array(module
, const char *, i
);
418 for (i
= 0; attrs
[i
]; i
++) {
420 const struct ldb_map_attribute
*attr
= map_find_attr_local(privdat
, attrs
[i
]);
421 enum ldb_map_attr_type map_type
;
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
;
430 case MAP_IGNORE
: break;
432 if (last_element
>= ar_size
) {
433 ret
= talloc_realloc(module
, ret
, const char *, ar_size
+1);
436 ret
[last_element
] = attr
->local_name
;
442 if (last_element
>= ar_size
) {
443 ret
= talloc_realloc(module
, ret
, const char *, ar_size
+1);
446 ret
[last_element
] = attr
->u
.rename
.remote_name
;
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);
458 ret
[last_element
] = attr
->u
.generate
.remote_names
[j
];
465 if (last_element
>= ar_size
) {
466 ret
= talloc_realloc(module
, ret
, const char *, ar_size
+1);
470 ret
[last_element
] = NULL
;
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
);
480 const char **ret
= talloc_array(module
, const char *, 1);
484 for (i
= 0; privdat
->attribute_maps
[i
].local_name
; i
++) {
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;
494 avail
= (ldb_msg_find_ldb_val(msg
, attr
->local_name
) != NULL
);
499 avail
= (ldb_msg_find_ldb_val(msg
, attr
->u
.rename
.remote_name
) != NULL
);
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
);
513 ret
= talloc_realloc(module
, ret
, const char *, count
+2);
514 ret
[count
] = attr
->local_name
;
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
)
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
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
;
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
;
555 case MAP_IGNORE
:break;
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
);
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
);
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
);
597 elm
= attr
->u
.generate
.generate_local(privdat
, msg
, attr
->local_name
, mi
);
600 ldb_msg_add(module
->ldb
, msg
, elm
, elm
->flags
);
603 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "Unknown attr->type for %s", attr
->local_name
);
608 talloc_free(newattrs
);
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
;
621 *fb
= talloc_zero(module
, struct ldb_message
);
622 (*fb
)->dn
= talloc_reference(*fb
, mo
->dn
);
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
;
636 ldb_debug(module
->ldb
, LDB_DEBUG_WARNING
, "Undefined local attribute '%s', ignoring\n", mo
->elements
[i
].name
);
637 map_type
= MAP_IGNORE
;
639 } else map_type
= attr
->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
);
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
);
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
);
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
);
686 attr
->u
.generate
.generate_remote(privdat
, attr
->local_name
, mo
, msg
);
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
;
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
);
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
;
726 ret
= ldb_next_delete_record(module
, dn
);
728 newdn
= map_local_dn(privdat
, module
, dn
);
730 ret
= ldb_delete(privdat
->mapped_ldb
, newdn
);
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
)
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
;
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
);
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
;
773 struct ldb_map_context
*privdat
= map_get_privdat(module
);
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
);
789 struct map_private
*map_private
= module
->private_data
;
790 map_private
->last_err_string
= ldb_errstring(privdat
->mapped_ldb
);
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
);
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
;
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");
817 } else if (extraret
== 0) {
818 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "No extra data found for remote DN");
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");
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
;
837 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "Discarded merged message because it did not match");
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
;
858 ret_fb
= map_search_bytree_fb(module
, base
, scope
, tree
, attrs
, &fbres
);
862 ret_mp
= map_search_bytree_mp(module
, base
, scope
, tree
, attrs
, &mpres
);
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
;
886 tree
= ldb_parse_tree(NULL
, expression
);
888 map
->last_err_string
= "expression parse failed";
892 ret
= map_search_bytree(module
, base
, scope
, tree
, attrs
, res
);
900 static int map_add(struct ldb_module
*module
, const struct ldb_message
*msg
)
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)
913 ldb_msg_add_string(module
->ldb
, fb
, "isMapped", "TRUE");
915 ret
= ldb_next_add_record(module
, fb
);
917 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "Adding fallback record failed");
921 ret
= ldb_add(privdat
->mapped_ldb
, mp
);
923 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "Adding mapped record failed");
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
;
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)
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
);
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
= {
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
;
1006 mods
= ldb_dn_string_compose(ldb
, NULL
, "@MAP=%s", name
);
1008 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "Can't construct DN");
1012 ret
= ldb_search(ldb
, mods
, LDB_SCOPE_BASE
, "", attrs
, &msg
);
1015 ldb_debug(ldb
, LDB_DEBUG_ERROR
, "Not enough results found looking for @MAP");
1019 url
= talloc_strdup(ldb
, ldb_msg_find_string(msg
[0], "@MAP_URL", NULL
));
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
)
1030 struct ldb_module
*ctx
;
1031 struct map_private
*data
;
1034 ctx
= talloc(ldb
, struct ldb_module
);
1038 data
= talloc(ctx
, struct map_private
);
1044 data
->context
.mapped_ldb
= ldb_init(data
);
1045 url
= map_find_url(ldb
, name
);
1048 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "@MAP=%s not set!\n", name
);
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
);
1059 data
->last_err_string
= NULL
;
1061 /* Get list of attribute maps */
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
];
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
];
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
;
1083 ctx
->prev
= ctx
->next
= NULL
;
1084 ctx
->ops
= &map_ops
;
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
);
1100 newval
= talloc(ctx
, struct ldb_val
);
1101 newval
->data
= (uint8_t *)ldb_dn_linearize(ctx
, newdn
);
1102 newval
->length
= strlen((char *)newval
->data
);
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
);
1120 newval
= talloc(ctx
, struct ldb_val
);
1121 newval
->data
= (uint8_t *)ldb_dn_linearize(ctx
, newdn
);
1122 newval
->length
= strlen((char *)newval
->data
);
1129 static struct ldb_val
map_convert_local_objectclass(struct ldb_map_context
*map
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
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
)
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
);