~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/lib/ldb/modules/ldb_map.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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