r9785: Add some testdata
[sfrench/samba-autobuild/.git] / source4 / lib / ldb / modules / ldb_map.c
1 /* 
2    ldb database library - map backend
3
4    Copyright (C) Jelmer Vernooij 2005
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9    
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 2 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 #include "includes.h"
26 #include "lib/ldb/include/ldb.h"
27 #include "lib/ldb/include/ldb_private.h"
28 #include "lib/ldb/modules/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         if (mpret == -1) {
758                 struct map_private *map_private = module->private_data;
759                 map_private->last_err_string = ldb_errstring(privdat->mapped_ldb);
760                 return -1;
761         }
762
763         /*
764          - per returned record, search fallback database for additional data (by dn)
765          - test if (full expression) is now true
766         */
767
768         *res = talloc_array(module, struct ldb_message *, mpret);
769
770         ret = 0;
771
772         for (i = 0; i < mpret; i++) {
773                 struct ldb_message *merged = ldb_map_message_incoming(module, attrs, newres[i]);
774                 struct ldb_message **extrares = NULL;
775                 int extraret;
776                 
777                 /* Merge with additional data from local database */
778                 extraret = ldb_next_search(module, merged->dn, LDB_SCOPE_BASE, "", NULL, &extrares);
779
780                 if (extraret == -1) {
781                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error searching for extra data!\n");
782                 } else if (extraret > 1) {
783                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "More than one result for extra data!\n");
784                         talloc_free(newres);
785                         return -1;
786                 } else if (extraret == 0) {
787                         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "No extra data found for remote DN");
788                 }
789                 
790                 if (extraret == 1) {
791                         int j;
792                         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Extra data found for remote DN");
793                         for (j = 0; j < extrares[0]->num_elements; j++) {
794                                 ldb_msg_add(module->ldb, merged, &(extrares[0]->elements[j]), extrares[0]->elements[j].flags);
795                         }
796
797                         ldb_msg_add_string(module->ldb, merged, "extraMapped", "TRUE");
798                 } else {
799                         ldb_msg_add_string(module->ldb, merged, "extraMapped", "FALSE");
800                 }
801                 
802                 if (ldb_match_msg(module->ldb, merged, tree, base, scope)) {
803                         (*res)[ret] = merged;
804                         ret++;
805                 } else {
806                         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Discarded merged message because it did not match");
807                 }
808         }
809
810         talloc_free(newres);
811
812         return ret;
813 }
814
815
816 /*
817   search for matching records using a ldb_parse_tree
818 */
819 static int map_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
820                               enum ldb_scope scope, struct ldb_parse_tree *tree,
821                               const char * const *attrs, struct ldb_message ***res)
822 {
823         struct ldb_message **fbres, **mpres;
824         int i;
825         int ret_fb, ret_mp;
826
827         ret_fb = map_search_bytree_fb(module, base, scope, tree, attrs, &fbres);
828         if (ret_fb == -1) 
829                 return -1;
830
831         ret_mp = map_search_bytree_mp(module, base, scope, tree, attrs, &mpres);
832         if (ret_mp == -1) {
833                 return -1;
834         }
835
836         /* Merge results */
837         *res = talloc_array(module, struct ldb_message *, ret_fb + ret_mp);
838
839         for (i = 0; i < ret_fb; i++) (*res)[i] = fbres[i];
840         for (i = 0; i < ret_mp; i++) (*res)[ret_fb+i] = mpres[i];
841
842         return ret_fb + ret_mp;
843 }
844 /*
845   search for matching records
846 */
847 static int map_search(struct ldb_module *module, const struct ldb_dn *base,
848                        enum ldb_scope scope, const char *expression,
849                        const char * const *attrs, struct ldb_message ***res)
850 {
851         struct map_private *map = module->private_data;
852         struct ldb_parse_tree *tree;
853         int ret;
854
855         tree = ldb_parse_tree(NULL, expression);
856         if (tree == NULL) {
857                 map->last_err_string = "expression parse failed";
858                 return -1;
859         }
860
861         ret = map_search_bytree(module, base, scope, tree, attrs, res);
862         talloc_free(tree);
863         return ret;
864 }
865
866 /*
867   add a record
868 */
869 static int map_add(struct ldb_module *module, const struct ldb_message *msg)
870 {
871         int ret;
872         struct ldb_map_context *privdat = map_get_privdat(module);
873         struct ldb_message *fb, *mp;
874
875         if (!map_is_mappable(privdat, msg)) {
876                 return ldb_next_add_record(module, msg);
877         }
878
879         if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1)
880                 return -1;
881                 
882         ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
883
884         ret = ldb_next_add_record(module, fb);
885         if (ret == -1) {
886                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding fallback record failed");
887                 return -1;
888         }
889                 
890         ret = ldb_add(privdat->mapped_ldb, mp);
891         if (ret == -1) {
892                 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding mapped record failed");
893                 return -1;
894         }
895
896         talloc_free(fb);
897         talloc_free(mp);
898
899         return ret;
900 }
901
902
903 /*
904   modify a record
905 */
906 static int map_modify(struct ldb_module *module, const struct ldb_message *msg)
907 {
908         struct ldb_map_context *privdat = map_get_privdat(module);
909         struct ldb_message *fb, *mp;
910         int ret;
911
912         if (!map_is_mappable(privdat, msg))
913                 return ldb_next_modify_record(module, msg);
914                 
915
916         if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1)
917                 return -1;
918                 
919         ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
920
921         ret = ldb_next_modify_record(module, fb);
922
923         ret = ldb_modify(privdat->mapped_ldb, mp);
924
925         talloc_free(fb);
926         talloc_free(mp);
927
928         return ret;
929 }
930
931 static int map_lock(struct ldb_module *module, const char *lockname)
932 {
933         return ldb_next_named_lock(module, lockname);
934 }
935
936 static int map_unlock(struct ldb_module *module, const char *lockname)
937 {
938         return ldb_next_named_unlock(module, lockname);
939 }
940
941 /*
942   return extended error information
943 */
944 static const char *map_errstring(struct ldb_module *module)
945 {
946         struct map_private *map = module->private_data;
947         
948         if (map->last_err_string)
949                 return map->last_err_string;
950
951         return ldb_next_errstring(module);
952 }
953
954 static const struct ldb_module_ops map_ops = {
955         .name          = "map",
956         .search        = map_search,
957         .search_bytree = map_search_bytree,
958         .add_record    = map_add,
959         .modify_record = map_modify,
960         .delete_record = map_delete,
961         .rename_record = map_rename,
962         .named_lock    = map_lock,
963         .named_unlock  = map_unlock,
964         .errstring     = map_errstring
965 };
966
967 static char *map_find_url(struct ldb_context *ldb, const char *name)
968 {
969         const char * const attrs[] = { "@MAP_URL" , NULL};
970         struct ldb_message **msg = NULL;
971         struct ldb_dn *mods;
972         char *url;
973         int ret;
974
975         mods = ldb_dn_string_compose(ldb, NULL, "@MAP=%s", name);
976         if (mods == NULL) {
977                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Can't construct DN");
978                 return NULL;
979         }
980
981         ret = ldb_search(ldb, mods, LDB_SCOPE_BASE, "", attrs, &msg);
982         talloc_free(mods);
983         if (ret < 1) {
984                 ldb_debug(ldb, LDB_DEBUG_ERROR, "Not enough results found looking for @MAP");
985                 return NULL;
986         }
987
988         url = talloc_strdup(ldb, ldb_msg_find_string(msg[0], "@MAP_URL", NULL));
989
990         talloc_free(msg);
991
992         return url;
993 }
994
995 /* the init function */
996 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)
997 {
998         int i, j;
999         struct ldb_module *ctx;
1000         struct map_private *data;
1001         char *url;
1002
1003         ctx = talloc(ldb, struct ldb_module);
1004         if (!ctx)
1005                 return NULL;
1006
1007         data = talloc(ctx, struct map_private);
1008         if (!data) {
1009                 talloc_free(ctx);
1010                 return NULL;
1011         }
1012
1013         data->context.mapped_ldb = ldb_init(data);
1014         url = map_find_url(ldb, name);
1015
1016         if (!url) {
1017                 ldb_debug(ldb, LDB_DEBUG_FATAL, "@MAP=%s not set!\n", name);
1018                 return NULL;
1019         }
1020
1021         if (ldb_connect(data->context.mapped_ldb, url, 0, NULL) != 0) {
1022                 ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to open mapped database for %s at '%s'\n", name, url);
1023                 return NULL;
1024         }
1025
1026         talloc_free(url);
1027
1028         data->last_err_string = NULL;
1029
1030         /* Get list of attribute maps */
1031         j = 0;
1032         data->context.attribute_maps = NULL;
1033
1034         for (i = 0; attrs[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] = attrs[i];
1037                 j++;
1038         }
1039
1040         for (i = 0; builtin_attribute_maps[i].local_name; i++) {
1041                 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1042                 data->context.attribute_maps[j] = builtin_attribute_maps[i];
1043                 j++;
1044         }
1045
1046         data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
1047         ZERO_STRUCT(data->context.attribute_maps[j].local_name);
1048
1049         data->context.objectclass_maps = ocls;
1050         ctx->private_data = data;
1051         ctx->ldb = ldb;
1052         ctx->prev = ctx->next = NULL;
1053         ctx->ops = &map_ops;
1054
1055         return ctx;
1056 }
1057
1058 static struct ldb_val map_convert_local_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1059 {
1060         struct ldb_dn *dn, *newdn;;
1061         struct ldb_val *newval;
1062
1063         dn = ldb_dn_explode(ctx, (char *)val->data);
1064
1065         newdn = map_local_dn(map, ctx, dn);
1066
1067         talloc_free(dn);
1068
1069         newval = talloc(ctx, struct ldb_val);
1070         newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1071         newval->length = strlen((char *)newval->data);
1072
1073         talloc_free(newdn);
1074
1075         return *newval;
1076 }
1077
1078 static struct ldb_val map_convert_remote_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1079 {
1080         struct ldb_dn *dn, *newdn;;
1081         struct ldb_val *newval;
1082
1083         dn = ldb_dn_explode(ctx, (char *)val->data);
1084
1085         newdn = map_remote_dn(map, ctx, dn);
1086
1087         talloc_free(dn);
1088
1089         newval = talloc(ctx, struct ldb_val);
1090         newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
1091         newval->length = strlen((char *)newval->data);
1092
1093         talloc_free(newdn);
1094
1095         return *newval;
1096 }
1097
1098 static struct ldb_val map_convert_local_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1099 {
1100         int i;
1101
1102         for (i = 0; map->objectclass_maps[i].local_name; i++) {
1103                 if (!strcmp(map->objectclass_maps[i].local_name, (char *)val->data)) {
1104                         struct ldb_val newval;
1105                         newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].remote_name);
1106                         newval.length = strlen((char *)newval.data);
1107
1108                         return ldb_val_dup(ctx, &newval);
1109                 }
1110         }
1111
1112         return ldb_val_dup(ctx, val); 
1113 }
1114
1115 static struct ldb_val map_convert_remote_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
1116 {
1117         int i;
1118
1119         for (i = 0; map->objectclass_maps[i].remote_name; i++) {
1120                 if (!strcmp(map->objectclass_maps[i].remote_name, (char *)val->data)) {
1121                         struct ldb_val newval;
1122                         newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].local_name);
1123                         newval.length = strlen((char *)newval.data);
1124
1125                         return ldb_val_dup(ctx, &newval);
1126                 }
1127         }
1128
1129         return ldb_val_dup(ctx, val); 
1130 }
1131
1132 static const struct ldb_map_attribute builtin_attribute_maps[] = {
1133         {
1134                 .local_name = "dn",
1135                 .type = MAP_CONVERT,
1136                 .u.convert.remote_name = "dn",
1137                 .u.convert.convert_local = map_convert_local_dn,
1138                 .u.convert.convert_remote = map_convert_remote_dn,
1139         },
1140         {
1141                 .local_name = "objectclass",
1142                 .type = MAP_CONVERT,
1143                 .u.convert.remote_name = "objectclass",
1144                 .u.convert.convert_local = map_convert_local_objectclass,
1145                 .u.convert.convert_remote = map_convert_remote_objectclass,
1146         },
1147         {
1148                 .local_name = NULL,
1149         }
1150 };
1151