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