LCOV - code coverage report
Current view: top level - lib/ldb/ldb_map - ldb_map.c (source / functions) Hit Total Coverage
Test: coverage report for master 469b22b8 Lines: 293 521 56.2 %
Date: 2024-06-10 12:05:21 Functions: 27 32 84.4 %

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

Generated by: LCOV version 1.14