Fix the mess with ldb includes.
[metze/samba/wip.git] / source4 / 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    Copyright (C) Simo Sorce 2008
7
8      ** NOTE! The following LGPL license applies to the ldb
9      ** library. This does NOT imply that all of Samba is released
10      ** under the LGPL
11    
12    This library is free software; you can redistribute it and/or
13    modify it under the terms of the GNU Lesser General Public
14    License as published by the Free Software Foundation; either
15    version 3 of the License, or (at your option) any later version.
16
17    This library is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20    Lesser General Public License for more details.
21
22    You should have received a copy of the GNU Lesser General Public
23    License along with this library; if not, see <http://www.gnu.org/licenses/>.
24
25 */
26
27 /* 
28  *  Name: ldb
29  *
30  *  Component: ldb ldb_map module
31  *
32  *  Description: Map portions of data into a different format on a
33  *  remote partition.
34  *
35  *  Author: Jelmer Vernooij, Martin Kuehl
36  */
37
38 #include "ldb_module.h"
39
40 #include "ldb_map.h"
41 #include "ldb_map_private.h"
42
43 #ifndef _PUBLIC_
44 #define _PUBLIC_
45 #endif
46
47 /* Description of the provided ldb requests:
48  - special attribute 'isMapped'
49
50  - search:
51      - if parse tree can be split
52          - search remote records w/ remote attrs and parse tree
53      - otherwise
54          - enumerate all remote records
55      - for each remote result
56          - map remote result to local message
57          - search local result
58          - is present
59              - merge local into remote result
60              - run callback on merged result
61          - otherwise
62              - run callback on remote result
63
64  - add:
65      - split message into local and remote part
66      - if local message is not empty
67          - add isMapped to local message
68          - add local message
69      - add remote message
70
71  - modify:
72      - split message into local and remote part
73      - if local message is not empty
74          - add isMapped to local message
75          - search for local record
76          - if present
77              - modify local record
78          - otherwise
79              - add local message
80      - modify remote record
81
82  - delete:
83      - search for local record
84      - if present
85          - delete local record
86      - delete remote record
87
88  - rename:
89      - search for local record
90      - if present
91          - rename local record
92          - modify local isMapped
93      - rename remote record
94 */
95
96
97
98 /* Private data structures
99  * ======================= */
100
101 /* Global private data */
102 /* Extract mappings from private data. */
103 const struct ldb_map_context *map_get_context(struct ldb_module *module)
104 {
105         const struct map_private *data = talloc_get_type(ldb_module_get_private(module), struct map_private);
106         return data->context;
107 }
108
109 /* Create a generic request context. */
110 struct map_context *map_init_context(struct ldb_module *module,
111                                         struct ldb_request *req)
112 {
113         struct ldb_context *ldb;
114         struct map_context *ac;
115
116         ldb = ldb_module_get_ctx(module);
117
118         ac = talloc_zero(req, struct map_context);
119         if (ac == NULL) {
120                 ldb_set_errstring(ldb, "Out of Memory");
121                 return NULL;
122         }
123
124         ac->module = module;
125         ac->req = req;
126
127         return ac;
128 }
129
130 /* Dealing with DNs for different partitions
131  * ========================================= */
132
133 /* Check whether any data should be stored in the local partition. */
134 bool map_check_local_db(struct ldb_module *module)
135 {
136         const struct ldb_map_context *data = map_get_context(module);
137
138         if (!data->remote_base_dn || !data->local_base_dn) {
139                 return false;
140         }
141
142         return true;
143 }
144
145 /* Copy a DN with the base DN of the local partition. */
146 static struct ldb_dn *ldb_dn_rebase_local(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn)
147 {
148         struct ldb_dn *new_dn;
149
150         new_dn = ldb_dn_copy(mem_ctx, dn);
151         if ( ! ldb_dn_validate(new_dn)) {
152                 talloc_free(new_dn);
153                 return NULL;
154         }
155
156         /* may be we don't need to rebase at all */
157         if ( ! data->remote_base_dn || ! data->local_base_dn) {
158                 return new_dn;
159         }
160
161         if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->remote_base_dn))) {
162                 talloc_free(new_dn);
163                 return NULL;
164         }
165
166         if ( ! ldb_dn_add_base(new_dn, data->local_base_dn)) {
167                 talloc_free(new_dn);
168                 return NULL;
169         }
170
171         return new_dn;
172 }
173
174 /* Copy a DN with the base DN of the remote partition. */
175 static struct ldb_dn *ldb_dn_rebase_remote(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn)
176 {
177         struct ldb_dn *new_dn;
178
179         new_dn = ldb_dn_copy(mem_ctx, dn);
180         if ( ! ldb_dn_validate(new_dn)) {
181                 talloc_free(new_dn);
182                 return NULL;
183         }
184
185         /* may be we don't need to rebase at all */
186         if ( ! data->remote_base_dn || ! data->local_base_dn) {
187                 return new_dn;
188         }
189
190         if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->local_base_dn))) {
191                 talloc_free(new_dn);
192                 return NULL;
193         }
194
195         if ( ! ldb_dn_add_base(new_dn, data->remote_base_dn)) {
196                 talloc_free(new_dn);
197                 return NULL;
198         }
199
200         return new_dn;
201 }
202
203 /* Run a request and make sure it targets the remote partition. */
204 /* TODO: free old DNs and messages? */
205 int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request)
206 {
207         const struct ldb_map_context *data = map_get_context(module);
208         struct ldb_context *ldb;
209         struct ldb_message *msg;
210
211         ldb = ldb_module_get_ctx(module);
212
213         switch (request->operation) {
214         case LDB_SEARCH:
215                 if (request->op.search.base) {
216                         request->op.search.base = ldb_dn_rebase_remote(request, data, request->op.search.base);
217                 } else {
218                         request->op.search.base = data->remote_base_dn;
219                         /* TODO: adjust scope? */
220                 }
221                 break;
222
223         case LDB_ADD:
224                 msg = ldb_msg_copy_shallow(request, request->op.add.message);
225                 msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn);
226                 request->op.add.message = msg;
227                 break;
228
229         case LDB_MODIFY:
230                 msg = ldb_msg_copy_shallow(request, request->op.mod.message);
231                 msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn);
232                 request->op.mod.message = msg;
233                 break;
234
235         case LDB_DELETE:
236                 request->op.del.dn = ldb_dn_rebase_remote(request, data, request->op.del.dn);
237                 break;
238
239         case LDB_RENAME:
240                 request->op.rename.olddn = ldb_dn_rebase_remote(request, data, request->op.rename.olddn);
241                 request->op.rename.newdn = ldb_dn_rebase_remote(request, data, request->op.rename.newdn);
242                 break;
243
244         default:
245                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
246                           "Invalid remote request!\n");
247                 return LDB_ERR_OPERATIONS_ERROR;
248         }
249
250         return ldb_next_request(module, request);
251 }
252
253
254 /* Finding mappings for attributes and objectClasses
255  * ================================================= */
256
257 /* Find an objectClass mapping by the local name. */
258 static const struct ldb_map_objectclass *map_objectclass_find_local(const struct ldb_map_context *data, const char *name)
259 {
260         int i;
261
262         for (i = 0; data->objectclass_maps && data->objectclass_maps[i].local_name; i++) {
263                 if (ldb_attr_cmp(data->objectclass_maps[i].local_name, name) == 0) {
264                         return &data->objectclass_maps[i];
265                 }
266         }
267
268         return NULL;
269 }
270
271 /* Find an objectClass mapping by the remote name. */
272 static const struct ldb_map_objectclass *map_objectclass_find_remote(const struct ldb_map_context *data, const char *name)
273 {
274         int i;
275
276         for (i = 0; data->objectclass_maps && data->objectclass_maps[i].remote_name; i++) {
277                 if (ldb_attr_cmp(data->objectclass_maps[i].remote_name, name) == 0) {
278                         return &data->objectclass_maps[i];
279                 }
280         }
281
282         return NULL;
283 }
284
285 /* Find an attribute mapping by the local name. */
286 const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name)
287 {
288         int i;
289
290         for (i = 0; data->attribute_maps[i].local_name; i++) {
291                 if (ldb_attr_cmp(data->attribute_maps[i].local_name, name) == 0) {
292                         return &data->attribute_maps[i];
293                 }
294         }
295         for (i = 0; data->attribute_maps[i].local_name; i++) {
296                 if (ldb_attr_cmp(data->attribute_maps[i].local_name, "*") == 0) {
297                         return &data->attribute_maps[i];
298                 }
299         }
300
301         return NULL;
302 }
303
304 /* Find an attribute mapping by the remote name. */
305 const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name)
306 {
307         const struct ldb_map_attribute *map;
308         const struct ldb_map_attribute *wildcard = NULL;
309         int i, j;
310
311         for (i = 0; data->attribute_maps[i].local_name; i++) {
312                 map = &data->attribute_maps[i];
313                 if (ldb_attr_cmp(map->local_name, "*") == 0) {
314                         wildcard = &data->attribute_maps[i];
315                 }
316
317                 switch (map->type) {
318                 case MAP_IGNORE:
319                         break;
320
321                 case MAP_KEEP:
322                         if (ldb_attr_cmp(map->local_name, name) == 0) {
323                                 return map;
324                         }
325                         break;
326
327                 case MAP_RENAME:
328                 case MAP_CONVERT:
329                         if (ldb_attr_cmp(map->u.rename.remote_name, name) == 0) {
330                                 return map;
331                         }
332                         break;
333
334                 case MAP_GENERATE:
335                         for (j = 0; map->u.generate.remote_names && map->u.generate.remote_names[j]; j++) {
336                                 if (ldb_attr_cmp(map->u.generate.remote_names[j], name) == 0) {
337                                         return map;
338                                 }
339                         }
340                         break;
341                 }
342         }
343
344         /* We didn't find it, so return the wildcard record if one was configured */
345         return wildcard;
346 }
347
348
349 /* Mapping attributes
350  * ================== */
351
352 /* Check whether an attribute will be mapped into the remote partition. */
353 bool map_attr_check_remote(const struct ldb_map_context *data, const char *attr)
354 {
355         const struct ldb_map_attribute *map = map_attr_find_local(data, attr);
356
357         if (map == NULL) {
358                 return false;
359         }
360         if (map->type == MAP_IGNORE) {
361                 return false;
362         }
363
364         return true;
365 }
366
367 /* Map an attribute name into the remote partition. */
368 const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr)
369 {
370         if (map == NULL) {
371                 return talloc_strdup(mem_ctx, attr);
372         }
373
374         switch (map->type) {
375         case MAP_KEEP:
376                 return talloc_strdup(mem_ctx, attr);
377
378         case MAP_RENAME:
379         case MAP_CONVERT:
380                 return talloc_strdup(mem_ctx, map->u.rename.remote_name);
381
382         default:
383                 return NULL;
384         }
385 }
386
387 /* Map an attribute name back into the local partition. */
388 const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr)
389 {
390         if (map == NULL) {
391                 return talloc_strdup(mem_ctx, attr);
392         }
393
394         if (map->type == MAP_KEEP) {
395                 return talloc_strdup(mem_ctx, attr);
396         }
397
398         return talloc_strdup(mem_ctx, map->local_name);
399 }
400
401
402 /* Merge two lists of attributes into a single one. */
403 int map_attrs_merge(struct ldb_module *module, void *mem_ctx, 
404                     const char ***attrs, const char * const *more_attrs)
405 {
406         int i, j, k;
407
408         for (i = 0; *attrs && (*attrs)[i]; i++) /* noop */ ;
409         for (j = 0; more_attrs && more_attrs[j]; j++) /* noop */ ;
410         
411         *attrs = talloc_realloc(mem_ctx, *attrs, const char *, i+j+1);
412         if (*attrs == NULL) {
413                 map_oom(module);
414                 return -1;
415         }
416
417         for (k = 0; k < j; k++) {
418                 (*attrs)[i + k] = more_attrs[k];
419         }
420
421         (*attrs)[i+k] = NULL;
422
423         return 0;
424 }
425
426 /* Mapping ldb values
427  * ================== */
428
429 /* Map an ldb value into the remote partition. */
430 struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, 
431                                  const struct ldb_map_attribute *map, const struct ldb_val *val)
432 {
433         if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_local)) {
434                 return map->u.convert.convert_local(module, mem_ctx, val);
435         }
436
437         return ldb_val_dup(mem_ctx, val);
438 }
439
440 /* Map an ldb value back into the local partition. */
441 struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, 
442                                   const struct ldb_map_attribute *map, const struct ldb_val *val)
443 {
444         if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_remote)) {
445                 return map->u.convert.convert_remote(module, mem_ctx, val);
446         }
447
448         return ldb_val_dup(mem_ctx, val);
449 }
450
451
452 /* Mapping DNs
453  * =========== */
454
455 /* Check whether a DN is below the local baseDN. */
456 bool ldb_dn_check_local(struct ldb_module *module, struct ldb_dn *dn)
457 {
458         const struct ldb_map_context *data = map_get_context(module);
459
460         if (!data->local_base_dn) {
461                 return true;
462         }
463
464         return ldb_dn_compare_base(data->local_base_dn, dn) == 0;
465 }
466
467 /* Map a DN into the remote partition. */
468 struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
469 {
470         const struct ldb_map_context *data = map_get_context(module);
471         struct ldb_context *ldb;
472         struct ldb_dn *newdn;
473         const struct ldb_map_attribute *map;
474         enum ldb_map_attr_type map_type;
475         const char *name;
476         struct ldb_val value;
477         int i, ret;
478
479         if (dn == NULL) {
480                 return NULL;
481         }
482
483         ldb = ldb_module_get_ctx(module);
484
485         newdn = ldb_dn_copy(mem_ctx, dn);
486         if (newdn == NULL) {
487                 map_oom(module);
488                 return NULL;
489         }
490
491         /* For each RDN, map the component name and possibly the value */
492         for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) {
493                 map = map_attr_find_local(data, ldb_dn_get_component_name(dn, i));
494
495                 /* Unknown attribute - leave this RDN as is and hope the best... */
496                 if (map == NULL) {
497                         map_type = MAP_KEEP;
498                 } else {
499                         map_type = map->type;
500                 }
501
502                 switch (map_type) {
503                 case MAP_IGNORE:
504                 case MAP_GENERATE:
505                         ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
506                                   "MAP_IGNORE/MAP_GENERATE attribute '%s' "
507                                   "used in DN!\n", ldb_dn_get_component_name(dn, i));
508                         goto failed;
509
510                 case MAP_CONVERT:
511                         if (map->u.convert.convert_local == NULL) {
512                                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
513                                           "'convert_local' not set for attribute '%s' "
514                                           "used in DN!\n", ldb_dn_get_component_name(dn, i));
515                                 goto failed;
516                         }
517                         /* fall through */
518                 case MAP_KEEP:
519                 case MAP_RENAME:
520                         name = map_attr_map_local(newdn, map, ldb_dn_get_component_name(dn, i));
521                         if (name == NULL) goto failed;
522
523                         value = ldb_val_map_local(module, newdn, map, ldb_dn_get_component_val(dn, i));
524                         if (value.data == NULL) goto failed;
525
526                         ret = ldb_dn_set_component(newdn, i, name, value);
527                         if (ret != LDB_SUCCESS) {
528                                 goto failed;
529                         }
530
531                         break;
532                 }
533         }
534
535         return newdn;
536
537 failed:
538         talloc_free(newdn);
539         return NULL;
540 }
541
542 /* Map a DN into the local partition. */
543 struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
544 {
545         const struct ldb_map_context *data = map_get_context(module);
546         struct ldb_context *ldb;
547         struct ldb_dn *newdn;
548         const struct ldb_map_attribute *map;
549         enum ldb_map_attr_type map_type;
550         const char *name;
551         struct ldb_val value;
552         int i, ret;
553
554         if (dn == NULL) {
555                 return NULL;
556         }
557
558         ldb = ldb_module_get_ctx(module);
559
560         newdn = ldb_dn_copy(mem_ctx, dn);
561         if (newdn == NULL) {
562                 map_oom(module);
563                 return NULL;
564         }
565
566         /* For each RDN, map the component name and possibly the value */
567         for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) {
568                 map = map_attr_find_remote(data, ldb_dn_get_component_name(dn, i));
569
570                 /* Unknown attribute - leave this RDN as is and hope the best... */
571                 if (map == NULL) {
572                         map_type = MAP_KEEP;
573                 } else {
574                         map_type = map->type;
575                 }
576
577                 switch (map_type) {
578                 case MAP_IGNORE:
579                 case MAP_GENERATE:
580                         ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
581                                   "MAP_IGNORE/MAP_GENERATE attribute '%s' "
582                                   "used in DN!\n", ldb_dn_get_component_name(dn, i));
583                         goto failed;
584
585                 case MAP_CONVERT:
586                         if (map->u.convert.convert_remote == NULL) {
587                                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
588                                           "'convert_remote' not set for attribute '%s' "
589                                           "used in DN!\n", ldb_dn_get_component_name(dn, i));
590                                 goto failed;
591                         }
592                         /* fall through */
593                 case MAP_KEEP:
594                 case MAP_RENAME:
595                         name = map_attr_map_remote(newdn, map, ldb_dn_get_component_name(dn, i));
596                         if (name == NULL) goto failed;
597
598                         value = ldb_val_map_remote(module, newdn, map, ldb_dn_get_component_val(dn, i));
599                         if (value.data == NULL) goto failed;
600
601                         ret = ldb_dn_set_component(newdn, i, name, value);
602                         if (ret != LDB_SUCCESS) {
603                                 goto failed;
604                         }
605
606                         break;
607                 }
608         }
609
610         return newdn;
611
612 failed:
613         talloc_free(newdn);
614         return NULL;
615 }
616
617 /* Map a DN and its base into the local partition. */
618 /* TODO: This should not be required with GUIDs. */
619 struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
620 {
621         const struct ldb_map_context *data = map_get_context(module);
622         struct ldb_dn *dn1, *dn2;
623
624         dn1 = ldb_dn_rebase_local(mem_ctx, data, dn);
625         dn2 = ldb_dn_map_remote(module, mem_ctx, dn1);
626
627         talloc_free(dn1);
628         return dn2;
629 }
630
631
632 /* Converting DNs and objectClasses (as ldb values)
633  * ================================================ */
634
635 /* Map a DN contained in an ldb value into the remote partition. */
636 static struct ldb_val ldb_dn_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
637 {
638         struct ldb_context *ldb;
639         struct ldb_dn *dn, *newdn;
640         struct ldb_val newval;
641
642         ldb = ldb_module_get_ctx(module);
643
644         dn = ldb_dn_from_ldb_val(mem_ctx, ldb, val);
645         if (! ldb_dn_validate(dn)) {
646                 newval.length = 0;
647                 newval.data = NULL;
648                 talloc_free(dn);
649                 return newval;
650         }
651         newdn = ldb_dn_map_local(module, mem_ctx, dn);
652         talloc_free(dn);
653
654         newval.length = 0;
655         newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn);
656         if (newval.data) {
657                 newval.length = strlen((char *)newval.data);
658         }
659         talloc_free(newdn);
660
661         return newval;
662 }
663
664 /* Map a DN contained in an ldb value into the local partition. */
665 static struct ldb_val ldb_dn_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
666 {
667         struct ldb_context *ldb;
668         struct ldb_dn *dn, *newdn;
669         struct ldb_val newval;
670
671         ldb = ldb_module_get_ctx(module);
672
673         dn = ldb_dn_from_ldb_val(mem_ctx, ldb, val);
674         if (! ldb_dn_validate(dn)) {
675                 newval.length = 0;
676                 newval.data = NULL;
677                 talloc_free(dn);
678                 return newval;
679         }
680         newdn = ldb_dn_map_remote(module, mem_ctx, dn);
681         talloc_free(dn);
682
683         newval.length = 0;
684         newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn);
685         if (newval.data) {
686                 newval.length = strlen((char *)newval.data);
687         }
688         talloc_free(newdn);
689
690         return newval;
691 }
692
693 /* Map an objectClass into the remote partition. */
694 static struct ldb_val map_objectclass_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
695 {
696         const struct ldb_map_context *data = map_get_context(module);
697         const char *name = (char *)val->data;
698         const struct ldb_map_objectclass *map = map_objectclass_find_local(data, name);
699         struct ldb_val newval;
700
701         if (map) {
702                 newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->remote_name);
703                 newval.length = strlen((char *)newval.data);
704                 return newval;
705         }
706
707         return ldb_val_dup(mem_ctx, val);
708 }
709
710 /* Generate a remote message with a mapped objectClass. */
711 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)
712 {
713         const struct ldb_map_context *data = map_get_context(module);
714         struct ldb_context *ldb;
715         struct ldb_message_element *el, *oc;
716         struct ldb_val val;
717         bool found_extensibleObject = false;
718         int i;
719
720         ldb = ldb_module_get_ctx(module);
721
722         /* Find old local objectClass */
723         oc = ldb_msg_find_element(old, "objectClass");
724         if (oc == NULL) {
725                 return;
726         }
727
728         /* Prepare new element */
729         el = talloc_zero(remote, struct ldb_message_element);
730         if (el == NULL) {
731                 ldb_oom(ldb);
732                 return;                 /* TODO: fail? */
733         }
734
735         /* Copy local objectClass element, reverse space for an extra value */
736         el->num_values = oc->num_values + 1;
737         el->values = talloc_array(el, struct ldb_val, el->num_values);
738         if (el->values == NULL) {
739                 talloc_free(el);
740                 ldb_oom(ldb);
741                 return;                 /* TODO: fail? */
742         }
743
744         /* Copy local element name "objectClass" */
745         el->name = talloc_strdup(el, local_attr);
746
747         /* Convert all local objectClasses */
748         for (i = 0; i < el->num_values - 1; i++) {
749                 el->values[i] = map_objectclass_convert_local(module, el->values, &oc->values[i]);
750                 if (ldb_attr_cmp((char *)el->values[i].data, data->add_objectclass) == 0) {
751                         found_extensibleObject = true;
752                 }
753         }
754
755         if (!found_extensibleObject) {
756                 val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass);
757                 val.length = strlen((char *)val.data);
758
759                 /* Append additional objectClass data->add_objectclass */
760                 el->values[i] = val;
761         } else {
762                 el->num_values--;
763         }
764
765         /* Add new objectClass to remote message */
766         ldb_msg_add(remote, el, 0);
767 }
768
769 /* Map an objectClass into the local partition. */
770 static struct ldb_val map_objectclass_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
771 {
772         const struct ldb_map_context *data = map_get_context(module);
773         const char *name = (char *)val->data;
774         const struct ldb_map_objectclass *map = map_objectclass_find_remote(data, name);
775         struct ldb_val newval;
776
777         if (map) {
778                 newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->local_name);
779                 newval.length = strlen((char *)newval.data);
780                 return newval;
781         }
782
783         return ldb_val_dup(mem_ctx, val);
784 }
785
786 /* Generate a local message with a mapped objectClass. */
787 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)
788 {
789         const struct ldb_map_context *data = map_get_context(module);
790         struct ldb_context *ldb;
791         struct ldb_message_element *el, *oc;
792         struct ldb_val val;
793         int i;
794
795         ldb = ldb_module_get_ctx(module);
796
797         /* Find old remote objectClass */
798         oc = ldb_msg_find_element(remote, "objectClass");
799         if (oc == NULL) {
800                 return NULL;
801         }
802
803         /* Prepare new element */
804         el = talloc_zero(mem_ctx, struct ldb_message_element);
805         if (el == NULL) {
806                 ldb_oom(ldb);
807                 return NULL;
808         }
809
810         /* Copy remote objectClass element */
811         el->num_values = oc->num_values;
812         el->values = talloc_array(el, struct ldb_val, el->num_values);
813         if (el->values == NULL) {
814                 talloc_free(el);
815                 ldb_oom(ldb);
816                 return NULL;
817         }
818
819         /* Copy remote element name "objectClass" */
820         el->name = talloc_strdup(el, local_attr);
821
822         /* Convert all remote objectClasses */
823         for (i = 0; i < el->num_values; i++) {
824                 el->values[i] = map_objectclass_convert_remote(module, el->values, &oc->values[i]);
825         }
826
827         val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass);
828         val.length = strlen((char *)val.data);
829
830         /* Remove last value if it was the string in data->add_objectclass (eg samba4top, extensibleObject) */
831         if (ldb_val_equal_exact(&val, &el->values[i-1])) {
832                 el->num_values--;
833                 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values);
834                 if (el->values == NULL) {
835                         talloc_free(el);
836                         ldb_oom(ldb);
837                         return NULL;
838                 }
839         }
840
841         return el;
842 }
843
844 static const struct ldb_map_attribute objectclass_convert_map = {
845         .local_name = "objectClass",
846         .type = MAP_CONVERT,
847         .u = {
848                 .convert = {
849                         .remote_name = "objectClass",
850                         .convert_local = map_objectclass_convert_local,
851                         .convert_remote = map_objectclass_convert_remote,
852                 },
853         },
854 };
855
856
857 /* Mappings for searches on objectClass= assuming a one-to-one
858  * mapping.  Needed because this is a generate operator for the
859  * add/modify code */
860 static int map_objectclass_convert_operator(struct ldb_module *module, void *mem_ctx, 
861                                             struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) 
862 {
863         
864         return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, &objectclass_convert_map);
865 }
866
867 /* Auxiliary request construction
868  * ============================== */
869
870 /* Build a request to search a record by its DN. */
871 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_map_callback_t callback)
872 {
873         const struct ldb_parse_tree *search_tree;
874         struct ldb_context *ldb;
875         struct ldb_request *req;
876         int ret;
877
878         ldb = ldb_module_get_ctx(ac->module);
879
880         if (tree) {
881                 search_tree = tree;
882         } else {
883                 search_tree = ldb_parse_tree(ac, NULL);
884                 if (search_tree == NULL) {
885                         return NULL;
886                 }
887         }
888
889         ret = ldb_build_search_req_ex(&req, ldb, ac,
890                                         dn, LDB_SCOPE_BASE,
891                                         search_tree, attrs,
892                                         NULL,
893                                         context, callback,
894                                         ac->req);
895         if (ret != LDB_SUCCESS) {
896                 return NULL;
897         }
898
899         return req;
900 }
901
902 /* Build a request to update the 'IS_MAPPED' attribute */
903 struct ldb_request *map_build_fixup_req(struct map_context *ac,
904                                         struct ldb_dn *olddn,
905                                         struct ldb_dn *newdn,
906                                         void *context,
907                                         ldb_map_callback_t callback)
908 {
909         struct ldb_context *ldb;
910         struct ldb_request *req;
911         struct ldb_message *msg;
912         const char *dn;
913         int ret;
914
915         ldb = ldb_module_get_ctx(ac->module);
916
917         /* Prepare message */
918         msg = ldb_msg_new(ac);
919         if (msg == NULL) {
920                 map_oom(ac->module);
921                 return NULL;
922         }
923
924         /* Update local 'IS_MAPPED' to the new remote DN */
925         msg->dn = ldb_dn_copy(msg, olddn);
926         dn = ldb_dn_alloc_linearized(msg, newdn);
927         if ( ! dn || ! ldb_dn_validate(msg->dn)) {
928                 goto failed;
929         }
930         if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
931                 goto failed;
932         }
933         if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
934                 goto failed;
935         }
936
937         /* Prepare request */
938         ret = ldb_build_mod_req(&req, ldb,
939                                 ac, msg, NULL,
940                                 context, callback,
941                                 ac->req);
942         if (ret != LDB_SUCCESS) {
943                 goto failed;
944         }
945         talloc_steal(req, msg);
946
947         return req;
948 failed:
949         talloc_free(msg);
950         return NULL;
951 }
952
953 /* Module initialization
954  * ===================== */
955
956
957 /* Builtin mappings for DNs and objectClasses */
958 static const struct ldb_map_attribute builtin_attribute_maps[] = {
959         {
960                 .local_name = "dn",
961                 .type = MAP_CONVERT,
962                 .u = {
963                         .convert = {
964                                  .remote_name = "dn",
965                                  .convert_local = ldb_dn_convert_local,
966                                  .convert_remote = ldb_dn_convert_remote,
967                          },
968                 },
969         },
970         {
971                 .local_name = NULL,
972         }
973 };
974
975 static const struct ldb_map_attribute objectclass_attribute_map = {
976         .local_name = "objectClass",
977         .type = MAP_GENERATE,
978         .convert_operator = map_objectclass_convert_operator,
979         .u = {
980                 .generate = {
981                         .remote_names = { "objectClass", NULL },
982                         .generate_local = map_objectclass_generate_local,
983                         .generate_remote = map_objectclass_generate_remote,
984                 },
985         },
986 };
987
988
989 /* Find the special 'MAP_DN_NAME' record and store local and remote
990  * base DNs in private data. */
991 static int map_init_dns(struct ldb_module *module, struct ldb_map_context *data, const char *name)
992 {
993         static const char * const attrs[] = { MAP_DN_FROM, MAP_DN_TO, NULL };
994         struct ldb_context *ldb;
995         struct ldb_dn *dn;
996         struct ldb_message *msg;
997         struct ldb_result *res;
998         int ret;
999
1000         if (!name) {
1001                 data->local_base_dn = NULL;
1002                 data->remote_base_dn = NULL;
1003                 return LDB_SUCCESS;
1004         }
1005
1006         ldb = ldb_module_get_ctx(module);
1007
1008         dn = ldb_dn_new_fmt(data, ldb, "%s=%s", MAP_DN_NAME, name);
1009         if ( ! ldb_dn_validate(dn)) {
1010                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
1011                           "Failed to construct '%s' DN!\n", MAP_DN_NAME);
1012                 return LDB_ERR_OPERATIONS_ERROR;
1013         }
1014
1015         ret = ldb_search(ldb, data, &res, dn, LDB_SCOPE_BASE, attrs, NULL);
1016         talloc_free(dn);
1017         if (ret != LDB_SUCCESS) {
1018                 return ret;
1019         }
1020         if (res->count == 0) {
1021                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
1022                           "No results for '%s=%s'!\n", MAP_DN_NAME, name);
1023                 talloc_free(res);
1024                 return LDB_ERR_CONSTRAINT_VIOLATION;
1025         }
1026         if (res->count > 1) {
1027                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
1028                           "Too many results for '%s=%s'!\n", MAP_DN_NAME, name);
1029                 talloc_free(res);
1030                 return LDB_ERR_CONSTRAINT_VIOLATION;
1031         }
1032
1033         msg = res->msgs[0];
1034         data->local_base_dn = ldb_msg_find_attr_as_dn(ldb, data, msg, MAP_DN_FROM);
1035         data->remote_base_dn = ldb_msg_find_attr_as_dn(ldb, data, msg, MAP_DN_TO);
1036         talloc_free(res);
1037
1038         return LDB_SUCCESS;
1039 }
1040
1041 /* Store attribute maps and objectClass maps in private data. */
1042 static int map_init_maps(struct ldb_module *module, struct ldb_map_context *data, 
1043                          const struct ldb_map_attribute *attrs, 
1044                          const struct ldb_map_objectclass *ocls, 
1045                          const char * const *wildcard_attributes)
1046 {
1047         int i, j, last;
1048         last = 0;
1049
1050         /* Count specified attribute maps */
1051         for (i = 0; attrs[i].local_name; i++) /* noop */ ;
1052         /* Count built-in attribute maps */
1053         for (j = 0; builtin_attribute_maps[j].local_name; j++) /* noop */ ;
1054
1055         /* Store list of attribute maps */
1056         data->attribute_maps = talloc_array(data, struct ldb_map_attribute, i+j+2);
1057         if (data->attribute_maps == NULL) {
1058                 map_oom(module);
1059                 return LDB_ERR_OPERATIONS_ERROR;
1060         }
1061
1062         /* Specified ones go first */
1063         for (i = 0; attrs[i].local_name; i++) {
1064                 data->attribute_maps[last] = attrs[i];
1065                 last++;
1066         }
1067
1068         /* Built-in ones go last */
1069         for (i = 0; builtin_attribute_maps[i].local_name; i++) {
1070                 data->attribute_maps[last] = builtin_attribute_maps[i];
1071                 last++;
1072         }
1073
1074         if (data->add_objectclass) {
1075                 /* ObjectClass one is very last, if required */
1076                 data->attribute_maps[last] = objectclass_attribute_map;
1077                 last++;
1078         } else if (ocls) {
1079                 data->attribute_maps[last] = objectclass_convert_map;
1080                 last++;
1081         }
1082
1083         /* Ensure 'local_name == NULL' for the last entry */
1084         memset(&data->attribute_maps[last], 0, sizeof(struct ldb_map_attribute));
1085
1086         /* Store list of objectClass maps */
1087         data->objectclass_maps = ocls;
1088
1089         data->wildcard_attributes = wildcard_attributes;
1090
1091         return LDB_SUCCESS;
1092 }
1093
1094 /* Initialize global private data. */
1095 _PUBLIC_ int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs, 
1096                           const struct ldb_map_objectclass *ocls,
1097                           const char * const *wildcard_attributes,
1098                           const char *add_objectclass,
1099                           const char *name)
1100 {
1101         struct map_private *data;
1102         int ret;
1103
1104         /* Prepare private data */
1105         data = talloc_zero(module, struct map_private);
1106         if (data == NULL) {
1107                 map_oom(module);
1108                 return LDB_ERR_OPERATIONS_ERROR;
1109         }
1110
1111         ldb_module_set_private(module, data);
1112
1113         data->context = talloc_zero(data, struct ldb_map_context);
1114         if (!data->context) {
1115                 map_oom(module);
1116                 return LDB_ERR_OPERATIONS_ERROR;                
1117         }
1118
1119         /* Store local and remote baseDNs */
1120         ret = map_init_dns(module, data->context, name);
1121         if (ret != LDB_SUCCESS) {
1122                 talloc_free(data);
1123                 return ret;
1124         }
1125
1126         data->context->add_objectclass = add_objectclass;
1127
1128         /* Store list of attribute and objectClass maps */
1129         ret = map_init_maps(module, data->context, attrs, ocls, wildcard_attributes);
1130         if (ret != LDB_SUCCESS) {
1131                 talloc_free(data);
1132                 return ret;
1133         }
1134
1135         return LDB_SUCCESS;
1136 }