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 2 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, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 * Component: ldb ldb_map module
31 * Description: Map portions of data into a different format on a
34 * Author: Jelmer Vernooij, Martin Kuehl
38 #include "ldb/include/includes.h"
40 #include "ldb/modules/ldb_map.h"
41 #include "ldb/modules/ldb_map_private.h"
43 /* Description of the provided ldb requests:
44 - special attribute 'isMapped'
47 - if parse tree can be split
48 - search remote records w/ remote attrs and parse tree
50 - enumerate all remote records
51 - for each remote result
52 - map remote result to local message
55 - merge local into remote result
56 - run callback on merged result
58 - run callback on remote result
61 - split message into local and remote part
62 - if local message is not empty
63 - add isMapped to local message
68 - split message into local and remote part
69 - if local message is not empty
70 - add isMapped to local message
71 - search for local record
76 - modify remote record
79 - search for local record
82 - delete remote record
85 - search for local record
88 - modify local isMapped
89 - rename remote record
94 /* Private data structures
95 * ======================= */
97 /* Global private data */
98 /* Extract mappings from private data. */
99 const struct ldb_map_context
*map_get_context(struct ldb_module
*module
)
101 const struct map_private
*data
= talloc_get_type(module
->private_data
, struct map_private
);
102 return data
->context
;
105 /* Create a generic request context. */
106 static struct map_context
*map_init_context(struct ldb_handle
*h
, struct ldb_request
*req
)
108 struct map_context
*ac
;
110 ac
= talloc_zero(h
, struct map_context
);
116 ac
->module
= h
->module
;
122 /* Create a search request context. */
123 struct map_search_context
*map_init_search_context(struct map_context
*ac
, struct ldb_reply
*ares
)
125 struct map_search_context
*sc
;
127 sc
= talloc_zero(ac
, struct map_search_context
);
134 sc
->local_res
= NULL
;
135 sc
->remote_res
= ares
;
140 /* Create a request context and handle. */
141 struct ldb_handle
*map_init_handle(struct ldb_request
*req
, struct ldb_module
*module
)
143 struct map_context
*ac
;
144 struct ldb_handle
*h
;
146 h
= talloc_zero(req
, struct ldb_handle
);
154 ac
= map_init_context(h
, req
);
160 h
->private_data
= (void *)ac
;
162 h
->state
= LDB_ASYNC_INIT
;
163 h
->status
= LDB_SUCCESS
;
169 /* Dealing with DNs for different partitions
170 * ========================================= */
172 /* Check whether any data should be stored in the local partition. */
173 BOOL
map_check_local_db(struct ldb_module
*module
)
175 const struct ldb_map_context
*data
= map_get_context(module
);
177 if (!data
->remote_base_dn
|| !data
->local_base_dn
) {
184 /* Copy a DN with the base DN of the local partition. */
185 static struct ldb_dn
*ldb_dn_rebase_local(void *mem_ctx
, const struct ldb_map_context
*data
, const struct ldb_dn
*dn
)
187 return ldb_dn_copy_rebase(mem_ctx
, dn
, data
->remote_base_dn
, data
->local_base_dn
);
190 /* Copy a DN with the base DN of the remote partition. */
191 static struct ldb_dn
*ldb_dn_rebase_remote(void *mem_ctx
, const struct ldb_map_context
*data
, const struct ldb_dn
*dn
)
193 return ldb_dn_copy_rebase(mem_ctx
, dn
, data
->local_base_dn
, data
->remote_base_dn
);
196 /* Run a request and make sure it targets the remote partition. */
197 /* TODO: free old DNs and messages? */
198 int ldb_next_remote_request(struct ldb_module
*module
, struct ldb_request
*request
)
200 const struct ldb_map_context
*data
= map_get_context(module
);
201 struct ldb_message
*msg
;
203 switch (request
->operation
) {
205 if (request
->op
.search
.base
) {
206 request
->op
.search
.base
= ldb_dn_rebase_remote(request
, data
, request
->op
.search
.base
);
208 request
->op
.search
.base
= data
->remote_base_dn
;
209 /* TODO: adjust scope? */
214 msg
= ldb_msg_copy_shallow(request
, request
->op
.add
.message
);
215 msg
->dn
= ldb_dn_rebase_remote(msg
, data
, msg
->dn
);
216 request
->op
.add
.message
= msg
;
220 msg
= ldb_msg_copy_shallow(request
, request
->op
.mod
.message
);
221 msg
->dn
= ldb_dn_rebase_remote(msg
, data
, msg
->dn
);
222 request
->op
.mod
.message
= msg
;
226 request
->op
.del
.dn
= ldb_dn_rebase_remote(request
, data
, request
->op
.del
.dn
);
230 request
->op
.rename
.olddn
= ldb_dn_rebase_remote(request
, data
, request
->op
.rename
.olddn
);
231 request
->op
.rename
.newdn
= ldb_dn_rebase_remote(request
, data
, request
->op
.rename
.newdn
);
235 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
236 "Invalid remote request!\n");
237 return LDB_ERR_OPERATIONS_ERROR
;
240 return ldb_next_request(module
, request
);
244 /* Finding mappings for attributes and objectClasses
245 * ================================================= */
247 /* Find an objectClass mapping by the local name. */
248 static const struct ldb_map_objectclass
*map_objectclass_find_local(const struct ldb_map_context
*data
, const char *name
)
252 for (i
= 0; data
->objectclass_maps
&& data
->objectclass_maps
[i
].local_name
; i
++) {
253 if (ldb_attr_cmp(data
->objectclass_maps
[i
].local_name
, name
) == 0) {
254 return &data
->objectclass_maps
[i
];
261 /* Find an objectClass mapping by the remote name. */
262 static const struct ldb_map_objectclass
*map_objectclass_find_remote(const struct ldb_map_context
*data
, const char *name
)
266 for (i
= 0; data
->objectclass_maps
&& data
->objectclass_maps
[i
].remote_name
; i
++) {
267 if (ldb_attr_cmp(data
->objectclass_maps
[i
].remote_name
, name
) == 0) {
268 return &data
->objectclass_maps
[i
];
275 /* Find an attribute mapping by the local name. */
276 const struct ldb_map_attribute
*map_attr_find_local(const struct ldb_map_context
*data
, const char *name
)
280 for (i
= 0; data
->attribute_maps
[i
].local_name
; i
++) {
281 if (ldb_attr_cmp(data
->attribute_maps
[i
].local_name
, name
) == 0) {
282 return &data
->attribute_maps
[i
];
285 for (i
= 0; data
->attribute_maps
[i
].local_name
; i
++) {
286 if (ldb_attr_cmp(data
->attribute_maps
[i
].local_name
, "*") == 0) {
287 return &data
->attribute_maps
[i
];
294 /* Find an attribute mapping by the remote name. */
295 const struct ldb_map_attribute
*map_attr_find_remote(const struct ldb_map_context
*data
, const char *name
)
297 const struct ldb_map_attribute
*map
;
298 const struct ldb_map_attribute
*wildcard
= NULL
;
301 for (i
= 0; data
->attribute_maps
[i
].local_name
; i
++) {
302 map
= &data
->attribute_maps
[i
];
303 if (ldb_attr_cmp(map
->local_name
, "*") == 0) {
304 wildcard
= &data
->attribute_maps
[i
];
312 if (ldb_attr_cmp(map
->local_name
, name
) == 0) {
319 if (ldb_attr_cmp(map
->u
.rename
.remote_name
, name
) == 0) {
325 for (j
= 0; map
->u
.generate
.remote_names
&& map
->u
.generate
.remote_names
[j
]; j
++) {
326 if (ldb_attr_cmp(map
->u
.generate
.remote_names
[j
], name
) == 0) {
334 /* We didn't find it, so return the wildcard record if one was configured */
339 /* Mapping attributes
340 * ================== */
342 /* Check whether an attribute will be mapped into the remote partition. */
343 BOOL
map_attr_check_remote(const struct ldb_map_context
*data
, const char *attr
)
345 const struct ldb_map_attribute
*map
= map_attr_find_local(data
, attr
);
350 if (map
->type
== MAP_IGNORE
) {
357 /* Map an attribute name into the remote partition. */
358 const char *map_attr_map_local(void *mem_ctx
, const struct ldb_map_attribute
*map
, const char *attr
)
361 return talloc_strdup(mem_ctx
, attr
);
366 return talloc_strdup(mem_ctx
, attr
);
370 return talloc_strdup(mem_ctx
, map
->u
.rename
.remote_name
);
377 /* Map an attribute name back into the local partition. */
378 const char *map_attr_map_remote(void *mem_ctx
, const struct ldb_map_attribute
*map
, const char *attr
)
381 return talloc_strdup(mem_ctx
, attr
);
384 if (map
->type
== MAP_KEEP
) {
385 return talloc_strdup(mem_ctx
, attr
);
388 return talloc_strdup(mem_ctx
, map
->local_name
);
392 /* Merge two lists of attributes into a single one. */
393 int map_attrs_merge(struct ldb_module
*module
, void *mem_ctx
,
394 const char ***attrs
, const char * const *more_attrs
)
398 for (i
= 0; *attrs
&& (*attrs
)[i
]; i
++) /* noop */ ;
399 for (j
= 0; more_attrs
&& more_attrs
[j
]; j
++) /* noop */ ;
401 *attrs
= talloc_realloc(mem_ctx
, *attrs
, const char *, i
+j
+1);
402 if (*attrs
== NULL
) {
407 for (k
= 0; k
< j
; k
++) {
408 (*attrs
)[i
+ k
] = more_attrs
[k
];
411 (*attrs
)[i
+k
] = NULL
;
416 /* Mapping ldb values
417 * ================== */
419 /* Map an ldb value into the remote partition. */
420 struct ldb_val
ldb_val_map_local(struct ldb_module
*module
, void *mem_ctx
,
421 const struct ldb_map_attribute
*map
, const struct ldb_val
*val
)
423 if (map
&& (map
->type
== MAP_CONVERT
) && (map
->u
.convert
.convert_local
)) {
424 return map
->u
.convert
.convert_local(module
, mem_ctx
, val
);
427 return ldb_val_dup(mem_ctx
, val
);
430 /* Map an ldb value back into the local partition. */
431 struct ldb_val
ldb_val_map_remote(struct ldb_module
*module
, void *mem_ctx
,
432 const struct ldb_map_attribute
*map
, const struct ldb_val
*val
)
434 if (map
&& (map
->type
== MAP_CONVERT
) && (map
->u
.convert
.convert_remote
)) {
435 return map
->u
.convert
.convert_remote(module
, mem_ctx
, val
);
438 return ldb_val_dup(mem_ctx
, val
);
445 /* Check whether a DN is below the local baseDN. */
446 BOOL
ldb_dn_check_local(struct ldb_module
*module
, const struct ldb_dn
*dn
)
448 const struct ldb_map_context
*data
= map_get_context(module
);
450 if (!data
->local_base_dn
) {
454 return ldb_dn_compare_base(module
->ldb
, data
->local_base_dn
, dn
) == 0;
457 /* Map a DN into the remote partition. */
458 struct ldb_dn
*ldb_dn_map_local(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_dn
*dn
)
460 const struct ldb_map_context
*data
= map_get_context(module
);
461 struct ldb_dn
*newdn
;
462 const struct ldb_map_attribute
*map
;
463 enum ldb_map_attr_type map_type
;
465 struct ldb_val value
;
472 newdn
= ldb_dn_copy(mem_ctx
, dn
);
478 /* For each RDN, map the component name and possibly the value */
479 for (i
= 0; i
< ldb_dn_get_comp_num(newdn
); i
++) {
480 map
= map_attr_find_local(data
, ldb_dn_get_component_name(dn
, i
));
482 /* Unknown attribute - leave this RDN as is and hope the best... */
486 map_type
= map
->type
;
492 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
493 "MAP_IGNORE/MAP_GENERATE attribute '%s' "
494 "used in DN!\n", ldb_dn_get_component_name(dn
, i
));
498 if (map
->u
.convert
.convert_local
== NULL
) {
499 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
500 "'convert_local' not set for attribute '%s' "
501 "used in DN!\n", ldb_dn_get_component_name(dn
, i
));
507 name
= map_attr_map_local(newdn
, map
, ldb_dn_get_component_name(dn
, i
));
508 if (name
== NULL
) goto failed
;
510 value
= ldb_val_map_local(module
, newdn
, map
, ldb_dn_get_component_val(dn
, i
));
511 if (value
.data
== NULL
) goto failed
;
513 ret
= ldb_dn_set_component(newdn
, i
, name
, value
);
514 if (ret
!= LDB_SUCCESS
) {
529 /* Map a DN into the local partition. */
530 struct ldb_dn
*ldb_dn_map_remote(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_dn
*dn
)
532 const struct ldb_map_context
*data
= map_get_context(module
);
533 struct ldb_dn
*newdn
;
534 const struct ldb_map_attribute
*map
;
535 enum ldb_map_attr_type map_type
;
537 struct ldb_val value
;
544 newdn
= ldb_dn_copy(mem_ctx
, dn
);
550 /* For each RDN, map the component name and possibly the value */
551 for (i
= 0; i
< ldb_dn_get_comp_num(newdn
); i
++) {
552 map
= map_attr_find_remote(data
, ldb_dn_get_component_name(dn
, i
));
554 /* Unknown attribute - leave this RDN as is and hope the best... */
558 map_type
= map
->type
;
564 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
565 "MAP_IGNORE/MAP_GENERATE attribute '%s' "
566 "used in DN!\n", ldb_dn_get_component_name(dn
, i
));
570 if (map
->u
.convert
.convert_remote
== NULL
) {
571 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
572 "'convert_remote' not set for attribute '%s' "
573 "used in DN!\n", ldb_dn_get_component_name(dn
, i
));
579 name
= map_attr_map_remote(newdn
, map
, ldb_dn_get_component_name(dn
, i
));
580 if (name
== NULL
) goto failed
;
582 value
= ldb_val_map_remote(module
, newdn
, map
, ldb_dn_get_component_val(dn
, i
));
583 if (value
.data
== NULL
) goto failed
;
585 ret
= ldb_dn_set_component(newdn
, i
, name
, value
);
586 if (ret
!= LDB_SUCCESS
) {
601 /* Map a DN and its base into the local partition. */
602 /* TODO: This should not be required with GUIDs. */
603 struct ldb_dn
*ldb_dn_map_rebase_remote(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_dn
*dn
)
605 const struct ldb_map_context
*data
= map_get_context(module
);
606 struct ldb_dn
*dn1
, *dn2
;
608 dn1
= ldb_dn_rebase_local(mem_ctx
, data
, dn
);
609 dn2
= ldb_dn_map_remote(module
, mem_ctx
, dn1
);
616 /* Converting DNs and objectClasses (as ldb values)
617 * ================================================ */
619 /* Map a DN contained in an ldb value into the remote partition. */
620 static struct ldb_val
ldb_dn_convert_local(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_val
*val
)
622 struct ldb_dn
*dn
, *newdn
;
623 struct ldb_val newval
;
625 dn
= ldb_dn_explode(mem_ctx
, (char *)val
->data
);
626 newdn
= ldb_dn_map_local(module
, mem_ctx
, dn
);
630 newval
.data
= (uint8_t *)ldb_dn_linearize(mem_ctx
, newdn
);
632 newval
.length
= strlen((char *)newval
.data
);
639 /* Map a DN contained in an ldb value into the local partition. */
640 static struct ldb_val
ldb_dn_convert_remote(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_val
*val
)
642 struct ldb_dn
*dn
, *newdn
;
643 struct ldb_val newval
;
645 dn
= ldb_dn_explode(mem_ctx
, (char *)val
->data
);
646 newdn
= ldb_dn_map_remote(module
, mem_ctx
, dn
);
650 newval
.data
= (uint8_t *)ldb_dn_linearize(mem_ctx
, newdn
);
652 newval
.length
= strlen((char *)newval
.data
);
659 /* Map an objectClass into the remote partition. */
660 static struct ldb_val
map_objectclass_convert_local(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_val
*val
)
662 const struct ldb_map_context
*data
= map_get_context(module
);
663 const char *name
= (char *)val
->data
;
664 const struct ldb_map_objectclass
*map
= map_objectclass_find_local(data
, name
);
665 struct ldb_val newval
;
668 newval
.data
= (uint8_t*)talloc_strdup(mem_ctx
, map
->remote_name
);
669 newval
.length
= strlen((char *)newval
.data
);
673 return ldb_val_dup(mem_ctx
, val
);
676 /* Generate a remote message with a mapped objectClass. */
677 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
)
679 struct ldb_message_element
*el
, *oc
;
681 BOOL found_extensibleObject
= False
;
684 /* Find old local objectClass */
685 oc
= ldb_msg_find_element(old
, "objectClass");
690 /* Prepare new element */
691 el
= talloc_zero(remote
, struct ldb_message_element
);
693 ldb_oom(module
->ldb
);
694 return; /* TODO: fail? */
697 /* Copy local objectClass element, reverse space for an extra value */
698 el
->num_values
= oc
->num_values
+ 1;
699 el
->values
= talloc_array(el
, struct ldb_val
, el
->num_values
);
700 if (el
->values
== NULL
) {
702 ldb_oom(module
->ldb
);
703 return; /* TODO: fail? */
706 /* Copy local element name "objectClass" */
707 el
->name
= talloc_strdup(el
, local_attr
);
709 /* Convert all local objectClasses */
710 for (i
= 0; i
< el
->num_values
- 1; i
++) {
711 el
->values
[i
] = map_objectclass_convert_local(module
, el
->values
, &oc
->values
[i
]);
712 if (ldb_attr_cmp((char *)el
->values
[i
].data
, "extensibleObject") == 0) {
713 found_extensibleObject
= True
;
717 if (!found_extensibleObject
) {
718 val
.data
= (uint8_t *)talloc_strdup(el
->values
, "extensibleObject");
719 val
.length
= strlen((char *)val
.data
);
721 /* Append additional objectClass "extensibleObject" */
727 /* Add new objectClass to remote message */
728 ldb_msg_add(remote
, el
, 0);
731 /* Map an objectClass into the local partition. */
732 static struct ldb_val
map_objectclass_convert_remote(struct ldb_module
*module
, void *mem_ctx
, const struct ldb_val
*val
)
734 const struct ldb_map_context
*data
= map_get_context(module
);
735 const char *name
= (char *)val
->data
;
736 const struct ldb_map_objectclass
*map
= map_objectclass_find_remote(data
, name
);
737 struct ldb_val newval
;
740 newval
.data
= (uint8_t*)talloc_strdup(mem_ctx
, map
->local_name
);
741 newval
.length
= strlen((char *)newval
.data
);
745 return ldb_val_dup(mem_ctx
, val
);
748 /* Generate a local message with a mapped objectClass. */
749 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
)
751 struct ldb_message_element
*el
, *oc
;
755 /* Find old remote objectClass */
756 oc
= ldb_msg_find_element(remote
, "objectClass");
761 /* Prepare new element */
762 el
= talloc_zero(mem_ctx
, struct ldb_message_element
);
764 ldb_oom(module
->ldb
);
768 /* Copy remote objectClass element */
769 el
->num_values
= oc
->num_values
;
770 el
->values
= talloc_array(el
, struct ldb_val
, el
->num_values
);
771 if (el
->values
== NULL
) {
773 ldb_oom(module
->ldb
);
777 /* Copy remote element name "objectClass" */
778 el
->name
= talloc_strdup(el
, local_attr
);
780 /* Convert all remote objectClasses */
781 for (i
= 0; i
< el
->num_values
; i
++) {
782 el
->values
[i
] = map_objectclass_convert_remote(module
, el
->values
, &oc
->values
[i
]);
785 val
.data
= (uint8_t *)talloc_strdup(el
->values
, "extensibleObject");
786 val
.length
= strlen((char *)val
.data
);
788 /* Remove last value if it was "extensibleObject" */
789 if (ldb_val_equal_exact(&val
, &el
->values
[i
-1])) {
791 el
->values
= talloc_realloc(el
, el
->values
, struct ldb_val
, el
->num_values
);
792 if (el
->values
== NULL
) {
794 ldb_oom(module
->ldb
);
802 /* Mappings for searches on objectClass= assuming a one-to-one
803 * mapping. Needed because this is a generate operator for the
805 static int map_objectclass_convert_operator(struct ldb_module
*module
, void *mem_ctx
,
806 struct ldb_parse_tree
**new, const struct ldb_parse_tree
*tree
)
809 static const struct ldb_map_attribute objectclass_map
= {
810 .local_name
= "objectClass",
814 .remote_name
= "objectClass",
815 .convert_local
= map_objectclass_convert_local
,
816 .convert_remote
= map_objectclass_convert_remote
,
821 return map_subtree_collect_remote_simple(module
, mem_ctx
, new, tree
, &objectclass_map
);
824 /* Auxiliary request construction
825 * ============================== */
827 /* Store the DN of a single search result in context. */
828 static int map_search_self_callback(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
830 struct map_context
*ac
;
832 if (context
== NULL
|| ares
== NULL
) {
833 ldb_set_errstring(ldb
, talloc_asprintf(ldb
, "NULL Context or Result in callback"));
834 return LDB_ERR_OPERATIONS_ERROR
;
837 ac
= talloc_get_type(context
, struct map_context
);
839 /* We are interested only in the single reply */
840 if (ares
->type
!= LDB_REPLY_ENTRY
) {
845 /* We have already found a remote DN */
847 ldb_set_errstring(ldb
, talloc_asprintf(ldb
, "Too many results to base search"));
849 return LDB_ERR_OPERATIONS_ERROR
;
853 ac
->local_dn
= ares
->message
->dn
;
858 /* Build a request to search a record by its DN. */
859 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
)
861 struct ldb_request
*req
;
863 req
= talloc_zero(ac
, struct ldb_request
);
869 req
->operation
= LDB_SEARCH
;
870 req
->op
.search
.base
= dn
;
871 req
->op
.search
.scope
= LDB_SCOPE_BASE
;
872 req
->op
.search
.attrs
= attrs
;
875 req
->op
.search
.tree
= tree
;
877 req
->op
.search
.tree
= ldb_parse_tree(req
, NULL
);
878 if (req
->op
.search
.tree
== NULL
) {
884 req
->controls
= NULL
;
885 req
->context
= context
;
886 req
->callback
= callback
;
887 ldb_set_timeout_from_prev_req(ac
->module
->ldb
, ac
->orig_req
, req
);
892 /* Build a request to search the local record by its DN. */
893 struct ldb_request
*map_search_self_req(struct map_context
*ac
, const struct ldb_dn
*dn
)
895 /* attrs[] is returned from this function in
896 * ac->search_req->op.search.attrs, so it must be static, as
897 * otherwise the compiler can put it on the stack */
898 static const char * const attrs
[] = { IS_MAPPED
, NULL
};
899 struct ldb_parse_tree
*tree
;
901 /* Limit search to records with 'IS_MAPPED' present */
902 /* TODO: `tree = ldb_parse_tree(ac, IS_MAPPED);' won't do. */
903 tree
= talloc_zero(ac
, struct ldb_parse_tree
);
909 tree
->operation
= LDB_OP_PRESENT
;
910 tree
->u
.present
.attr
= talloc_strdup(tree
, IS_MAPPED
);
912 return map_search_base_req(ac
, dn
, attrs
, tree
, ac
, map_search_self_callback
);
915 /* Build a request to update the 'IS_MAPPED' attribute */
916 struct ldb_request
*map_build_fixup_req(struct map_context
*ac
, const struct ldb_dn
*olddn
, const struct ldb_dn
*newdn
)
918 struct ldb_request
*req
;
919 struct ldb_message
*msg
;
922 /* Prepare request */
923 req
= talloc_zero(ac
, struct ldb_request
);
929 /* Prepare message */
930 msg
= ldb_msg_new(req
);
936 /* Update local 'IS_MAPPED' to the new remote DN */
937 msg
->dn
= discard_const_p(struct ldb_dn
, olddn
);
938 dn
= ldb_dn_linearize(msg
, newdn
);
942 if (ldb_msg_add_empty(msg
, IS_MAPPED
, LDB_FLAG_MOD_REPLACE
, NULL
) != 0) {
945 if (ldb_msg_add_string(msg
, IS_MAPPED
, dn
) != 0) {
949 req
->operation
= LDB_MODIFY
;
950 req
->op
.mod
.message
= msg
;
951 req
->controls
= NULL
;
954 req
->callback
= NULL
;
964 /* Asynchronous call structure
965 * =========================== */
967 /* Figure out which request is currently pending. */
968 static struct ldb_request
*map_get_req(struct map_context
*ac
)
971 case MAP_SEARCH_SELF_MODIFY
:
972 case MAP_SEARCH_SELF_DELETE
:
973 case MAP_SEARCH_SELF_RENAME
:
974 return ac
->search_req
;
977 case MAP_MODIFY_REMOTE
:
978 case MAP_DELETE_REMOTE
:
979 case MAP_RENAME_REMOTE
:
980 return ac
->remote_req
;
982 case MAP_RENAME_FIXUP
:
986 case MAP_MODIFY_LOCAL
:
987 case MAP_DELETE_LOCAL
:
988 case MAP_RENAME_LOCAL
:
989 return ac
->local_req
;
991 case MAP_SEARCH_REMOTE
:
996 return NULL
; /* unreachable; silences a warning */
999 typedef int (*map_next_function
)(struct ldb_handle
*handle
);
1001 /* Figure out the next request to run. */
1002 static map_next_function
map_get_next(struct map_context
*ac
)
1005 case MAP_SEARCH_REMOTE
:
1009 return map_add_do_remote
;
1010 case MAP_ADD_REMOTE
:
1013 case MAP_SEARCH_SELF_MODIFY
:
1014 return map_modify_do_local
;
1015 case MAP_MODIFY_LOCAL
:
1016 return map_modify_do_remote
;
1017 case MAP_MODIFY_REMOTE
:
1020 case MAP_SEARCH_SELF_DELETE
:
1021 return map_delete_do_local
;
1022 case MAP_DELETE_LOCAL
:
1023 return map_delete_do_remote
;
1024 case MAP_DELETE_REMOTE
:
1027 case MAP_SEARCH_SELF_RENAME
:
1028 return map_rename_do_local
;
1029 case MAP_RENAME_LOCAL
:
1030 return map_rename_do_fixup
;
1031 case MAP_RENAME_FIXUP
:
1032 return map_rename_do_remote
;
1033 case MAP_RENAME_REMOTE
:
1037 return NULL
; /* unreachable; silences a warning */
1040 /* Wait for the current pending request to finish and continue with the next. */
1041 static int map_wait_next(struct ldb_handle
*handle
)
1043 struct map_context
*ac
;
1044 struct ldb_request
*req
;
1045 map_next_function next
;
1048 if (handle
== NULL
|| handle
->private_data
== NULL
) {
1049 return LDB_ERR_OPERATIONS_ERROR
;
1052 if (handle
->state
== LDB_ASYNC_DONE
) {
1053 return handle
->status
;
1056 handle
->state
= LDB_ASYNC_PENDING
;
1057 handle
->status
= LDB_SUCCESS
;
1059 ac
= talloc_get_type(handle
->private_data
, struct map_context
);
1061 if (ac
->step
== MAP_SEARCH_REMOTE
) {
1063 for (i
= 0; i
< ac
->num_searches
; i
++) {
1064 req
= ac
->search_reqs
[i
];
1065 ret
= ldb_wait(req
->handle
, LDB_WAIT_NONE
);
1067 if (ret
!= LDB_SUCCESS
) {
1068 handle
->status
= ret
;
1071 if (req
->handle
->status
!= LDB_SUCCESS
) {
1072 handle
->status
= req
->handle
->status
;
1075 if (req
->handle
->state
!= LDB_ASYNC_DONE
) {
1081 req
= map_get_req(ac
);
1083 ret
= ldb_wait(req
->handle
, LDB_WAIT_NONE
);
1085 if (ret
!= LDB_SUCCESS
) {
1086 handle
->status
= ret
;
1089 if (req
->handle
->status
!= LDB_SUCCESS
) {
1090 handle
->status
= req
->handle
->status
;
1093 if (req
->handle
->state
!= LDB_ASYNC_DONE
) {
1097 next
= map_get_next(ac
);
1099 return next(handle
);
1106 handle
->state
= LDB_ASYNC_DONE
;
1110 /* Wait for all current pending requests to finish. */
1111 static int map_wait_all(struct ldb_handle
*handle
)
1115 while (handle
->state
!= LDB_ASYNC_DONE
) {
1116 ret
= map_wait_next(handle
);
1117 if (ret
!= LDB_SUCCESS
) {
1122 return handle
->status
;
1125 /* Wait for pending requests to finish. */
1126 static int map_wait(struct ldb_handle
*handle
, enum ldb_wait_type type
)
1128 if (type
== LDB_WAIT_ALL
) {
1129 return map_wait_all(handle
);
1131 return map_wait_next(handle
);
1136 /* Module initialization
1137 * ===================== */
1139 /* Provided module operations */
1140 static const struct ldb_module_ops map_ops
= {
1143 .modify
= map_modify
,
1145 .rename
= map_rename
,
1146 .search
= map_search
,
1150 /* Builtin mappings for DNs and objectClasses */
1151 static const struct ldb_map_attribute builtin_attribute_maps
[] = {
1154 .type
= MAP_CONVERT
,
1157 .remote_name
= "dn",
1158 .convert_local
= ldb_dn_convert_local
,
1159 .convert_remote
= ldb_dn_convert_remote
,
1164 .local_name
= "objectClass",
1165 .type
= MAP_GENERATE
,
1166 .convert_operator
= map_objectclass_convert_operator
,
1169 .remote_names
= { "objectClass", NULL
},
1170 .generate_local
= map_objectclass_generate_local
,
1171 .generate_remote
= map_objectclass_generate_remote
,
1180 /* Find the special 'MAP_DN_NAME' record and store local and remote
1181 * base DNs in private data. */
1182 static int map_init_dns(struct ldb_module
*module
, struct ldb_map_context
*data
, const char *name
)
1184 static const char * const attrs
[] = { MAP_DN_FROM
, MAP_DN_TO
, NULL
};
1186 struct ldb_message
*msg
;
1187 struct ldb_result
*res
;
1191 data
->local_base_dn
= NULL
;
1192 data
->remote_base_dn
= NULL
;
1196 dn
= ldb_dn_string_compose(data
, NULL
, "%s=%s", MAP_DN_NAME
, name
);
1198 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
1199 "Failed to construct '%s' DN!\n", MAP_DN_NAME
);
1200 return LDB_ERR_OPERATIONS_ERROR
;
1203 ret
= ldb_search(module
->ldb
, dn
, LDB_SCOPE_BASE
, NULL
, attrs
, &res
);
1205 if (ret
!= LDB_SUCCESS
) {
1208 if (res
->count
== 0) {
1209 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
1210 "No results for '%s=%s'!\n", MAP_DN_NAME
, name
);
1212 return LDB_ERR_CONSTRAINT_VIOLATION
;
1214 if (res
->count
> 1) {
1215 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "ldb_map: "
1216 "Too many results for '%s=%s'!\n", MAP_DN_NAME
, name
);
1218 return LDB_ERR_CONSTRAINT_VIOLATION
;
1222 data
->local_base_dn
= ldb_msg_find_attr_as_dn(data
, msg
, MAP_DN_FROM
);
1223 data
->remote_base_dn
= ldb_msg_find_attr_as_dn(data
, msg
, MAP_DN_TO
);
1229 /* Store attribute maps and objectClass maps in private data. */
1230 static int map_init_maps(struct ldb_module
*module
, struct ldb_map_context
*data
,
1231 const struct ldb_map_attribute
*attrs
,
1232 const struct ldb_map_objectclass
*ocls
,
1233 const char * const *wildcard_attributes
)
1238 /* Count specified attribute maps */
1239 for (i
= 0; attrs
[i
].local_name
; i
++) /* noop */ ;
1240 /* Count built-in attribute maps */
1241 for (j
= 0; builtin_attribute_maps
[j
].local_name
; j
++) /* noop */ ;
1243 /* Store list of attribute maps */
1244 data
->attribute_maps
= talloc_array(data
, struct ldb_map_attribute
, i
+j
+1);
1245 if (data
->attribute_maps
== NULL
) {
1247 return LDB_ERR_OPERATIONS_ERROR
;
1250 /* Specified ones go first */
1251 for (i
= 0; attrs
[i
].local_name
; i
++) {
1252 data
->attribute_maps
[last
] = attrs
[i
];
1256 /* Built-in ones go last */
1257 for (i
= 0; builtin_attribute_maps
[i
].local_name
; i
++) {
1258 data
->attribute_maps
[last
] = builtin_attribute_maps
[i
];
1262 /* Ensure 'local_name == NULL' for the last entry */
1263 memset(&data
->attribute_maps
[last
], 0, sizeof(struct ldb_map_attribute
));
1265 /* Store list of objectClass maps */
1266 data
->objectclass_maps
= ocls
;
1268 data
->wildcard_attributes
= wildcard_attributes
;
1273 /* Copy the list of provided module operations. */
1274 _PUBLIC_
struct ldb_module_ops
ldb_map_get_ops(void)
1279 /* Initialize global private data. */
1280 _PUBLIC_
int ldb_map_init(struct ldb_module
*module
, const struct ldb_map_attribute
*attrs
,
1281 const struct ldb_map_objectclass
*ocls
,
1282 const char * const *wildcard_attributes
,
1285 struct map_private
*data
;
1288 /* Prepare private data */
1289 data
= talloc_zero(module
, struct map_private
);
1292 return LDB_ERR_OPERATIONS_ERROR
;
1295 module
->private_data
= data
;
1297 data
->context
= talloc_zero(data
, struct ldb_map_context
);
1298 if (!data
->context
) {
1300 return LDB_ERR_OPERATIONS_ERROR
;
1303 /* Store local and remote baseDNs */
1304 ret
= map_init_dns(module
, data
->context
, name
);
1305 if (ret
!= LDB_SUCCESS
) {
1310 /* Store list of attribute and objectClass maps */
1311 ret
= map_init_maps(module
, data
->context
, attrs
, ocls
, wildcard_attributes
);
1312 if (ret
!= LDB_SUCCESS
) {
1320 /* Usage note for initialization of this module:
1322 * ldb_map is meant to be used from a different module that sets up
1323 * the mappings and gets registered in ldb.
1325 * 'ldb_map_init' initializes the private data of this module and
1326 * stores the attribute and objectClass maps in there. It also looks
1327 * up the '@MAP' special DN so requests can be redirected to the
1330 * This function should be called from the 'init_context' op of the
1331 * module using ldb_map.
1333 * 'ldb_map_get_ops' returns a copy of ldb_maps module operations.
1335 * It should be called from the initialize function of the using
1336 * module, which should then override the 'init_context' op with a
1337 * function making the appropriate calls to 'ldb_map_init'.