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