root/source4/lib/ldb/ldb_map/ldb_map.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. map_get_context
  2. map_init_context
  3. map_check_local_db
  4. ldb_dn_rebase_local
  5. ldb_dn_rebase_remote
  6. ldb_next_remote_request
  7. map_objectclass_find_local
  8. map_objectclass_find_remote
  9. map_attr_find_local
  10. map_attr_find_remote
  11. map_attr_check_remote
  12. map_attr_map_local
  13. map_attr_map_remote
  14. map_attrs_merge
  15. ldb_val_map_local
  16. ldb_val_map_remote
  17. ldb_dn_check_local
  18. ldb_dn_map_local
  19. ldb_dn_map_remote
  20. ldb_dn_map_rebase_remote
  21. ldb_dn_convert_local
  22. ldb_dn_convert_remote
  23. map_objectclass_convert_local
  24. map_objectclass_generate_remote
  25. map_objectclass_convert_remote
  26. map_objectclass_generate_local
  27. map_objectclass_convert_operator
  28. map_search_base_req
  29. map_build_fixup_req
  30. map_init_dns
  31. map_init_maps
  32. ldb_map_init

   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)
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
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, 
     /* [<][>][^][v][top][bottom][index][help] */
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 }

/* [<][>][^][v][top][bottom][index][help] */