r9718: Work a bit on the SWAT interface
[kai/samba.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 static const struct ldb_map_attribute builtin_attribute_maps[];
38
39 struct map_private {
40         struct ldb_map_context context;
41         const char *last_err_string;
42 };
43
44
45 /* find an attribute by the local name */
46 static const struct ldb_map_attribute *map_find_attr_local(struct ldb_map_context *privdat, const char *attr)
47 {
48         int i;
49
50         for (i = 0; privdat->attribute_maps[i].local_name; i++) {
51                 if (!ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr)) 
52                         return &privdat->attribute_maps[i];
53         }
54
55         return NULL;
56 }
57
58 /* find an attribute by the remote name */
59 static const struct ldb_map_attribute *map_find_attr_remote(struct ldb_map_context *privdat, const char *attr)
60 {
61         int i;
62
63         for (i = 0; privdat->attribute_maps[i].local_name; i++) {
64                 if (privdat->attribute_maps[i].type == MAP_IGNORE)
65                         continue;
66
67                 if (privdat->attribute_maps[i].type == MAP_GENERATE)
68                         continue;
69
70                 if (privdat->attribute_maps[i].type == MAP_KEEP &&
71                         ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr) == 0)
72                         return &privdat->attribute_maps[i];
73
74                 if ((privdat->attribute_maps[i].type == MAP_RENAME ||
75                         privdat->attribute_maps[i].type == MAP_CONVERT) &&
76                         ldb_attr_cmp(privdat->attribute_maps[i].u.rename.remote_name, attr) == 0) 
77                         return &privdat->attribute_maps[i];
78
79         }
80
81         return NULL;
82 }
83
84 static struct ldb_parse_tree *ldb_map_parse_tree(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_parse_tree *tree)
85 {
86         int i;
87         const struct ldb_map_attribute *attr;
88         struct ldb_parse_tree *new_tree;
89         enum ldb_map_attr_type map_type;
90         struct ldb_val value, newvalue;
91         struct ldb_map_context *privdat = &((struct map_private *)module->private_data)->context;
92
93         if (tree == NULL)
94                 return NULL;
95         
96
97         /* Find attr in question and:
98          *  - if it has a convert_operator function, run that
99          *  - otherwise, replace attr name with required[0] */
100
101         if (tree->operation == LDB_OP_AND || 
102                 tree->operation == LDB_OP_OR) {
103                 
104                 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
105                 new_tree->u.list.elements = talloc_array(new_tree, struct ldb_parse_tree *, tree->u.list.num_elements);
106                 for (i = 0; i < new_tree->u.list.num_elements; i++) {
107                         new_tree->u.list.elements[i] = ldb_map_parse_tree(module, new_tree, tree->u.list.elements[i]);
108                 }
109
110                 return new_tree;
111         }
112                 
113         if (tree->operation == LDB_OP_NOT) {
114                 new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
115                 new_tree->u.isnot.child = ldb_map_parse_tree(module, new_tree, tree->u.isnot.child);
116                 return new_tree;
117         }
118
119         /* tree->operation is LDB_OP_EQUALITY, LDB_OP_SUBSTRING, LDB_OP_GREATER,
120          * LDB_OP_LESS, LDB_OP_APPROX, LDB_OP_PRESENT or LDB_OP_EXTENDED
121          *
122          * (all have attr as the first element)
123          */
124
125         attr = map_find_attr_local(privdat, tree->u.equality.attr);
126
127         if (!attr) {
128                 DEBUG(0, ("Unable to find local attribute '%s', leaving as is\n", tree->u.equality.attr));
129                 map_type = MAP_KEEP;
130         } else {
131                 map_type = attr->type;
132         }
133
134         if (attr && attr->convert_operator) {
135                 /* Run convert_operator */
136                 return attr->convert_operator(privdat, module, tree);
137         }
138
139         if (map_type == MAP_IGNORE) {
140                 DEBUG(0, ("Search on ignored attribute '%s'!\n", tree->u.equality.attr));
141                 return NULL;
142         }
143
144         if (map_type == MAP_GENERATE) {
145                 DEBUG(0, ("Can't do conversion for MAP_GENERATE in map_parse_tree without convert_operator for '%s'\n", tree->u.equality.attr));
146                 return NULL;
147         }
148
149         if (tree->operation == LDB_OP_EQUALITY) {
150                 value = tree->u.equality.value;
151         } else if (tree->operation == LDB_OP_LESS || tree->operation == LDB_OP_GREATER ||
152                            tree->operation == LDB_OP_APPROX) {
153                 value = tree->u.comparison.value;
154         } else if (tree->operation == LDB_OP_EXTENDED) {
155                 value = tree->u.extended.value;
156         }
157         
158         new_tree = talloc_memdup(ctx, tree, sizeof(*tree));
159
160         if (map_type == MAP_KEEP) {
161                 new_tree->u.equality.attr = talloc_strdup(new_tree, tree->u.equality.attr);
162         } else { /* MAP_RENAME / MAP_CONVERT */
163                 new_tree->u.equality.attr = talloc_strdup(new_tree, attr->u.rename.remote_name);
164         }
165
166         if (new_tree->operation == LDB_OP_PRESENT) 
167                 return new_tree;
168                 
169         if (new_tree->operation == LDB_OP_SUBSTRING) {
170                 new_tree->u.substring.chunks = NULL; /* FIXME! */
171                 return new_tree;
172         }
173
174         if (map_type == MAP_CONVERT) {
175                 newvalue = attr->u.convert.convert_local(privdat, new_tree, &value);
176         } else {
177                 newvalue = ldb_val_dup(new_tree, &value);
178         }
179
180         if (new_tree->operation == LDB_OP_EQUALITY) {
181                 new_tree->u.equality.value = newvalue;
182         } else if (new_tree->operation == LDB_OP_LESS || new_tree->operation == LDB_OP_GREATER ||
183                            new_tree->operation == LDB_OP_APPROX) {
184                 new_tree->u.comparison.value = newvalue;
185         } else if (new_tree->operation == LDB_OP_EXTENDED) {
186                 new_tree->u.extended.value = newvalue;
187                 new_tree->u.extended.rule_id = talloc_strdup(new_tree, tree->u.extended.rule_id);
188         }
189         
190         return new_tree;
191 }
192
193 /* Remote DN -> Local DN */
194 static struct ldb_dn *map_remote_dn(struct ldb_map_context *privdat, TALLOC_CTX *ctx, const struct ldb_dn *dn)
195 {
196         struct ldb_dn *newdn;
197         int i;
198
199         if (dn == NULL)
200                 return NULL;
201
202         newdn = talloc_memdup(ctx, dn, sizeof(*dn));
203         if (!newdn) 
204                 return NULL;
205
206         newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); 
207
208         if (!newdn->components)
209                 return NULL;
210
211         /* For each rdn, map the attribute name and possibly the 
212          * complete rdn */
213         
214         for (i = 0; i < dn->comp_num; i++) {
215                 const struct ldb_map_attribute *attr = map_find_attr_remote(privdat, dn->components[i].name);
216                 enum ldb_map_attr_type map_type;
217
218                 /* Unknown attribute - leave this dn as is and hope the best... */
219                 if (!attr) map_type = MAP_KEEP;
220                 else map_type = attr->type;
221                         
222                 switch (map_type) { 
223                 case MAP_IGNORE:
224                 case MAP_GENERATE:
225                         DEBUG(0, ("Local MAP_IGNORE or MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name));
226                         talloc_free(newdn);
227                         return NULL;
228
229                 case MAP_KEEP:
230                         newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
231                         newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
232                         break;
233                         
234                 case MAP_CONVERT:
235                         newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
236                         newdn->components[i].value = attr->u.convert.convert_remote(privdat, ctx, &dn->components[i].value);
237                         break;
238                         
239                 case MAP_RENAME:
240                         newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name);
241                         newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
242                         break;
243                 }
244         }
245         return newdn;
246 }
247
248 /* Local DN -> Remote DN */
249 static struct ldb_dn *map_local_dn(struct ldb_map_context *privdat, TALLOC_CTX *ctx, const struct ldb_dn *dn)
250 {       
251         struct ldb_dn *newdn;
252         int i;
253
254         if (dn == NULL)
255                 return NULL;
256
257         newdn = talloc_memdup(ctx, dn, sizeof(*dn));
258         if (!newdn) 
259                 return NULL;
260
261         newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); 
262
263         if (!newdn->components)
264                 return NULL;
265
266         /* For each rdn, map the attribute name and possibly the 
267          * complete rdn using an equality convert_operator call */
268         
269         for (i = 0; i < dn->comp_num; i++) {
270                 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, dn->components[i].name);
271                 enum ldb_map_attr_type map_type;
272
273                 /* Unknown attribute - leave this dn as is and hope the best... */
274                 if (!attr) map_type = MAP_KEEP; else map_type = attr->type;
275                 
276                 switch (map_type) 
277                 {
278                         case MAP_IGNORE: 
279                         case MAP_GENERATE:
280                         DEBUG(0, ("Local MAP_IGNORE/MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name));
281                         talloc_free(newdn);
282                         return NULL;
283
284                         case MAP_CONVERT: 
285                                 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.convert.remote_name);
286                                 newdn->components[i].value = attr->u.convert.convert_local(privdat, newdn->components, &dn->components[i].value);
287                         break;
288                         
289                         case MAP_RENAME:
290                                 newdn->components[i].name = talloc_strdup(newdn->components, attr->u.rename.remote_name);
291                                 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
292                         break;
293
294                         case MAP_KEEP:
295                                 newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name);
296                                 newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value);
297                         continue;
298                 }
299         }
300
301         return newdn;
302 }
303
304 /* Loop over ldb_map_attribute array and add remote_names */
305 static const char **ldb_map_attrs(struct ldb_module *module, const char *const attrs[])
306 {
307         int i;
308         const char **ret;
309         int ar_size = 0, last_element = 0;
310         struct ldb_map_context *privdat = &((struct map_private *)module->private_data)->context;
311
312         if (attrs == NULL) 
313                 return NULL;
314
315         /* Start with good guess of number of elements */
316         for (i = 0; attrs[i]; i++);
317
318         ret = talloc_array(module, const char *, i);
319         ar_size = i;
320
321         for (i = 0; attrs[i]; i++) {
322                 int j;
323                 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
324                 enum ldb_map_attr_type map_type;
325
326                 if (!attr) {
327                         DEBUG(0, ("Local attribute '%s' does not have a definition!\n", attrs[i]));
328                         map_type = MAP_IGNORE;
329                 } else map_type = attr->type;
330
331                 switch (map_type)
332                 { 
333                         case MAP_IGNORE: break;
334                         case MAP_KEEP: 
335                                 if (last_element >= ar_size) {
336                                         ret = talloc_realloc(module, ret, const char *, ar_size+1);
337                                         ar_size++;
338                                 }
339                                 ret[last_element] = attr->local_name;
340                                 last_element++;
341                                 break;
342
343                         case MAP_RENAME:
344                         case MAP_CONVERT:
345                                 if (last_element >= ar_size) {
346                                         ret = talloc_realloc(module, ret, const char *, ar_size+1);
347                                         ar_size++;
348                                 }
349                                 ret[last_element] = attr->u.rename.remote_name;
350                                 last_element++;
351                                 break;
352
353                         case MAP_GENERATE:
354                                 /* Add remote_names[] for this attribute to the list of 
355                                  * attributes to request from the remote server */
356                                 for (j = 0; attr->u.generate.remote_names[j]; j++) {
357                                         if (last_element >= ar_size) {
358                                                 ret = talloc_realloc(module, ret, const char *, ar_size+1);
359                                                 ar_size++;
360                                         }
361                                         ret[last_element] = attr->u.generate.remote_names[j];                   
362                                         last_element++;
363                                 }
364                                 break;
365                 } 
366         }
367         
368         if (last_element >= ar_size) {
369                 ret = talloc_realloc(module, ret, const char *, ar_size+1);
370                 ar_size++;
371         }
372
373         ret[last_element] = NULL;
374
375         return ret;
376 }
377
378 static const char **available_local_attributes(struct ldb_module *module, const struct ldb_message *msg)
379 {
380         struct ldb_map_context *privdat = &((struct map_private *)module->private_data)->context;
381         int i, j;
382         int count = 0;
383         const char **ret = talloc_array(module, const char *, 1);
384
385         ret[0] = NULL;
386
387         for (i = 0; privdat->attribute_maps[i].local_name; i++) {
388                 BOOL avail = False;
389                 const struct ldb_map_attribute *attr = &privdat->attribute_maps[i];
390
391                 /* If all remote attributes for this attribute are present, add the 
392                  * local one to the list */
393                 
394                 switch (attr->type) {
395                 case MAP_IGNORE: break;
396                 case MAP_KEEP: 
397                                 avail = (ldb_msg_find_ldb_val(msg, attr->local_name) != NULL); 
398                                 break;
399                                 
400                 case MAP_RENAME:
401                 case MAP_CONVERT:
402                                 avail = (ldb_msg_find_ldb_val(msg, attr->u.rename.remote_name) != NULL);
403                                 break;
404
405                 case MAP_GENERATE:
406                                 avail = True;
407                                 for (j = 0; attr->u.generate.remote_names[j]; j++) {
408                                         avail &= (ldb_msg_find_ldb_val(msg, attr->u.generate.remote_names[j]) != NULL);
409                                 }
410                                 break;
411                 }
412
413                 if (!avail)
414                         continue;
415
416                 ret = talloc_realloc(module, ret, const char *, count+2);
417                 ret[count] = attr->local_name;
418                 ret[count+1] = NULL;
419                 count++;
420         }
421
422         return ret;
423 }
424
425 /* Used for search */
426 static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, const char * const*attrs, const struct ldb_message *mi)
427 {
428         int i, j;
429         struct ldb_message *msg = talloc_zero(module, struct ldb_message);
430         struct ldb_message_element *elm, *oldelm;
431         struct ldb_map_context *privdat = &((struct map_private *)module->private_data)->context;
432         const char **newattrs = NULL;
433
434         msg->dn = map_remote_dn(privdat, module, mi->dn);
435
436         /* Loop over attrs, find in ldb_map_attribute array and 
437          * run generate() */
438
439         if (attrs == NULL) {
440                 /* Generate list of the local attributes that /can/ be generated
441                  * using the specific remote attributes */
442
443                 attrs = newattrs = available_local_attributes(module, mi);
444         }
445
446         for (i = 0; attrs[i]; i++) {
447                 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]);
448                 enum ldb_map_attr_type map_type;
449
450                 if (!attr) {
451                         DEBUG(0, ("Unable to find local attribute '%s' when generating incoming message\n", attrs[i]));
452                         map_type = MAP_IGNORE;
453                 } else map_type = attr->type;
454
455                 switch (map_type) {
456                         case MAP_IGNORE:break;
457                         case MAP_RENAME:
458                                 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
459                                 if (!oldelm) continue;
460
461                                 elm = talloc(msg, struct ldb_message_element);
462                                 elm->name = talloc_strdup(elm, attr->local_name);
463                                 elm->num_values = oldelm->num_values;
464                                 elm->values = talloc_reference(elm, oldelm->values);
465
466                                 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
467                                 break;
468                                 
469                         case MAP_CONVERT:
470                                 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
471                                 if (!oldelm) continue;
472
473                                 elm = talloc(msg, struct ldb_message_element);
474                                 elm->name = talloc_strdup(elm, attr->local_name);
475                                 elm->num_values = oldelm->num_values;
476                                 elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
477
478                                 for (j = 0; j < oldelm->num_values; j++)
479                                         elm->values[j] = attr->u.convert.convert_remote(privdat, elm, &oldelm->values[j]);
480
481                                 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
482                                 break;
483
484                         case MAP_KEEP:
485                                 oldelm = ldb_msg_find_element(mi, attr->local_name);
486                                 if (!oldelm) continue;
487                                 
488                                 elm = talloc(msg, struct ldb_message_element);
489
490                                 elm->num_values = oldelm->num_values;
491                                 elm->values = talloc_reference(elm, oldelm->values);
492                                 elm->name = talloc_strdup(elm, oldelm->name);
493
494                                 ldb_msg_add(module->ldb, msg, elm, oldelm->flags);
495                                 break;
496
497                         case MAP_GENERATE:
498                                 elm = attr->u.generate.generate_local(privdat, msg, attr->local_name, mi);
499                                 if (!elm) continue;
500
501                                 ldb_msg_add(module->ldb, msg, elm, elm->flags);
502                                 break;
503                         default: 
504                                 DEBUG(0, ("Unknown attr->type for %s", attr->local_name));
505                                 break;
506                 }
507         }
508
509         talloc_free(newattrs);
510
511         return msg;
512 }
513
514 /* Used for add, modify */
515 static struct ldb_message *ldb_map_message_outgoing(struct ldb_module *module, const struct ldb_message *mo)
516 {
517         struct ldb_map_context *privdat = &((struct map_private *)module->private_data)->context;
518         struct ldb_message *msg = talloc_zero(module, struct ldb_message);
519         struct ldb_message_element *elm;
520         int i,j;
521         
522         msg->private_data = mo->private_data;
523         
524         msg->dn = map_local_dn(privdat, module, mo->dn);
525
526         /* Loop over mi and call generate_remote for each attribute */
527         for (i = 0; i < mo->num_elements; i++) {
528                 const struct ldb_map_attribute *attr = map_find_attr_local(privdat, mo->elements[i].name);
529                 enum ldb_map_attr_type map_type;
530
531                 if (!attr) {
532                         DEBUG(0, ("Undefined local attribute '%s', ignoring\n", mo->elements[i].name));
533                         map_type = MAP_IGNORE;
534                         continue;
535                 } else map_type = attr->type;
536
537                 switch (map_type) {
538                 case MAP_IGNORE: break;
539                 case MAP_RENAME:
540                         elm = talloc(msg, struct ldb_message_element);
541
542                         elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
543                         elm->num_values = mo->elements[i].num_values;
544                         elm->values = talloc_reference(elm, mo->elements[i].values);
545
546                         ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags);
547                         break;
548
549                 case MAP_CONVERT:
550                         elm = talloc(msg, struct ldb_message_element);
551
552                         elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
553                         elm->num_values = mo->elements[i].num_values;
554                         elm->values = talloc_array(elm, struct ldb_val, elm->num_values);
555                         
556                         for (j = 0; j < elm->num_values; j++) {
557                                 elm->values[j] = attr->u.convert.convert_local(privdat, msg, &mo->elements[i].values[j]);
558                         }
559
560                         ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags);
561                         break;
562
563                 case MAP_KEEP:
564                         elm = talloc(msg, struct ldb_message_element);
565
566                         elm->num_values = mo->elements[i].num_values;
567                         elm->values = talloc_reference(elm, mo->elements[i].values);
568                         elm->name = talloc_strdup(elm, mo->elements[i].name);
569                         
570                         ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags);      
571                         break;
572
573                 case MAP_GENERATE:
574                         attr->u.generate.generate_remote(privdat, attr->local_name, mo, msg);
575                         break;
576                 } 
577         }
578
579         return msg;
580 }
581
582 /*
583   rename a record
584 */
585 static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
586 {
587         struct ldb_map_context *privdat = &((struct map_private *)module->private_data)->context;
588         struct ldb_dn *n_olddn, *n_newdn;
589         int ret;
590         
591         n_olddn = map_local_dn(privdat, module, olddn);
592         n_newdn = map_local_dn(privdat, module, newdn);
593
594         ret = ldb_next_rename_record(module, n_olddn, n_newdn);
595
596         talloc_free(n_olddn);
597         talloc_free(n_newdn);
598         
599         return ret;
600 }
601
602 /*
603   delete a record
604 */
605 static int map_delete(struct ldb_module *module, const struct ldb_dn *dn)
606 {
607         struct ldb_map_context *privdat = &((struct map_private *)module->private_data)->context;
608         struct ldb_dn *newdn;
609         int ret;
610
611         newdn = map_local_dn(privdat, module, dn);
612
613         ret = ldb_next_delete_record(module, newdn);
614
615         talloc_free(newdn);
616
617         return ret;
618 }
619
620 /*
621   search for matching records using a ldb_parse_tree
622 */
623 static int map_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
624                               enum ldb_scope scope, struct ldb_parse_tree *tree,
625                               const char * const *attrs, struct ldb_message ***res)
626 {
627         int ret;
628         const char **newattrs;
629         struct ldb_parse_tree *new_tree;
630         struct ldb_dn *new_base;
631         struct ldb_message **newres;
632         struct ldb_map_context *privdat = &((struct map_private *)module->private_data)->context;
633         int i;
634
635         new_tree = ldb_map_parse_tree(module, module, tree);
636         newattrs = ldb_map_attrs(module, attrs); 
637         new_base = map_local_dn(privdat, module, base);
638
639         ret = ldb_next_search_bytree(module, new_base, scope, new_tree, newattrs, &newres);
640
641         talloc_free(new_base);
642         talloc_free(new_tree);
643         talloc_free(newattrs);
644
645         *res = talloc_array(module, struct ldb_message *, ret);
646
647         for (i = 0; i < ret; i++) {
648                 (*res)[i] = ldb_map_message_incoming(module, attrs, newres[i]);
649                 talloc_free(newres[i]);
650         }
651
652         return ret;
653 }
654 /*
655   search for matching records
656 */
657 static int map_search(struct ldb_module *module, const struct ldb_dn *base,
658                        enum ldb_scope scope, const char *expression,
659                        const char * const *attrs, struct ldb_message ***res)
660 {
661         struct map_private *map = module->private_data;
662         struct ldb_parse_tree *tree;
663         int ret;
664
665         tree = ldb_parse_tree(NULL, expression);
666         if (tree == NULL) {
667                 map->last_err_string = "expression parse failed";
668                 return -1;
669         }
670
671         ret = map_search_bytree(module, base, scope, tree, attrs, res);
672         talloc_free(tree);
673         return ret;
674 }
675
676 /*
677   add a record
678 */
679 static int map_add(struct ldb_module *module, const struct ldb_message *msg)
680 {
681         struct ldb_message *nmsg = ldb_map_message_outgoing(module, msg);
682         int ret;
683
684         ret = ldb_next_add_record(module, nmsg);
685
686         talloc_free(nmsg);
687
688         return ret;
689 }
690
691
692 /*
693   modify a record
694 */
695 static int map_modify(struct ldb_module *module, const struct ldb_message *msg)
696 {
697         struct ldb_message *nmsg = ldb_map_message_outgoing(module, msg);
698         int ret;
699
700         ret = ldb_next_modify_record(module, nmsg);
701
702         talloc_free(nmsg);
703
704         return ret;
705 }
706
707 static int map_lock(struct ldb_module *module, const char *lockname)
708 {
709         return ldb_next_named_lock(module, lockname);
710 }
711
712 static int map_unlock(struct ldb_module *module, const char *lockname)
713 {
714         return ldb_next_named_unlock(module, lockname);
715 }
716
717 /*
718   return extended error information
719 */
720 static const char *map_errstring(struct ldb_module *module)
721 {
722         struct map_private *map = module->private_data;
723         
724         if (map->last_err_string)
725                 return map->last_err_string;
726
727         return ldb_next_errstring(module);
728 }
729
730 static const struct ldb_module_ops map_ops = {
731         .name          = "map",
732         .search        = map_search,
733         .search_bytree = map_search_bytree,
734         .add_record    = map_add,
735         .modify_record = map_modify,
736         .delete_record = map_delete,
737         .rename_record = map_rename,
738         .named_lock    = map_lock,
739         .named_unlock  = map_unlock,
740         .errstring     = map_errstring
741 };
742
743 /* the init function */
744 struct ldb_module *ldb_map_init(struct ldb_context *ldb, const struct ldb_map_attribute *attrs, const struct ldb_map_objectclass *ocls, const char *options[])
745 {
746         int i, j;
747         struct ldb_module *ctx;
748         struct map_private *data;
749
750         ctx = talloc(ldb, struct ldb_module);
751         if (!ctx)
752                 return NULL;
753
754         data = talloc(ctx, struct map_private);
755         if (!data) {
756                 talloc_free(ctx);
757                 return NULL;
758         }
759
760         data->last_err_string = NULL;
761
762         /* Get list of attribute maps */
763         j = 0;
764         data->context.attribute_maps = NULL;
765
766         for (i = 0; attrs[i].local_name; i++) {
767                 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
768                 data->context.attribute_maps[j] = attrs[i];
769                 j++;
770         }
771
772         for (i = 0; builtin_attribute_maps[i].local_name; i++) {
773                 data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
774                 data->context.attribute_maps[j] = builtin_attribute_maps[i];
775                 j++;
776         }
777
778         data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1);
779         ZERO_STRUCT(data->context.attribute_maps[j].local_name);
780
781         data->context.objectclass_maps = ocls;
782         ctx->private_data = data;
783         ctx->ldb = ldb;
784         ctx->prev = ctx->next = NULL;
785         ctx->ops = &map_ops;
786
787         return ctx;
788 }
789
790 static struct ldb_val map_convert_local_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
791 {
792         struct ldb_dn *dn, *newdn;;
793         struct ldb_val *newval;
794
795         dn = ldb_dn_explode(ctx, (char *)val->data);
796
797         newdn = map_local_dn(map, ctx, dn);
798
799         talloc_free(dn);
800
801         newval = talloc(ctx, struct ldb_val);
802         newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
803         newval->length = strlen((char *)newval->data);
804
805         talloc_free(newdn);
806
807         return *newval;
808 }
809
810 static struct ldb_val map_convert_remote_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
811 {
812         struct ldb_dn *dn, *newdn;;
813         struct ldb_val *newval;
814
815         dn = ldb_dn_explode(ctx, (char *)val->data);
816
817         newdn = map_remote_dn(map, ctx, dn);
818
819         talloc_free(dn);
820
821         newval = talloc(ctx, struct ldb_val);
822         newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn);
823         newval->length = strlen((char *)newval->data);
824
825         talloc_free(newdn);
826
827         return *newval;
828 }
829
830 static struct ldb_val map_convert_local_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
831 {
832         int i;
833
834         for (i = 0; map->objectclass_maps[i].local_name; i++) {
835                 if (!strcmp(map->objectclass_maps[i].local_name, (char *)val->data)) {
836                         struct ldb_val newval;
837                         newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].remote_name);
838                         newval.length = strlen((char *)newval.data);
839
840                         return ldb_val_dup(ctx, &newval);
841                 }
842         }
843
844         DEBUG(1, ("Unable to map local object class '%s'\n", (char *)val->data));
845         return ldb_val_dup(ctx, val); 
846 }
847
848 static struct ldb_val map_convert_remote_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val)
849 {
850         int i;
851
852         for (i = 0; map->objectclass_maps[i].remote_name; i++) {
853                 if (!strcmp(map->objectclass_maps[i].remote_name, (char *)val->data)) {
854                         struct ldb_val newval;
855                         newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].local_name);
856                         newval.length = strlen((char *)newval.data);
857
858                         return ldb_val_dup(ctx, &newval);
859                 }
860         }
861
862         DEBUG(1, ("Unable to map remote object class '%s'\n", (char *)val->data));
863         return ldb_val_dup(ctx, val); 
864 }
865
866 static const struct ldb_map_attribute builtin_attribute_maps[] = {
867         {
868                 .local_name = "dn",
869                 .type = MAP_CONVERT,
870                 .u.convert.remote_name = "dn",
871                 .u.convert.convert_local = map_convert_local_dn,
872                 .u.convert.convert_remote = map_convert_remote_dn,
873         },
874         {
875                 .local_name = "objectclass",
876                 .type = MAP_CONVERT,
877                 .u.convert.remote_name = "objectclass",
878                 .u.convert.convert_local = map_convert_local_objectclass,
879                 .u.convert.convert_remote = map_convert_remote_objectclass,
880         },
881         {
882                 .local_name = NULL,
883         }
884 };
885