ldb_map objectClass munging: Don't hard-code 'extensibleObject'.
[ira/wip.git] / source / lib / ldb / ldb_map / ldb_map.c
1 /*
2    ldb database mapping module
3
4    Copyright (C) Jelmer Vernooij 2005
5    Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
6
7      ** NOTE! The following LGPL license applies to the ldb
8      ** library. This does NOT imply that all of Samba is released
9      ** under the LGPL
10    
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU Lesser General Public
13    License as published by the Free Software Foundation; either
14    version 3 of the License, or (at your option) any later version.
15
16    This library is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    Lesser General Public License for more details.
20
21    You should have received a copy of the GNU Lesser General Public
22    License along with this library; if not, see <http://www.gnu.org/licenses/>.
23
24 */
25
26 /* 
27  *  Name: ldb
28  *
29  *  Component: ldb ldb_map module
30  *
31  *  Description: Map portions of data into a different format on a
32  *  remote partition.
33  *
34  *  Author: Jelmer Vernooij, Martin Kuehl
35  */
36
37 #include "ldb_includes.h"
38
39 #include "ldb_map.h"
40 #include "ldb_map_private.h"
41
42 #ifndef _PUBLIC_
43 #define _PUBLIC_
44 #endif
45
46 /* Description of the provided ldb requests:
47  - special attribute 'isMapped'
48
49  - search:
50      - if parse tree can be split
51          - search remote records w/ remote attrs and parse tree
52      - otherwise
53          - enumerate all remote records
54      - for each remote result
55          - map remote result to local message
56          - search local result
57          - is present
58              - merge local into remote result
59              - run callback on merged result
60          - otherwise
61              - run callback on remote result
62
63  - add:
64      - split message into local and remote part
65      - if local message is not empty
66          - add isMapped to local message
67          - add local message
68      - add remote message
69
70  - modify:
71      - split message into local and remote part
72      - if local message is not empty
73          - add isMapped to local message
74          - search for local record
75          - if present
76              - modify local record
77          - otherwise
78              - add local message
79      - modify remote record
80
81  - delete:
82      - search for local record
83      - if present
84          - delete local record
85      - delete remote record
86
87  - rename:
88      - search for local record
89      - if present
90          - rename local record
91          - modify local isMapped
92      - rename remote record
93 */
94
95
96
97 /* Private data structures
98  * ======================= */
99
100 /* Global private data */
101 /* Extract mappings from private data. */
102 const struct ldb_map_context *map_get_context(struct ldb_module *module)
103 {
104         const struct map_private *data = talloc_get_type(module->private_data, struct map_private);
105         return data->context;
106 }
107
108 /* Create a generic request context. */
109 static struct map_context *map_init_context(struct ldb_handle *h, struct ldb_request *req)
110 {
111         struct map_context *ac;
112
113         ac = talloc_zero(h, struct map_context);
114         if (ac == NULL) {
115                 map_oom(h->module);
116                 return NULL;
117         }
118
119         ac->module = h->module;
120         ac->orig_req = req;
121
122         return ac;
123 }
124
125 /* Create a search request context. */
126 struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares)
127 {
128         struct map_search_context *sc;
129
130         sc = talloc_zero(ac, struct map_search_context);
131         if (sc == NULL) {
132                 map_oom(ac->module);
133                 return NULL;
134         }
135
136         sc->ac = ac;
137         sc->local_res = NULL;
138         sc->remote_res = ares;
139
140         return sc;
141 }
142
143 /* Create a request context and handle. */
144 struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module)
145 {
146         struct map_context *ac;
147         struct ldb_handle *h;
148
149         h = talloc_zero(req, struct ldb_handle);
150         if (h == NULL) {
151                 map_oom(module);
152                 return NULL;
153         }
154
155         h->module = module;
156
157         ac = map_init_context(h, req);
158         if (ac == NULL) {
159                 talloc_free(h);
160                 return NULL;
161         }
162
163         h->private_data = (void *)ac;
164
165         h->state = LDB_ASYNC_INIT;
166         h->status = LDB_SUCCESS;
167
168         return h;
169 }
170
171
172 /* Dealing with DNs for different partitions
173  * ========================================= */
174
175 /* Check whether any data should be stored in the local partition. */
176 bool map_check_local_db(struct ldb_module *module)
177 {
178         const struct ldb_map_context *data = map_get_context(module);
179
180         if (!data->remote_base_dn || !data->local_base_dn) {
181                 return false;
182         }
183
184         return true;
185 }
186
187 /* Copy a DN with the base DN of the local partition. */
188 static struct ldb_dn *ldb_dn_rebase_local(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn)
189 {
190         struct ldb_dn *new_dn;
191
192         new_dn = ldb_dn_copy(mem_ctx, dn);
193         if ( ! ldb_dn_validate(new_dn)) {
194                 talloc_free(new_dn);
195                 return NULL;
196         }
197
198         /* may be we don't need to rebase at all */
199         if ( ! data->remote_base_dn || ! data->local_base_dn) {
200                 return new_dn;
201         }
202
203         if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->remote_base_dn))) {
204                 talloc_free(new_dn);
205                 return NULL;
206         }
207
208         if ( ! ldb_dn_add_base(new_dn, data->local_base_dn)) {
209                 talloc_free(new_dn);
210                 return NULL;
211         }
212
213         return new_dn;
214 }
215
216 /* Copy a DN with the base DN of the remote partition. */
217 static struct ldb_dn *ldb_dn_rebase_remote(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn)
218 {
219         struct ldb_dn *new_dn;
220
221         new_dn = ldb_dn_copy(mem_ctx, dn);
222         if ( ! ldb_dn_validate(new_dn)) {
223                 talloc_free(new_dn);
224                 return NULL;
225         }
226
227         /* may be we don't need to rebase at all */
228         if ( ! data->remote_base_dn || ! data->local_base_dn) {
229                 return new_dn;
230         }
231
232         if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->local_base_dn))) {
233                 talloc_free(new_dn);
234                 return NULL;
235         }
236
237         if ( ! ldb_dn_add_base(new_dn, data->remote_base_dn)) {
238                 talloc_free(new_dn);
239                 return NULL;
240         }
241
242         return new_dn;
243 }
244
245 /* Run a request and make sure it targets the remote partition. */
246 /* TODO: free old DNs and messages? */
247 int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request)
248 {
249         const struct ldb_map_context *data = map_get_context(module);
250         struct ldb_message *msg;
251
252         switch (request->operation) {
253         case LDB_SEARCH:
254                 if (request->op.search.base) {
255                         request->op.search.base = ldb_dn_rebase_remote(request, data, request->op.search.base);
256                 } else {
257                         request->op.search.base = data->remote_base_dn;
258                         /* TODO: adjust scope? */
259                 }
260                 break;
261
262         case LDB_ADD:
263                 msg = ldb_msg_copy_shallow(request, request->op.add.message);
264                 msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn);
265                 request->op.add.message = msg;
266                 break;
267
268         case LDB_MODIFY:
269                 msg = ldb_msg_copy_shallow(request, request->op.mod.message);
270                 msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn);
271                 request->op.mod.message = msg;
272                 break;
273
274         case LDB_DELETE:
275                 request->op.del.dn = ldb_dn_rebase_remote(request, data, request->op.del.dn);
276                 break;
277
278         case LDB_RENAME:
279                 request->op.rename.olddn = ldb_dn_rebase_remote(request, data, request->op.rename.olddn);
280                 request->op.rename.newdn = ldb_dn_rebase_remote(request, data, request->op.rename.newdn);
281                 break;
282
283         default:
284                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
285                           "Invalid remote request!\n");
286                 return LDB_ERR_OPERATIONS_ERROR;
287         }
288
289         return ldb_next_request(module, request);
290 }
291
292
293 /* Finding mappings for attributes and objectClasses
294  * ================================================= */
295
296 /* Find an objectClass mapping by the local name. */
297 static const struct ldb_map_objectclass *map_objectclass_find_local(const struct ldb_map_context *data, const char *name)
298 {
299         int i;
300
301         for (i = 0; data->objectclass_maps && data->objectclass_maps[i].local_name; i++) {
302                 if (ldb_attr_cmp(data->objectclass_maps[i].local_name, name) == 0) {
303                         return &data->objectclass_maps[i];
304                 }
305         }
306
307         return NULL;
308 }
309
310 /* Find an objectClass mapping by the remote name. */
311 static const struct ldb_map_objectclass *map_objectclass_find_remote(const struct ldb_map_context *data, const char *name)
312 {
313         int i;
314
315         for (i = 0; data->objectclass_maps && data->objectclass_maps[i].remote_name; i++) {
316                 if (ldb_attr_cmp(data->objectclass_maps[i].remote_name, name) == 0) {
317                         return &data->objectclass_maps[i];
318                 }
319         }
320
321         return NULL;
322 }
323
324 /* Find an attribute mapping by the local name. */
325 const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name)
326 {
327         int i;
328
329         for (i = 0; data->attribute_maps[i].local_name; i++) {
330                 if (ldb_attr_cmp(data->attribute_maps[i].local_name, name) == 0) {
331                         return &data->attribute_maps[i];
332                 }
333         }
334         for (i = 0; data->attribute_maps[i].local_name; i++) {
335                 if (ldb_attr_cmp(data->attribute_maps[i].local_name, "*") == 0) {
336                         return &data->attribute_maps[i];
337                 }
338         }
339
340         return NULL;
341 }
342
343 /* Find an attribute mapping by the remote name. */
344 const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name)
345 {
346         const struct ldb_map_attribute *map;
347         const struct ldb_map_attribute *wildcard = NULL;
348         int i, j;
349
350         for (i = 0; data->attribute_maps[i].local_name; i++) {
351                 map = &data->attribute_maps[i];
352                 if (ldb_attr_cmp(map->local_name, "*") == 0) {
353                         wildcard = &data->attribute_maps[i];
354                 }
355
356                 switch (map->type) {
357                 case MAP_IGNORE:
358                         break;
359
360                 case MAP_KEEP:
361                         if (ldb_attr_cmp(map->local_name, name) == 0) {
362                                 return map;
363                         }
364                         break;
365
366                 case MAP_RENAME:
367                 case MAP_CONVERT:
368                         if (ldb_attr_cmp(map->u.rename.remote_name, name) == 0) {
369                                 return map;
370                         }
371                         break;
372
373                 case MAP_GENERATE:
374                         for (j = 0; map->u.generate.remote_names && map->u.generate.remote_names[j]; j++) {
375                                 if (ldb_attr_cmp(map->u.generate.remote_names[j], name) == 0) {
376                                         return map;
377                                 }
378                         }
379                         break;
380                 }
381         }
382
383         /* We didn't find it, so return the wildcard record if one was configured */
384         return wildcard;
385 }
386
387
388 /* Mapping attributes
389  * ================== */
390
391 /* Check whether an attribute will be mapped into the remote partition. */
392 bool map_attr_check_remote(const struct ldb_map_context *data, const char *attr)
393 {
394         const struct ldb_map_attribute *map = map_attr_find_local(data, attr);
395
396         if (map == NULL) {
397                 return false;
398         }
399         if (map->type == MAP_IGNORE) {
400                 return false;
401         }
402
403         return true;
404 }
405
406 /* Map an attribute name into the remote partition. */
407 const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr)
408 {
409         if (map == NULL) {
410                 return talloc_strdup(mem_ctx, attr);
411         }
412
413         switch (map->type) {
414         case MAP_KEEP:
415                 return talloc_strdup(mem_ctx, attr);
416
417         case MAP_RENAME:
418         case MAP_CONVERT:
419                 return talloc_strdup(mem_ctx, map->u.rename.remote_name);
420
421         default:
422                 return NULL;
423         }
424 }
425
426 /* Map an attribute name back into the local partition. */
427 const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr)
428 {
429         if (map == NULL) {
430                 return talloc_strdup(mem_ctx, attr);
431         }
432
433         if (map->type == MAP_KEEP) {
434                 return talloc_strdup(mem_ctx, attr);
435         }
436
437         return talloc_strdup(mem_ctx, map->local_name);
438 }
439
440
441 /* Merge two lists of attributes into a single one. */
442 int map_attrs_merge(struct ldb_module *module, void *mem_ctx, 
443                     const char ***attrs, const char * const *more_attrs)
444 {
445         int i, j, k;
446
447         for (i = 0; *attrs && (*attrs)[i]; i++) /* noop */ ;
448         for (j = 0; more_attrs && more_attrs[j]; j++) /* noop */ ;
449         
450         *attrs = talloc_realloc(mem_ctx, *attrs, const char *, i+j+1);
451         if (*attrs == NULL) {
452                 map_oom(module);
453                 return -1;
454         }
455
456         for (k = 0; k < j; k++) {
457                 (*attrs)[i + k] = more_attrs[k];
458         }
459
460         (*attrs)[i+k] = NULL;
461
462         return 0;
463 }
464
465 /* Mapping ldb values
466  * ================== */
467
468 /* Map an ldb value into the remote partition. */
469 struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, 
470                                  const struct ldb_map_attribute *map, const struct ldb_val *val)
471 {
472         if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_local)) {
473                 return map->u.convert.convert_local(module, mem_ctx, val);
474         }
475
476         return ldb_val_dup(mem_ctx, val);
477 }
478
479 /* Map an ldb value back into the local partition. */
480 struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, 
481                                   const struct ldb_map_attribute *map, const struct ldb_val *val)
482 {
483         if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_remote)) {
484                 return map->u.convert.convert_remote(module, mem_ctx, val);
485         }
486
487         return ldb_val_dup(mem_ctx, val);
488 }
489
490
491 /* Mapping DNs
492  * =========== */
493
494 /* Check whether a DN is below the local baseDN. */
495 bool ldb_dn_check_local(struct ldb_module *module, struct ldb_dn *dn)
496 {
497         const struct ldb_map_context *data = map_get_context(module);
498
499         if (!data->local_base_dn) {
500                 return true;
501         }
502
503         return ldb_dn_compare_base(data->local_base_dn, dn) == 0;
504 }
505
506 /* Map a DN into the remote partition. */
507 struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
508 {
509         const struct ldb_map_context *data = map_get_context(module);
510         struct ldb_dn *newdn;
511         const struct ldb_map_attribute *map;
512         enum ldb_map_attr_type map_type;
513         const char *name;
514         struct ldb_val value;
515         int i, ret;
516
517         if (dn == NULL) {
518                 return NULL;
519         }
520
521         newdn = ldb_dn_copy(mem_ctx, dn);
522         if (newdn == NULL) {
523                 map_oom(module);
524                 return NULL;
525         }
526
527         /* For each RDN, map the component name and possibly the value */
528         for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) {
529                 map = map_attr_find_local(data, ldb_dn_get_component_name(dn, i));
530
531                 /* Unknown attribute - leave this RDN as is and hope the best... */
532                 if (map == NULL) {
533                         map_type = MAP_KEEP;
534                 } else {
535                         map_type = map->type;
536                 }
537
538                 switch (map_type) {
539                 case MAP_IGNORE:
540                 case MAP_GENERATE:
541                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
542                                   "MAP_IGNORE/MAP_GENERATE attribute '%s' "
543                                   "used in DN!\n", ldb_dn_get_component_name(dn, i));
544                         goto failed;
545
546                 case MAP_CONVERT:
547                         if (map->u.convert.convert_local == NULL) {
548                                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
549                                           "'convert_local' not set for attribute '%s' "
550                                           "used in DN!\n", ldb_dn_get_component_name(dn, i));
551                                 goto failed;
552                         }
553                         /* fall through */
554                 case MAP_KEEP:
555                 case MAP_RENAME:
556                         name = map_attr_map_local(newdn, map, ldb_dn_get_component_name(dn, i));
557                         if (name == NULL) goto failed;
558
559                         value = ldb_val_map_local(module, newdn, map, ldb_dn_get_component_val(dn, i));
560                         if (value.data == NULL) goto failed;
561
562                         ret = ldb_dn_set_component(newdn, i, name, value);
563                         if (ret != LDB_SUCCESS) {
564                                 goto failed;
565                         }
566
567                         break;
568                 }
569         }
570
571         return newdn;
572
573 failed:
574         talloc_free(newdn);
575         return NULL;
576 }
577
578 /* Map a DN into the local partition. */
579 struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
580 {
581         const struct ldb_map_context *data = map_get_context(module);
582         struct ldb_dn *newdn;
583         const struct ldb_map_attribute *map;
584         enum ldb_map_attr_type map_type;
585         const char *name;
586         struct ldb_val value;
587         int i, ret;
588
589         if (dn == NULL) {
590                 return NULL;
591         }
592
593         newdn = ldb_dn_copy(mem_ctx, dn);
594         if (newdn == NULL) {
595                 map_oom(module);
596                 return NULL;
597         }
598
599         /* For each RDN, map the component name and possibly the value */
600         for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) {
601                 map = map_attr_find_remote(data, ldb_dn_get_component_name(dn, i));
602
603                 /* Unknown attribute - leave this RDN as is and hope the best... */
604                 if (map == NULL) {
605                         map_type = MAP_KEEP;
606                 } else {
607                         map_type = map->type;
608                 }
609
610                 switch (map_type) {
611                 case MAP_IGNORE:
612                 case MAP_GENERATE:
613                         ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
614                                   "MAP_IGNORE/MAP_GENERATE attribute '%s' "
615                                   "used in DN!\n", ldb_dn_get_component_name(dn, i));
616                         goto failed;
617
618                 case MAP_CONVERT:
619                         if (map->u.convert.convert_remote == NULL) {
620                                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
621                                           "'convert_remote' not set for attribute '%s' "
622                                           "used in DN!\n", ldb_dn_get_component_name(dn, i));
623                                 goto failed;
624                         }
625                         /* fall through */
626                 case MAP_KEEP:
627                 case MAP_RENAME:
628                         name = map_attr_map_remote(newdn, map, ldb_dn_get_component_name(dn, i));
629                         if (name == NULL) goto failed;
630
631                         value = ldb_val_map_remote(module, newdn, map, ldb_dn_get_component_val(dn, i));
632                         if (value.data == NULL) goto failed;
633
634                         ret = ldb_dn_set_component(newdn, i, name, value);
635                         if (ret != LDB_SUCCESS) {
636                                 goto failed;
637                         }
638
639                         break;
640                 }
641         }
642
643         return newdn;
644
645 failed:
646         talloc_free(newdn);
647         return NULL;
648 }
649
650 /* Map a DN and its base into the local partition. */
651 /* TODO: This should not be required with GUIDs. */
652 struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
653 {
654         const struct ldb_map_context *data = map_get_context(module);
655         struct ldb_dn *dn1, *dn2;
656
657         dn1 = ldb_dn_rebase_local(mem_ctx, data, dn);
658         dn2 = ldb_dn_map_remote(module, mem_ctx, dn1);
659
660         talloc_free(dn1);
661         return dn2;
662 }
663
664
665 /* Converting DNs and objectClasses (as ldb values)
666  * ================================================ */
667
668 /* Map a DN contained in an ldb value into the remote partition. */
669 static struct ldb_val ldb_dn_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
670 {
671         struct ldb_dn *dn, *newdn;
672         struct ldb_val newval;
673
674         dn = ldb_dn_new(mem_ctx, module->ldb, (char *)val->data);
675         if (! ldb_dn_validate(dn)) {
676                 newval.length = 0;
677                 newval.data = NULL;
678                 talloc_free(dn);
679                 return newval;
680         }
681         newdn = ldb_dn_map_local(module, mem_ctx, dn);
682         talloc_free(dn);
683
684         newval.length = 0;
685         newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn);
686         if (newval.data) {
687                 newval.length = strlen((char *)newval.data);
688         }
689         talloc_free(newdn);
690
691         return newval;
692 }
693
694 /* Map a DN contained in an ldb value into the local partition. */
695 static struct ldb_val ldb_dn_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
696 {
697         struct ldb_dn *dn, *newdn;
698         struct ldb_val newval;
699
700         dn = ldb_dn_new(mem_ctx, module->ldb, (char *)val->data);
701         if (! ldb_dn_validate(dn)) {
702                 newval.length = 0;
703                 newval.data = NULL;
704                 talloc_free(dn);
705                 return newval;
706         }
707         newdn = ldb_dn_map_remote(module, mem_ctx, dn);
708         talloc_free(dn);
709
710         newval.length = 0;
711         newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn);
712         if (newval.data) {
713                 newval.length = strlen((char *)newval.data);
714         }
715         talloc_free(newdn);
716
717         return newval;
718 }
719
720 /* Map an objectClass into the remote partition. */
721 static struct ldb_val map_objectclass_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
722 {
723         const struct ldb_map_context *data = map_get_context(module);
724         const char *name = (char *)val->data;
725         const struct ldb_map_objectclass *map = map_objectclass_find_local(data, name);
726         struct ldb_val newval;
727
728         if (map) {
729                 newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->remote_name);
730                 newval.length = strlen((char *)newval.data);
731                 return newval;
732         }
733
734         return ldb_val_dup(mem_ctx, val);
735 }
736
737 /* Generate a remote message with a mapped objectClass. */
738 static void map_objectclass_generate_remote(struct ldb_module *module, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local)
739 {
740         const struct ldb_map_context *data = map_get_context(module);
741         struct ldb_message_element *el, *oc;
742         struct ldb_val val;
743         bool found_extensibleObject = false;
744         int i;
745
746         /* Find old local objectClass */
747         oc = ldb_msg_find_element(old, "objectClass");
748         if (oc == NULL) {
749                 return;
750         }
751
752         /* Prepare new element */
753         el = talloc_zero(remote, struct ldb_message_element);
754         if (el == NULL) {
755                 ldb_oom(module->ldb);
756                 return;                 /* TODO: fail? */
757         }
758
759         /* Copy local objectClass element, reverse space for an extra value */
760         el->num_values = oc->num_values + 1;
761         el->values = talloc_array(el, struct ldb_val, el->num_values);
762         if (el->values == NULL) {
763                 talloc_free(el);
764                 ldb_oom(module->ldb);
765                 return;                 /* TODO: fail? */
766         }
767
768         /* Copy local element name "objectClass" */
769         el->name = talloc_strdup(el, local_attr);
770
771         /* Convert all local objectClasses */
772         for (i = 0; i < el->num_values - 1; i++) {
773                 el->values[i] = map_objectclass_convert_local(module, el->values, &oc->values[i]);
774                 if (ldb_attr_cmp((char *)el->values[i].data, data->add_objectclass) == 0) {
775                         found_extensibleObject = true;
776                 }
777         }
778
779         if (!found_extensibleObject) {
780                 val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass);
781                 val.length = strlen((char *)val.data);
782
783                 /* Append additional objectClass data->add_objectclass */
784                 el->values[i] = val;
785         } else {
786                 el->num_values--;
787         }
788
789         /* Add new objectClass to remote message */
790         ldb_msg_add(remote, el, 0);
791 }
792
793 /* Map an objectClass into the local partition. */
794 static struct ldb_val map_objectclass_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
795 {
796         const struct ldb_map_context *data = map_get_context(module);
797         const char *name = (char *)val->data;
798         const struct ldb_map_objectclass *map = map_objectclass_find_remote(data, name);
799         struct ldb_val newval;
800
801         if (map) {
802                 newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->local_name);
803                 newval.length = strlen((char *)newval.data);
804                 return newval;
805         }
806
807         return ldb_val_dup(mem_ctx, val);
808 }
809
810 /* Generate a local message with a mapped objectClass. */
811 static struct ldb_message_element *map_objectclass_generate_local(struct ldb_module *module, void *mem_ctx, const char *local_attr, const struct ldb_message *remote)
812 {
813         struct ldb_message_element *el, *oc;
814         struct ldb_val val;
815         int i;
816
817         /* Find old remote objectClass */
818         oc = ldb_msg_find_element(remote, "objectClass");
819         if (oc == NULL) {
820                 return NULL;
821         }
822
823         /* Prepare new element */
824         el = talloc_zero(mem_ctx, struct ldb_message_element);
825         if (el == NULL) {
826                 ldb_oom(module->ldb);
827                 return NULL;
828         }
829
830         /* Copy remote objectClass element */
831         el->num_values = oc->num_values;
832         el->values = talloc_array(el, struct ldb_val, el->num_values);
833         if (el->values == NULL) {
834                 talloc_free(el);
835                 ldb_oom(module->ldb);
836                 return NULL;
837         }
838
839         /* Copy remote element name "objectClass" */
840         el->name = talloc_strdup(el, local_attr);
841
842         /* Convert all remote objectClasses */
843         for (i = 0; i < el->num_values; i++) {
844                 el->values[i] = map_objectclass_convert_remote(module, el->values, &oc->values[i]);
845         }
846
847         val.data = (uint8_t *)talloc_strdup(el->values, "extensibleObject");
848         val.length = strlen((char *)val.data);
849
850         /* Remove last value if it was "extensibleObject" */
851         if (ldb_val_equal_exact(&val, &el->values[i-1])) {
852                 el->num_values--;
853                 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values);
854                 if (el->values == NULL) {
855                         talloc_free(el);
856                         ldb_oom(module->ldb);
857                         return NULL;
858                 }
859         }
860
861         return el;
862 }
863
864 static const struct ldb_map_attribute objectclass_convert_map = {
865         .local_name = "objectClass",
866         .type = MAP_CONVERT,
867         .u = {
868                 .convert = {
869                         .remote_name = "objectClass",
870                         .convert_local = map_objectclass_convert_local,
871                         .convert_remote = map_objectclass_convert_remote,
872                 },
873         },
874 };
875
876
877 /* Mappings for searches on objectClass= assuming a one-to-one
878  * mapping.  Needed because this is a generate operator for the
879  * add/modify code */
880 static int map_objectclass_convert_operator(struct ldb_module *module, void *mem_ctx, 
881                                             struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) 
882 {
883         
884         return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, &objectclass_convert_map);
885 }
886
887 /* Auxiliary request construction
888  * ============================== */
889
890 /* Store the DN of a single search result in context. */
891 static int map_search_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
892 {
893         struct map_context *ac;
894
895         if (context == NULL || ares == NULL) {
896                 ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
897                 return LDB_ERR_OPERATIONS_ERROR;
898         }
899
900         ac = talloc_get_type(context, struct map_context);
901
902         /* We are interested only in the single reply */
903         if (ares->type != LDB_REPLY_ENTRY) {
904                 talloc_free(ares);
905                 return LDB_SUCCESS;
906         }
907
908         /* We have already found a remote DN */
909         if (ac->local_dn) {
910                 ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results to base search"));
911                 talloc_free(ares);
912                 return LDB_ERR_OPERATIONS_ERROR;
913         }
914
915         /* Store local DN */
916         ac->local_dn = ares->message->dn;
917
918         return LDB_SUCCESS;
919 }
920
921 /* Build a request to search a record by its DN. */
922 struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback)
923 {
924         struct ldb_request *req;
925
926         req = talloc_zero(ac, struct ldb_request);
927         if (req == NULL) {
928                 map_oom(ac->module);
929                 return NULL;
930         }
931
932         req->operation = LDB_SEARCH;
933         req->op.search.base = dn;
934         req->op.search.scope = LDB_SCOPE_BASE;
935         req->op.search.attrs = attrs;
936
937         if (tree) {
938                 req->op.search.tree = tree;
939         } else {
940                 req->op.search.tree = ldb_parse_tree(req, NULL);
941                 if (req->op.search.tree == NULL) {
942                         talloc_free(req);
943                         return NULL;
944                 }
945         }
946
947         req->controls = NULL;
948         req->context = context;
949         req->callback = callback;
950         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, req);
951
952         return req;
953 }
954
955 /* Build a request to search the local record by its DN. */
956 struct ldb_request *map_search_self_req(struct map_context *ac, struct ldb_dn *dn)
957 {
958         /* attrs[] is returned from this function in
959          * ac->search_req->op.search.attrs, so it must be static, as
960          * otherwise the compiler can put it on the stack */
961         static const char * const attrs[] = { IS_MAPPED, NULL };
962         struct ldb_parse_tree *tree;
963
964         /* Limit search to records with 'IS_MAPPED' present */
965         /* TODO: `tree = ldb_parse_tree(ac, IS_MAPPED);' won't do. */
966         tree = talloc_zero(ac, struct ldb_parse_tree);
967         if (tree == NULL) {
968                 map_oom(ac->module);
969                 return NULL;
970         }
971
972         tree->operation = LDB_OP_PRESENT;
973         tree->u.present.attr = talloc_strdup(tree, IS_MAPPED);
974
975         return map_search_base_req(ac, dn, attrs, tree, ac, map_search_self_callback);
976 }
977
978 /* Build a request to update the 'IS_MAPPED' attribute */
979 struct ldb_request *map_build_fixup_req(struct map_context *ac, struct ldb_dn *olddn, struct ldb_dn *newdn)
980 {
981         struct ldb_request *req;
982         struct ldb_message *msg;
983         const char *dn;
984
985         /* Prepare request */
986         req = talloc_zero(ac, struct ldb_request);
987         if (req == NULL) {
988                 map_oom(ac->module);
989                 return NULL;
990         }
991
992         /* Prepare message */
993         msg = ldb_msg_new(req);
994         if (msg == NULL) {
995                 map_oom(ac->module);
996                 goto failed;
997         }
998
999         /* Update local 'IS_MAPPED' to the new remote DN */
1000         msg->dn = ldb_dn_copy(msg, olddn);
1001         dn = ldb_dn_alloc_linearized(msg, newdn);
1002         if ( ! dn || ! ldb_dn_validate(msg->dn)) {
1003                 goto failed;
1004         }
1005         if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
1006                 goto failed;
1007         }
1008         if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
1009                 goto failed;
1010         }
1011
1012         req->operation = LDB_MODIFY;
1013         req->op.mod.message = msg;
1014         req->controls = NULL;
1015         req->handle = NULL;
1016         req->context = NULL;
1017         req->callback = NULL;
1018
1019         return req;
1020
1021 failed:
1022         talloc_free(req);
1023         return NULL;
1024 }
1025
1026
1027 /* Asynchronous call structure
1028  * =========================== */
1029
1030 /* Figure out which request is currently pending. */
1031 static struct ldb_request *map_get_req(struct map_context *ac)
1032 {
1033         switch (ac->step) {
1034         case MAP_SEARCH_SELF_MODIFY:
1035         case MAP_SEARCH_SELF_DELETE:
1036         case MAP_SEARCH_SELF_RENAME:
1037                 return ac->search_req;
1038
1039         case MAP_ADD_REMOTE:
1040         case MAP_MODIFY_REMOTE:
1041         case MAP_DELETE_REMOTE:
1042         case MAP_RENAME_REMOTE:
1043                 return ac->remote_req;
1044
1045         case MAP_RENAME_FIXUP:
1046                 return ac->down_req;
1047
1048         case MAP_ADD_LOCAL:
1049         case MAP_MODIFY_LOCAL:
1050         case MAP_DELETE_LOCAL:
1051         case MAP_RENAME_LOCAL:
1052                 return ac->local_req;
1053
1054         case MAP_SEARCH_REMOTE:
1055                 /* Can't happen */
1056                 break;
1057         }
1058
1059         return NULL;            /* unreachable; silences a warning */
1060 }
1061
1062 typedef int (*map_next_function)(struct ldb_handle *handle);
1063
1064 /* Figure out the next request to run. */
1065 static map_next_function map_get_next(struct map_context *ac)
1066 {
1067         switch (ac->step) {
1068         case MAP_SEARCH_REMOTE:
1069                 return NULL;
1070
1071         case MAP_ADD_LOCAL:
1072                 return map_add_do_remote;
1073         case MAP_ADD_REMOTE:
1074                 return NULL;
1075
1076         case MAP_SEARCH_SELF_MODIFY:
1077                 return map_modify_do_local;
1078         case MAP_MODIFY_LOCAL:
1079                 return map_modify_do_remote;
1080         case MAP_MODIFY_REMOTE:
1081                 return NULL;
1082
1083         case MAP_SEARCH_SELF_DELETE:
1084                 return map_delete_do_local;
1085         case MAP_DELETE_LOCAL:
1086                 return map_delete_do_remote;
1087         case MAP_DELETE_REMOTE:
1088                 return NULL;
1089
1090         case MAP_SEARCH_SELF_RENAME:
1091                 return map_rename_do_local;
1092         case MAP_RENAME_LOCAL:
1093                 return map_rename_do_fixup;
1094         case MAP_RENAME_FIXUP:
1095                 return map_rename_do_remote;
1096         case MAP_RENAME_REMOTE:
1097                 return NULL;
1098         }
1099
1100         return NULL;            /* unreachable; silences a warning */
1101 }
1102
1103 /* Wait for the current pending request to finish and continue with the next. */
1104 static int map_wait_next(struct ldb_handle *handle)
1105 {
1106         struct map_context *ac;
1107         struct ldb_request *req;
1108         map_next_function next;
1109         int ret;
1110
1111         if (handle == NULL || handle->private_data == NULL) {
1112                 return LDB_ERR_OPERATIONS_ERROR;
1113         }
1114
1115         if (handle->state == LDB_ASYNC_DONE) {
1116                 return handle->status;
1117         }
1118
1119         handle->state = LDB_ASYNC_PENDING;
1120         handle->status = LDB_SUCCESS;
1121
1122         ac = talloc_get_type(handle->private_data, struct map_context);
1123
1124         if (ac->step == MAP_SEARCH_REMOTE) {
1125                 int i;
1126                 for (i = 0; i < ac->num_searches; i++) {
1127                         req = ac->search_reqs[i];
1128                         ret = ldb_wait(req->handle, LDB_WAIT_NONE);
1129
1130                         if (ret != LDB_SUCCESS) {
1131                                 handle->status = ret;
1132                                 goto done;
1133                         }
1134                         if (req->handle->status != LDB_SUCCESS) {
1135                                 handle->status = req->handle->status;
1136                                 goto done;
1137                         }
1138                         if (req->handle->state != LDB_ASYNC_DONE) {
1139                                 return LDB_SUCCESS;
1140                         }
1141                 }
1142         } else {
1143
1144                 req = map_get_req(ac);
1145
1146                 ret = ldb_wait(req->handle, LDB_WAIT_NONE);
1147
1148                 if (ret != LDB_SUCCESS) {
1149                         handle->status = ret;
1150                         goto done;
1151                 }
1152                 if (req->handle->status != LDB_SUCCESS) {
1153                         handle->status = req->handle->status;
1154                         goto done;
1155                 }
1156                 if (req->handle->state != LDB_ASYNC_DONE) {
1157                         return LDB_SUCCESS;
1158                 }
1159
1160                 next = map_get_next(ac);
1161                 if (next) {
1162                         return next(handle);
1163                 }
1164         }
1165
1166         ret = LDB_SUCCESS;
1167
1168 done:
1169         handle->state = LDB_ASYNC_DONE;
1170         return ret;
1171 }
1172
1173 /* Wait for all current pending requests to finish. */
1174 static int map_wait_all(struct ldb_handle *handle)
1175 {
1176         int ret;
1177
1178         while (handle->state != LDB_ASYNC_DONE) {
1179                 ret = map_wait_next(handle);
1180                 if (ret != LDB_SUCCESS) {
1181                         return ret;
1182                 }
1183         }
1184
1185         return handle->status;
1186 }
1187
1188 /* Wait for pending requests to finish. */
1189 static int map_wait(struct ldb_handle *handle, enum ldb_wait_type type)
1190 {
1191         if (type == LDB_WAIT_ALL) {
1192                 return map_wait_all(handle);
1193         } else {
1194                 return map_wait_next(handle);
1195         }
1196 }
1197
1198
1199 /* Module initialization
1200  * ===================== */
1201
1202 /* Provided module operations */
1203 static const struct ldb_module_ops map_ops = {
1204         .name           = "ldb_map",
1205         .add            = map_add,
1206         .modify         = map_modify,
1207         .del            = map_delete,
1208         .rename         = map_rename,
1209         .search         = map_search,
1210         .wait           = map_wait,
1211 };
1212
1213 /* Builtin mappings for DNs and objectClasses */
1214 static const struct ldb_map_attribute builtin_attribute_maps[] = {
1215         {
1216                 .local_name = "dn",
1217                 .type = MAP_CONVERT,
1218                 .u = {
1219                         .convert = {
1220                                  .remote_name = "dn",
1221                                  .convert_local = ldb_dn_convert_local,
1222                                  .convert_remote = ldb_dn_convert_remote,
1223                          },
1224                 },
1225         },
1226         {
1227                 .local_name = NULL,
1228         }
1229 };
1230
1231 static const struct ldb_map_attribute objectclass_attribute_map = {
1232         .local_name = "objectClass",
1233         .type = MAP_GENERATE,
1234         .convert_operator = map_objectclass_convert_operator,
1235         .u = {
1236                 .generate = {
1237                         .remote_names = { "objectClass", NULL },
1238                         .generate_local = map_objectclass_generate_local,
1239                         .generate_remote = map_objectclass_generate_remote,
1240                 },
1241         },
1242 };
1243
1244
1245 /* Find the special 'MAP_DN_NAME' record and store local and remote
1246  * base DNs in private data. */
1247 static int map_init_dns(struct ldb_module *module, struct ldb_map_context *data, const char *name)
1248 {
1249         static const char * const attrs[] = { MAP_DN_FROM, MAP_DN_TO, NULL };
1250         struct ldb_dn *dn;
1251         struct ldb_message *msg;
1252         struct ldb_result *res;
1253         int ret;
1254
1255         if (!name) {
1256                 data->local_base_dn = NULL;
1257                 data->remote_base_dn = NULL;
1258                 return LDB_SUCCESS;
1259         }
1260
1261         dn = ldb_dn_new_fmt(data, module->ldb, "%s=%s", MAP_DN_NAME, name);
1262         if ( ! ldb_dn_validate(dn)) {
1263                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
1264                           "Failed to construct '%s' DN!\n", MAP_DN_NAME);
1265                 return LDB_ERR_OPERATIONS_ERROR;
1266         }
1267
1268         ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, NULL, attrs, &res);
1269         talloc_free(dn);
1270         if (ret != LDB_SUCCESS) {
1271                 return ret;
1272         }
1273         if (res->count == 0) {
1274                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
1275                           "No results for '%s=%s'!\n", MAP_DN_NAME, name);
1276                 talloc_free(res);
1277                 return LDB_ERR_CONSTRAINT_VIOLATION;
1278         }
1279         if (res->count > 1) {
1280                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
1281                           "Too many results for '%s=%s'!\n", MAP_DN_NAME, name);
1282                 talloc_free(res);
1283                 return LDB_ERR_CONSTRAINT_VIOLATION;
1284         }
1285
1286         msg = res->msgs[0];
1287         data->local_base_dn = ldb_msg_find_attr_as_dn(module->ldb, data, msg, MAP_DN_FROM);
1288         data->remote_base_dn = ldb_msg_find_attr_as_dn(module->ldb, data, msg, MAP_DN_TO);
1289         talloc_free(res);
1290
1291         return LDB_SUCCESS;
1292 }
1293
1294 /* Store attribute maps and objectClass maps in private data. */
1295 static int map_init_maps(struct ldb_module *module, struct ldb_map_context *data, 
1296                          const struct ldb_map_attribute *attrs, 
1297                          const struct ldb_map_objectclass *ocls, 
1298                          const char * const *wildcard_attributes)
1299 {
1300         int i, j, last;
1301         last = 0;
1302
1303         /* Count specified attribute maps */
1304         for (i = 0; attrs[i].local_name; i++) /* noop */ ;
1305         /* Count built-in attribute maps */
1306         for (j = 0; builtin_attribute_maps[j].local_name; j++) /* noop */ ;
1307
1308         /* Store list of attribute maps */
1309         data->attribute_maps = talloc_array(data, struct ldb_map_attribute, i+j+2);
1310         if (data->attribute_maps == NULL) {
1311                 map_oom(module);
1312                 return LDB_ERR_OPERATIONS_ERROR;
1313         }
1314
1315         /* Specified ones go first */
1316         for (i = 0; attrs[i].local_name; i++) {
1317                 data->attribute_maps[last] = attrs[i];
1318                 last++;
1319         }
1320
1321         /* Built-in ones go last */
1322         for (i = 0; builtin_attribute_maps[i].local_name; i++) {
1323                 data->attribute_maps[last] = builtin_attribute_maps[i];
1324                 last++;
1325         }
1326
1327         if (data->add_objectclass) {
1328                 /* ObjectClass one is very last, if required */
1329                 data->attribute_maps[last] = objectclass_attribute_map;
1330                 last++;
1331         } else if (ocls) {
1332                 data->attribute_maps[last] = objectclass_convert_map;
1333                 last++;
1334         }
1335
1336         /* Ensure 'local_name == NULL' for the last entry */
1337         memset(&data->attribute_maps[last], 0, sizeof(struct ldb_map_attribute));
1338
1339         /* Store list of objectClass maps */
1340         data->objectclass_maps = ocls;
1341
1342         data->wildcard_attributes = wildcard_attributes;
1343
1344         return LDB_SUCCESS;
1345 }
1346
1347 /* Copy the list of provided module operations. */
1348 _PUBLIC_ struct ldb_module_ops ldb_map_get_ops(void)
1349 {
1350         return map_ops;
1351 }
1352
1353 /* Initialize global private data. */
1354 _PUBLIC_ int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs, 
1355                           const struct ldb_map_objectclass *ocls,
1356                           const char * const *wildcard_attributes,
1357                           const char *add_objectclass,
1358                           const char *name)
1359 {
1360         struct map_private *data;
1361         int ret;
1362
1363         /* Prepare private data */
1364         data = talloc_zero(module, struct map_private);
1365         if (data == NULL) {
1366                 map_oom(module);
1367                 return LDB_ERR_OPERATIONS_ERROR;
1368         }
1369
1370         module->private_data = data;
1371
1372         data->context = talloc_zero(data, struct ldb_map_context);
1373         if (!data->context) {
1374                 map_oom(module);
1375                 return LDB_ERR_OPERATIONS_ERROR;                
1376         }
1377
1378         /* Store local and remote baseDNs */
1379         ret = map_init_dns(module, data->context, name);
1380         if (ret != LDB_SUCCESS) {
1381                 talloc_free(data);
1382                 return ret;
1383         }
1384
1385         data->context->add_objectclass = add_objectclass;
1386
1387         /* Store list of attribute and objectClass maps */
1388         ret = map_init_maps(module, data->context, attrs, ocls, wildcard_attributes);
1389         if (ret != LDB_SUCCESS) {
1390                 talloc_free(data);
1391                 return ret;
1392         }
1393
1394         return LDB_SUCCESS;
1395 }
1396
1397 /* Usage note for initialization of this module:
1398  *
1399  * ldb_map is meant to be used from a different module that sets up
1400  * the mappings and gets registered in ldb.
1401  *
1402  * 'ldb_map_init' initializes the private data of this module and
1403  * stores the attribute and objectClass maps in there.  It also looks
1404  * up the '@MAP' special DN so requests can be redirected to the
1405  * remote partition.
1406  *
1407  * This function should be called from the 'init_context' op of the
1408  * module using ldb_map.
1409  *
1410  * 'ldb_map_get_ops' returns a copy of ldb_maps module operations.
1411  *
1412  * It should be called from the initialize function of the using
1413  * module, which should then override the 'init_context' op with a
1414  * function making the appropriate calls to 'ldb_map_init'.
1415  */