2 ldb database mapping module
4 Copyright (C) Jelmer Vernooij 2005
5 Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
7 * NOTICE: this module is NOT released under the GNU LGPL license as
8 * other ldb code. This module is release under the GNU GPL v2 or
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * Component: ldb ldb_map module
30 * Description: Map portions of data into a different format on a
33 * Author: Jelmer Vernooij, Martin Kuehl
37 #include "ldb/include/includes.h"
39 #include "ldb/modules/ldb_map.h"
40 #include "ldb/modules/ldb_map_private.h"
42 /* Description of the provided ldb requests:
43 - special attribute 'isMapped'
46 - if parse tree can be split
47 - search remote records w/ remote attrs and parse tree
49 - enumerate all remote records
50 - for each remote result
51 - map remote result to local message
54 - merge local into remote result
55 - run callback on merged result
57 - run callback on remote result
60 - split message into local and remote part
61 - if local message is not empty
62 - add isMapped to local message
67 - split message into local and remote part
68 - if local message is not empty
69 - add isMapped to local message
70 - search for local record
75 - modify remote record
78 - search for local record
81 - delete remote record
84 - search for local record
87 - modify local isMapped
88 - rename remote record
93 /* Private data structures
94 * ======================= */
96 /* Global private data */
97 /* Extract mappings from private data. */
98 const struct ldb_map_context
*map_get_context(struct ldb_module
*module
)
100 const struct map_private
*data
= talloc_get_type(module
->private_data
, struct map_private
);
101 return data
->context
;
104 /* Create a generic request context. */
105 static struct map_context
*map_init_context(struct ldb_handle
*h
, struct ldb_request
*req
)
107 struct map_context
*ac
;
109 ac
= talloc_zero(h
, struct map_context
);
115 ac
->module
= h
->module
;
121 /* Create a search request context. */
122 struct map_search_context
*map_init_search_context(struct map_context
*ac
, struct ldb_reply
*ares
)
124 struct map_search_context
*sc
;
126 sc
= talloc_zero(ac
, struct map_search_context
);
133 sc
->local_res
= NULL
;
134 sc
->remote_res
= ares
;
139 /* Create a request context and handle. */
140 struct ldb_handle
*map_init_handle(struct ldb_request
*req
, struct ldb_module
*module
)
142 struct map_context
*ac
;
143 struct ldb_handle
*h
;
145 h
= talloc_zero(req
, struct ldb_handle
);
153 ac
= map_init_context(h
, req
);
159 h
->private_data
= (void *)ac
;
161 h
->state
= LDB_ASYNC_INIT
;
162 h
->status
= LDB_SUCCESS
;
168 /* Dealing with DNs for different partitions
169 * ========================================= */
171 /* Check whether any data should be stored in the local partition. */
172 BOOL
map_check_local_db(struct ldb_module
*module
)
174 const struct ldb_map_context
*data
= map_get_context(module
);
176 if (!data
->remote_base_dn
|| !data
->local_base_dn
) {
183 /* Copy a DN with the base DN of the local partition. */
184 static struct ldb_dn
*ldb_dn_rebase_local(void *mem_ctx
, const struct ldb_map_context
*data
, const struct ldb_dn
*dn
)
186 return ldb_dn_copy_rebase(mem_ctx
, dn
, data
->remote_base_dn
, data
->local_base_dn
);
189 /* Copy a DN with the base DN of the remote partition. */
190 static struct ldb_dn
*ldb_dn_rebase_remote(void *mem_ctx
, const struct ldb_map_context
*data
, const struct ldb_dn
*dn
)
192 return ldb_dn_copy_rebase(mem_ctx
, dn
, data
->local_base_dn
, data
->remote_base_dn
);
195 /* Run a request and make sure it targets the remote partition. */
196 /* TODO: free old DNs and messages? */
197 int ldb_next_remote_request(struct ldb_module
*module
, struct ldb_request
*request
)
199 const struct ldb_map_context
*data
= map_get_context(module
);
200 struct ldb_message
*msg
;
202 switch (request
->operation
) {
204 if (request
->op
.search
.base
) {
205 request
->op
.search
.base
= ldb_dn_rebase_remote(request
, data
, request
->op
.search
.base
);
207 request
->op
.search
.base
= data
->remote_base_dn
;
208 /* TODO: adjust scope? */
213 msg
= ldb_msg_copy_shallow(request
, request
->op
.add
.message
);
214 msg
->dn
= ldb_dn_rebase_remote(msg
, data
, msg
->dn
);
215 request
->op
.add
.message
= msg
;
219 msg
= ldb_msg_copy_shallow(request
, request
->op
.mod
.message
);
220 msg
->dn
= ldb_dn_rebase_remote(msg
, data
, msg
->dn
);
221 request
->op
.mod
.message
= msg
;
225 request
->op
.del
.dn
= ldb_dn_rebase_remote(request
, data
, request
->op
.del
.dn
);
229 request
->op
.rename
.olddn
= ldb_dn_rebase_remote(request
, data
, request
->op
.rename
.olddn
);
230 request
->op
.rename
.newdn
= ldb_dn_rebase_remote(request
, data
, request
->op
.rename
.newdn
);
234 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
235 "Invalid remote request!\n");
236 return LDB_ERR_OPERATIONS_ERROR
;
239 return ldb_next_request(module
, request
);
243 /* Finding mappings for attributes and objectClasses
244 * ================================================= */
246 /* Find an objectClass mapping by the local name. */
247 static const struct ldb_map_objectclass
*map_objectclass_find_local(const struct ldb_map_context
*data
, const char *name
)
251 for (i
= 0; data
->objectclass_maps
&& data
->objectclass_maps
[i
].local_name
; i
++) {
252 if (ldb_attr_cmp(data
->objectclass_maps
[i
].local_name
, name
) == 0) {
253 return &data
->objectclass_maps
[i
];
260 /* Find an objectClass mapping by the remote name. */
261 static const struct ldb_map_objectclass
*map_objectclass_find_remote(const struct ldb_map_context
*data
, const char *name
)
265 for (i
= 0; data
->objectclass_maps
&& data
->objectclass_maps
[i
].remote_name
; i
++) {
266 if (ldb_attr_cmp(data
->objectclass_maps
[i
].remote_name
, name
) == 0) {
267 return &data
->objectclass_maps
[i
];
274 /* Find an attribute mapping by the local name. */
275 const struct ldb_map_attribute
*map_attr_find_local(const struct ldb_map_context
*data
, const char *name
)
279 for (i
= 0; data
->attribute_maps
[i
].local_name
; i
++) {
280 if (ldb_attr_cmp(data
->attribute_maps
[i
].local_name
, name
) == 0) {
281 return &data
->attribute_maps
[i
];
284 for (i
= 0; data
->attribute_maps
[i
].local_name
; i
++) {
285 if (ldb_attr_cmp(data
->attribute_maps
[i
].local_name
, "*") == 0) {
286 return &data
->attribute_maps
[i
];
293 /* Find an attribute mapping by the remote name. */
294 const struct ldb_map_attribute
*map_attr_find_remote(const struct ldb_map_context
*data
, const char *name
)
296 const struct ldb_map_attribute
*map
;
297 const struct ldb_map_attribute
*wildcard
= NULL
;
300 for (i
= 0; data
->attribute_maps
[i
].local_name
; i
++) {
301 map
= &data
->attribute_maps
[i
];
302 if (ldb_attr_cmp(map
->local_name
, "*") == 0) {
303 wildcard
= &data
->attribute_maps
[i
];
311 if (ldb_attr_cmp(map
->local_name
, name
) == 0) {
318 if (ldb_attr_cmp(map
->u
.rename
.remote_name
, name
) == 0) {
324 for (j
= 0; map
->u
.generate
.remote_names
&& map
->u
.generate
.remote_names
[j
]; j
++) {
325 if (ldb_attr_cmp(map
->u
.generate
.remote_names
[j
], name
) == 0) {
333 /* We didn't find it, so return the wildcard record if one was configured */
338 /* Mapping attributes
339 * ================== */
341 /* Check whether an attribute will be mapped into the remote partition. */
342 BOOL
map_attr_check_remote(const struct ldb_map_context
*data
, const char *attr
)
344 const struct ldb_map_attribute
*map
= map_attr_find_local(data
, attr
);
349 if (map
->type
== MAP_IGNORE
) {
356 /* Map an attribute name into the remote partition. */
357 const char *map_attr_map_local(void *mem_ctx
, const struct ldb_map_attribute
*map
, const char *attr
)
360 return talloc_strdup(mem_ctx
, attr
);
365 return talloc_strdup(mem_ctx
, attr
);
369 return talloc_strdup(mem_ctx
, map
->u
.rename
.remote_name
);
376 /* Map an attribute name back into the local partition. */
377 const char *map_attr_map_remote(void *mem_ctx
, const struct ldb_map_attribute
*map
, const char *attr
)
380 return talloc_strdup(mem_ctx
, attr
);
383 if (map
->type
== MAP_KEEP
) {
384 return talloc_strdup(mem_ctx
, attr
);
387 return talloc_strdup(mem_ctx
, map
->local_name
);
391 /* Merge two lists of attributes into a single one. */
392 int map_attrs_merge(struct ldb_module
*module
, void *mem_ctx
,
393 const char ***attrs
, const char * const *more_attrs
)
397 for (i
= 0; *attrs
&& (*attrs
)[i
]; i
++) /* noop */ ;
398 for (j
= 0; more_attrs
&& more_attrs
[j
]; j
++) /* noop */ ;
400 *attrs
= talloc_realloc(mem_ctx
, *attrs
, const char *, i
+j
+1);
401 if (*attrs
== NULL
) {
406 for (k
= 0; k
< j
; k
++) {
407 (*attrs
)[i
+ k
] = more_attrs
[k
];
410 (*attrs
)[i
+k
] = NULL
;
415 /* Mapping ldb values
416 * ================== */
418 /* Map an ldb value into the remote partition. */
419 struct ldb_val
ldb_val_map_local(struct ldb_module
*module
, void *mem_ctx
,
420 const struct ldb_map_attribute
*map
, const struct ldb_val
*val
)
422 if (map
&& (map
->type
== MAP_CONVERT
) && (map
->u
.convert
.convert_local
)) {
423 return map
->u
.convert
.convert_local(module
, mem_ctx
, val
);
426 return ldb_val_dup(mem_ctx
, val
);
429 /* Map an ldb value back into the local partition. */
430 struct ldb_val
ldb_val_map_remote(struct ldb_module
*module
, void *mem_ctx
,
431 const struct ldb_map_attribute
*map
, const struct ldb_val
*val
)
433 if (map
&& (map
->type
== MAP_CONVERT
) && (map
->u
.convert
.convert_remote
)) {
434 return map
->u
.convert
.convert_remote(module
, mem_ctx
, val
);
437 return ldb_val_dup(mem_ctx
, val
);
444 /* Check whether a DN is below the local baseDN. */
445 BOOL
ldb_dn_check_local(struct ldb_module
*module
, const struct ldb_dn
*dn
)
447 const struct ldb_map_context
*data
= map_get_context(module
);
449 if (!data
->local_base_dn
) {
453 return ldb_dn_compare_base(module
->ldb
, data
->local_base_dn
, dn
) == 0;
456 /* Map a DN into the remote partition. */
457 struct ldb_dn
*ldb_dn_map_local(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_dn
*dn
)
459 const struct ldb_map_context
*data
= map_get_context(module
);
460 struct ldb_dn
*newdn
;
461 const struct ldb_map_attribute
*map
;
462 enum ldb_map_attr_type map_type
;
464 struct ldb_val value
;
471 newdn
= ldb_dn_copy(mem_ctx
, dn
);
477 /* For each RDN, map the component name and possibly the value */
478 for (i
= 0; i
< ldb_dn_get_comp_num(newdn
); i
++) {
479 map
= map_attr_find_local(data
, ldb_dn_get_component_name(dn
, i
));
481 /* Unknown attribute - leave this RDN as is and hope the best... */
485 map_type
= map
->type
;
491 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
492 "MAP_IGNORE/MAP_GENERATE attribute '%s' "
493 "used in DN!\n", ldb_dn_get_component_name(dn
, i
));
497 if (map
->u
.convert
.convert_local
== NULL
) {
498 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
499 "'convert_local' not set for attribute '%s' "
500 "used in DN!\n", ldb_dn_get_component_name(dn
, i
));
506 name
= map_attr_map_local(newdn
, map
, ldb_dn_get_component_name(dn
, i
));
507 if (name
== NULL
) goto failed
;
509 value
= ldb_val_map_local(module
, newdn
, map
, ldb_dn_get_component_val(dn
, i
));
510 if (value
.data
== NULL
) goto failed
;
512 ret
= ldb_dn_set_component(newdn
, i
, name
, value
);
513 if (ret
!= LDB_SUCCESS
) {
528 /* Map a DN into the local partition. */
529 struct ldb_dn
*ldb_dn_map_remote(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_dn
*dn
)
531 const struct ldb_map_context
*data
= map_get_context(module
);
532 struct ldb_dn
*newdn
;
533 const struct ldb_map_attribute
*map
;
534 enum ldb_map_attr_type map_type
;
536 struct ldb_val value
;
543 newdn
= ldb_dn_copy(mem_ctx
, dn
);
549 /* For each RDN, map the component name and possibly the value */
550 for (i
= 0; i
< ldb_dn_get_comp_num(newdn
); i
++) {
551 map
= map_attr_find_remote(data
, ldb_dn_get_component_name(dn
, i
));
553 /* Unknown attribute - leave this RDN as is and hope the best... */
557 map_type
= map
->type
;
563 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
564 "MAP_IGNORE/MAP_GENERATE attribute '%s' "
565 "used in DN!\n", ldb_dn_get_component_name(dn
, i
));
569 if (map
->u
.convert
.convert_remote
== NULL
) {
570 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
571 "'convert_remote' not set for attribute '%s' "
572 "used in DN!\n", ldb_dn_get_component_name(dn
, i
));
578 name
= map_attr_map_remote(newdn
, map
, ldb_dn_get_component_name(dn
, i
));
579 if (name
== NULL
) goto failed
;
581 value
= ldb_val_map_remote(module
, newdn
, map
, ldb_dn_get_component_val(dn
, i
));
582 if (value
.data
== NULL
) goto failed
;
584 ret
= ldb_dn_set_component(newdn
, i
, name
, value
);
585 if (ret
!= LDB_SUCCESS
) {
600 /* Map a DN and its base into the local partition. */
601 /* TODO: This should not be required with GUIDs. */
602 struct ldb_dn
*ldb_dn_map_rebase_remote(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_dn
*dn
)
604 const struct ldb_map_context
*data
= map_get_context(module
);
605 struct ldb_dn
*dn1
, *dn2
;
607 dn1
= ldb_dn_rebase_local(mem_ctx
, data
, dn
);
608 dn2
= ldb_dn_map_remote(module
, mem_ctx
, dn1
);
615 /* Converting DNs and objectClasses (as ldb values)
616 * ================================================ */
618 /* Map a DN contained in an ldb value into the remote partition. */
619 static struct ldb_val
ldb_dn_convert_local(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_val
*val
)
621 struct ldb_dn
*dn
, *newdn
;
622 struct ldb_val newval
;
624 dn
= ldb_dn_explode(mem_ctx
, (char *)val
->data
);
625 newdn
= ldb_dn_map_local(module
, mem_ctx
, dn
);
629 newval
.data
= (uint8_t *)ldb_dn_linearize(mem_ctx
, newdn
);
631 newval
.length
= strlen((char *)newval
.data
);
638 /* Map a DN contained in an ldb value into the local partition. */
639 static struct ldb_val
ldb_dn_convert_remote(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_val
*val
)
641 struct ldb_dn
*dn
, *newdn
;
642 struct ldb_val newval
;
644 dn
= ldb_dn_explode(mem_ctx
, (char *)val
->data
);
645 newdn
= ldb_dn_map_remote(module
, mem_ctx
, dn
);
649 newval
.data
= (uint8_t *)ldb_dn_linearize(mem_ctx
, newdn
);
651 newval
.length
= strlen((char *)newval
.data
);
658 /* Map an objectClass into the remote partition. */
659 static struct ldb_val
map_objectclass_convert_local(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_val
*val
)
661 const struct ldb_map_context
*data
= map_get_context(module
);
662 const char *name
= (char *)val
->data
;
663 const struct ldb_map_objectclass
*map
= map_objectclass_find_local(data
, name
);
664 struct ldb_val newval
;
667 newval
.data
= (uint8_t*)talloc_strdup(mem_ctx
, map
->remote_name
);
668 newval
.length
= strlen((char *)newval
.data
);
672 return ldb_val_dup(mem_ctx
, val
);
675 /* Generate a remote message with a mapped objectClass. */
676 static void map_objectclass_generate_remote(struct ldb_module
*module
, const char *local_attr
, const struct ldb_message
*old
, struct ldb_message
*remote
, struct ldb_message
*local
)
678 struct ldb_message_element
*el
, *oc
;
680 BOOL found_extensibleObject
= False
;
683 /* Find old local objectClass */
684 oc
= ldb_msg_find_element(old
, "objectClass");
689 /* Prepare new element */
690 el
= talloc_zero(remote
, struct ldb_message_element
);
692 ldb_oom(module
->ldb
);
693 return; /* TODO: fail? */
696 /* Copy local objectClass element, reverse space for an extra value */
697 el
->num_values
= oc
->num_values
+ 1;
698 el
->values
= talloc_array(el
, struct ldb_val
, el
->num_values
);
699 if (el
->values
== NULL
) {
701 ldb_oom(module
->ldb
);
702 return; /* TODO: fail? */
705 /* Copy local element name "objectClass" */
706 el
->name
= talloc_strdup(el
, local_attr
);
708 /* Convert all local objectClasses */
709 for (i
= 0; i
< el
->num_values
- 1; i
++) {
710 el
->values
[i
] = map_objectclass_convert_local(module
, el
->values
, &oc
->values
[i
]);
711 if (ldb_attr_cmp((char *)el
->values
[i
].data
, "extensibleObject") == 0) {
712 found_extensibleObject
= True
;
716 if (!found_extensibleObject
) {
717 val
.data
= (uint8_t *)talloc_strdup(el
->values
, "extensibleObject");
718 val
.length
= strlen((char *)val
.data
);
720 /* Append additional objectClass "extensibleObject" */
726 /* Add new objectClass to remote message */
727 ldb_msg_add(remote
, el
, 0);
730 /* Map an objectClass into the local partition. */
731 static struct ldb_val
map_objectclass_convert_remote(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_val
*val
)
733 const struct ldb_map_context
*data
= map_get_context(module
);
734 const char *name
= (char *)val
->data
;
735 const struct ldb_map_objectclass
*map
= map_objectclass_find_remote(data
, name
);
736 struct ldb_val newval
;
739 newval
.data
= (uint8_t*)talloc_strdup(mem_ctx
, map
->local_name
);
740 newval
.length
= strlen((char *)newval
.data
);
744 return ldb_val_dup(mem_ctx
, val
);
747 /* Generate a local message with a mapped objectClass. */
748 static struct ldb_message_element
*map_objectclass_generate_local(struct ldb_module
*module
, void *mem_ctx
, const char *local_attr
, const struct ldb_message
*remote
)
750 struct ldb_message_element
*el
, *oc
;
754 /* Find old remote objectClass */
755 oc
= ldb_msg_find_element(remote
, "objectClass");
760 /* Prepare new element */
761 el
= talloc_zero(mem_ctx
, struct ldb_message_element
);
763 ldb_oom(module
->ldb
);
767 /* Copy remote objectClass element */
768 el
->num_values
= oc
->num_values
;
769 el
->values
= talloc_array(el
, struct ldb_val
, el
->num_values
);
770 if (el
->values
== NULL
) {
772 ldb_oom(module
->ldb
);
776 /* Copy remote element name "objectClass" */
777 el
->name
= talloc_strdup(el
, local_attr
);
779 /* Convert all remote objectClasses */
780 for (i
= 0; i
< el
->num_values
; i
++) {
781 el
->values
[i
] = map_objectclass_convert_remote(module
, el
->values
, &oc
->values
[i
]);
784 val
.data
= (uint8_t *)talloc_strdup(el
->values
, "extensibleObject");
785 val
.length
= strlen((char *)val
.data
);
787 /* Remove last value if it was "extensibleObject" */
788 if (ldb_val_equal_exact(&val
, &el
->values
[i
-1])) {
790 el
->values
= talloc_realloc(el
, el
->values
, struct ldb_val
, el
->num_values
);
791 if (el
->values
== NULL
) {
793 ldb_oom(module
->ldb
);
801 /* Mappings for searches on objectClass= assuming a one-to-one
802 * mapping. Needed because this is a generate operator for the
804 static int map_objectclass_convert_operator(struct ldb_module
*module
, void *mem_ctx
,
805 struct ldb_parse_tree
**new, const struct ldb_parse_tree
*tree
)
808 static const struct ldb_map_attribute objectclass_map
= {
809 .local_name
= "objectClass",
813 .remote_name
= "objectClass",
814 .convert_local
= map_objectclass_convert_local
,
815 .convert_remote
= map_objectclass_convert_remote
,
820 return map_subtree_collect_remote_simple(module
, mem_ctx
, new, tree
, &objectclass_map
);
823 /* Auxiliary request construction
824 * ============================== */
826 /* Store the DN of a single search result in context. */
827 static int map_search_self_callback(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
829 struct map_context
*ac
;
831 if (context
== NULL
|| ares
== NULL
) {
832 ldb_set_errstring(ldb
, talloc_asprintf(ldb
, "NULL Context or Result in callback"));
833 return LDB_ERR_OPERATIONS_ERROR
;
836 ac
= talloc_get_type(context
, struct map_context
);
838 /* We are interested only in the single reply */
839 if (ares
->type
!= LDB_REPLY_ENTRY
) {
844 /* We have already found a remote DN */
846 ldb_set_errstring(ldb
, talloc_asprintf(ldb
, "Too many results to base search"));
848 return LDB_ERR_OPERATIONS_ERROR
;
852 ac
->local_dn
= ares
->message
->dn
;
857 /* Build a request to search a record by its DN. */
858 struct ldb_request
*map_search_base_req(struct map_context
*ac
, const struct ldb_dn
*dn
, const char * const *attrs
, const struct ldb_parse_tree
*tree
, void *context
, ldb_search_callback callback
)
860 struct ldb_request
*req
;
862 req
= talloc_zero(ac
, struct ldb_request
);
868 req
->operation
= LDB_SEARCH
;
869 req
->op
.search
.base
= dn
;
870 req
->op
.search
.scope
= LDB_SCOPE_BASE
;
871 req
->op
.search
.attrs
= attrs
;
874 req
->op
.search
.tree
= tree
;
876 req
->op
.search
.tree
= ldb_parse_tree(req
, NULL
);
877 if (req
->op
.search
.tree
== NULL
) {
883 req
->controls
= NULL
;
884 req
->context
= context
;
885 req
->callback
= callback
;
886 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, req
);
891 /* Build a request to search the local record by its DN. */
892 struct ldb_request
*map_search_self_req(struct map_context
*ac
, const struct ldb_dn
*dn
)
894 /* attrs[] is returned from this function in
895 * ac->search_req->op.search.attrs, so it must be static, as
896 * otherwise the compiler can put it on the stack */
897 static const char * const attrs
[] = { IS_MAPPED
, NULL
};
898 struct ldb_parse_tree
*tree
;
900 /* Limit search to records with 'IS_MAPPED' present */
901 /* TODO: `tree = ldb_parse_tree(ac, IS_MAPPED);' won't do. */
902 tree
= talloc_zero(ac
, struct ldb_parse_tree
);
908 tree
->operation
= LDB_OP_PRESENT
;
909 tree
->u
.present
.attr
= talloc_strdup(tree
, IS_MAPPED
);
911 return map_search_base_req(ac
, dn
, attrs
, tree
, ac
, map_search_self_callback
);
914 /* Build a request to update the 'IS_MAPPED' attribute */
915 struct ldb_request
*map_build_fixup_req(struct map_context
*ac
, const struct ldb_dn
*olddn
, const struct ldb_dn
*newdn
)
917 struct ldb_request
*req
;
918 struct ldb_message
*msg
;
921 /* Prepare request */
922 req
= talloc_zero(ac
, struct ldb_request
);
928 /* Prepare message */
929 msg
= ldb_msg_new(req
);
935 /* Update local 'IS_MAPPED' to the new remote DN */
936 msg
->dn
= discard_const_p(struct ldb_dn
, olddn
);
937 dn
= ldb_dn_linearize(msg
, newdn
);
941 if (ldb_msg_add_empty(msg
, IS_MAPPED
, LDB_FLAG_MOD_REPLACE
, NULL
) != 0) {
944 if (ldb_msg_add_string(msg
, IS_MAPPED
, dn
) != 0) {
948 req
->operation
= LDB_MODIFY
;
949 req
->op
.mod
.message
= msg
;
950 req
->controls
= NULL
;
953 req
->callback
= NULL
;
963 /* Asynchronous call structure
964 * =========================== */
966 /* Figure out which request is currently pending. */
967 static struct ldb_request
*map_get_req(struct map_context
*ac
)
970 case MAP_SEARCH_SELF_MODIFY
:
971 case MAP_SEARCH_SELF_DELETE
:
972 case MAP_SEARCH_SELF_RENAME
:
973 return ac
->search_req
;
976 case MAP_MODIFY_REMOTE
:
977 case MAP_DELETE_REMOTE
:
978 case MAP_RENAME_REMOTE
:
979 return ac
->remote_req
;
981 case MAP_RENAME_FIXUP
:
985 case MAP_MODIFY_LOCAL
:
986 case MAP_DELETE_LOCAL
:
987 case MAP_RENAME_LOCAL
:
988 return ac
->local_req
;
990 case MAP_SEARCH_REMOTE
:
995 return NULL
; /* unreachable; silences a warning */
998 typedef int (*map_next_function
)(struct ldb_handle
*handle
);
1000 /* Figure out the next request to run. */
1001 static map_next_function
map_get_next(struct map_context
*ac
)
1004 case MAP_SEARCH_REMOTE
:
1008 return map_add_do_remote
;
1009 case MAP_ADD_REMOTE
:
1012 case MAP_SEARCH_SELF_MODIFY
:
1013 return map_modify_do_local
;
1014 case MAP_MODIFY_LOCAL
:
1015 return map_modify_do_remote
;
1016 case MAP_MODIFY_REMOTE
:
1019 case MAP_SEARCH_SELF_DELETE
:
1020 return map_delete_do_local
;
1021 case MAP_DELETE_LOCAL
:
1022 return map_delete_do_remote
;
1023 case MAP_DELETE_REMOTE
:
1026 case MAP_SEARCH_SELF_RENAME
:
1027 return map_rename_do_local
;
1028 case MAP_RENAME_LOCAL
:
1029 return map_rename_do_fixup
;
1030 case MAP_RENAME_FIXUP
:
1031 return map_rename_do_remote
;
1032 case MAP_RENAME_REMOTE
:
1036 return NULL
; /* unreachable; silences a warning */
1039 /* Wait for the current pending request to finish and continue with the next. */
1040 static int map_wait_next(struct ldb_handle
*handle
)
1042 struct map_context
*ac
;
1043 struct ldb_request
*req
;
1044 map_next_function next
;
1047 if (handle
== NULL
|| handle
->private_data
== NULL
) {
1048 return LDB_ERR_OPERATIONS_ERROR
;
1051 if (handle
->state
== LDB_ASYNC_DONE
) {
1052 return handle
->status
;
1055 handle
->state
= LDB_ASYNC_PENDING
;
1056 handle
->status
= LDB_SUCCESS
;
1058 ac
= talloc_get_type(handle
->private_data
, struct map_context
);
1060 if (ac
->step
== MAP_SEARCH_REMOTE
) {
1062 for (i
= 0; i
< ac
->num_searches
; i
++) {
1063 req
= ac
->search_reqs
[i
];
1064 ret
= ldb_wait(req
->handle
, LDB_WAIT_NONE
);
1066 if (ret
!= LDB_SUCCESS
) {
1067 handle
->status
= ret
;
1070 if (req
->handle
->status
!= LDB_SUCCESS
) {
1071 handle
->status
= req
->handle
->status
;
1074 if (req
->handle
->state
!= LDB_ASYNC_DONE
) {
1080 req
= map_get_req(ac
);
1082 ret
= ldb_wait(req
->handle
, LDB_WAIT_NONE
);
1084 if (ret
!= LDB_SUCCESS
) {
1085 handle
->status
= ret
;
1088 if (req
->handle
->status
!= LDB_SUCCESS
) {
1089 handle
->status
= req
->handle
->status
;
1092 if (req
->handle
->state
!= LDB_ASYNC_DONE
) {
1096 next
= map_get_next(ac
);
1098 return next(handle
);
1105 handle
->state
= LDB_ASYNC_DONE
;
1109 /* Wait for all current pending requests to finish. */
1110 static int map_wait_all(struct ldb_handle
*handle
)
1114 while (handle
->state
!= LDB_ASYNC_DONE
) {
1115 ret
= map_wait_next(handle
);
1116 if (ret
!= LDB_SUCCESS
) {
1121 return handle
->status
;
1124 /* Wait for pending requests to finish. */
1125 static int map_wait(struct ldb_handle
*handle
, enum ldb_wait_type type
)
1127 if (type
== LDB_WAIT_ALL
) {
1128 return map_wait_all(handle
);
1130 return map_wait_next(handle
);
1135 /* Module initialization
1136 * ===================== */
1138 /* Provided module operations */
1139 static const struct ldb_module_ops map_ops
= {
1142 .modify
= map_modify
,
1144 .rename
= map_rename
,
1145 .search
= map_search
,
1149 /* Builtin mappings for DNs and objectClasses */
1150 static const struct ldb_map_attribute builtin_attribute_maps
[] = {
1153 .type
= MAP_CONVERT
,
1156 .remote_name
= "dn",
1157 .convert_local
= ldb_dn_convert_local
,
1158 .convert_remote
= ldb_dn_convert_remote
,
1163 .local_name
= "objectClass",
1164 .type
= MAP_GENERATE
,
1165 .convert_operator
= map_objectclass_convert_operator
,
1168 .remote_names
= { "objectClass", NULL
},
1169 .generate_local
= map_objectclass_generate_local
,
1170 .generate_remote
= map_objectclass_generate_remote
,
1179 /* Find the special 'MAP_DN_NAME' record and store local and remote
1180 * base DNs in private data. */
1181 static int map_init_dns(struct ldb_module
*module
, struct ldb_map_context
*data
, const char *name
)
1183 static const char * const attrs
[] = { MAP_DN_FROM
, MAP_DN_TO
, NULL
};
1185 struct ldb_message
*msg
;
1186 struct ldb_result
*res
;
1190 data
->local_base_dn
= NULL
;
1191 data
->remote_base_dn
= NULL
;
1195 dn
= ldb_dn_string_compose(data
, NULL
, "%s=%s", MAP_DN_NAME
, name
);
1197 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
1198 "Failed to construct '%s' DN!\n", MAP_DN_NAME
);
1199 return LDB_ERR_OPERATIONS_ERROR
;
1202 ret
= ldb_search(module
->ldb
, module
->ldb
, &res
, dn
, LDB_SCOPE_BASE
, attrs
, NULL
);
1204 if (ret
!= LDB_SUCCESS
) {
1207 if (res
->count
== 0) {
1208 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
1209 "No results for '%s=%s'!\n", MAP_DN_NAME
, name
);
1211 return LDB_ERR_CONSTRAINT_VIOLATION
;
1213 if (res
->count
> 1) {
1214 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
1215 "Too many results for '%s=%s'!\n", MAP_DN_NAME
, name
);
1217 return LDB_ERR_CONSTRAINT_VIOLATION
;
1221 data
->local_base_dn
= ldb_msg_find_attr_as_dn(data
, msg
, MAP_DN_FROM
);
1222 data
->remote_base_dn
= ldb_msg_find_attr_as_dn(data
, msg
, MAP_DN_TO
);
1228 /* Store attribute maps and objectClass maps in private data. */
1229 static int map_init_maps(struct ldb_module
*module
, struct ldb_map_context
*data
,
1230 const struct ldb_map_attribute
*attrs
,
1231 const struct ldb_map_objectclass
*ocls
,
1232 const char * const *wildcard_attributes
)
1237 /* Count specified attribute maps */
1238 for (i
= 0; attrs
[i
].local_name
; i
++) /* noop */ ;
1239 /* Count built-in attribute maps */
1240 for (j
= 0; builtin_attribute_maps
[j
].local_name
; j
++) /* noop */ ;
1242 /* Store list of attribute maps */
1243 data
->attribute_maps
= talloc_array(data
, struct ldb_map_attribute
, i
+j
+1);
1244 if (data
->attribute_maps
== NULL
) {
1246 return LDB_ERR_OPERATIONS_ERROR
;
1249 /* Specified ones go first */
1250 for (i
= 0; attrs
[i
].local_name
; i
++) {
1251 data
->attribute_maps
[last
] = attrs
[i
];
1255 /* Built-in ones go last */
1256 for (i
= 0; builtin_attribute_maps
[i
].local_name
; i
++) {
1257 data
->attribute_maps
[last
] = builtin_attribute_maps
[i
];
1261 /* Ensure 'local_name == NULL' for the last entry */
1262 memset(&data
->attribute_maps
[last
], 0, sizeof(struct ldb_map_attribute
));
1264 /* Store list of objectClass maps */
1265 data
->objectclass_maps
= ocls
;
1267 data
->wildcard_attributes
= wildcard_attributes
;
1272 /* Copy the list of provided module operations. */
1273 _PUBLIC_
struct ldb_module_ops
ldb_map_get_ops(void)
1278 /* Initialize global private data. */
1279 _PUBLIC_
int ldb_map_init(struct ldb_module
*module
, const struct ldb_map_attribute
*attrs
,
1280 const struct ldb_map_objectclass
*ocls
,
1281 const char * const *wildcard_attributes
,
1284 struct map_private
*data
;
1287 /* Prepare private data */
1288 data
= talloc_zero(module
, struct map_private
);
1291 return LDB_ERR_OPERATIONS_ERROR
;
1294 module
->private_data
= data
;
1296 data
->context
= talloc_zero(data
, struct ldb_map_context
);
1297 if (!data
->context
) {
1299 return LDB_ERR_OPERATIONS_ERROR
;
1302 /* Store local and remote baseDNs */
1303 ret
= map_init_dns(module
, data
->context
, name
);
1304 if (ret
!= LDB_SUCCESS
) {
1309 /* Store list of attribute and objectClass maps */
1310 ret
= map_init_maps(module
, data
->context
, attrs
, ocls
, wildcard_attributes
);
1311 if (ret
!= LDB_SUCCESS
) {
1319 /* Usage note for initialization of this module:
1321 * ldb_map is meant to be used from a different module that sets up
1322 * the mappings and gets registered in ldb.
1324 * 'ldb_map_init' initializes the private data of this module and
1325 * stores the attribute and objectClass maps in there. It also looks
1326 * up the '@MAP' special DN so requests can be redirected to the
1329 * This function should be called from the 'init_context' op of the
1330 * module using ldb_map.
1332 * 'ldb_map_get_ops' returns a copy of ldb_maps module operations.
1334 * It should be called from the initialize function of the using
1335 * module, which should then override the 'init_context' op with a
1336 * function making the appropriate calls to 'ldb_map_init'.