~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

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