r9751: Remove C version of samba3dump (the EJS version works nicely as well).
[kai/samba.git] / source / lib / ldb / ldb_map / 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 "lib/ldb/include/ldb.h"
27 #include "lib/ldb/include/ldb_private.h"
28 #include "lib/ldb/ldb_map/ldb_map.h"
29
30 /* TODO:
31  *  - objectclass hint in ldb_map_attribute 
32  *     for use when multiple remote attributes (independant of each other)
33  *     map to one local attribute. E.g.: (uid, gidNumber) -> unixName
34  *     (use MAP_GENERATE instead ?) 
35  */
36
37 /*
38  - special attribute 'isMapped'
39  - add/modify
40         - split up ldb_message into fallback and mapped parts if is_mappable
41  - search: 
42         - search local one for not isMapped entries
43         - remove remote attributes from ldb_parse_tree
44         - search remote one
45          - per record, search local one for additional data (by dn)
46          - test if (full expression) is now true
47  - delete
48         - delete both
49  - rename
50         - rename locally and remotely
51 */
52
53 static const struct ldb_map_attribute builtin_attribute_maps[];
54
55 struct map_private {
56         struct ldb_map_context context;
57         const char *last_err_string;
58 };
59
60 static struct ldb_map_context *map_get_privdat(struct ldb_module *module)
61 {
62         return &((struct map_private *)module->private_data)->context;
63 }
64
65 static const struct ldb_map_objectclass *map_find_objectclass_local(struct ldb_map_context *privdat, const char *name)
66 {
67         int i;
68         for (i = 0; privdat->objectclass_maps[i].local_name; i++) {
69                 if (!ldb_attr_cmp(privdat->objectclass_maps[i].local_name, name))
70                         return &privdat->objectclass_maps[i];
71         }
72
73         return NULL;
74 }
75
76 /* Decide whether a add/modify should be pushed to the 
77  * remote LDAP server. We currently only do this if we see an objectClass we know */
78 static BOOL map_is_mappable(struct ldb_map_context *privdat, const struct ldb_message *msg)
79 {
80         int i;
81         struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
82
83         /* No objectClass... */
84         if (el == NULL) {
85                 return False;
86         }
87
88         for (i = 0; i < el->num_values; i++) {
89                 if (map_find_objectclass_local(privdat, (char *)el->values[i].data))
90                         return True;
91         }
92
93         return False;
94 }
95
96 /* find an attribute by the local name */
97 static const struct ldb_map_attribute *map_find_attr_local(struct ldb_map_context *privdat, const char *attr)
98 {
99         int i;
100
101         for (i = 0; privdat->attribute_maps[i].local_name; i++) {
102                 if (!ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr)) 
103                         return &privdat->attribute_maps[i];
104         }
105
106         return NULL;
107 }
108
109 /* find an attribute by the remote name */
110 static const struct ldb_map_attribute *map_find_attr_remote(struct ldb_map_context *privdat, const char *attr)
111 {
112         int i;
113
114         for (i = 0; privdat->attribute_maps[i].local_name; i++) {
115                 if (privdat->attribute_maps[i].type == MAP_IGNORE)
116                         continue;
117
118                 if (privdat->attribute_maps[i].type == MAP_GENERATE)
119                         continue;
120
121                 if (privdat->attribute_maps[i].type == MAP_KEEP &&
122                         ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr) == 0)
123                         return &privdat->attribute_maps[i];
124
125                 if ((privdat->attribute_maps[i].type == MAP_RENAME ||
126                         privdat->attribute_maps[i].type == MAP_CONVERT) &&
127                         ldb_attr_cmp(privdat->attribute_maps[i].u.rename.remote_name, attr) == 0) 
128                         return &privdat->attribute_maps[i];
129
130         }
131
132         return NULL;
133 }
134
135 static struct ldb_parse_tree *ldb_map_parse_tree(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_parse_tree *tree)
136 {
137         int i;
138         const struct ldb_map_attribute *attr;
139         struct ldb_parse_tree *new_tree;
140         enum ldb_map_attr_type map_type;
141         struct ldb_val value, newvalue;
142         struct ldb_map_context *privdat = map_get_privdat(module);
143
144         if (tree == NULL)
145                 return NULL;
146         
147
148         /* Find attr in question and:
149          *  - if it has a convert_operator function, run that
150          *  - otherwise, replace attr name with required[0] */
151
152         if (tree->operation == LDB_OP_AND || 
153                 tree->operation == LDB_OP_OR) {
154                 
155                 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
156                 new_tree->u.list.elements = talloc_array(new_tree, struct ldb_parse_tree *, tree->u.list.num_elements);
157                 new_tree->u.list.num_elements = 0;
158                 for (i = 0; i < tree->u.list.num_elements; i++) {
159                         struct ldb_parse_tree *child = ldb_map_parse_tree(module, new_tree, tree->u.list.elements[i]);
160                         
161                         if (child) {
162                                 new_tree->u.list.elements[i] = child;
163                                 new_tree->u.list.num_elements++;
164                         }
165                 }
166
167                 return new_tree;
168         }
169                 
170         if (tree->operation == LDB_OP_NOT) {
171                 struct ldb_parse_tree *child;
172                 
173                 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
174                 child = ldb_map_parse_tree(module, new_tree, tree->u.isnot.child);
175
176                 if (!child) {
177                         talloc_free(new_tree);
178                         return NULL;
179                 }
180
181                 new_tree->u.isnot.child = child;
182                 return new_tree;
183         }
184
185         /* tree->operation is LDB_OP_EQUALITY, LDB_OP_SUBSTRING, LDB_OP_GREATER,
186          * LDB_OP_LESS, LDB_OP_APPROX, LDB_OP_PRESENT or LDB_OP_EXTENDED
187          *
188          * (all have attr as the first element)
189          */
190
191         attr = map_find_attr_local(privdat, tree->u.equality.attr);
192
193         if (!attr) {
194                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s', leaving as is\n", tree->u.equality.attr);
195                 map_type = MAP_KEEP;
196         } else {
197                 map_type = attr->type;
198         }
199
200         if (attr && attr->convert_operator) {
201                 /* Run convert_operator */
202                 return attr->convert_operator(privdat, module, tree);
203         }
204
205         if (map_type == MAP_IGNORE) {
206                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Search on ignored attribute '%s'\n", tree->u.equality.attr);
207                 return NULL;
208         }
209
210         if (map_type == MAP_GENERATE) {
211                 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);
212                 return NULL;
213         }
214
215         if (tree->operation == LDB_OP_EQUALITY) {
216                 value = tree->u.equality.value;
217         } else if (tree->operation == LDB_OP_LESS || tree->operation == LDB_OP_GREATER ||
218                            tree->operation == LDB_OP_APPROX) {
219                 value = tree->u.comparison.value;
220         } else if (tree->operation == LDB_OP_EXTENDED) {
221                 value = tree->u.extended.value;
222         }
223         
224         new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
225
226         if (map_type == MAP_KEEP) {
227                 new_tree->u.equality.attr = talloc_strdup(new_tree, tree->u.equality.attr);
228         } else { /* MAP_RENAME / MAP_CONVERT */
229                 new_tree->u.equality.attr = talloc_strdup(new_tree, attr->u.rename.remote_name);
230         }
231
232         if (new_tree->operation == LDB_OP_PRESENT) 
233                 return new_tree;
234                 
235         if (new_tree->operation == LDB_OP_SUBSTRING) {
236                 new_tree->u.substring.chunks = NULL; /* FIXME! */
237                 return new_tree;
238         }
239
240         if (map_type == MAP_CONVERT) {
241                 newvalue = attr->u.convert.convert_local(privdat, new_tree, &value);
242         } else {
243                 newvalue = ldb_val_dup(new_tree, &value);
244         }
245
246         if (new_tree->operation == LDB_OP_EQUALITY) {
247                 new_tree->u.equality.value = newvalue;
248         } else if (new_tree->operation == LDB_OP_LESS || new_tree->operation == LDB_OP_GREATER ||
249                            new_tree->operation == LDB_OP_APPROX) {
250                 new_tree->u.comparison.value = newvalue;
251         } else if (new_tree->operation == LDB_OP_EXTENDED) {
252                 new_tree->u.extended.value = newvalue;
253                 new_tree->u.extended.rule_id = talloc_strdup(new_tree, tree->u.extended.rule_id);
254         }
255         
256         return new_tree;
257 }
258
259 /* Remote DN -> Local DN */
260 static struct ldb_dn *map_remote_dn(struct ldb_map_context *privdat, TALLOC_CTX *ctx, const struct ldb_dn *dn)
261 {
262         struct ldb_dn *newdn;
263         int i;
264
265         if (dn == NULL)
266                 return NULL;
267
268         newdn = talloc_memdup(ctx, dn, sizeof(*dn));
269         if (!newdn) 
270                 return NULL;
271
272         newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); 
273
274         if (!newdn->components)
275                 return NULL;
276
277         /* For each rdn, map the attribute name and possibly the 
278          * complete rdn */
279         
280         for (i = 0; i < dn->comp_num; i++) {
281                 const struct ldb_map_attribute *attr = map_find_attr_remote(privdat, dn->components[i].name);
282                 enum ldb_map_attr_type map_type;
283
284                 /* Unknown attribute - leave this dn as is and hope the best... */
285                 if (!attr) map_type = MAP_KEEP;
286                 else map_type = attr->type;
287                         
288                 switch (map_type) { 
289                 case MAP_IGNORE:
290                 case MAP_GENERATE:
291                         DEBUG(0, ("Local MAP_IGNORE or MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name));
292                         talloc_free(newdn);
293                         return NULL;
294
295                 case MAP_KEEP:
296                         newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
297                         newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
298                         break;
299                         
300                 case MAP_CONVERT:
301                         newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
302                         newdn->components[i].value = attr->u.convert.convert_remote(privdat, ctx, &dn->components[i].value);
303                         break;
304                         
305                 case MAP_RENAME:
306                         newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
307                         newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
308                         break;
309                 }
310         }
311         return newdn;
312 }
313
314 /* Local DN -> Remote DN */
315 static struct ldb_dn *map_local_dn(struct ldb_map_context *privdat, TALLOC_CTX *ctx, const struct ldb_dn *dn)
316 {       
317         struct ldb_dn *newdn;
318         int i;
319
320         if (dn == NULL)
321                 return NULL;
322
323         newdn = talloc_memdup(ctx, dn, sizeof(*dn));
324         if (!newdn) 
325                 return NULL;
326
327         newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); 
328
329         if (!newdn->components)
330                 return NULL;
331
332         /* For each rdn, map the attribute name and possibly the 
333          * complete rdn using an equality convert_operator call */
334         
335         for (i = 0; i < dn->comp_num; i++) {
336                 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, dn->components[i].name);
337                 enum ldb_map_attr_type map_type;
338
339                 /* Unknown attribute - leave this dn as is and hope the best... */
340                 if (!attr) map_type = MAP_KEEP; else map_type = attr->type;
341                 
342                 switch (map_type) 
343                 {
344                         case MAP_IGNORE: 
345                         case MAP_GENERATE:
346                         DEBUG(0, ("Local MAP_IGNORE/MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name));
347                         talloc_free(newdn);
348                         return NULL;
349
350                         case MAP_CONVERT: 
351                                 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.convert.remote_name);
352                                 newdn->components[i].value = attr->u.convert.convert_local(privdat, newdn->components, &dn->components[i].value);
353                         break;
354                         
355                         case MAP_RENAME:
356                                 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.rename.remote_name);
357                                 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
358                         break;
359
360                         case MAP_KEEP:
361                                 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
362                                 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
363                         continue;
364                 }
365         }
366
367         return newdn;
368 }
369
370 /* Loop over ldb_map_attribute array and add remote_names */
371 static const char **ldb_map_attrs(struct ldb_module *module, const char *const attrs[])
372 {
373         int i;
374         const char **ret;
375         int ar_size = 0, last_element = 0;
376         struct ldb_map_context *privdat = map_get_privdat(module);
377
378         if (attrs == NULL) 
379                 return NULL;
380
381         /* Start with good guess of number of elements */
382         for (i = 0; attrs[i]; i++);
383
384         ret = talloc_array(module, const char *, i);
385         ar_size = i;
386
387         for (i = 0; attrs[i]; i++) {
388                 int j;
389                 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
390                 enum ldb_map_attr_type map_type;
391
392                 if (!attr) {
393                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Local attribute '%s' does not have a definition!\n", attrs[i]);
394                         map_type = MAP_IGNORE;
395                 } else map_type = attr->type;
396
397                 switch (map_type)
398                 { 
399                         case MAP_IGNORE: break;
400                         case MAP_KEEP: 
401                                 if (last_element >= ar_size) {
402                                         ret = talloc_realloc(module, ret, const char *, ar_size+1);
403                                         ar_size++;
404                                 }
405                                 ret[last_element] = attr->local_name;
406                                 last_element++;
407                                 break;
408
409                         case MAP_RENAME:
410                         case MAP_CONVERT:
411                                 if (last_element >= ar_size) {
412                                         ret = talloc_realloc(module, ret, const char *, ar_size+1);
413                                         ar_size++;
414                                 }
415                                 ret[last_element] = attr->u.rename.remote_name;
416                                 last_element++;
417                                 break;
418
419                         case MAP_GENERATE:
420                                 /* Add remote_names[] for this attribute to the list of 
421                                  * attributes to request from the remote server */
422                                 for (j = 0; attr->u.generate.remote_names[j]; j++) {
423                                         if (last_element >= ar_size) {
424                                                 ret = talloc_realloc(module, ret, const char *, ar_size+1);
425                                                 ar_size++;
426                                         }
427                                         ret[last_element] = attr->u.generate.remote_names[j];                   
428                                         last_element++;
429                                 }
430                                 break;
431                 } 
432         }
433         
434         if (last_element >= ar_size) {
435                 ret = talloc_realloc(module, ret, const char *, ar_size+1);
436                 ar_size++;
437         }
438
439         ret[last_element] = NULL;
440
441         return ret;
442 }
443
444 static const char **available_local_attributes(struct ldb_module *module, const struct ldb_message *msg)
445 {
446         struct ldb_map_context *privdat = map_get_privdat(module);
447         int i, j;
448         int count = 0;
449         const char **ret = talloc_array(module, const char *, 1);
450
451         ret[0] = NULL;
452
453         for (i = 0; privdat->attribute_maps[i].local_name; i++) {
454                 BOOL avail = False;
455                 const struct ldb_map_attribute *attr = &privdat->attribute_maps[i];
456
457                 /* If all remote attributes for this attribute are present, add the 
458                  * local one to the list */
459                 
460                 switch (attr->type) {
461                 case MAP_IGNORE: break;
462                 case MAP_KEEP: 
463                                 avail = (ldb_msg_find_ldb_val(msg, attr->local_name) != NULL); 
464                                 break;
465                                 
466                 case MAP_RENAME:
467                 case MAP_CONVERT:
468                                 avail = (ldb_msg_find_ldb_val(msg, attr->u.rename.remote_name) != NULL);
469                                 break;
470
471                 case MAP_GENERATE:
472                                 avail = True;
473                                 for (j = 0; attr->u.generate.remote_names[j]; j++) {
474                                         avail &= (ldb_msg_find_ldb_val(msg, attr->u.generate.remote_names[j]) != NULL);
475                                 }
476                                 break;
477                 }
478
479                 if (!avail)
480                         continue;
481
482                 ret = talloc_realloc(module, ret, const char *, count+2);
483                 ret[count] = attr->local_name;
484                 ret[count+1] = NULL;
485                 count++;
486         }
487
488         return ret;
489 }
490
491 /* Used for search */
492 static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, const char * const*attrs, const struct ldb_message *mi)
493 {
494         int i, j;
495         struct ldb_message *msg = talloc_zero(module, struct ldb_message);
496         struct ldb_message_element *elm, *oldelm;
497         struct ldb_map_context *privdat = map_get_privdat(module);
498         const char **newattrs = NULL;
499
500         msg->dn = map_remote_dn(privdat, module, mi->dn);
501
502         ldb_msg_add_string(module->ldb, msg, "mappedFromDn", ldb_dn_linearize(msg, mi->dn));
503
504         /* Loop over attrs, find in ldb_map_attribute array and 
505          * run generate() */
506
507         if (attrs == NULL) {
508                 /* Generate list of the local attributes that /can/ be generated
509                  * using the specific remote attributes */
510
511                 attrs = newattrs = available_local_attributes(module, mi);
512         }
513
514         for (i = 0; attrs[i]; i++) {
515                 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
516                 enum ldb_map_attr_type map_type;
517
518                 if (!attr) {
519                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s' when generating incoming message\n", attrs[i]);
520                         map_type = MAP_IGNORE;
521                 } else map_type = attr->type;
522
523                 switch (map_type) {
524                         case MAP_IGNORE:break;
525                         case MAP_RENAME:
526                                 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
527                                 if (!oldelm) continue;
528
529                                 elm = talloc(msg, struct ldb_message_element);
530                                 elm->name = talloc_strdup(elm, attr->local_name);
531                                 elm->num_values = oldelm->num_values;
532                                 elm->values = talloc_reference(elm, oldelm->values);
533
534                                 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
535                                 break;
536                                 
537                         case MAP_CONVERT:
538                                 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
539                                 if (!oldelm) continue;
540
541                                 elm = talloc(msg, struct ldb_message_element);
542                                 elm->name = talloc_strdup(elm, attr->local_name);
543                                 elm->num_values = oldelm->num_values;
544                                 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
545
546                                 for (j = 0; j < oldelm->num_values; j++)
547                                         elm->values[j] = attr->u.convert.convert_remote(privdat, elm, &oldelm->values[j]);
548
549                                 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
550                                 break;
551
552                         case MAP_KEEP:
553                                 oldelm = ldb_msg_find_element(mi, attr->local_name);
554                                 if (!oldelm) continue;
555                                 
556                                 elm = talloc(msg, struct ldb_message_element);
557
558                                 elm->num_values = oldelm->num_values;
559                                 elm->values = talloc_reference(elm, oldelm->values);
560                                 elm->name = talloc_strdup(elm, oldelm->name);
561
562                                 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
563                                 break;
564
565                         case MAP_GENERATE:
566                                 elm = attr->u.generate.generate_local(privdat, msg, attr->local_name, mi);
567                                 if (!elm) continue;
568
569                                 ldb_msg_add(module->ldb, msg, elm, elm->flags);
570                                 break;
571                         default: 
572                                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Unknown attr->type for %s", attr->local_name);
573                                 break;
574                 }
575         }
576
577         talloc_free(newattrs);
578
579         return msg;
580 }
581
582 /* Used for add, modify */
583 static int ldb_map_message_outgoing(struct ldb_module *module, const struct ldb_message *mo, struct ldb_message **fb, struct ldb_message **mp)
584 {
585         struct ldb_map_context *privdat = map_get_privdat(module);
586         struct ldb_message *msg = talloc_zero(module, struct ldb_message);
587         struct ldb_message_element *elm;
588         int i,j;
589
590         *fb = talloc_zero(module, struct ldb_message);
591         (*fb)->dn = talloc_reference(*fb, mo->dn);
592
593         *mp = msg;
594
595         msg->private_data = mo->private_data;
596         
597         msg->dn = map_local_dn(privdat, module, mo->dn);
598
599         /* Loop over mi and call generate_remote for each attribute */
600         for (i = 0; i < mo->num_elements; i++) {
601                 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, mo->elements[i].name);
602                 enum ldb_map_attr_type map_type;
603
604                 if (!attr) {
605                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Undefined local attribute '%s', ignoring\n", mo->elements[i].name);
606                         map_type = MAP_IGNORE;
607                         continue;
608                 } else map_type = attr->type;
609
610                 switch (map_type) {
611                 case MAP_IGNORE: /* Add to fallback message */
612                         elm = talloc(*fb, struct ldb_message_element);
613
614                         elm->num_values = mo->elements[i].num_values;
615                         elm->values = talloc_reference(elm, mo->elements[i].values);
616                         elm->name = talloc_strdup(elm, mo->elements[i].name);
617                         
618                         ldb_msg_add(module->ldb, *fb, elm, mo->elements[i].flags);      
619                         break;
620                 case MAP_RENAME:
621                         elm = talloc(msg, struct ldb_message_element);
622
623                         elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
624                         elm->num_values = mo->elements[i].num_values;
625                         elm->values = talloc_reference(elm, mo->elements[i].values);
626
627                         ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags);
628                         break;
629
630                 case MAP_CONVERT:
631                         elm = talloc(msg, struct ldb_message_element);
632
633                         elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
634                         elm->num_values = mo->elements[i].num_values;
635                         elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
636                         
637                         for (j = 0; j < elm->num_values; j++) {
638                                 elm->values[j] = attr->u.convert.convert_local(privdat, msg, &mo->elements[i].values[j]);
639                         }
640
641                         ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags);
642                         break;
643
644                 case MAP_KEEP:
645                         elm = talloc(msg, struct ldb_message_element);
646
647                         elm->num_values = mo->elements[i].num_values;
648                         elm->values = talloc_reference(elm, mo->elements[i].values);
649                         elm->name = talloc_strdup(elm, mo->elements[i].name);
650                         
651                         ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags);      
652                         break;
653
654                 case MAP_GENERATE:
655                         attr->u.generate.generate_remote(privdat, attr->local_name, mo, msg);
656                         break;
657                 } 
658         }
659
660         return 0;
661 }
662
663
664 /*
665   rename a record
666 */
667 static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
668 {
669         struct ldb_map_context *privdat = map_get_privdat(module);
670         struct ldb_dn *n_olddn, *n_newdn;
671         int ret;
672
673         ret = ldb_next_rename_record(module, olddn, newdn);
674         
675         n_olddn = map_local_dn(privdat, module, olddn);
676         n_newdn = map_local_dn(privdat, module, newdn);
677
678         ret = ldb_rename(privdat->mapped_ldb, n_olddn, n_newdn);
679
680         talloc_free(n_olddn);
681         talloc_free(n_newdn);
682         
683         return ret;
684 }
685
686 /*
687   delete a record
688 */
689 static int map_delete(struct ldb_module *module, const struct ldb_dn *dn)
690 {
691         struct ldb_map_context *privdat = map_get_privdat(module);
692         struct ldb_dn *newdn;
693         int ret;
694
695         ret = ldb_next_delete_record(module, dn);
696         
697         newdn = map_local_dn(privdat, module, dn);
698
699         ret = ldb_delete(privdat->mapped_ldb, newdn);
700
701         talloc_free(newdn);
702
703         return ret;
704 }
705
706 /* search fallback database */
707 static int map_search_bytree_fb(struct ldb_module *module, const struct ldb_dn *base,
708                               enum ldb_scope scope, struct ldb_parse_tree *tree,
709                               const char * const *attrs, struct ldb_message ***res)
710 {
711         int ret;
712         struct ldb_parse_tree t_and, t_not, t_present, *childs[2];
713
714         t_present.operation = LDB_OP_PRESENT;
715         t_present.u.present.attr = talloc_strdup(NULL, "isMapped");
716
717         t_not.operation = LDB_OP_NOT;
718         t_not.u.isnot.child = &t_present;
719
720         childs[0] = &t_not;
721         childs[1] = tree;
722         t_and.operation = LDB_OP_AND;
723         t_and.u.list.num_elements = 2;
724         t_and.u.list.elements = childs;
725         
726         ret = ldb_next_search_bytree(module, base, scope, &t_and, attrs, res);
727
728         talloc_free(t_present.u.present.attr);
729
730         return ret;
731 }
732
733 static int map_search_bytree_mp(struct ldb_module *module, const struct ldb_dn *base,
734                               enum ldb_scope scope, struct ldb_parse_tree *tree,
735                               const char * const *attrs, struct ldb_message ***res)
736 {
737         struct ldb_parse_tree *new_tree;
738         struct ldb_dn *new_base;
739         struct ldb_message **newres;
740         const char **newattrs;
741         int mpret, ret;
742         struct ldb_map_context *privdat = map_get_privdat(module);
743         int i;
744
745         /*- search mapped database */
746
747         new_tree = ldb_map_parse_tree(module, module, tree);
748         newattrs = ldb_map_attrs(module, attrs); 
749         new_base = map_local_dn(privdat, module, base);
750
751         mpret = ldb_search_bytree(privdat->mapped_ldb, new_base, scope, new_tree, newattrs, &newres);
752
753         talloc_free(new_base);
754         talloc_free(new_tree);
755         talloc_free(newattrs);
756
757         /*
758          - per returned record, search local one for additional data (by dn)
759          - test if (full expression) is now true
760         */
761
762
763         *res = talloc_array(module, struct ldb_message *, mpret);
764
765         ret = 0;
766
767         for (i = 0; i < mpret; i++) {
768                 struct ldb_message *merged = ldb_map_message_incoming(module, attrs, newres[i]);
769                 struct ldb_message **extrares = NULL;
770                 int extraret;
771                 
772                 /* Merge with additional data from local database */
773                 extraret = ldb_next_search(module, merged->dn, LDB_SCOPE_BASE, "", NULL, &extrares);
774
775                 if (extraret == -1) {
776                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error searching for extra data!\n");
777                 } else if (extraret > 1) {
778                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "More then one result for extra data!\n");
779                         talloc_free(newres);
780                         return -1;
781                 } else if (extraret == 0) {
782                         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "No extra data found for remote DN");
783                 }
784                 
785                 if (extraret == 1) {
786                         int j;
787                         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Extra data found for remote DN");
788                         for (j = 0; j < extrares[0]->num_elements; j++) {
789                                 ldb_msg_add(module->ldb, merged, &(extrares[0]->elements[j]), extrares[0]->elements[j].flags);
790                         }
791
792                         ldb_msg_add_string(module->ldb, merged, "extraMapped", "TRUE");
793                 } else {
794                         ldb_msg_add_string(module->ldb, merged, "extraMapped", "FALSE");
795                 }
796                 
797                 if (ldb_match_msg(module->ldb, merged, tree, base, scope)) {
798                         (*res)[ret] = merged;
799                         ret++;
800                 } else {
801                         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Discarded merged message because it did not match");
802                 }
803         }
804
805         talloc_free(newres);
806
807         return ret;
808 }
809
810
811 /*
812   search for matching records using a ldb_parse_tree
813 */
814 static int map_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
815                               enum ldb_scope scope, struct ldb_parse_tree *tree,
816                               const char * const *attrs, struct ldb_message ***res)
817 {
818         struct ldb_message **fbres, **mpres;
819         int i;
820         int ret_fb, ret_mp;
821
822         ret_fb = map_search_bytree_fb(module, base, scope, tree, attrs, &fbres);
823         if (ret_fb == -1)
824                 return -1;
825
826         ret_mp = map_search_bytree_mp(module, base, scope, tree, attrs, &mpres);
827         if (ret_mp == -1)
828                 return -1;
829
830         /* Merge results */
831         *res = talloc_array(module, struct ldb_message *, ret_fb + ret_mp);
832
833         for (i = 0; i < ret_fb; i++) (*res)[i] = fbres[i];
834         for (i = 0; i < ret_mp; i++) (*res)[ret_fb+i] = mpres[i];
835
836         return ret_fb + ret_mp;
837 }
838 /*
839   search for matching records
840 */
841 static int map_search(struct ldb_module *module, const struct ldb_dn *base,
842                        enum ldb_scope scope, const char *expression,
843                        const char * const *attrs, struct ldb_message ***res)
844 {
845         struct map_private *map = module->private_data;
846         struct ldb_parse_tree *tree;
847         int ret;
848
849         tree = ldb_parse_tree(NULL, expression);
850         if (tree == NULL) {
851                 map->last_err_string = "expression parse failed";
852                 return -1;
853         }
854
855         ret = map_search_bytree(module, base, scope, tree, attrs, res);
856         talloc_free(tree);
857         return ret;
858 }
859
860 /*
861   add a record
862 */
863 static int map_add(struct ldb_module *module, const struct ldb_message *msg)
864 {
865         int ret;
866         struct ldb_map_context *privdat = map_get_privdat(module);
867         struct ldb_message *fb, *mp;
868
869         if (!map_is_mappable(privdat, msg)) {
870                 return ldb_next_add_record(module, msg);
871         }
872
873         if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1)
874                 return -1;
875                 
876         ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
877
878         ret = ldb_next_add_record(module, fb);
879         if (ret == -1) {
880                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding fallback record failed");
881                 return -1;
882         }
883                 
884         ret = ldb_add(privdat->mapped_ldb, mp);
885         if (ret == -1) {
886                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding mapped record failed");
887                 return -1;
888         }
889
890         talloc_free(fb);
891         talloc_free(mp);
892
893         return ret;
894 }
895
896
897 /*
898   modify a record
899 */
900 static int map_modify(struct ldb_module *module, const struct ldb_message *msg)
901 {
902         struct ldb_map_context *privdat = map_get_privdat(module);
903         struct ldb_message *fb, *mp;
904         int ret;
905
906         if (!map_is_mappable(privdat, msg))
907                 return ldb_next_modify_record(module, msg);
908                 
909
910         if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1)
911                 return -1;
912                 
913         ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
914
915         ret = ldb_next_modify_record(module, fb);
916
917         ret = ldb_modify(privdat->mapped_ldb, mp);
918
919         talloc_free(fb);
920         talloc_free(mp);
921
922         return ret;
923 }
924
925 static int map_lock(struct ldb_module *module, const char *lockname)
926 {
927         return ldb_next_named_lock(module, lockname);
928 }
929
930 static int map_unlock(struct ldb_module *module, const char *lockname)
931 {
932         return ldb_next_named_unlock(module, lockname);
933 }
934
935 /*
936   return extended error information
937 */
938 static const char *map_errstring(struct ldb_module *module)
939 {
940         struct map_private *map = module->private_data;
941         
942         if (map->last_err_string)
943                 return map->last_err_string;
944
945         return ldb_next_errstring(module);
946 }
947
948 static const struct ldb_module_ops map_ops = {
949         .name          = "map",
950         .search        = map_search,
951         .search_bytree = map_search_bytree,
952         .add_record    = map_add,
953         .modify_record = map_modify,
954         .delete_record = map_delete,
955         .rename_record = map_rename,
956         .named_lock    = map_lock,
957         .named_unlock  = map_unlock,
958         .errstring     = map_errstring
959 };
960
961 static char *map_find_url(struct ldb_context *ldb, const char *name)
962 {
963         const char * const attrs[] = { "@MAP_URL" , NULL};
964         struct ldb_message **msg = NULL;
965         struct ldb_dn *mods;
966         char *url;
967         int ret;
968
969         mods = ldb_dn_string_compose(ldb, NULL, "@MAP=%s", name);
970         if (mods == NULL) {
971                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Can't construct DN");
972                 return NULL;
973         }
974
975         ret = ldb_search(ldb, mods, LDB_SCOPE_BASE, "", attrs, &msg);
976         talloc_free(mods);
977         if (ret < 1) {
978                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Not enough results found looking for @MAP");
979                 return NULL;
980         }
981
982         url = talloc_strdup(ldb, ldb_msg_find_string(msg[0], "@MAP_URL", NULL));
983
984         talloc_free(msg);
985
986         return url;
987 }
988
989 /* the init function */
990 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)
991 {
992         int i, j;
993         struct ldb_module *ctx;
994         struct map_private *data;
995         char *url;
996
997         ctx = talloc(ldb, struct ldb_module);
998         if (!ctx)
999                 return NULL;
1000
1001         data = talloc(ctx, struct map_private);
1002         if (!data) {
1003                 talloc_free(ctx);
1004                 return NULL;
1005         }
1006
1007         data->context.mapped_ldb = ldb_init(data);
1008         url = map_find_url(ldb, name);
1009
1010         if (!url) {
1011                 ldb_debug(ldb, LDB_DEBUG_FATAL, "@MAP=%s not set!\n", name);
1012                 return NULL;
1013         }
1014
1015         if (ldb_connect(data->context.mapped_ldb, url, 0, NULL) != 0) {
1016                 ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to open mapped database for %s at '%s'\n", name, url);
1017                 return NULL;
1018         }
1019
1020         talloc_free(url);
1021
1022         data->last_err_string = NULL;
1023
1024         /* Get list of attribute maps */
1025         j = 0;
1026         data->context.attribute_maps = NULL;
1027
1028         for (i = 0; attrs[i].local_name; i++) {
1029                 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1030                 data->context.attribute_maps[j] = attrs[i];
1031                 j++;
1032         }
1033
1034         for (i = 0; builtin_attribute_maps[i].local_name; i++) {
1035                 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1036                 data->context.attribute_maps[j] = builtin_attribute_maps[i];
1037                 j++;
1038         }
1039
1040         data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1041         ZERO_STRUCT(data->context.attribute_maps[j].local_name);
1042
1043         data->context.objectclass_maps = ocls;
1044         ctx->private_data = data;
1045         ctx->ldb = ldb;
1046         ctx->prev = ctx->next = NULL;
1047         ctx->ops = &map_ops;
1048
1049         return ctx;
1050 }
1051
1052 static struct ldb_val map_convert_local_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1053 {
1054         struct ldb_dn *dn, *newdn;;
1055         struct ldb_val *newval;
1056
1057         dn = ldb_dn_explode(ctx, (char *)val->data);
1058
1059         newdn = map_local_dn(map, ctx, dn);
1060
1061         talloc_free(dn);
1062
1063         newval = talloc(ctx, struct ldb_val);
1064         newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1065         newval->length = strlen((char *)newval->data);
1066
1067         talloc_free(newdn);
1068
1069         return *newval;
1070 }
1071
1072 static struct ldb_val map_convert_remote_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1073 {
1074         struct ldb_dn *dn, *newdn;;
1075         struct ldb_val *newval;
1076
1077         dn = ldb_dn_explode(ctx, (char *)val->data);
1078
1079         newdn = map_remote_dn(map, ctx, dn);
1080
1081         talloc_free(dn);
1082
1083         newval = talloc(ctx, struct ldb_val);
1084         newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1085         newval->length = strlen((char *)newval->data);
1086
1087         talloc_free(newdn);
1088
1089         return *newval;
1090 }
1091
1092 static struct ldb_val map_convert_local_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1093 {
1094         int i;
1095
1096         for (i = 0; map->objectclass_maps[i].local_name; i++) {
1097                 if (!strcmp(map->objectclass_maps[i].local_name, (char *)val->data)) {
1098                         struct ldb_val newval;
1099                         newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].remote_name);
1100                         newval.length = strlen((char *)newval.data);
1101
1102                         return ldb_val_dup(ctx, &newval);
1103                 }
1104         }
1105
1106         return ldb_val_dup(ctx, val); 
1107 }
1108
1109 static struct ldb_val map_convert_remote_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1110 {
1111         int i;
1112
1113         for (i = 0; map->objectclass_maps[i].remote_name; i++) {
1114                 if (!strcmp(map->objectclass_maps[i].remote_name, (char *)val->data)) {
1115                         struct ldb_val newval;
1116                         newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].local_name);
1117                         newval.length = strlen((char *)newval.data);
1118
1119                         return ldb_val_dup(ctx, &newval);
1120                 }
1121         }
1122
1123         return ldb_val_dup(ctx, val); 
1124 }
1125
1126 static const struct ldb_map_attribute builtin_attribute_maps[] = {
1127         {
1128                 .local_name = "dn",
1129                 .type = MAP_CONVERT,
1130                 .u.convert.remote_name = "dn",
1131                 .u.convert.convert_local = map_convert_local_dn,
1132                 .u.convert.convert_remote = map_convert_remote_dn,
1133         },
1134         {
1135                 .local_name = "objectclass",
1136                 .type = MAP_CONVERT,
1137                 .u.convert.remote_name = "objectclass",
1138                 .u.convert.convert_local = map_convert_local_objectclass,
1139                 .u.convert.convert_remote = map_convert_remote_objectclass,
1140         },
1141         {
1142                 .local_name = NULL,
1143         }
1144 };
1145