r9899: Be more conservative about what is sent to the remote server in ldb_map.
[gd/samba/.git] / source4 / lib / ldb / modules / ldb_map.c
1 /* 
2    ldb database library - map backend
3
4    Copyright (C) Jelmer Vernooij 2005
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9    
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.
14
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.
19
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
23 */
24
25 #include "includes.h"
26 #include "ldb/include/ldb.h"
27 #include "ldb/include/ldb_private.h"
28 #include "ldb/modules/ldb_map.h"
29
30 /* FIXME:
31  *  - per remote objectclass: 
32  *     - remote name
33  *     - local name
34  *     - remote bases
35  *     - musts
36  *     - mays
37  */
38
39 /*
40  - special attribute 'isMapped'
41  - add/modify
42         - split up ldb_message into fallback and mapped parts if is_mappable
43  - search: 
44         - search local one for not isMapped entries
45         - remove remote attributes from ldb_parse_tree
46         - search remote one
47          - per record, search local one for additional data (by dn)
48          - test if (full expression) is now true
49  - delete
50         - delete both
51  - rename
52         - rename locally and remotely
53 */
54
55 static struct ldb_val map_convert_local_dn(struct ldb_module *map,
56                                            TALLOC_CTX *ctx,
57                                            const struct ldb_val *val);
58 static struct ldb_val map_convert_remote_dn(struct ldb_module *map,
59                                             TALLOC_CTX *ctx,
60                                             const struct ldb_val *val);
61 static struct ldb_val map_convert_local_objectclass(struct ldb_module *map,
62                                                     TALLOC_CTX *ctx,
63                                                     const struct ldb_val *val);
64 static struct ldb_val map_convert_remote_objectclass(struct ldb_module *map,
65                                                      TALLOC_CTX *ctx,
66                                                      const struct ldb_val *val);
67
68 static const struct ldb_map_attribute builtin_attribute_maps[] = {
69         {
70                 .local_name = "dn",
71                 .type = MAP_CONVERT,
72                 .u = {
73                         .convert = {
74                                 .remote_name = "dn",
75                                 .convert_local = map_convert_local_dn,
76                                 .convert_remote = map_convert_remote_dn,
77                         },
78                 },
79         },
80         {
81                 .local_name = "objectclass",
82                 .type = MAP_CONVERT,
83                 .u = {
84                         .convert = {
85                                 .remote_name = "objectclass",
86                                 .convert_local = map_convert_local_objectclass,
87                                 .convert_remote = map_convert_remote_objectclass,
88                         },
89                 },
90         },
91         {
92                 .local_name = NULL,
93         }
94 };
95
96 static const struct ldb_map_objectclass *map_find_objectclass_remote(struct ldb_map_context *privdat, const char *name)
97 {
98         int i;
99         for (i = 0; privdat->objectclass_maps[i].remote_name; i++) {
100                 if (!ldb_attr_cmp(privdat->objectclass_maps[i].remote_name, name))
101                         return &privdat->objectclass_maps[i];
102         }
103
104         return NULL;
105 }
106
107 struct map_private {
108         struct ldb_map_context context;
109         const char *last_err_string;
110 };
111
112 static struct ldb_map_context *map_get_privdat(struct ldb_module *module)
113 {
114         return &((struct map_private *)module->private_data)->context;
115 }
116
117 /* Check whether the given attribute can fit into the specified 
118  * message, obeying objectClass restrictions */
119 static int map_msg_valid_attr(struct ldb_module *module, const struct ldb_message *msg, const char *attr)
120 {
121         struct ldb_map_context *map = module->private_data;
122         int i, j;
123         struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
124
125         if (el == NULL) {
126                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Can't find objectClass");
127                 return 0;
128         }
129
130         for (i = 0; i < el->num_values; i++) {
131                 const struct ldb_map_objectclass *class = map_find_objectclass_remote(map, (char *)el->values[i].data);
132
133                 if (!class) 
134                         continue;
135                 
136                 for (j = 0; class->musts[j]; j++) {
137                         if (!ldb_attr_cmp(class->musts[j], attr))
138                                 return 1;
139                 }
140
141                 for (j = 0; class->mays[j]; j++) {
142                         if (!ldb_attr_cmp(class->mays[j], attr))
143                                 return 1;
144                 }
145         }
146
147         return 0;
148
149
150
151 /* find an attribute by the local name */
152 static const struct ldb_map_attribute *map_find_attr_local(struct ldb_map_context *privdat, const char *attr)
153 {
154         int i;
155
156         for (i = 0; privdat->attribute_maps[i].local_name; i++) {
157                 if (!ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr)) 
158                         return &privdat->attribute_maps[i];
159         }
160
161         return NULL;
162 }
163
164 /* Check if a given attribute can be created by doing mapping from a local attribute to a remote one */
165 static int map_msg_can_map_attr(struct ldb_module *module, const struct ldb_message *msg, const char *attr_name)
166 {
167         struct ldb_map_context *map = module->private_data;
168         int i, j;
169         
170         for (i = 0; i < msg->num_elements; i++) {
171                 const struct ldb_map_attribute *attr = map_find_attr_local(map, msg->elements[i].name);
172
173                 if (!attr) 
174                         continue;
175
176                 switch (attr->type) {
177                 case MAP_IGNORE: continue;
178                 case MAP_KEEP:
179                                 if (ldb_attr_cmp(attr->local_name, attr_name) == 0) return 1;
180                                 break;
181                 case MAP_RENAME:
182                 case MAP_CONVERT:
183                                 if (ldb_attr_cmp(attr->u.rename.remote_name, attr_name) == 0) return 1;
184                                 break;
185                 case MAP_GENERATE:
186                                 for (j = 0; attr->u.generate.remote_names[j]; j++) {
187                                         if (ldb_attr_cmp(attr->u.generate.remote_names[j], attr_name) == 0) return 1;
188                                 }
189                                 break;
190                 }
191         }
192
193         return 0;
194 }
195
196
197
198 /* find an attribute by the remote name */
199 static const struct ldb_map_attribute *map_find_attr_remote(struct ldb_map_context *privdat, const char *attr)
200 {
201         int i;
202
203         for (i = 0; privdat->attribute_maps[i].local_name; i++) {
204                 if (privdat->attribute_maps[i].type == MAP_IGNORE)
205                         continue;
206
207                 if (privdat->attribute_maps[i].type == MAP_GENERATE)
208                         continue;
209
210                 if (privdat->attribute_maps[i].type == MAP_KEEP &&
211                         ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr) == 0)
212                         return &privdat->attribute_maps[i];
213
214                 if ((privdat->attribute_maps[i].type == MAP_RENAME ||
215                         privdat->attribute_maps[i].type == MAP_CONVERT) &&
216                         ldb_attr_cmp(privdat->attribute_maps[i].u.rename.remote_name, attr) == 0) 
217                         return &privdat->attribute_maps[i];
218
219         }
220
221         return NULL;
222 }
223
224 static struct ldb_parse_tree *ldb_map_parse_tree(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_parse_tree *tree)
225 {
226         int i;
227         const struct ldb_map_attribute *attr;
228         struct ldb_parse_tree *new_tree;
229         enum ldb_map_attr_type map_type;
230         struct ldb_val value, newvalue;
231         struct ldb_map_context *privdat = map_get_privdat(module);
232
233         if (tree == NULL)
234                 return NULL;
235         
236
237         /* Find attr in question and:
238          *  - if it has a convert_operator function, run that
239          *  - otherwise, replace attr name with required[0] */
240
241         if (tree->operation == LDB_OP_AND || 
242                 tree->operation == LDB_OP_OR) {
243                 
244                 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
245                 new_tree->u.list.elements = talloc_array(new_tree, struct ldb_parse_tree *, tree->u.list.num_elements);
246                 new_tree->u.list.num_elements = 0;
247                 for (i = 0; i < tree->u.list.num_elements; i++) {
248                         struct ldb_parse_tree *child = ldb_map_parse_tree(module, new_tree, tree->u.list.elements[i]);
249                         
250                         if (child) {
251                                 new_tree->u.list.elements[i] = child;
252                                 new_tree->u.list.num_elements++;
253                         }
254                 }
255
256                 return new_tree;
257         }
258                 
259         if (tree->operation == LDB_OP_NOT) {
260                 struct ldb_parse_tree *child;
261                 
262                 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
263                 child = ldb_map_parse_tree(module, new_tree, tree->u.isnot.child);
264
265                 if (!child) {
266                         talloc_free(new_tree);
267                         return NULL;
268                 }
269
270                 new_tree->u.isnot.child = child;
271                 return new_tree;
272         }
273
274         /* tree->operation is LDB_OP_EQUALITY, LDB_OP_SUBSTRING, LDB_OP_GREATER,
275          * LDB_OP_LESS, LDB_OP_APPROX, LDB_OP_PRESENT or LDB_OP_EXTENDED
276          *
277          * (all have attr as the first element)
278          */
279
280         attr = map_find_attr_local(privdat, tree->u.equality.attr);
281
282         if (!attr) {
283                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Unable to find local attribute '%s', removing from parse tree\n", tree->u.equality.attr);
284                 map_type = MAP_IGNORE;
285         } else {
286                 map_type = attr->type;
287         }
288
289         if (attr && attr->convert_operator) {
290                 /* Run convert_operator */
291                 return attr->convert_operator(privdat, module, tree);
292         }
293
294         if (map_type == MAP_IGNORE) {
295                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Not mapping search on ignored attribute '%s'\n", tree->u.equality.attr);
296                 return NULL;
297         }
298
299         if (map_type == MAP_GENERATE) {
300                 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);
301                 return NULL;
302         }
303
304         if (tree->operation == LDB_OP_EQUALITY) {
305                 value = tree->u.equality.value;
306         } else if (tree->operation == LDB_OP_LESS || tree->operation == LDB_OP_GREATER ||
307                            tree->operation == LDB_OP_APPROX) {
308                 value = tree->u.comparison.value;
309         } else if (tree->operation == LDB_OP_EXTENDED) {
310                 value = tree->u.extended.value;
311         }
312         
313         new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
314
315         if (map_type == MAP_KEEP) {
316                 new_tree->u.equality.attr = talloc_strdup(new_tree, tree->u.equality.attr);
317         } else { /* MAP_RENAME / MAP_CONVERT */
318                 new_tree->u.equality.attr = talloc_strdup(new_tree, attr->u.rename.remote_name);
319         }
320
321         if (new_tree->operation == LDB_OP_PRESENT) 
322                 return new_tree;
323                 
324         if (new_tree->operation == LDB_OP_SUBSTRING) {
325                 new_tree->u.substring.chunks = NULL; /* FIXME! */
326                 return new_tree;
327         }
328
329         if (map_type == MAP_CONVERT) {
330                 newvalue = attr->u.convert.convert_local(module, new_tree, &value);
331         } else {
332                 newvalue = ldb_val_dup(new_tree, &value);
333         }
334
335         if (new_tree->operation == LDB_OP_EQUALITY) {
336                 new_tree->u.equality.value = newvalue;
337         } else if (new_tree->operation == LDB_OP_LESS || new_tree->operation == LDB_OP_GREATER ||
338                            new_tree->operation == LDB_OP_APPROX) {
339                 new_tree->u.comparison.value = newvalue;
340         } else if (new_tree->operation == LDB_OP_EXTENDED) {
341                 new_tree->u.extended.value = newvalue;
342                 new_tree->u.extended.rule_id = talloc_strdup(new_tree, tree->u.extended.rule_id);
343         }
344         
345         return new_tree;
346 }
347
348 /* Remote DN -> Local DN */
349 static struct ldb_dn *map_remote_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_dn *dn)
350 {
351         struct ldb_dn *newdn;
352         int i;
353
354         if (dn == NULL)
355                 return NULL;
356
357         newdn = talloc_memdup(ctx, dn, sizeof(*dn));
358         if (!newdn) 
359                 return NULL;
360
361         newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); 
362
363         if (!newdn->components)
364                 return NULL;
365
366         /* For each rdn, map the attribute name and possibly the 
367          * complete rdn */
368         
369         for (i = 0; i < dn->comp_num; i++) {
370                 const struct ldb_map_attribute *attr = map_find_attr_remote(module->private_data, dn->components[i].name);
371                 enum ldb_map_attr_type map_type;
372
373                 /* Unknown attribute - leave this dn as is and hope the best... */
374                 if (!attr) map_type = MAP_KEEP;
375                 else map_type = attr->type;
376                         
377                 switch (map_type) { 
378                 case MAP_IGNORE:
379                 case MAP_GENERATE:
380                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Local MAP_IGNORE or MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name);
381                         talloc_free(newdn);
382                         return NULL;
383
384                 case MAP_KEEP:
385                         newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
386                         newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
387                         break;
388                         
389                 case MAP_CONVERT:
390                         newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
391                         newdn->components[i].value = attr->u.convert.convert_remote(module, ctx, &dn->components[i].value);
392                         break;
393                         
394                 case MAP_RENAME:
395                         newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
396                         newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
397                         break;
398                 }
399         }
400         return newdn;
401 }
402
403 /* Local DN -> Remote DN */
404 static struct ldb_dn *map_local_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_dn *dn)
405 {       
406         struct ldb_dn *newdn;
407         int i;
408
409         if (dn == NULL)
410                 return NULL;
411
412         newdn = talloc_memdup(ctx, dn, sizeof(*dn));
413         if (!newdn) 
414                 return NULL;
415
416         newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); 
417
418         if (!newdn->components)
419                 return NULL;
420
421         /* For each rdn, map the attribute name and possibly the 
422          * complete rdn using an equality convert_operator call */
423         
424         for (i = 0; i < dn->comp_num; i++) {
425                 const struct ldb_map_attribute *attr = map_find_attr_local(module->private_data, dn->components[i].name);
426                 enum ldb_map_attr_type map_type;
427
428                 /* Unknown attribute - leave this dn as is and hope the best... */
429                 if (!attr) map_type = MAP_KEEP; else map_type = attr->type;
430                 
431                 switch (map_type) 
432                 {
433                         case MAP_IGNORE: 
434                         case MAP_GENERATE:
435                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Local MAP_IGNORE/MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name);
436                         talloc_free(newdn);
437                         return NULL;
438
439                         case MAP_CONVERT: 
440                                 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.convert.remote_name);
441                                 newdn->components[i].value = attr->u.convert.convert_local(module, newdn->components, &dn->components[i].value);
442                         break;
443                         
444                         case MAP_RENAME:
445                                 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.rename.remote_name);
446                                 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
447                         break;
448
449                         case MAP_KEEP:
450                                 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
451                                 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
452                         continue;
453                 }
454         }
455
456         return newdn;
457 }
458
459 /* Loop over ldb_map_attribute array and add remote_names */
460 static const char **ldb_map_attrs(struct ldb_module *module, const char *const attrs[])
461 {
462         int i;
463         const char **ret;
464         int ar_size = 0, last_element = 0;
465         struct ldb_map_context *privdat = map_get_privdat(module);
466
467         if (attrs == NULL) 
468                 return NULL;
469
470         /* Start with good guess of number of elements */
471         for (i = 0; attrs[i]; i++);
472
473         ret = talloc_array(module, const char *, i);
474         ar_size = i;
475
476         for (i = 0; attrs[i]; i++) {
477                 int j;
478                 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
479                 enum ldb_map_attr_type map_type;
480
481                 if (!attr) {
482                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Local attribute '%s' does not have a definition!\n", attrs[i]);
483                         map_type = MAP_IGNORE;
484                 } else map_type = attr->type;
485
486                 switch (map_type)
487                 { 
488                         case MAP_IGNORE: break;
489                         case MAP_KEEP: 
490                                 if (last_element >= ar_size) {
491                                         ret = talloc_realloc(module, ret, const char *, ar_size+1);
492                                         ar_size++;
493                                 }
494                                 ret[last_element] = attr->local_name;
495                                 last_element++;
496                                 break;
497
498                         case MAP_RENAME:
499                         case MAP_CONVERT:
500                                 if (last_element >= ar_size) {
501                                         ret = talloc_realloc(module, ret, const char *, ar_size+1);
502                                         ar_size++;
503                                 }
504                                 ret[last_element] = attr->u.rename.remote_name;
505                                 last_element++;
506                                 break;
507
508                         case MAP_GENERATE:
509                                 /* Add remote_names[] for this attribute to the list of 
510                                  * attributes to request from the remote server */
511                                 for (j = 0; attr->u.generate.remote_names[j]; j++) {
512                                         if (last_element >= ar_size) {
513                                                 ret = talloc_realloc(module, ret, const char *, ar_size+1);
514                                                 ar_size++;
515                                         }
516                                         ret[last_element] = attr->u.generate.remote_names[j];                   
517                                         last_element++;
518                                 }
519                                 break;
520                 } 
521         }
522         
523         if (last_element >= ar_size) {
524                 ret = talloc_realloc(module, ret, const char *, ar_size+1);
525                 ar_size++;
526         }
527
528         ret[last_element] = NULL;
529
530         return ret;
531 }
532
533 static const char **available_local_attributes(struct ldb_module *module, const struct ldb_message *msg)
534 {
535         struct ldb_map_context *privdat = map_get_privdat(module);
536         int i, j;
537         int count = 0;
538         const char **ret = talloc_array(module, const char *, 1);
539
540         ret[0] = NULL;
541
542         for (i = 0; privdat->attribute_maps[i].local_name; i++) {
543                 int avail = 0;
544                 const struct ldb_map_attribute *attr = &privdat->attribute_maps[i];
545
546                 /* If all remote attributes for this attribute are present, add the 
547                  * local one to the list */
548                 
549                 switch (attr->type) {
550                 case MAP_IGNORE: break;
551                 case MAP_KEEP: 
552                                 avail = (ldb_msg_find_ldb_val(msg, attr->local_name) != NULL); 
553                                 break;
554                                 
555                 case MAP_RENAME:
556                 case MAP_CONVERT:
557                                 avail = (ldb_msg_find_ldb_val(msg, attr->u.rename.remote_name) != NULL);
558                                 break;
559
560                 case MAP_GENERATE:
561                                 avail = 1;
562                                 for (j = 0; attr->u.generate.remote_names[j]; j++) {
563                                         avail &= (ldb_msg_find_ldb_val(msg, attr->u.generate.remote_names[j]) != NULL);
564                                 }
565                                 break;
566                 }
567
568                 if (!avail)
569                         continue;
570
571                 ret = talloc_realloc(module, ret, const char *, count+2);
572                 ret[count] = attr->local_name;
573                 ret[count+1] = NULL;
574                 count++;
575         }
576
577         return ret;
578 }
579
580 /* Used for search */
581 static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, const char * const*attrs, const struct ldb_message *mi)
582 {
583         int i, j;
584         struct ldb_message *msg = talloc_zero(module, struct ldb_message);
585         struct ldb_message_element *elm, *oldelm;
586         struct ldb_map_context *privdat = map_get_privdat(module);
587         const char **newattrs = NULL;
588
589         msg->dn = map_remote_dn(module, module, mi->dn);
590
591         /* Loop over attrs, find in ldb_map_attribute array and 
592          * run generate() */
593
594         if (attrs == NULL) {
595                 /* Generate list of the local attributes that /can/ be generated
596                  * using the specific remote attributes */
597
598                 attrs = newattrs = available_local_attributes(module, mi);
599         }
600
601         for (i = 0; attrs[i]; i++) {
602                 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
603                 enum ldb_map_attr_type map_type;
604
605                 if (!attr) {
606                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s' when generating incoming message\n", attrs[i]);
607                         map_type = MAP_IGNORE;
608                 } else map_type = attr->type;
609
610                 switch (map_type) {
611                         case MAP_IGNORE:break;
612                         case MAP_RENAME:
613                                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Renaming remote attribute %s to %s", attr->u.rename.remote_name, attr->local_name);
614                                 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
615                                 if (!oldelm)
616                                         continue;
617
618                                 elm = talloc(msg, struct ldb_message_element);
619                                 elm->name = talloc_strdup(elm, attr->local_name);
620                                 elm->num_values = oldelm->num_values;
621                                 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
622                                 for (j = 0; j < oldelm->num_values; j++)
623                                         elm->values[j] = ldb_val_dup(elm, &oldelm->values[j]);
624
625                                 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
626                                 break;
627                                 
628                         case MAP_CONVERT:
629                                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Converting remote attribute %s to %s", attr->u.rename.remote_name, attr->local_name);
630                                 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
631                                 if (!oldelm) 
632                                         continue;
633
634                                 elm = talloc(msg, struct ldb_message_element);
635                                 elm->name = talloc_strdup(elm, attr->local_name);
636                                 elm->num_values = oldelm->num_values;
637                                 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
638
639                                 for (j = 0; j < oldelm->num_values; j++)
640                                         elm->values[j] = attr->u.convert.convert_remote(module, elm, &oldelm->values[j]);
641
642                                 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
643                                 break;
644
645                         case MAP_KEEP:
646                                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Keeping remote attribute %s", attr->local_name);
647                                 oldelm = ldb_msg_find_element(mi, attr->local_name);
648                                 if (!oldelm) continue;
649                                 
650                                 elm = talloc(msg, struct ldb_message_element);
651
652                                 elm->num_values = oldelm->num_values;
653                                 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
654                                 for (j = 0; j < oldelm->num_values; j++)
655                                         elm->values[j] = ldb_val_dup(elm, &oldelm->values[j]);
656
657                                 elm->name = talloc_strdup(elm, oldelm->name);
658
659                                 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
660                                 break;
661
662                         case MAP_GENERATE:
663                                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Generating local attribute %s", attr->local_name);
664                                 elm = attr->u.generate.generate_local(module, msg, attr->local_name, mi);
665                                 if (!elm) continue;
666
667                                 ldb_msg_add(module->ldb, msg, elm, elm->flags);
668                                 break;
669                         default: 
670                                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Unknown attr->type for %s", attr->local_name);
671                                 break;
672                 }
673         }
674
675         talloc_free(newattrs);
676
677         return msg;
678 }
679
680 /*
681   rename a record
682 */
683 static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
684 {
685         struct ldb_map_context *privdat = map_get_privdat(module);
686         struct ldb_dn *n_olddn, *n_newdn;
687         int fb_ret, mp_ret;
688
689         fb_ret = ldb_next_rename_record(module, olddn, newdn);
690         
691         if (fb_ret != -1) {
692                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record renamed");
693                 return fb_ret;
694         }
695         
696         n_olddn = map_local_dn(module, module, olddn);
697         n_newdn = map_local_dn(module, module, newdn);
698
699         mp_ret = ldb_rename(privdat->mapped_ldb, n_olddn, n_newdn);
700         if (mp_ret != -1) {
701                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Mapped record renamed");
702         }
703
704         ldb_next_rename_record(module, olddn, newdn);
705         
706         talloc_free(n_olddn);
707         talloc_free(n_newdn);
708         
709         return mp_ret;
710 }
711
712 /*
713   delete a record
714 */
715 static int map_delete(struct ldb_module *module, const struct ldb_dn *dn)
716 {
717         struct ldb_map_context *privdat = map_get_privdat(module);
718         struct ldb_dn *newdn;
719         int fb_ret, mp_ret;
720
721         fb_ret = ldb_next_delete_record(module, dn);
722         if (fb_ret != -1) {
723                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record deleted");
724                 return fb_ret;
725         }
726
727         newdn = map_local_dn(module, module, dn);
728
729         mp_ret = ldb_delete(privdat->mapped_ldb, newdn);
730         if (mp_ret != -1) {
731                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Mapped record deleted");
732         }
733
734         ldb_next_delete_record(module, newdn);
735
736         talloc_free(newdn);
737
738         return mp_ret;
739 }
740
741 /* search fallback database */
742 static int map_search_bytree_fb(struct ldb_module *module, const struct ldb_dn *base,
743                               enum ldb_scope scope, struct ldb_parse_tree *tree,
744                               const char * const *attrs, struct ldb_message ***res)
745 {
746         int ret;
747         struct ldb_parse_tree t_and, t_not, t_present, *childs[2];
748
749         t_present.operation = LDB_OP_PRESENT;
750         t_present.u.present.attr = talloc_strdup(NULL, "isMapped");
751
752         t_not.operation = LDB_OP_NOT;
753         t_not.u.isnot.child = &t_present;
754
755         childs[0] = &t_not;
756         childs[1] = tree;
757         t_and.operation = LDB_OP_AND;
758         t_and.u.list.num_elements = 2;
759         t_and.u.list.elements = childs;
760         
761         ret = ldb_next_search_bytree(module, base, scope, &t_and, attrs, res);
762
763         talloc_free(t_present.u.present.attr);
764
765         return ret;
766 }
767
768 /* Search in the database against which we are mapping */
769 static int map_search_bytree_mp(struct ldb_module *module, const struct ldb_dn *base,
770                               enum ldb_scope scope, struct ldb_parse_tree *tree,
771                               const char * const *attrs, struct ldb_message ***res)
772 {
773         struct ldb_parse_tree *new_tree;
774         struct ldb_dn *new_base;
775         struct ldb_message **newres;
776         const char **newattrs;
777         int mpret, ret;
778         struct ldb_map_context *privdat = map_get_privdat(module);
779         int i;
780
781         /*- search mapped database */
782
783         new_tree = ldb_map_parse_tree(module, module, tree);
784         if (new_tree == NULL) {
785                 /* All attributes used in the parse tree are 
786                  * local, apparently. Fall back to enumerating the complete remote 
787                  * database... Rather a slow search then no results. */
788                 new_tree = talloc_zero(module, struct ldb_parse_tree);
789                 new_tree->operation = LDB_OP_PRESENT;
790                 new_tree->u.present.attr = talloc_strdup(new_tree, "dn");
791                 return 0;
792         }
793                 
794         newattrs = ldb_map_attrs(module, attrs); 
795         new_base = map_local_dn(module, module, base);
796
797         mpret = ldb_search_bytree(privdat->mapped_ldb, new_base, scope, new_tree, newattrs, &newres);
798
799         talloc_free(new_base);
800         talloc_free(new_tree);
801         talloc_free(newattrs);
802
803         if (mpret == -1) {
804                 struct map_private *map_private = module->private_data;
805                 map_private->last_err_string = ldb_errstring(privdat->mapped_ldb);
806                 return -1;
807         }
808
809         /*
810          - per returned record, search fallback database for additional data (by dn)
811          - test if (full expression) is now true
812         */
813
814         *res = talloc_array(module, struct ldb_message *, mpret);
815
816         ret = 0;
817
818         for (i = 0; i < mpret; i++) {
819                 struct ldb_message *merged;
820                 struct ldb_message **extrares = NULL;
821                 int extraret;
822
823                 /* Always get special DN's from the fallback database */
824                 if (ldb_dn_is_special(newres[i]->dn))
825                         continue;
826
827                 merged = ldb_map_message_incoming(module, attrs, newres[i]);
828                 
829                 /* Merge with additional data from fallback database */
830                 extraret = ldb_next_search(module, merged->dn, LDB_SCOPE_BASE, "", NULL, &extrares);
831
832                 if (extraret == -1) {
833                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error searching for extra data!\n");
834                 } else if (extraret > 1) {
835                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "More than one result for extra data!\n");
836                         talloc_free(newres);
837                         return -1;
838                 } else if (extraret == 0) {
839                         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "No extra data found for remote DN: %s", ldb_dn_linearize(merged, merged->dn));
840                 }
841                 
842                 if (extraret == 1) {
843                         int j;
844                         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Extra data found for remote DN: %s", ldb_dn_linearize(merged, merged->dn));
845                         for (j = 0; j < extrares[0]->num_elements; j++) {
846                                 ldb_msg_add(module->ldb, merged, &(extrares[0]->elements[j]), extrares[0]->elements[j].flags);
847                         }
848                 }
849                 
850                 if (ldb_match_msg(module->ldb, merged, tree, base, scope) != 0) {
851                         (*res)[ret] = merged;
852                         ret++;
853                 } else {
854                         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Discarded merged message because it did not match");
855                 }
856         }
857
858         talloc_free(newres);
859
860         return ret;
861 }
862
863
864 /*
865   search for matching records using a ldb_parse_tree
866 */
867 static int map_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
868                               enum ldb_scope scope, struct ldb_parse_tree *tree,
869                               const char * const *attrs, struct ldb_message ***res)
870 {
871         struct ldb_message **fbres, **mpres;
872         int i;
873         int ret_fb, ret_mp;
874
875         ret_fb = map_search_bytree_fb(module, base, scope, tree, attrs, &fbres);
876         if (ret_fb == -1) 
877                 return -1;
878
879         /* special dn's are never mapped.. */
880         if (ldb_dn_is_special(base)) {
881                 *res = fbres;
882                 return ret_fb;
883         }
884
885         ret_mp = map_search_bytree_mp(module, base, scope, tree, attrs, &mpres);
886         if (ret_mp == -1) {
887                 return -1;
888         }
889
890         /* Merge results */
891         *res = talloc_array(module, struct ldb_message *, ret_fb + ret_mp);
892
893         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Merging %d mapped and %d fallback messages", ret_mp, ret_fb);
894
895         for (i = 0; i < ret_fb; i++) (*res)[i] = fbres[i];
896         for (i = 0; i < ret_mp; i++) (*res)[ret_fb+i] = mpres[i];
897
898         return ret_fb + ret_mp;
899 }
900 /*
901   search for matching records
902 */
903 static int map_search(struct ldb_module *module, const struct ldb_dn *base,
904                        enum ldb_scope scope, const char *expression,
905                        const char * const *attrs, struct ldb_message ***res)
906 {
907         struct map_private *map = module->private_data;
908         struct ldb_parse_tree *tree;
909         int ret;
910
911         tree = ldb_parse_tree(NULL, expression);
912         if (tree == NULL) {
913                 map->last_err_string = "expression parse failed";
914                 return -1;
915         }
916
917         ret = map_search_bytree(module, base, scope, tree, attrs, res);
918         talloc_free(tree);
919         return ret;
920 }
921
922 static int msg_contains_objectclass(const struct ldb_message *msg, const char *name)
923 {
924         struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
925         int i;
926         
927         for (i = 0; i < el->num_values; i++) {
928                 if (ldb_attr_cmp((char *)el->values[i].data, name) == 0) {
929                         return 1;
930                 }
931         }
932
933         return 0;
934 }
935
936 /*
937   add a record
938 */
939 static int map_add(struct ldb_module *module, const struct ldb_message *msg)
940 {
941         int ret;
942         struct ldb_map_context *privdat = map_get_privdat(module);
943         struct ldb_message *fb, *mp;
944         struct ldb_message_element *ocs;
945         int i;
946
947         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add");
948
949         if (ldb_dn_is_special(msg->dn)) {
950                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add: Added fallback record");
951                 return ldb_next_add_record(module, msg);
952         }
953
954         mp = talloc_zero(module, struct ldb_message);
955         mp->dn = map_local_dn(module, mp, msg->dn);
956
957         fb = talloc_zero(module, struct ldb_message);
958         fb->dn = talloc_reference(fb, msg->dn);
959
960         /* We add objectClass, so 'top' should be no problem */
961         ldb_msg_add_string(module->ldb, mp, "objectClass", "top");
962         
963         /* make a list of remote objectclasses that can be used 
964          *   given the attributes that are available and add to 
965          *   mp_msg */
966         for (i = 0; privdat->objectclass_maps[i].local_name; i++) {
967                 int j, has_musts, has_baseclasses;
968                 
969                 /* Add this objectClass to the list if all musts are present */
970                 for (j = 0; privdat->objectclass_maps[i].musts[j]; j++) {
971                         if (!map_msg_can_map_attr(module, msg, privdat->objectclass_maps[i].musts[j])) 
972                                 break;
973                 }
974
975                 has_musts = (privdat->objectclass_maps[i].musts[j] == NULL);
976
977                 /* Check if base classes are present as well */
978                 for (j = 0; privdat->objectclass_maps[i].base_classes[j]; j++) {
979                         if (!msg_contains_objectclass(mp, privdat->objectclass_maps[i].base_classes[j]))
980                                 break;
981                 }
982
983                 has_baseclasses = (privdat->objectclass_maps[i].base_classes[j] == NULL);
984                 
985                 /* Apparently, it contains all required elements */
986                 if (has_musts && has_baseclasses) {
987                         ldb_msg_add_string(module->ldb, mp, "objectClass", privdat->objectclass_maps[i].remote_name);   
988                 }
989         }
990
991         ocs = ldb_msg_find_element(mp, "objectClass");
992         if (ocs->num_values == 1) { /* Only top */
993                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add: Added fallback record");
994                 return ldb_next_add_record(module, msg);
995         }
996         
997         /*
998          * - try to map as much attributes as possible where allowed and add them to mp_msg
999          * - add other attributes to fb_msg
1000          */
1001         for (i = 0; i < msg->num_elements; i++) {
1002                 const struct ldb_map_attribute *attr;
1003                 struct ldb_message_element *elm;
1004                 enum ldb_map_attr_type map_type;
1005                 int j;
1006                 int mapped = 0;
1007
1008                 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0)
1009                         continue;
1010
1011                 attr = map_find_attr_local(privdat, msg->elements[i].name);
1012
1013                 if (!attr) {
1014                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Undefined local attribute '%s', ignoring\n", msg->elements[i].name);
1015                         map_type = MAP_IGNORE;
1016                 } else map_type = attr->type;
1017
1018                 /* Decide whether or not we need to map or fallback */
1019                 switch (map_type) {
1020                 case MAP_GENERATE:
1021                         attr->u.generate.generate_remote(module, attr->local_name, msg, mp, fb);
1022                         continue;
1023                 case MAP_KEEP:
1024                         mapped = map_msg_valid_attr(module, mp, attr->local_name);
1025                 case MAP_IGNORE: mapped = 0; break;
1026                 case MAP_CONVERT:
1027                 case MAP_RENAME: mapped = map_msg_valid_attr(module, mp, attr->u.rename.remote_name);
1028                         break;
1029                 }
1030
1031                 if (mapped) {
1032                         switch (map_type) {
1033                         case MAP_KEEP:
1034                                 elm = talloc(fb, struct ldb_message_element);
1035
1036                                 elm->num_values = msg->elements[i].num_values;
1037                                 elm->values = talloc_reference(elm, msg->elements[i].values);
1038                                 elm->name = talloc_strdup(elm, msg->elements[i].name);
1039                                 break;
1040
1041                         case MAP_RENAME:
1042                                 elm = talloc(mp, struct ldb_message_element);
1043
1044                                 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
1045                                 elm->num_values = msg->elements[i].num_values;
1046                                 elm->values = talloc_reference(elm, msg->elements[i].values);
1047                                 break;
1048
1049                         case MAP_CONVERT:
1050                                 elm = talloc(mp, struct ldb_message_element);
1051
1052                                 elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
1053                                 elm->num_values = msg->elements[i].num_values;
1054                                 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
1055
1056                                 for (j = 0; j < elm->num_values; j++) {
1057                                         elm->values[j] = attr->u.convert.convert_local(module, mp, &msg->elements[i].values[j]);
1058                                 }
1059
1060                                 mapped = map_msg_valid_attr(module, mp, attr->u.convert.remote_name);
1061
1062                                 break;
1063
1064                         case MAP_GENERATE:
1065                         case MAP_IGNORE:
1066                                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "This line should never be reached");
1067                                 break;
1068                         } 
1069                         ldb_msg_add(module->ldb, mp, elm, 0);
1070                 } else {
1071                         elm = talloc(fb, struct ldb_message_element);
1072
1073                         elm->num_values = msg->elements[i].num_values;
1074                         elm->values = talloc_reference(elm, msg->elements[i].values);
1075                         elm->name = talloc_strdup(elm, msg->elements[i].name);
1076
1077                         ldb_msg_add(module->ldb, fb, elm, 0);
1078                 }
1079         }
1080
1081         ret = ldb_add(privdat->mapped_ldb, mp);
1082         if (ret == -1) {
1083                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Adding mapped record failed: %s", ldb_errstring(privdat->mapped_ldb));
1084                 return -1;
1085         }
1086
1087         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add: Added mapped record");
1088
1089         ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
1090         ret = ldb_next_add_record(module, fb);
1091         if (ret == -1) {
1092                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Adding fallback record failed: %s", ldb_next_errstring(module));
1093                 return -1;
1094         }
1095
1096         talloc_free(fb);
1097         talloc_free(mp);
1098
1099         return ret;
1100 }
1101
1102
1103 /*
1104   modify a record
1105 */
1106 static int map_modify(struct ldb_module *module, const struct ldb_message *msg)
1107 {
1108         struct ldb_map_context *privdat = map_get_privdat(module);
1109         struct ldb_message *fb, *mp;
1110         struct ldb_message_element *elm;
1111         int fb_ret, mp_ret;
1112         int i,j;
1113
1114         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_modify");
1115
1116         if (ldb_dn_is_special(msg->dn))
1117                 return ldb_next_modify_record(module, msg);
1118
1119         fb = talloc_zero(module, struct ldb_message);
1120         fb->dn = talloc_reference(fb, msg->dn);
1121
1122         mp = talloc_zero(module, struct ldb_message);
1123         mp->dn = map_local_dn(module, mp, msg->dn);
1124
1125         /* Loop over mi and call generate_remote for each attribute */
1126         for (i = 0; i < msg->num_elements; i++) {
1127                 const struct ldb_map_attribute *attr;
1128                 enum ldb_map_attr_type map_type;
1129
1130                 if (ldb_attr_cmp(msg->elements[i].name, "isMapped") == 0)
1131                         continue;
1132
1133                 attr = map_find_attr_local(privdat, msg->elements[i].name);
1134
1135                 if (!attr) {
1136                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Undefined local attribute '%s', ignoring\n", msg->elements[i].name);
1137                         map_type = MAP_IGNORE;
1138                 } else map_type = attr->type;
1139         
1140                 switch (map_type) {
1141                 case MAP_IGNORE: /* Add to fallback message */
1142                         elm = talloc(fb, struct ldb_message_element);
1143
1144                         elm->num_values = msg->elements[i].num_values;
1145                         elm->values = talloc_reference(elm, msg->elements[i].values);
1146                         elm->name = talloc_strdup(elm, msg->elements[i].name);
1147                         
1148                         ldb_msg_add(module->ldb, fb, elm, msg->elements[i].flags);      
1149                         break;
1150                 case MAP_RENAME:
1151                         elm = talloc(mp, struct ldb_message_element);
1152
1153                         elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
1154                         elm->num_values = msg->elements[i].num_values;
1155                         elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
1156                         for (j = 0; j < elm->num_values; j++) {
1157                                 elm->values[j] = msg->elements[i].values[j];
1158                         }
1159
1160                         ldb_msg_add(module->ldb, mp, elm, msg->elements[i].flags);
1161                         break;
1162
1163                 case MAP_CONVERT:
1164                         elm = talloc(mp, struct ldb_message_element);
1165
1166                         elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
1167                         elm->num_values = msg->elements[i].num_values;
1168                         elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
1169                         
1170                         for (j = 0; j < elm->num_values; j++) {
1171                                 elm->values[j] = attr->u.convert.convert_local(module, mp, &msg->elements[i].values[j]);
1172                         }
1173
1174                         ldb_msg_add(module->ldb, mp, elm, msg->elements[i].flags);
1175                         break;
1176
1177                 case MAP_KEEP:
1178                         elm = talloc(mp, struct ldb_message_element);
1179
1180                         elm->num_values = msg->elements[i].num_values;
1181                         elm->values = talloc_reference(elm, msg->elements[i].values);
1182                         elm->name = talloc_strdup(elm, msg->elements[i].name);
1183                         
1184                         ldb_msg_add(module->ldb, mp, elm, msg->elements[i].flags);      
1185                         break;
1186
1187                 case MAP_GENERATE:
1188                         attr->u.generate.generate_remote(module, attr->local_name, msg, mp, fb);
1189                         break;
1190                 } 
1191         }
1192
1193         if (fb->num_elements > 0) {
1194                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Modifying fallback record with %d elements", fb->num_elements);
1195                 fb_ret = ldb_next_modify_record(module, fb);
1196                 if (fb_ret == -1) {
1197                         ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
1198                         fb_ret = ldb_next_add_record(module, fb);
1199                 }
1200         }
1201         talloc_free(fb);
1202
1203         if (mp->num_elements > 0) {
1204                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Modifying mapped record with %d elements", mp->num_elements);
1205                 mp_ret = ldb_modify(privdat->mapped_ldb, mp);
1206         }
1207         talloc_free(mp);
1208
1209         return (mp_ret == -1 || fb_ret == -1)?-1:0;
1210 }
1211
1212 static int map_lock(struct ldb_module *module, const char *lockname)
1213 {
1214         return ldb_next_named_lock(module, lockname);
1215 }
1216
1217 static int map_unlock(struct ldb_module *module, const char *lockname)
1218 {
1219         return ldb_next_named_unlock(module, lockname);
1220 }
1221
1222 /*
1223   return extended error information
1224 */
1225 static const char *map_errstring(struct ldb_module *module)
1226 {
1227         struct map_private *map = module->private_data;
1228         
1229         if (map->last_err_string)
1230                 return map->last_err_string;
1231
1232         return ldb_next_errstring(module);
1233 }
1234
1235 static const struct ldb_module_ops map_ops = {
1236         .name          = "map",
1237         .search        = map_search,
1238         .search_bytree = map_search_bytree,
1239         .add_record    = map_add,
1240         .modify_record = map_modify,
1241         .delete_record = map_delete,
1242         .rename_record = map_rename,
1243         .named_lock    = map_lock,
1244         .named_unlock  = map_unlock,
1245         .errstring     = map_errstring
1246 };
1247
1248 static char *map_find_url(struct ldb_context *ldb, const char *name)
1249 {
1250         const char * const attrs[] = { "@MAP_URL" , NULL};
1251         struct ldb_message **msg = NULL;
1252         struct ldb_dn *mods;
1253         char *url;
1254         int ret;
1255
1256         mods = ldb_dn_string_compose(ldb, NULL, "@MAP=%s", name);
1257         if (mods == NULL) {
1258                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Can't construct DN");
1259                 return NULL;
1260         }
1261
1262         ret = ldb_search(ldb, mods, LDB_SCOPE_BASE, "", attrs, &msg);
1263         talloc_free(mods);
1264         if (ret < 1) {
1265                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Not enough results found looking for @MAP");
1266                 return NULL;
1267         }
1268
1269         url = talloc_strdup(ldb, ldb_msg_find_string(msg[0], "@MAP_URL", NULL));
1270
1271         talloc_free(msg);
1272
1273         return url;
1274 }
1275
1276 /* the init function */
1277 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)
1278 {
1279         int i, j;
1280         struct ldb_module *ctx;
1281         struct map_private *data;
1282         char *url;
1283
1284         ctx = talloc(ldb, struct ldb_module);
1285         if (!ctx)
1286                 return NULL;
1287
1288         data = talloc(ctx, struct map_private);
1289         if (!data) {
1290                 talloc_free(ctx);
1291                 return NULL;
1292         }
1293
1294         data->context.mapped_ldb = ldb_init(data);
1295         ldb_set_debug(data->context.mapped_ldb, ldb->debug_ops.debug, ldb->debug_ops.context);
1296         url = map_find_url(ldb, name);
1297
1298         if (!url) {
1299                 ldb_debug(ldb, LDB_DEBUG_FATAL, "@MAP=%s not set!\n", name);
1300                 return NULL;
1301         }
1302
1303         if (ldb_connect(data->context.mapped_ldb, url, 0, NULL) != 0) {
1304                 ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to open mapped database for %s at '%s'\n", name, url);
1305                 return NULL;
1306         }
1307
1308         talloc_free(url);
1309
1310         data->last_err_string = NULL;
1311
1312         /* Get list of attribute maps */
1313         j = 0;
1314         data->context.attribute_maps = NULL;
1315
1316         for (i = 0; attrs[i].local_name; i++) {
1317                 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1318                 data->context.attribute_maps[j] = attrs[i];
1319                 j++;
1320         }
1321
1322         for (i = 0; builtin_attribute_maps[i].local_name; i++) {
1323                 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1324                 data->context.attribute_maps[j] = builtin_attribute_maps[i];
1325                 j++;
1326         }
1327
1328         data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1329         memset(&data->context.attribute_maps[j], 0, sizeof(struct ldb_map_attribute));
1330
1331         data->context.objectclass_maps = ocls;
1332         ctx->private_data = data;
1333         ctx->ldb = ldb;
1334         ctx->prev = ctx->next = NULL;
1335         ctx->ops = &map_ops;
1336
1337         return ctx;
1338 }
1339
1340 static struct ldb_val map_convert_local_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1341 {
1342         struct ldb_dn *dn, *newdn;
1343         struct ldb_val *newval;
1344
1345         dn = ldb_dn_explode(ctx, (char *)val->data);
1346
1347         newdn = map_local_dn(module, ctx, dn);
1348
1349         talloc_free(dn);
1350
1351         newval = talloc(ctx, struct ldb_val);
1352         newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1353         newval->length = strlen((char *)newval->data);
1354
1355         talloc_free(newdn);
1356
1357         return *newval;
1358 }
1359
1360 static struct ldb_val map_convert_remote_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1361 {
1362         struct ldb_dn *dn, *newdn;
1363         struct ldb_val *newval;
1364
1365         dn = ldb_dn_explode(ctx, (char *)val->data);
1366
1367         newdn = map_remote_dn(module, ctx, dn);
1368
1369         talloc_free(dn);
1370
1371         newval = talloc(ctx, struct ldb_val);
1372         newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1373         newval->length = strlen((char *)newval->data);
1374
1375         talloc_free(newdn);
1376
1377         return *newval;
1378 }
1379
1380 static struct ldb_val map_convert_local_objectclass(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1381 {
1382         int i;
1383         struct ldb_map_context *map = module->private_data;
1384
1385         for (i = 0; map->objectclass_maps[i].local_name; i++) {
1386                 if (!strcmp(map->objectclass_maps[i].local_name, (char *)val->data)) {
1387                         struct ldb_val newval;
1388                         newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].remote_name);
1389                         newval.length = strlen((char *)newval.data);
1390
1391                         return ldb_val_dup(ctx, &newval);
1392                 }
1393         }
1394
1395         return ldb_val_dup(ctx, val); 
1396 }
1397
1398 static struct ldb_val map_convert_remote_objectclass(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
1399 {
1400         int i;
1401         struct ldb_map_context *map = module->private_data;
1402
1403         for (i = 0; map->objectclass_maps[i].remote_name; i++) {
1404                 if (!strcmp(map->objectclass_maps[i].remote_name, (char *)val->data)) {
1405                         struct ldb_val newval;
1406                         newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].local_name);
1407                         newval.length = strlen((char *)newval.data);
1408
1409                         return ldb_val_dup(ctx, &newval);
1410                 }
1411         }
1412
1413         return ldb_val_dup(ctx, val); 
1414 }
1415