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