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