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