2
ldb database mapping module
4
Copyright (C) Jelmer Vernooij 2005
5
Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
6
Copyright (C) Simo Sorce 2008
8
** NOTE! The following LGPL license applies to the ldb
9
** library. This does NOT imply that all of Samba is released
12
This library is free software; you can redistribute it and/or
13
modify it under the terms of the GNU Lesser General Public
14
License as published by the Free Software Foundation; either
15
version 3 of the License, or (at your option) any later version.
17
This library is distributed in the hope that it will be useful,
18
but WITHOUT ANY WARRANTY; without even the implied warranty of
19
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20
Lesser General Public License for more details.
22
You should have received a copy of the GNU Lesser General Public
23
License along with this library; if not, see <http://www.gnu.org/licenses/>.
30
* Component: ldb ldb_map module
32
* Description: Map portions of data into a different format on a
35
* Author: Jelmer Vernooij, Martin Kuehl
38
#include "ldb_includes.h"
40
#include "ldb_map_private.h"
46
/* Description of the provided ldb requests:
47
- special attribute 'isMapped'
50
- if parse tree can be split
51
- search remote records w/ remote attrs and parse tree
53
- enumerate all remote records
54
- for each remote result
55
- map remote result to local message
58
- merge local into remote result
59
- run callback on merged result
61
- run callback on remote result
64
- split message into local and remote part
65
- if local message is not empty
66
- add isMapped to local message
71
- split message into local and remote part
72
- if local message is not empty
73
- add isMapped to local message
74
- search for local record
79
- modify remote record
82
- search for local record
85
- delete remote record
88
- search for local record
91
- modify local isMapped
92
- rename remote record
97
/* Private data structures
98
* ======================= */
100
/* Global private data */
101
/* Extract mappings from private data. */
102
const struct ldb_map_context *map_get_context(struct ldb_module *module)
104
const struct map_private *data = talloc_get_type(ldb_module_get_private(module), struct map_private);
105
return data->context;
108
/* Create a generic request context. */
109
struct map_context *map_init_context(struct ldb_module *module,
110
struct ldb_request *req)
112
struct ldb_context *ldb;
113
struct map_context *ac;
115
ldb = ldb_module_get_ctx(module);
117
ac = talloc_zero(req, struct map_context);
119
ldb_set_errstring(ldb, "Out of Memory");
129
/* Dealing with DNs for different partitions
130
* ========================================= */
132
/* Check whether any data should be stored in the local partition. */
133
bool map_check_local_db(struct ldb_module *module)
135
const struct ldb_map_context *data = map_get_context(module);
137
if (!data->remote_base_dn || !data->local_base_dn) {
144
/* Copy a DN with the base DN of the local partition. */
145
static struct ldb_dn *ldb_dn_rebase_local(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn)
147
struct ldb_dn *new_dn;
149
new_dn = ldb_dn_copy(mem_ctx, dn);
150
if ( ! ldb_dn_validate(new_dn)) {
155
/* may be we don't need to rebase at all */
156
if ( ! data->remote_base_dn || ! data->local_base_dn) {
160
if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->remote_base_dn))) {
165
if ( ! ldb_dn_add_base(new_dn, data->local_base_dn)) {
173
/* Copy a DN with the base DN of the remote partition. */
174
static struct ldb_dn *ldb_dn_rebase_remote(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn)
176
struct ldb_dn *new_dn;
178
new_dn = ldb_dn_copy(mem_ctx, dn);
179
if ( ! ldb_dn_validate(new_dn)) {
184
/* may be we don't need to rebase at all */
185
if ( ! data->remote_base_dn || ! data->local_base_dn) {
189
if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->local_base_dn))) {
194
if ( ! ldb_dn_add_base(new_dn, data->remote_base_dn)) {
202
/* Run a request and make sure it targets the remote partition. */
203
/* TODO: free old DNs and messages? */
204
int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request)
206
const struct ldb_map_context *data = map_get_context(module);
207
struct ldb_context *ldb;
208
struct ldb_message *msg;
210
ldb = ldb_module_get_ctx(module);
212
switch (request->operation) {
214
if (request->op.search.base) {
215
request->op.search.base = ldb_dn_rebase_remote(request, data, request->op.search.base);
217
request->op.search.base = data->remote_base_dn;
218
/* TODO: adjust scope? */
223
msg = ldb_msg_copy_shallow(request, request->op.add.message);
224
msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn);
225
request->op.add.message = msg;
229
msg = ldb_msg_copy_shallow(request, request->op.mod.message);
230
msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn);
231
request->op.mod.message = msg;
235
request->op.del.dn = ldb_dn_rebase_remote(request, data, request->op.del.dn);
239
request->op.rename.olddn = ldb_dn_rebase_remote(request, data, request->op.rename.olddn);
240
request->op.rename.newdn = ldb_dn_rebase_remote(request, data, request->op.rename.newdn);
244
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
245
"Invalid remote request!\n");
246
return LDB_ERR_OPERATIONS_ERROR;
249
return ldb_next_request(module, request);
253
/* Finding mappings for attributes and objectClasses
254
* ================================================= */
256
/* Find an objectClass mapping by the local name. */
257
static const struct ldb_map_objectclass *map_objectclass_find_local(const struct ldb_map_context *data, const char *name)
261
for (i = 0; data->objectclass_maps && data->objectclass_maps[i].local_name; i++) {
262
if (ldb_attr_cmp(data->objectclass_maps[i].local_name, name) == 0) {
263
return &data->objectclass_maps[i];
270
/* Find an objectClass mapping by the remote name. */
271
static const struct ldb_map_objectclass *map_objectclass_find_remote(const struct ldb_map_context *data, const char *name)
275
for (i = 0; data->objectclass_maps && data->objectclass_maps[i].remote_name; i++) {
276
if (ldb_attr_cmp(data->objectclass_maps[i].remote_name, name) == 0) {
277
return &data->objectclass_maps[i];
284
/* Find an attribute mapping by the local name. */
285
const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name)
289
for (i = 0; data->attribute_maps[i].local_name; i++) {
290
if (ldb_attr_cmp(data->attribute_maps[i].local_name, name) == 0) {
291
return &data->attribute_maps[i];
294
for (i = 0; data->attribute_maps[i].local_name; i++) {
295
if (ldb_attr_cmp(data->attribute_maps[i].local_name, "*") == 0) {
296
return &data->attribute_maps[i];
303
/* Find an attribute mapping by the remote name. */
304
const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name)
306
const struct ldb_map_attribute *map;
307
const struct ldb_map_attribute *wildcard = NULL;
310
for (i = 0; data->attribute_maps[i].local_name; i++) {
311
map = &data->attribute_maps[i];
312
if (ldb_attr_cmp(map->local_name, "*") == 0) {
313
wildcard = &data->attribute_maps[i];
321
if (ldb_attr_cmp(map->local_name, name) == 0) {
328
if (ldb_attr_cmp(map->u.rename.remote_name, name) == 0) {
334
for (j = 0; map->u.generate.remote_names && map->u.generate.remote_names[j]; j++) {
335
if (ldb_attr_cmp(map->u.generate.remote_names[j], name) == 0) {
343
/* We didn't find it, so return the wildcard record if one was configured */
348
/* Mapping attributes
349
* ================== */
351
/* Check whether an attribute will be mapped into the remote partition. */
352
bool map_attr_check_remote(const struct ldb_map_context *data, const char *attr)
354
const struct ldb_map_attribute *map = map_attr_find_local(data, attr);
359
if (map->type == MAP_IGNORE) {
366
/* Map an attribute name into the remote partition. */
367
const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr)
370
return talloc_strdup(mem_ctx, attr);
375
return talloc_strdup(mem_ctx, attr);
379
return talloc_strdup(mem_ctx, map->u.rename.remote_name);
386
/* Map an attribute name back into the local partition. */
387
const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr)
390
return talloc_strdup(mem_ctx, attr);
393
if (map->type == MAP_KEEP) {
394
return talloc_strdup(mem_ctx, attr);
397
return talloc_strdup(mem_ctx, map->local_name);
401
/* Merge two lists of attributes into a single one. */
402
int map_attrs_merge(struct ldb_module *module, void *mem_ctx,
403
const char ***attrs, const char * const *more_attrs)
407
for (i = 0; *attrs && (*attrs)[i]; i++) /* noop */ ;
408
for (j = 0; more_attrs && more_attrs[j]; j++) /* noop */ ;
410
*attrs = talloc_realloc(mem_ctx, *attrs, const char *, i+j+1);
411
if (*attrs == NULL) {
416
for (k = 0; k < j; k++) {
417
(*attrs)[i + k] = more_attrs[k];
420
(*attrs)[i+k] = NULL;
425
/* Mapping ldb values
426
* ================== */
428
/* Map an ldb value into the remote partition. */
429
struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx,
430
const struct ldb_map_attribute *map, const struct ldb_val *val)
432
if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_local)) {
433
return map->u.convert.convert_local(module, mem_ctx, val);
436
return ldb_val_dup(mem_ctx, val);
439
/* Map an ldb value back into the local partition. */
440
struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx,
441
const struct ldb_map_attribute *map, const struct ldb_val *val)
443
if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_remote)) {
444
return map->u.convert.convert_remote(module, mem_ctx, val);
447
return ldb_val_dup(mem_ctx, val);
454
/* Check whether a DN is below the local baseDN. */
455
bool ldb_dn_check_local(struct ldb_module *module, struct ldb_dn *dn)
457
const struct ldb_map_context *data = map_get_context(module);
459
if (!data->local_base_dn) {
463
return ldb_dn_compare_base(data->local_base_dn, dn) == 0;
466
/* Map a DN into the remote partition. */
467
struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
469
const struct ldb_map_context *data = map_get_context(module);
470
struct ldb_context *ldb;
471
struct ldb_dn *newdn;
472
const struct ldb_map_attribute *map;
473
enum ldb_map_attr_type map_type;
475
struct ldb_val value;
482
ldb = ldb_module_get_ctx(module);
484
newdn = ldb_dn_copy(mem_ctx, dn);
490
/* For each RDN, map the component name and possibly the value */
491
for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) {
492
map = map_attr_find_local(data, ldb_dn_get_component_name(dn, i));
494
/* Unknown attribute - leave this RDN as is and hope the best... */
498
map_type = map->type;
504
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
505
"MAP_IGNORE/MAP_GENERATE attribute '%s' "
506
"used in DN!\n", ldb_dn_get_component_name(dn, i));
510
if (map->u.convert.convert_local == NULL) {
511
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
512
"'convert_local' not set for attribute '%s' "
513
"used in DN!\n", ldb_dn_get_component_name(dn, i));
519
name = map_attr_map_local(newdn, map, ldb_dn_get_component_name(dn, i));
520
if (name == NULL) goto failed;
522
value = ldb_val_map_local(module, newdn, map, ldb_dn_get_component_val(dn, i));
523
if (value.data == NULL) goto failed;
525
ret = ldb_dn_set_component(newdn, i, name, value);
526
if (ret != LDB_SUCCESS) {
541
/* Map a DN into the local partition. */
542
struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
544
const struct ldb_map_context *data = map_get_context(module);
545
struct ldb_context *ldb;
546
struct ldb_dn *newdn;
547
const struct ldb_map_attribute *map;
548
enum ldb_map_attr_type map_type;
550
struct ldb_val value;
557
ldb = ldb_module_get_ctx(module);
559
newdn = ldb_dn_copy(mem_ctx, dn);
565
/* For each RDN, map the component name and possibly the value */
566
for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) {
567
map = map_attr_find_remote(data, ldb_dn_get_component_name(dn, i));
569
/* Unknown attribute - leave this RDN as is and hope the best... */
573
map_type = map->type;
579
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
580
"MAP_IGNORE/MAP_GENERATE attribute '%s' "
581
"used in DN!\n", ldb_dn_get_component_name(dn, i));
585
if (map->u.convert.convert_remote == NULL) {
586
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
587
"'convert_remote' not set for attribute '%s' "
588
"used in DN!\n", ldb_dn_get_component_name(dn, i));
594
name = map_attr_map_remote(newdn, map, ldb_dn_get_component_name(dn, i));
595
if (name == NULL) goto failed;
597
value = ldb_val_map_remote(module, newdn, map, ldb_dn_get_component_val(dn, i));
598
if (value.data == NULL) goto failed;
600
ret = ldb_dn_set_component(newdn, i, name, value);
601
if (ret != LDB_SUCCESS) {
616
/* Map a DN and its base into the local partition. */
617
/* TODO: This should not be required with GUIDs. */
618
struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
620
const struct ldb_map_context *data = map_get_context(module);
621
struct ldb_dn *dn1, *dn2;
623
dn1 = ldb_dn_rebase_local(mem_ctx, data, dn);
624
dn2 = ldb_dn_map_remote(module, mem_ctx, dn1);
631
/* Converting DNs and objectClasses (as ldb values)
632
* ================================================ */
634
/* Map a DN contained in an ldb value into the remote partition. */
635
static struct ldb_val ldb_dn_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
637
struct ldb_context *ldb;
638
struct ldb_dn *dn, *newdn;
639
struct ldb_val newval;
641
ldb = ldb_module_get_ctx(module);
643
dn = ldb_dn_from_ldb_val(mem_ctx, ldb, val);
644
if (! ldb_dn_validate(dn)) {
650
newdn = ldb_dn_map_local(module, mem_ctx, dn);
654
newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn);
656
newval.length = strlen((char *)newval.data);
663
/* Map a DN contained in an ldb value into the local partition. */
664
static struct ldb_val ldb_dn_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
666
struct ldb_context *ldb;
667
struct ldb_dn *dn, *newdn;
668
struct ldb_val newval;
670
ldb = ldb_module_get_ctx(module);
672
dn = ldb_dn_from_ldb_val(mem_ctx, ldb, val);
673
if (! ldb_dn_validate(dn)) {
679
newdn = ldb_dn_map_remote(module, mem_ctx, dn);
683
newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn);
685
newval.length = strlen((char *)newval.data);
692
/* Map an objectClass into the remote partition. */
693
static struct ldb_val map_objectclass_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
695
const struct ldb_map_context *data = map_get_context(module);
696
const char *name = (char *)val->data;
697
const struct ldb_map_objectclass *map = map_objectclass_find_local(data, name);
698
struct ldb_val newval;
701
newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->remote_name);
702
newval.length = strlen((char *)newval.data);
706
return ldb_val_dup(mem_ctx, val);
709
/* Generate a remote message with a mapped objectClass. */
710
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)
712
const struct ldb_map_context *data = map_get_context(module);
713
struct ldb_context *ldb;
714
struct ldb_message_element *el, *oc;
716
bool found_extensibleObject = false;
719
ldb = ldb_module_get_ctx(module);
721
/* Find old local objectClass */
722
oc = ldb_msg_find_element(old, "objectClass");
727
/* Prepare new element */
728
el = talloc_zero(remote, struct ldb_message_element);
731
return; /* TODO: fail? */
734
/* Copy local objectClass element, reverse space for an extra value */
735
el->num_values = oc->num_values + 1;
736
el->values = talloc_array(el, struct ldb_val, el->num_values);
737
if (el->values == NULL) {
740
return; /* TODO: fail? */
743
/* Copy local element name "objectClass" */
744
el->name = talloc_strdup(el, local_attr);
746
/* Convert all local objectClasses */
747
for (i = 0; i < el->num_values - 1; i++) {
748
el->values[i] = map_objectclass_convert_local(module, el->values, &oc->values[i]);
749
if (ldb_attr_cmp((char *)el->values[i].data, data->add_objectclass) == 0) {
750
found_extensibleObject = true;
754
if (!found_extensibleObject) {
755
val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass);
756
val.length = strlen((char *)val.data);
758
/* Append additional objectClass data->add_objectclass */
764
/* Add new objectClass to remote message */
765
ldb_msg_add(remote, el, 0);
768
/* Map an objectClass into the local partition. */
769
static struct ldb_val map_objectclass_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
771
const struct ldb_map_context *data = map_get_context(module);
772
const char *name = (char *)val->data;
773
const struct ldb_map_objectclass *map = map_objectclass_find_remote(data, name);
774
struct ldb_val newval;
777
newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->local_name);
778
newval.length = strlen((char *)newval.data);
782
return ldb_val_dup(mem_ctx, val);
785
/* Generate a local message with a mapped objectClass. */
786
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)
788
const struct ldb_map_context *data = map_get_context(module);
789
struct ldb_context *ldb;
790
struct ldb_message_element *el, *oc;
794
ldb = ldb_module_get_ctx(module);
796
/* Find old remote objectClass */
797
oc = ldb_msg_find_element(remote, "objectClass");
802
/* Prepare new element */
803
el = talloc_zero(mem_ctx, struct ldb_message_element);
809
/* Copy remote objectClass element */
810
el->num_values = oc->num_values;
811
el->values = talloc_array(el, struct ldb_val, el->num_values);
812
if (el->values == NULL) {
818
/* Copy remote element name "objectClass" */
819
el->name = talloc_strdup(el, local_attr);
821
/* Convert all remote objectClasses */
822
for (i = 0; i < el->num_values; i++) {
823
el->values[i] = map_objectclass_convert_remote(module, el->values, &oc->values[i]);
826
val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass);
827
val.length = strlen((char *)val.data);
829
/* Remove last value if it was the string in data->add_objectclass (eg samba4top, extensibleObject) */
830
if (ldb_val_equal_exact(&val, &el->values[i-1])) {
832
el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values);
833
if (el->values == NULL) {
843
static const struct ldb_map_attribute objectclass_convert_map = {
844
.local_name = "objectClass",
848
.remote_name = "objectClass",
849
.convert_local = map_objectclass_convert_local,
850
.convert_remote = map_objectclass_convert_remote,
856
/* Mappings for searches on objectClass= assuming a one-to-one
857
* mapping. Needed because this is a generate operator for the
859
static int map_objectclass_convert_operator(struct ldb_module *module, void *mem_ctx,
860
struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
863
return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, &objectclass_convert_map);
866
/* Auxiliary request construction
867
* ============================== */
869
/* Build a request to search a record by its DN. */
870
struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_map_callback_t callback)
872
const struct ldb_parse_tree *search_tree;
873
struct ldb_context *ldb;
874
struct ldb_request *req;
877
ldb = ldb_module_get_ctx(ac->module);
882
search_tree = ldb_parse_tree(ac, NULL);
883
if (search_tree == NULL) {
888
ret = ldb_build_search_req_ex(&req, ldb, ac,
894
if (ret != LDB_SUCCESS) {
901
/* Build a request to update the 'IS_MAPPED' attribute */
902
struct ldb_request *map_build_fixup_req(struct map_context *ac,
903
struct ldb_dn *olddn,
904
struct ldb_dn *newdn,
906
ldb_map_callback_t callback)
908
struct ldb_context *ldb;
909
struct ldb_request *req;
910
struct ldb_message *msg;
914
ldb = ldb_module_get_ctx(ac->module);
916
/* Prepare message */
917
msg = ldb_msg_new(ac);
923
/* Update local 'IS_MAPPED' to the new remote DN */
924
msg->dn = ldb_dn_copy(msg, olddn);
925
dn = ldb_dn_alloc_linearized(msg, newdn);
926
if ( ! dn || ! ldb_dn_validate(msg->dn)) {
929
if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
932
if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
936
/* Prepare request */
937
ret = ldb_build_mod_req(&req, ldb,
941
if (ret != LDB_SUCCESS) {
944
talloc_steal(req, msg);
952
/* Module initialization
953
* ===================== */
956
/* Builtin mappings for DNs and objectClasses */
957
static const struct ldb_map_attribute builtin_attribute_maps[] = {
964
.convert_local = ldb_dn_convert_local,
965
.convert_remote = ldb_dn_convert_remote,
974
static const struct ldb_map_attribute objectclass_attribute_map = {
975
.local_name = "objectClass",
976
.type = MAP_GENERATE,
977
.convert_operator = map_objectclass_convert_operator,
980
.remote_names = { "objectClass", NULL },
981
.generate_local = map_objectclass_generate_local,
982
.generate_remote = map_objectclass_generate_remote,
988
/* Find the special 'MAP_DN_NAME' record and store local and remote
989
* base DNs in private data. */
990
static int map_init_dns(struct ldb_module *module, struct ldb_map_context *data, const char *name)
992
static const char * const attrs[] = { MAP_DN_FROM, MAP_DN_TO, NULL };
993
struct ldb_context *ldb;
995
struct ldb_message *msg;
996
struct ldb_result *res;
1000
data->local_base_dn = NULL;
1001
data->remote_base_dn = NULL;
1005
ldb = ldb_module_get_ctx(module);
1007
dn = ldb_dn_new_fmt(data, ldb, "%s=%s", MAP_DN_NAME, name);
1008
if ( ! ldb_dn_validate(dn)) {
1009
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
1010
"Failed to construct '%s' DN!\n", MAP_DN_NAME);
1011
return LDB_ERR_OPERATIONS_ERROR;
1014
ret = ldb_search(ldb, data, &res, dn, LDB_SCOPE_BASE, attrs, NULL);
1016
if (ret != LDB_SUCCESS) {
1019
if (res->count == 0) {
1020
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
1021
"No results for '%s=%s'!\n", MAP_DN_NAME, name);
1023
return LDB_ERR_CONSTRAINT_VIOLATION;
1025
if (res->count > 1) {
1026
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
1027
"Too many results for '%s=%s'!\n", MAP_DN_NAME, name);
1029
return LDB_ERR_CONSTRAINT_VIOLATION;
1033
data->local_base_dn = ldb_msg_find_attr_as_dn(ldb, data, msg, MAP_DN_FROM);
1034
data->remote_base_dn = ldb_msg_find_attr_as_dn(ldb, data, msg, MAP_DN_TO);
1040
/* Store attribute maps and objectClass maps in private data. */
1041
static int map_init_maps(struct ldb_module *module, struct ldb_map_context *data,
1042
const struct ldb_map_attribute *attrs,
1043
const struct ldb_map_objectclass *ocls,
1044
const char * const *wildcard_attributes)
1049
/* Count specified attribute maps */
1050
for (i = 0; attrs[i].local_name; i++) /* noop */ ;
1051
/* Count built-in attribute maps */
1052
for (j = 0; builtin_attribute_maps[j].local_name; j++) /* noop */ ;
1054
/* Store list of attribute maps */
1055
data->attribute_maps = talloc_array(data, struct ldb_map_attribute, i+j+2);
1056
if (data->attribute_maps == NULL) {
1058
return LDB_ERR_OPERATIONS_ERROR;
1061
/* Specified ones go first */
1062
for (i = 0; attrs[i].local_name; i++) {
1063
data->attribute_maps[last] = attrs[i];
1067
/* Built-in ones go last */
1068
for (i = 0; builtin_attribute_maps[i].local_name; i++) {
1069
data->attribute_maps[last] = builtin_attribute_maps[i];
1073
if (data->add_objectclass) {
1074
/* ObjectClass one is very last, if required */
1075
data->attribute_maps[last] = objectclass_attribute_map;
1078
data->attribute_maps[last] = objectclass_convert_map;
1082
/* Ensure 'local_name == NULL' for the last entry */
1083
memset(&data->attribute_maps[last], 0, sizeof(struct ldb_map_attribute));
1085
/* Store list of objectClass maps */
1086
data->objectclass_maps = ocls;
1088
data->wildcard_attributes = wildcard_attributes;
1093
/* Initialize global private data. */
1094
_PUBLIC_ int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs,
1095
const struct ldb_map_objectclass *ocls,
1096
const char * const *wildcard_attributes,
1097
const char *add_objectclass,
1100
struct map_private *data;
1103
/* Prepare private data */
1104
data = talloc_zero(module, struct map_private);
1107
return LDB_ERR_OPERATIONS_ERROR;
1110
ldb_module_set_private(module, data);
1112
data->context = talloc_zero(data, struct ldb_map_context);
1113
if (!data->context) {
1115
return LDB_ERR_OPERATIONS_ERROR;
1118
/* Store local and remote baseDNs */
1119
ret = map_init_dns(module, data->context, name);
1120
if (ret != LDB_SUCCESS) {
1125
data->context->add_objectclass = add_objectclass;
1127
/* Store list of attribute and objectClass maps */
1128
ret = map_init_maps(module, data->context, attrs, ocls, wildcard_attributes);
1129
if (ret != LDB_SUCCESS) {