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