LCOV - code coverage report
Current view: top level - lib/ldb/ldb_map - ldb_map_outbound.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 447 685 65.3 %
Date: 2021-09-23 10:06:22 Functions: 25 30 83.3 %

          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) Andrew Bartlett <abartlet@samba.org> 2006
       7             :    Copyright (C) Simo Sorce <idra@samba.org> 2008
       8             : 
       9             :      ** NOTE! The following LGPL license applies to the ldb
      10             :      ** library. This does NOT imply that all of Samba is released
      11             :      ** under the LGPL
      12             :    
      13             :    This library is free software; you can redistribute it and/or
      14             :    modify it under the terms of the GNU Lesser General Public
      15             :    License as published by the Free Software Foundation; either
      16             :    version 3 of the License, or (at your option) any later version.
      17             : 
      18             :    This library is distributed in the hope that it will be useful,
      19             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      20             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      21             :    Lesser General Public License for more details.
      22             : 
      23             :    You should have received a copy of the GNU Lesser General Public
      24             :    License along with this library; if not, see <http://www.gnu.org/licenses/>.
      25             : 
      26             : */
      27             : 
      28             : #include "replace.h"
      29             : #include "system/filesys.h"
      30             : #include "system/time.h"
      31             : #include "ldb_map.h"
      32             : #include "ldb_map_private.h"
      33             : 
      34             : 
      35             : /* Mapping attributes
      36             :  * ================== */
      37             : 
      38             : /* Select attributes that stay in the local partition. */
      39         155 : static const char **map_attrs_select_local(struct ldb_module *module, void *mem_ctx, const char * const *attrs)
      40             : {
      41         155 :         const struct ldb_map_context *data = map_get_context(module);
      42             :         const char **result;
      43             :         unsigned int i, last;
      44             : 
      45         155 :         if (attrs == NULL)
      46           0 :                 return NULL;
      47             : 
      48         155 :         last = 0;
      49         155 :         result = talloc_array(mem_ctx, const char *, 1);
      50         155 :         if (result == NULL) {
      51           0 :                 goto failed;
      52             :         }
      53         155 :         result[0] = NULL;
      54             : 
      55         658 :         for (i = 0; attrs[i]; i++) {
      56             :                 /* Wildcards and ignored attributes are kept locally */
      57         994 :                 if ((ldb_attr_cmp(attrs[i], "*") == 0) ||
      58         491 :                     (!map_attr_check_remote(data, attrs[i]))) {
      59         260 :                         result = talloc_realloc(mem_ctx, result, const char *, last+2);
      60         260 :                         if (result == NULL) {
      61           0 :                                 goto failed;
      62             :                         }
      63             : 
      64         260 :                         result[last] = talloc_strdup(result, attrs[i]);
      65         260 :                         result[last+1] = NULL;
      66         260 :                         last++;
      67             :                 }
      68             :         }
      69             : 
      70           0 :         return result;
      71             : 
      72           0 : failed:
      73           0 :         talloc_free(result);
      74           0 :         map_oom(module);
      75           0 :         return NULL;
      76             : }
      77             : 
      78             : /* Collect attributes that are mapped into the remote partition. */
      79         155 : static const char **map_attrs_collect_remote(struct ldb_module *module, void *mem_ctx, 
      80             :                                              const char * const *attrs)
      81             : {
      82         155 :         const struct ldb_map_context *data = map_get_context(module);
      83             :         const char **result;
      84             :         const struct ldb_map_attribute *map;
      85         155 :         const char *name=NULL;
      86             :         unsigned int i, j, last;
      87             :         int ret;
      88             : 
      89         155 :         last = 0;
      90         155 :         result = talloc_array(mem_ctx, const char *, 1);
      91         155 :         if (result == NULL) {
      92           0 :                 goto failed;
      93             :         }
      94         155 :         result[0] = NULL;
      95             : 
      96         646 :         for (i = 0; attrs[i]; i++) {
      97             :                 /* Wildcards are kept remotely, too */
      98         503 :                 if (ldb_attr_cmp(attrs[i], "*") == 0) {
      99          12 :                         const char **new_attrs = NULL;
     100          12 :                         ret = map_attrs_merge(module, mem_ctx, &new_attrs, attrs);
     101          12 :                         if (ret != LDB_SUCCESS) {
     102           0 :                                 goto failed;
     103             :                         }
     104          12 :                         ret = map_attrs_merge(module, mem_ctx, &new_attrs, data->wildcard_attributes);
     105          12 :                         if (ret != LDB_SUCCESS) {
     106           0 :                                 goto failed;
     107             :                         }
     108             : 
     109          12 :                         attrs = new_attrs;
     110          12 :                         break;
     111             :                 }
     112             :         }
     113             : 
     114         658 :         for (i = 0; attrs[i]; i++) {
     115             :                 /* Wildcards are kept remotely, too */
     116         503 :                 if (ldb_attr_cmp(attrs[i], "*") == 0) {
     117             :                         /* Add all 'include in wildcard' attributes */
     118           0 :                         name = attrs[i];
     119           0 :                         goto named;
     120             :                 }
     121             : 
     122             :                 /* Add remote names of mapped attrs */
     123         491 :                 map = map_attr_find_local(data, attrs[i]);
     124         491 :                 if (map == NULL) {
     125         147 :                         continue;
     126             :                 }
     127             : 
     128         344 :                 switch (map->type) {
     129         101 :                 case LDB_MAP_IGNORE:
     130         101 :                         continue;
     131             : 
     132          31 :                 case LDB_MAP_KEEP:
     133          31 :                         name = attrs[i];
     134          31 :                         goto named;
     135             : 
     136         207 :                 case LDB_MAP_RENAME:
     137             :                 case LDB_MAP_RENDROP:
     138             :                 case LDB_MAP_CONVERT:
     139         207 :                         name = map->u.rename.remote_name;
     140         207 :                         goto named;
     141             : 
     142           0 :                 case LDB_MAP_GENERATE:
     143             :                         /* Add all remote names of "generate" attrs */
     144           5 :                         for (j = 0; map->u.generate.remote_names[j]; j++) {
     145           5 :                                 result = talloc_realloc(mem_ctx, result, const char *, last+2);
     146           5 :                                 if (result == NULL) {
     147           0 :                                         goto failed;
     148             :                                 }
     149             : 
     150           5 :                                 result[last] = talloc_strdup(result, map->u.generate.remote_names[j]);
     151           5 :                                 result[last+1] = NULL;
     152           5 :                                 last++;
     153             :                         }
     154           5 :                         continue;
     155             :                 }
     156             : 
     157         250 :         named:  /* We found a single remote name, add that */
     158         250 :                 result = talloc_realloc(mem_ctx, result, const char *, last+2);
     159         250 :                 if (result == NULL) {
     160           0 :                         goto failed;
     161             :                 }
     162             : 
     163         250 :                 result[last] = talloc_strdup(result, name);
     164         250 :                 result[last+1] = NULL;
     165         250 :                 last++;
     166             :         }
     167             : 
     168           0 :         return result;
     169             : 
     170           0 : failed:
     171           0 :         talloc_free(result);
     172           0 :         map_oom(module);
     173           0 :         return NULL;
     174             : }
     175             : 
     176             : /* Split attributes that stay in the local partition from those that
     177             :  * are mapped into the remote partition. */
     178           0 : static int map_attrs_partition(struct ldb_module *module, void *mem_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *attrs)
     179             : {
     180         155 :         *local_attrs = map_attrs_select_local(module, mem_ctx, attrs);
     181         155 :         *remote_attrs = map_attrs_collect_remote(module, mem_ctx, attrs);
     182             : 
     183           0 :         return 0;
     184             : }
     185             : 
     186             : /* Mapping message elements
     187             :  * ======================== */
     188             : 
     189             : /* Add an element to a message, overwriting any old identically named elements. */
     190         702 : static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_element *el)
     191             : {
     192             :         struct ldb_message_element *old;
     193             :         unsigned j;
     194         702 :         old = ldb_msg_find_element(msg, el->name);
     195             : 
     196             :         /* no local result, add as new element */
     197         702 :         if (old == NULL) {
     198         616 :                 if (ldb_msg_add_empty(msg, el->name, 0, &old) != 0) {
     199           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     200             :                 }
     201             :         }
     202             :         else {
     203          86 :                 talloc_free(old->values);
     204             :         }
     205             : 
     206         702 :         old->values = talloc_array(msg->elements, struct ldb_val, el->num_values);
     207         702 :         old->num_values = el->num_values;
     208         702 :         if (old->values == NULL) {
     209           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     210             :         }
     211             :         /* copy the values into the element */
     212         753 :         for (j=0;j<el->num_values;j++) {
     213         753 :                 old->values[j] = ldb_val_dup(old->values, &el->values[j]);
     214         753 :                 if (old->values[j].data == NULL && el->values[j].length != 0) {
     215           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     216             :                 }
     217             :         }
     218             : 
     219           0 :         return 0;
     220             : }
     221             : 
     222             : /* Map a message element back into the local partition. */
     223         526 : static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *module, 
     224             :                                                          void *mem_ctx, 
     225             :                                                          const struct ldb_map_attribute *map, 
     226             :                                                          const char *attr_name,
     227             :                                                          const struct ldb_message_element *old)
     228             : {
     229         526 :         const struct ldb_map_context *data = map_get_context(module);
     230         526 :         const char *local_attr_name = attr_name;
     231             :         struct ldb_message_element *el;
     232             :         unsigned int i;
     233             : 
     234         526 :         el = talloc_zero(mem_ctx, struct ldb_message_element);
     235         526 :         if (el == NULL) {
     236           0 :                 map_oom(module);
     237           0 :                 return NULL;
     238             :         }
     239             : 
     240         526 :         el->values = talloc_array(el, struct ldb_val, old->num_values);
     241         526 :         if (el->values == NULL) {
     242           0 :                 talloc_free(el);
     243           0 :                 map_oom(module);
     244           0 :                 return NULL;
     245             :         }
     246             : 
     247       45168 :         for (i = 0; data->attribute_maps[i].local_name; i++) {
     248       45236 :                 struct ldb_map_attribute *am = &data->attribute_maps[i];
     249       49970 :                 if (((am->type == LDB_MAP_RENAME || am->type == LDB_MAP_RENDROP) &&
     250        4734 :                         !strcmp(am->u.rename.remote_name, attr_name))
     251       49970 :                     || (am->type == LDB_MAP_CONVERT &&
     252        4734 :                         !strcmp(am->u.convert.remote_name, attr_name))) {
     253             : 
     254           0 :                         local_attr_name = am->local_name;
     255           0 :                         break;
     256             :                 }
     257             :         }
     258             : 
     259         526 :         el->name = talloc_strdup(el, local_attr_name);
     260         526 :         if (el->name == NULL) {
     261           0 :                 talloc_free(el);
     262           0 :                 map_oom(module);
     263           0 :                 return NULL;
     264             :         }
     265             : 
     266         573 :         for (i = 0; i < old->num_values; i++) {
     267         577 :                 el->values[i] = ldb_val_map_remote(module, el->values, map, &old->values[i]);
     268             :                 /* Conversions might fail, in which case bail */
     269         577 :                 if (!el->values[i].data) {
     270           4 :                         talloc_free(el);
     271           0 :                         return NULL;
     272             :                 }
     273         573 :                 el->num_values++;
     274             :         }
     275             : 
     276           0 :         return el;
     277             : }
     278             : 
     279             : /* Merge a remote message element into a local message. */
     280        3314 : static int ldb_msg_el_merge(struct ldb_module *module, struct ldb_message *local, 
     281             :                             struct ldb_message *remote, const char *attr_name)
     282             : {
     283        3314 :         const struct ldb_map_context *data = map_get_context(module);
     284             :         const struct ldb_map_attribute *map;
     285        3314 :         struct ldb_message_element *old, *el=NULL;
     286        3314 :         const char *remote_name = NULL;
     287             :         struct ldb_context *ldb;
     288             : 
     289        3314 :         ldb = ldb_module_get_ctx(module);
     290             : 
     291             :         /* We handle wildcards in ldb_msg_el_merge_wildcard */
     292        3314 :         if (ldb_attr_cmp(attr_name, "*") == 0) {
     293           0 :                 return LDB_SUCCESS;
     294             :         }
     295             : 
     296        3286 :         map = map_attr_find_local(data, attr_name);
     297             : 
     298             :         /* Unknown attribute in remote message:
     299             :          * skip, attribute was probably auto-generated */
     300        3286 :         if (map == NULL) {
     301           0 :                 return LDB_SUCCESS;
     302             :         }
     303             : 
     304        3178 :         switch (map->type) {
     305           0 :         case LDB_MAP_IGNORE:
     306           0 :                 break;
     307         261 :         case LDB_MAP_CONVERT:
     308         261 :                 remote_name = map->u.convert.remote_name;
     309         261 :                 break;
     310         186 :         case LDB_MAP_KEEP:
     311         186 :                 remote_name = attr_name;
     312         186 :                 break;
     313         611 :         case LDB_MAP_RENAME:
     314             :         case LDB_MAP_RENDROP:
     315         611 :                 remote_name = map->u.rename.remote_name;
     316         611 :                 break;
     317           0 :         case LDB_MAP_GENERATE:
     318           0 :                 break;
     319             :         }
     320             : 
     321        3178 :         switch (map->type) {
     322           0 :         case LDB_MAP_IGNORE:
     323           0 :                 return LDB_SUCCESS;
     324             : 
     325         261 :         case LDB_MAP_CONVERT:
     326         261 :                 if (map->u.convert.convert_remote == NULL) {
     327           0 :                         ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
     328             :                                   "Skipping attribute '%s': "
     329             :                                   "'convert_remote' not set",
     330             :                                   attr_name);
     331           0 :                         return LDB_SUCCESS;
     332             :                 }
     333             : 
     334             :                 FALL_THROUGH;
     335             :         case LDB_MAP_KEEP:
     336             :         case LDB_MAP_RENAME:
     337             :         case LDB_MAP_RENDROP:
     338        1058 :                 old = ldb_msg_find_element(remote, remote_name);
     339        1058 :                 if (old) {
     340         526 :                         el = ldb_msg_el_map_remote(module, local, map, attr_name, old);
     341             :                 } else {
     342           0 :                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
     343             :                 }
     344         526 :                 break;
     345             : 
     346          50 :         case LDB_MAP_GENERATE:
     347          50 :                 if (map->u.generate.generate_local == NULL) {
     348           0 :                         ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
     349             :                                   "Skipping attribute '%s': "
     350             :                                   "'generate_local' not set",
     351             :                                   attr_name);
     352           0 :                         return LDB_SUCCESS;
     353             :                 }
     354             : 
     355          50 :                 el = map->u.generate.generate_local(module, local, attr_name, remote);
     356          50 :                 if (!el) {
     357             :                         /* Generation failure is probably due to lack of source attributes */
     358           0 :                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
     359             :                 }
     360           0 :                 break;
     361             :         }
     362             : 
     363         540 :         if (el == NULL) {
     364           0 :                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
     365             :         }
     366             : 
     367         536 :         return ldb_msg_replace(local, el);
     368             : }
     369             : 
     370             : /* Handle wildcard parts of merging a remote message element into a local message. */
     371          28 : static int ldb_msg_el_merge_wildcard(struct ldb_module *module, struct ldb_message *local, 
     372             :                                      struct ldb_message *remote)
     373             : {
     374          28 :         const struct ldb_map_context *data = map_get_context(module);
     375          28 :         const struct ldb_map_attribute *map = map_attr_find_local(data, "*");
     376          28 :         struct ldb_message_element *el=NULL;
     377             :         unsigned int i;
     378             :         int ret;
     379             : 
     380             :         /* Perhaps we have a mapping for "*" */
     381          28 :         if (map && map->type == LDB_MAP_KEEP) {
     382             :                 /* We copy everything over, and hope that anything with a 
     383             :                    more specific rule is overwritten */
     384           0 :                 for (i = 0; i < remote->num_elements; i++) {
     385           0 :                         el = ldb_msg_el_map_remote(module, local, map, remote->elements[i].name,
     386           0 :                                                    &remote->elements[i]);
     387           0 :                         if (el == NULL) {
     388           0 :                                 return LDB_ERR_OPERATIONS_ERROR;
     389             :                         }
     390             :                         
     391           0 :                         ret = ldb_msg_replace(local, el);
     392           0 :                         if (ret) {
     393           0 :                                 return ret;
     394             :                         }
     395             :                 }
     396             :         }
     397             :         
     398             :         /* Now walk the list of possible mappings, and apply each */
     399        2408 :         for (i = 0; data->attribute_maps[i].local_name; i++) {
     400        2408 :                 ret = ldb_msg_el_merge(module, local, remote, 
     401           0 :                                        data->attribute_maps[i].local_name);
     402        2408 :                 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
     403         421 :                         continue;
     404        1987 :                 } else if (ret) {
     405           0 :                         return ret;
     406             :                 } else {
     407        1987 :                         continue;
     408             :                 }
     409             :         }
     410             : 
     411           0 :         return LDB_SUCCESS;
     412             : }
     413             : 
     414             : /* Mapping messages
     415             :  * ================ */
     416             : 
     417             : /* Merge two local messages into a single one. */
     418           0 : static int ldb_msg_merge_local(struct ldb_module *module, struct ldb_message *msg1, struct ldb_message *msg2)
     419             : {
     420             :         unsigned int i;
     421             :         int ret;
     422             : 
     423         166 :         for (i = 0; i < msg2->num_elements; i++) {
     424         166 :                 ret = ldb_msg_replace(msg1, &msg2->elements[i]);
     425         166 :                 if (ret) {
     426           0 :                         return ret;
     427             :                 }
     428             :         }
     429             : 
     430           0 :         return LDB_SUCCESS;
     431             : }
     432             : 
     433             : /* Merge a local and a remote message into a single local one. */
     434         231 : static int ldb_msg_merge_remote(struct map_context *ac, struct ldb_message *local, 
     435             :                                 struct ldb_message *remote)
     436             : {
     437             :         unsigned int i;
     438             :         int ret;
     439         231 :         const char * const *attrs = ac->all_attrs;
     440         231 :         if (!attrs) {
     441           0 :                 ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
     442           0 :                 if (ret) {
     443           0 :                         return ret;
     444             :                 }
     445             :         }
     446             : 
     447        1109 :         for (i = 0; attrs && attrs[i]; i++) {
     448         906 :                 if (ldb_attr_cmp(attrs[i], "*") == 0) {
     449          28 :                         ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
     450          28 :                         if (ret) {
     451           0 :                                 return ret;
     452             :                         }
     453           0 :                         break;
     454             :                 }
     455             :         }
     456             : 
     457             :         /* Try to map each attribute back;
     458             :          * Add to local message is possible,
     459             :          * Overwrite old local attribute if necessary */
     460         906 :         for (i = 0; attrs && attrs[i]; i++) {
     461         906 :                 ret = ldb_msg_el_merge(ac->module, local, remote, 
     462           0 :                                        attrs[i]);
     463         906 :                 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
     464         755 :                 } else if (ret) {
     465           0 :                         return ret;
     466             :                 }
     467             :         }
     468             : 
     469           0 :         return LDB_SUCCESS;
     470             : }
     471             : 
     472             : /* Mapping search results
     473             :  * ====================== */
     474             : 
     475             : /* Map a search result back into the local partition. */
     476         231 : static int map_reply_remote(struct map_context *ac, struct ldb_reply *ares)
     477             : {
     478             :         struct ldb_message *msg;
     479             :         struct ldb_dn *dn;
     480             :         int ret;
     481             : 
     482             :         /* There is no result message, skip */
     483         231 :         if (ares->type != LDB_REPLY_ENTRY) {
     484           0 :                 return 0;
     485             :         }
     486             : 
     487             :         /* Create a new result message */
     488         231 :         msg = ldb_msg_new(ares);
     489         231 :         if (msg == NULL) {
     490           0 :                 map_oom(ac->module);
     491           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     492             :         }
     493             : 
     494             :         /* Merge remote message into new message */
     495         231 :         ret = ldb_msg_merge_remote(ac, msg, ares->message);
     496         231 :         if (ret) {
     497           0 :                 talloc_free(msg);
     498           0 :                 return ret;
     499             :         }
     500             : 
     501             :         /* Create corresponding local DN */
     502         231 :         dn = ldb_dn_map_rebase_remote(ac->module, msg, ares->message->dn);
     503         231 :         if (dn == NULL) {
     504           0 :                 talloc_free(msg);
     505           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     506             :         }
     507         231 :         msg->dn = dn;
     508             : 
     509             :         /* Store new message with new DN as the result */
     510         231 :         talloc_free(ares->message);
     511         231 :         ares->message = msg;
     512             : 
     513         231 :         return 0;
     514             : }
     515             : 
     516             : /* Mapping parse trees
     517             :  * =================== */
     518             : 
     519             : /* Check whether a parse tree can safely be split in two. */
     520           0 : static bool ldb_parse_tree_check_splittable(const struct ldb_parse_tree *tree)
     521             : {
     522         111 :         const struct ldb_parse_tree *subtree = tree;
     523         111 :         bool negate = false;
     524             : 
     525         113 :         while (subtree) {
     526         113 :                 switch (subtree->operation) {
     527           2 :                 case LDB_OP_NOT:
     528           2 :                         negate = !negate;
     529           2 :                         subtree = subtree->u.isnot.child;
     530           2 :                         continue;
     531             : 
     532           5 :                 case LDB_OP_AND:
     533           5 :                         return !negate; /* if negate: False */
     534             : 
     535           0 :                 case LDB_OP_OR:
     536           0 :                         return negate;  /* if negate: True */
     537             : 
     538           0 :                 default:
     539           0 :                         return true;    /* simple parse tree */
     540             :                 }
     541             :         }
     542             : 
     543           0 :         return true;                    /* no parse tree */
     544             : }
     545             : 
     546             : /* Collect a list of attributes required to match a given parse tree. */
     547         432 : static int ldb_parse_tree_collect_attrs(struct ldb_module *module, void *mem_ctx, const char ***attrs, const struct ldb_parse_tree *tree)
     548             : {
     549             :         const char **new_attrs;
     550             :         unsigned int i;
     551             :         int ret;
     552             : 
     553         441 :         if (tree == NULL) {
     554           0 :                 return 0;
     555             :         }
     556             : 
     557         441 :         switch (tree->operation) {
     558           0 :         case LDB_OP_OR:
     559             :         case LDB_OP_AND:                /* attributes stored in list of subtrees */
     560         277 :                 for (i = 0; i < tree->u.list.num_elements; i++) {
     561         277 :                         ret = ldb_parse_tree_collect_attrs(module, mem_ctx, 
     562         277 :                                                            attrs, tree->u.list.elements[i]);
     563         277 :                         if (ret) {
     564           0 :                                 return ret;
     565             :                         }
     566             :                 }
     567           0 :                 return 0;
     568             : 
     569           9 :         case LDB_OP_NOT:                /* attributes stored in single subtree */
     570           9 :                 return ldb_parse_tree_collect_attrs(module, mem_ctx, attrs, tree->u.isnot.child);
     571             : 
     572         300 :         default:                        /* single attribute in tree */
     573         300 :                 new_attrs = ldb_attr_list_copy_add(mem_ctx, *attrs, tree->u.equality.attr);
     574         300 :                 talloc_free(*attrs);
     575         300 :                 *attrs = new_attrs;
     576         300 :                 return 0;
     577             :         }
     578             : }
     579             : 
     580             : static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
     581             : 
     582             : /* Select a negated subtree that queries attributes in the local partition */
     583           9 : static int map_subtree_select_local_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
     584             : {
     585             :         struct ldb_parse_tree *child;
     586             :         int ret;
     587             : 
     588             :         /* Prepare new tree */
     589           9 :         *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
     590           9 :         if (*new == NULL) {
     591           0 :                 map_oom(module);
     592           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     593             :         }
     594             : 
     595             :         /* Generate new subtree */
     596           9 :         ret = map_subtree_select_local(module, *new, &child, tree->u.isnot.child);
     597           9 :         if (ret) {
     598           0 :                 talloc_free(*new);
     599           0 :                 return ret;
     600             :         }
     601             : 
     602             :         /* Prune tree without subtree */
     603           9 :         if (child == NULL) {
     604           4 :                 talloc_free(*new);
     605           4 :                 *new = NULL;
     606           4 :                 return 0;
     607             :         }
     608             : 
     609           5 :         (*new)->u.isnot.child = child;
     610             : 
     611           5 :         return ret;
     612             : }
     613             : 
     614             : /* Select a list of subtrees that query attributes in the local partition */
     615         132 : static int map_subtree_select_local_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
     616             : {
     617             :         unsigned int i, j;
     618         132 :         int ret=0;
     619             : 
     620             :         /* Prepare new tree */
     621         132 :         *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
     622         132 :         if (*new == NULL) {
     623           0 :                 map_oom(module);
     624           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     625             :         }
     626             : 
     627             :         /* Prepare list of subtrees */
     628         132 :         (*new)->u.list.num_elements = 0;
     629         132 :         (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
     630         132 :         if ((*new)->u.list.elements == NULL) {
     631           0 :                 map_oom(module);
     632           0 :                 talloc_free(*new);
     633           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     634             :         }
     635             : 
     636             :         /* Generate new list of subtrees */
     637           0 :         j = 0;
     638         277 :         for (i = 0; i < tree->u.list.num_elements; i++) {
     639         277 :                 struct ldb_parse_tree *child = NULL;
     640         277 :                 ret = map_subtree_select_local(module, *new, &child, tree->u.list.elements[i]);
     641         277 :                 if (ret) {
     642           0 :                         talloc_free(*new);
     643           0 :                         return ret;
     644             :                 }
     645             : 
     646         277 :                 if (child) {
     647         121 :                         (*new)->u.list.elements[j] = child;
     648         121 :                         j++;
     649             :                 }
     650             :         }
     651             : 
     652             :         /* Prune tree without subtrees */
     653         132 :         if (j == 0) {
     654          16 :                 talloc_free(*new);
     655          16 :                 *new = NULL;
     656          16 :                 return 0;
     657             :         }
     658             : 
     659             :         /* Fix subtree list size */
     660         116 :         (*new)->u.list.num_elements = j;
     661         116 :         (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
     662             : 
     663         116 :         return ret;
     664             : }
     665             : 
     666             : /* Select a simple subtree that queries attributes in the local partition */
     667         124 : static int map_subtree_select_local_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
     668             : {
     669             :         /* Prepare new tree */
     670         124 :         *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
     671         124 :         if (*new == NULL) {
     672           0 :                 map_oom(module);
     673           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     674             :         }
     675             : 
     676           0 :         return 0;
     677             : }
     678             : 
     679             : /* Select subtrees that query attributes in the local partition */
     680         441 : static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
     681             : {
     682         441 :         const struct ldb_map_context *data = map_get_context(module);
     683             : 
     684         441 :         if (tree == NULL) {
     685           0 :                 return 0;
     686             :         }
     687             : 
     688         441 :         if (tree->operation == LDB_OP_NOT) {
     689           9 :                 return map_subtree_select_local_not(module, mem_ctx, new, tree);
     690             :         }
     691             : 
     692         432 :         if (tree->operation == LDB_OP_AND || tree->operation == LDB_OP_OR) {
     693         132 :                 return map_subtree_select_local_list(module, mem_ctx, new, tree);
     694             :         }
     695             : 
     696         300 :         if (map_attr_check_remote(data, tree->u.equality.attr)) {
     697         176 :                 *new = NULL;
     698         176 :                 return 0;
     699             :         }
     700             : 
     701         124 :         return map_subtree_select_local_simple(module, mem_ctx, new, tree);
     702             : }
     703             : 
     704             : static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
     705             : 
     706             : /* Collect a negated subtree that queries attributes in the remote partition */
     707           9 : static int map_subtree_collect_remote_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
     708             : {
     709             :         struct ldb_parse_tree *child;
     710             :         int ret;
     711             : 
     712             :         /* Prepare new tree */
     713           9 :         *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
     714           9 :         if (*new == NULL) {
     715           0 :                 map_oom(module);
     716           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     717             :         }
     718             : 
     719             :         /* Generate new subtree */
     720           9 :         ret = map_subtree_collect_remote(module, *new, &child, tree->u.isnot.child);
     721           9 :         if (ret) {
     722           0 :                 talloc_free(*new);
     723           0 :                 return ret;
     724             :         }
     725             : 
     726             :         /* Prune tree without subtree */
     727           9 :         if (child == NULL) {
     728           3 :                 talloc_free(*new);
     729           3 :                 *new = NULL;
     730           3 :                 return 0;
     731             :         }
     732             : 
     733           6 :         (*new)->u.isnot.child = child;
     734             : 
     735           6 :         return ret;
     736             : }
     737             : 
     738             : /* Collect a list of subtrees that query attributes in the remote partition */
     739         132 : static int map_subtree_collect_remote_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
     740             : {
     741             :         unsigned int i, j;
     742         132 :         int ret=0;
     743             : 
     744             :         /* Prepare new tree */
     745         132 :         *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
     746         132 :         if (*new == NULL) {
     747           0 :                 map_oom(module);
     748           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     749             :         }
     750             : 
     751             :         /* Prepare list of subtrees */
     752         132 :         (*new)->u.list.num_elements = 0;
     753         132 :         (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
     754         132 :         if ((*new)->u.list.elements == NULL) {
     755           0 :                 map_oom(module);
     756           0 :                 talloc_free(*new);
     757           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     758             :         }
     759             : 
     760             :         /* Generate new list of subtrees */
     761           0 :         j = 0;
     762         277 :         for (i = 0; i < tree->u.list.num_elements; i++) {
     763             :                 struct ldb_parse_tree *child;
     764         277 :                 ret = map_subtree_collect_remote(module, *new, &child, tree->u.list.elements[i]);
     765         277 :                 if (ret) {
     766           0 :                         talloc_free(*new);
     767           0 :                         return ret;
     768             :                 }
     769             : 
     770         277 :                 if (child) {
     771         153 :                         (*new)->u.list.elements[j] = child;
     772         153 :                         j++;
     773             :                 }
     774             :         }
     775             : 
     776             :         /* Prune tree without subtrees */
     777         132 :         if (j == 0) {
     778           5 :                 talloc_free(*new);
     779           5 :                 *new = NULL;
     780           5 :                 return 0;
     781             :         }
     782             : 
     783             :         /* Fix subtree list size */
     784         127 :         (*new)->u.list.num_elements = j;
     785         127 :         (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
     786             : 
     787         127 :         return ret;
     788             : }
     789             : 
     790             : /* Collect a simple subtree that queries attributes in the remote partition */
     791         172 : int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree, const struct ldb_map_attribute *map)
     792             : {
     793             :         const char *attr;
     794             : 
     795             :         /* Prepare new tree */
     796         172 :         *new = talloc(mem_ctx, struct ldb_parse_tree);
     797         172 :         if (*new == NULL) {
     798           0 :                 map_oom(module);
     799           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     800             :         }
     801         172 :         **new = *tree;
     802             :         
     803         172 :         if (map->type == LDB_MAP_KEEP) {
     804             :                 /* Nothing to do here */
     805           0 :                 return 0;
     806             :         }
     807             : 
     808             :         /* Store attribute and value in new tree */
     809         157 :         switch (tree->operation) {
     810         105 :         case LDB_OP_PRESENT:
     811         105 :                 attr = map_attr_map_local(*new, map, tree->u.present.attr);
     812         105 :                 (*new)->u.present.attr = attr;
     813         105 :                 break;
     814           0 :         case LDB_OP_SUBSTRING:
     815             :         {
     816           0 :                 attr = map_attr_map_local(*new, map, tree->u.substring.attr);
     817           0 :                 (*new)->u.substring.attr = attr;
     818           0 :                 break;
     819             :         }
     820          52 :         case LDB_OP_EQUALITY:
     821          52 :                 attr = map_attr_map_local(*new, map, tree->u.equality.attr);
     822          52 :                 (*new)->u.equality.attr = attr;
     823          52 :                 break;
     824           0 :         case LDB_OP_LESS:
     825             :         case LDB_OP_GREATER:
     826             :         case LDB_OP_APPROX:
     827           0 :                 attr = map_attr_map_local(*new, map, tree->u.comparison.attr);
     828           0 :                 (*new)->u.comparison.attr = attr;
     829           0 :                 break;
     830           0 :         case LDB_OP_EXTENDED:
     831           0 :                 attr = map_attr_map_local(*new, map, tree->u.extended.attr);
     832           0 :                 (*new)->u.extended.attr = attr;
     833           0 :                 break;
     834           0 :         default:                        /* unknown kind of simple subtree */
     835           0 :                 talloc_free(*new);
     836           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     837             :         }
     838             : 
     839         157 :         if (attr == NULL) {
     840           0 :                 talloc_free(*new);
     841           0 :                 *new = NULL;
     842           0 :                 return 0;
     843             :         }
     844             : 
     845         157 :         if (map->type == LDB_MAP_RENAME || map->type == LDB_MAP_RENDROP) {
     846             :                 /* Nothing more to do here, the attribute has been renamed */
     847           0 :                 return 0;
     848             :         }
     849             : 
     850             :         /* Store attribute and value in new tree */
     851         138 :         switch (tree->operation) {
     852           0 :         case LDB_OP_PRESENT:
     853           0 :                 break;
     854           0 :         case LDB_OP_SUBSTRING:
     855             :         {
     856             :                 int i;
     857             :                 /* Map value */
     858           0 :                 (*new)->u.substring.chunks = NULL;
     859           0 :                 for (i=0; tree->u.substring.chunks && tree->u.substring.chunks[i]; i++) {
     860           0 :                         (*new)->u.substring.chunks = talloc_realloc(*new, (*new)->u.substring.chunks, struct ldb_val *, i+2);
     861           0 :                         if (!(*new)->u.substring.chunks) {
     862           0 :                                 talloc_free(*new);
     863           0 :                                 *new = NULL;
     864           0 :                                 return 0;
     865             :                         }
     866           0 :                         (*new)->u.substring.chunks[i] = talloc(*new, struct ldb_val);
     867           0 :                         if (!(*new)->u.substring.chunks[i]) {
     868           0 :                                 talloc_free(*new);
     869           0 :                                 *new = NULL;
     870           0 :                                 return 0;
     871             :                         }
     872           0 :                         *(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, tree->u.substring.chunks[i]);
     873           0 :                         (*new)->u.substring.chunks[i+1] = NULL;
     874             :                 }
     875           0 :                 break;
     876             :         }
     877          33 :         case LDB_OP_EQUALITY:
     878          33 :                 (*new)->u.equality.value = ldb_val_map_local(module, *new, map, &tree->u.equality.value);
     879          33 :                 break;
     880           0 :         case LDB_OP_LESS:
     881             :         case LDB_OP_GREATER:
     882             :         case LDB_OP_APPROX:
     883           0 :                 (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, &tree->u.comparison.value);
     884           0 :                 break;
     885           0 :         case LDB_OP_EXTENDED:
     886           0 :                 (*new)->u.extended.value = ldb_val_map_local(module, *new, map, &tree->u.extended.value);
     887           0 :                 (*new)->u.extended.rule_id = talloc_strdup(*new, tree->u.extended.rule_id);
     888           0 :                 break;
     889           0 :         default:                        /* unknown kind of simple subtree */
     890           0 :                 talloc_free(*new);
     891           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     892             :         }
     893             : 
     894           0 :         return 0;
     895             : }
     896             : 
     897             : /* Collect subtrees that query attributes in the remote partition */
     898         441 : static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
     899             : {
     900         441 :         const struct ldb_map_context *data = map_get_context(module);
     901             :         const struct ldb_map_attribute *map;
     902             :         struct ldb_context *ldb;
     903             : 
     904         441 :         ldb = ldb_module_get_ctx(module);
     905             : 
     906         441 :         if (tree == NULL) {
     907           0 :                 return 0;
     908             :         }
     909             : 
     910         441 :         if (tree->operation == LDB_OP_NOT) {
     911           9 :                 return map_subtree_collect_remote_not(module, mem_ctx, new, tree);
     912             :         }
     913             : 
     914         432 :         if ((tree->operation == LDB_OP_AND) || (tree->operation == LDB_OP_OR)) {
     915         132 :                 return map_subtree_collect_remote_list(module, mem_ctx, new, tree);
     916             :         }
     917             : 
     918         300 :         if (!map_attr_check_remote(data, tree->u.equality.attr)) {
     919         124 :                 *new = NULL;
     920         124 :                 return 0;
     921             :         }
     922             : 
     923         176 :         map = map_attr_find_local(data, tree->u.equality.attr);
     924         176 :         if (map == NULL) {
     925           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     926             :         }
     927         176 :         if (map->convert_operator) {
     928           0 :                 return map->convert_operator(module, mem_ctx, new, tree);
     929             :         }
     930             : 
     931         176 :         if (map->type == LDB_MAP_GENERATE) {
     932           4 :                 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
     933             :                           "Skipping attribute '%s': "
     934             :                           "'convert_operator' not set",
     935           0 :                           tree->u.equality.attr);
     936           4 :                 *new = NULL;
     937           4 :                 return 0;
     938             :         }
     939             : 
     940         172 :         return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, map);
     941             : }
     942             : 
     943             : /* Split subtrees that query attributes in the local partition from
     944             :  * those that query the remote partition. */
     945         155 : static int ldb_parse_tree_partition(struct ldb_module *module,
     946             :                                         void *mem_ctx,
     947             :                                         struct ldb_parse_tree **local_tree,
     948             :                                         struct ldb_parse_tree **remote_tree,
     949             :                                         const struct ldb_parse_tree *tree)
     950             : {
     951             :         int ret;
     952             : 
     953         155 :         *local_tree = NULL;
     954         155 :         *remote_tree = NULL;
     955             : 
     956             :         /* No original tree */
     957         155 :         if (tree == NULL) {
     958           0 :                 return 0;
     959             :         }
     960             : 
     961             :         /* Generate local tree */
     962         155 :         ret = map_subtree_select_local(module, mem_ctx, local_tree, tree);
     963         155 :         if (ret) {
     964           0 :                 return ret;
     965             :         }
     966             : 
     967             :         /* Generate remote tree */
     968         155 :         ret = map_subtree_collect_remote(module, mem_ctx, remote_tree, tree);
     969         155 :         if (ret) {
     970           0 :                 talloc_free(*local_tree);
     971           0 :                 return ret;
     972             :         }
     973             : 
     974           0 :         return 0;
     975             : }
     976             : 
     977             : /* Collect a list of attributes required either explicitly from a
     978             :  * given list or implicitly  from a given parse tree; split the
     979             :  * collected list into local and remote parts. */
     980         155 : static int map_attrs_collect_and_partition(struct ldb_module *module, struct map_context *ac,
     981             :                                            const char * const *search_attrs, 
     982             :                                            const struct ldb_parse_tree *tree)
     983             : {
     984             :         void *tmp_ctx;
     985             :         const char **tree_attrs;
     986             :         const char **remote_attrs;
     987             :         const char **local_attrs;
     988             :         int ret;
     989             : 
     990             :         /* There is no tree, just partition the searched attributes */
     991         155 :         if (tree == NULL) {
     992           0 :                 ret = map_attrs_partition(module, ac, 
     993             :                                           &local_attrs, &remote_attrs, search_attrs);
     994           0 :                 if (ret == 0) {
     995           0 :                         ac->local_attrs = local_attrs;
     996           0 :                         ac->remote_attrs = remote_attrs;
     997           0 :                         ac->all_attrs = search_attrs;
     998             :                 }
     999           0 :                 return ret; 
    1000             :         }
    1001             : 
    1002             :         /* Create context for temporary memory */
    1003         155 :         tmp_ctx = talloc_new(ac);
    1004         155 :         if (tmp_ctx == NULL) {
    1005           0 :                 goto oom;
    1006             :         }
    1007             : 
    1008             :         /* Prepare list of attributes from tree */
    1009         155 :         tree_attrs = talloc_array(tmp_ctx, const char *, 1);
    1010         155 :         if (tree_attrs == NULL) {
    1011           0 :                 talloc_free(tmp_ctx);
    1012           0 :                 goto oom;
    1013             :         }
    1014         155 :         tree_attrs[0] = NULL;
    1015             : 
    1016             :         /* Collect attributes from tree */
    1017         155 :         ret = ldb_parse_tree_collect_attrs(module, tmp_ctx, &tree_attrs, tree);
    1018         155 :         if (ret) {
    1019           0 :                 goto done;
    1020             :         }
    1021             : 
    1022             :         /* Merge attributes from search operation */
    1023         155 :         ret = map_attrs_merge(module, tmp_ctx, &tree_attrs, search_attrs);
    1024         155 :         if (ret) {
    1025           0 :                 goto done;
    1026             :         }
    1027             : 
    1028             :         /* Split local from remote attributes */
    1029         310 :         ret = map_attrs_partition(module, ac, &local_attrs, 
    1030             :                                   &remote_attrs, tree_attrs);
    1031             :         
    1032           0 :         if (ret == 0) {
    1033         155 :                 ac->local_attrs = local_attrs;
    1034         155 :                 ac->remote_attrs = remote_attrs;
    1035         155 :                 talloc_steal(ac, tree_attrs);
    1036         155 :                 ac->all_attrs = tree_attrs;
    1037             :         }
    1038         155 : done:
    1039             :         /* Free temporary memory */
    1040         155 :         talloc_free(tmp_ctx);
    1041         155 :         return ret;
    1042             : 
    1043           0 : oom:
    1044           0 :         map_oom(module);
    1045           0 :         return LDB_ERR_OPERATIONS_ERROR;
    1046             : }
    1047             : 
    1048             : 
    1049             : /* Outbound requests: search
    1050             :  * ========================= */
    1051             : 
    1052             : static int map_remote_search_callback(struct ldb_request *req,
    1053             :                                         struct ldb_reply *ares);
    1054             : static int map_local_merge_callback(struct ldb_request *req,
    1055             :                                         struct ldb_reply *ares);
    1056             : static int map_search_local(struct map_context *ac);
    1057             : 
    1058         231 : static int map_save_entry(struct map_context *ac, struct ldb_reply *ares)
    1059             : {
    1060             :         struct map_reply *mr;
    1061             : 
    1062         231 :         mr = talloc_zero(ac, struct map_reply);
    1063         231 :         if (mr == NULL) {
    1064           0 :                 map_oom(ac->module);
    1065           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1066             :         }
    1067         231 :         mr->remote = talloc_steal(mr, ares);
    1068         231 :         if (ac->r_current) {
    1069         159 :                 ac->r_current->next = mr;
    1070             :         } else {
    1071             :                 /* first entry */
    1072          72 :                 ac->r_list = mr;
    1073             :         }
    1074         231 :         ac->r_current = mr;
    1075             : 
    1076         231 :         return LDB_SUCCESS;
    1077             : }
    1078             : 
    1079             : /* Pass a merged search result up the callback chain. */
    1080         231 : int map_return_entry(struct map_context *ac, struct ldb_reply *ares)
    1081             : {
    1082             :         struct ldb_message_element *el;
    1083             :         const char * const *attrs;
    1084             :         struct ldb_context *ldb;
    1085             :         unsigned int i;
    1086             :         int ret;
    1087             :         bool matched;
    1088             : 
    1089         231 :         ldb = ldb_module_get_ctx(ac->module);
    1090             : 
    1091             :         /* Merged result doesn't match original query, skip */
    1092         462 :         ret = ldb_match_msg_error(ldb, ares->message,
    1093         231 :                                   ac->req->op.search.tree,
    1094           0 :                                   ac->req->op.search.base,
    1095         231 :                                   ac->req->op.search.scope,
    1096             :                                   &matched);
    1097         231 :         if (ret != LDB_SUCCESS) return ret;
    1098         231 :         if (!matched) {
    1099         107 :                 ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_map: "
    1100             :                           "Skipping record '%s': "
    1101             :                           "doesn't match original search",
    1102         107 :                           ldb_dn_get_linearized(ares->message->dn));
    1103         107 :                 return LDB_SUCCESS;
    1104             :         }
    1105             : 
    1106             :         /* Limit result to requested attrs */
    1107         239 :         if (ac->req->op.search.attrs &&
    1108         115 :             (! ldb_attr_in_list(ac->req->op.search.attrs, "*"))) {
    1109             : 
    1110         115 :                 attrs = ac->req->op.search.attrs;
    1111         115 :                 i = 0;
    1112             : 
    1113        1056 :                 while (i < ares->message->num_elements) {
    1114             : 
    1115         826 :                         el = &ares->message->elements[i];
    1116         826 :                         if ( ! ldb_attr_in_list(attrs, el->name)) {
    1117         683 :                                 ldb_msg_remove_element(ares->message, el);
    1118             :                         } else {
    1119         143 :                                 i++;
    1120             :                         }
    1121             :                 }
    1122             :         }
    1123             : 
    1124         124 :         return ldb_module_send_entry(ac->req, ares->message, ares->controls);
    1125             : }
    1126             : 
    1127             : /* Search a record. */
    1128         227 : int ldb_map_search(struct ldb_module *module, struct ldb_request *req)
    1129             : {
    1130             :         struct ldb_parse_tree *remote_tree;
    1131             :         struct ldb_parse_tree *local_tree;
    1132             :         struct ldb_request *remote_req;
    1133             :         struct ldb_context *ldb;
    1134             :         struct map_context *ac;
    1135             :         int ret;
    1136             : 
    1137         227 :         const char *wildcard[] = { "*", NULL };
    1138             :         const char * const *attrs;
    1139             : 
    1140         227 :         ldb = ldb_module_get_ctx(module);
    1141             : 
    1142             :         /* if we're not yet initialized, go to the next module */
    1143         227 :         if (!ldb_module_get_private(module))
    1144          11 :                 return ldb_next_request(module, req);
    1145             : 
    1146             :         /* Do not manipulate our control entries */
    1147         216 :         if (ldb_dn_is_special(req->op.search.base)) {
    1148          53 :                 return ldb_next_request(module, req);
    1149             :         }
    1150             : 
    1151             :         /* No mapping requested, skip to next module */
    1152         163 :         if ((req->op.search.base) && (!ldb_dn_check_local(module, req->op.search.base))) {
    1153           8 :                 return ldb_next_request(module, req);
    1154             :         }
    1155             : 
    1156             :         /* TODO: How can we be sure about which partition we are
    1157             :          *       targetting when there is no search base? */
    1158             : 
    1159             :         /* Prepare context and handle */
    1160         155 :         ac = map_init_context(module, req);
    1161         155 :         if (ac == NULL) {
    1162           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1163             :         }
    1164             : 
    1165             :         /* It is easier to deal with the two different ways of
    1166             :          * expressing the wildcard in the same codepath */
    1167         155 :         attrs = req->op.search.attrs;
    1168         155 :         if (attrs == NULL) {
    1169          12 :                 attrs = wildcard;
    1170             :         }
    1171             : 
    1172             :         /* Split local from remote attrs */
    1173         155 :         ret = map_attrs_collect_and_partition(module, ac, 
    1174         155 :                                               attrs, req->op.search.tree);
    1175         155 :         if (ret) {
    1176           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1177             :         }
    1178             : 
    1179             :         /* Split local from remote tree */
    1180         155 :         ret = ldb_parse_tree_partition(module, ac,
    1181             :                                        &local_tree, &remote_tree,
    1182         155 :                                        req->op.search.tree);
    1183         155 :         if (ret) {
    1184           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1185             :         }
    1186             : 
    1187         266 :         if (((local_tree != NULL) && (remote_tree != NULL)) &&
    1188         222 :             (!ldb_parse_tree_check_splittable(req->op.search.tree))) {
    1189             :                 /* The query can't safely be split, enumerate the remote partition */
    1190         106 :                 local_tree = NULL;
    1191         106 :                 remote_tree = NULL;
    1192             :         }
    1193             : 
    1194         155 :         if (local_tree == NULL) {
    1195             :                 /* Construct default local parse tree */
    1196         142 :                 local_tree = talloc_zero(ac, struct ldb_parse_tree);
    1197         142 :                 if (local_tree == NULL) {
    1198           0 :                         map_oom(ac->module);
    1199           0 :                         return LDB_ERR_OPERATIONS_ERROR;
    1200             :                 }
    1201             : 
    1202         142 :                 local_tree->operation = LDB_OP_PRESENT;
    1203         142 :                 local_tree->u.present.attr = talloc_strdup(local_tree, IS_MAPPED);
    1204             :         }
    1205         155 :         if (remote_tree == NULL) {
    1206             :                 /* Construct default remote parse tree */
    1207         115 :                 remote_tree = ldb_parse_tree(ac, NULL);
    1208         115 :                 if (remote_tree == NULL) {
    1209           0 :                         return LDB_ERR_OPERATIONS_ERROR;
    1210             :                 }
    1211             :         }
    1212             : 
    1213         155 :         ac->local_tree = local_tree;
    1214             : 
    1215             :         /* Prepare the remote operation */
    1216         155 :         ret = ldb_build_search_req_ex(&remote_req, ldb, ac,
    1217             :                                       req->op.search.base,
    1218             :                                       req->op.search.scope,
    1219             :                                       remote_tree,
    1220             :                                       ac->remote_attrs,
    1221             :                                       req->controls,
    1222             :                                       ac, map_remote_search_callback,
    1223             :                                       req);
    1224         155 :         LDB_REQ_SET_LOCATION(remote_req);
    1225         155 :         if (ret != LDB_SUCCESS) {
    1226           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1227             :         }
    1228             : 
    1229         155 :         return ldb_next_remote_request(module, remote_req);
    1230             : }
    1231             : 
    1232             : /* Now, search the local part of a remote search result. */
    1233         386 : static int map_remote_search_callback(struct ldb_request *req,
    1234             :                                         struct ldb_reply *ares)
    1235             : {
    1236             :         struct map_context *ac;
    1237             :         int ret;
    1238             : 
    1239         386 :         ac = talloc_get_type(req->context, struct map_context);
    1240             : 
    1241         386 :         if (!ares) {
    1242           0 :                 return ldb_module_done(ac->req, NULL, NULL,
    1243             :                                         LDB_ERR_OPERATIONS_ERROR);
    1244             :         }
    1245         386 :         if (ares->error != LDB_SUCCESS) {
    1246          19 :                 return ldb_module_done(ac->req, ares->controls,
    1247             :                                         ares->response, ares->error);
    1248             :         }
    1249             : 
    1250         367 :         switch (ares->type) {
    1251           0 :         case LDB_REPLY_REFERRAL:
    1252             : 
    1253             :                 /* ignore referrals */
    1254           0 :                 talloc_free(ares);
    1255           0 :                 return LDB_SUCCESS;
    1256             : 
    1257         231 :         case LDB_REPLY_ENTRY:
    1258             : 
    1259             :                 /* Map result record into a local message */
    1260         231 :                 ret = map_reply_remote(ac, ares);
    1261         231 :                 if (ret) {
    1262           0 :                         talloc_free(ares);
    1263           0 :                         return ldb_module_done(ac->req, NULL, NULL,
    1264             :                                                 LDB_ERR_OPERATIONS_ERROR);
    1265             :                 }
    1266             : 
    1267             :                 /* if we have no local db, then we can just return the reply to
    1268             :                  * the upper layer, otherwise we must save it and process it
    1269             :                  * when all replies ahve been gathered */
    1270         231 :                 if ( ! map_check_local_db(ac->module)) {
    1271           0 :                         ret = map_return_entry(ac, ares);
    1272             :                 } else {
    1273         231 :                         ret = map_save_entry(ac,ares);
    1274             :                 }
    1275             : 
    1276         231 :                 if (ret != LDB_SUCCESS) {
    1277           0 :                         talloc_free(ares);
    1278           0 :                         return ldb_module_done(ac->req, NULL, NULL, ret);
    1279             :                 }
    1280           0 :                 break;
    1281             : 
    1282         136 :         case LDB_REPLY_DONE:
    1283             : 
    1284         136 :                 if ( ! map_check_local_db(ac->module)) {
    1285           0 :                         return ldb_module_done(ac->req, ares->controls,
    1286             :                                                 ares->response, LDB_SUCCESS);
    1287             :                 }
    1288             : 
    1289             :                 /* reset the pointer to the start of the list */
    1290         136 :                 ac->r_current = ac->r_list;
    1291             : 
    1292             :                 /* no entry just return */
    1293         136 :                 if (ac->r_current == NULL) {
    1294          64 :                         ret = ldb_module_done(ac->req, ares->controls,
    1295             :                                                 ares->response, LDB_SUCCESS);
    1296          64 :                         talloc_free(ares);
    1297          64 :                         return ret;
    1298             :                 }
    1299             : 
    1300          72 :                 ac->remote_done_ares = talloc_steal(ac, ares);
    1301             : 
    1302          72 :                 ret = map_search_local(ac);
    1303          72 :                 if (ret != LDB_SUCCESS) {
    1304           0 :                         return ldb_module_done(ac->req, NULL, NULL, ret);
    1305             :                 }
    1306             :         }
    1307             : 
    1308           0 :         return LDB_SUCCESS;
    1309             : }
    1310             : 
    1311         231 : static int map_search_local(struct map_context *ac)
    1312             : {
    1313             :         struct ldb_request *search_req;
    1314             : 
    1315         231 :         if (ac->r_current == NULL || ac->r_current->remote == NULL) {
    1316           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1317             :         }
    1318             : 
    1319             :         /* Prepare local search request */
    1320             :         /* TODO: use GUIDs here instead? */
    1321         231 :         search_req = map_search_base_req(ac,
    1322         231 :                                          ac->r_current->remote->message->dn,
    1323             :                                          NULL, NULL,
    1324             :                                          ac, map_local_merge_callback);
    1325         231 :         if (search_req == NULL) {
    1326           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1327             :         }
    1328             : 
    1329         231 :         return ldb_next_request(ac->module, search_req);
    1330             : }
    1331             : 
    1332             : /* Merge the remote and local parts of a search result. */
    1333         328 : int map_local_merge_callback(struct ldb_request *req, struct ldb_reply *ares)
    1334             : {
    1335             :         struct ldb_context *ldb;
    1336             :         struct map_context *ac;
    1337             :         int ret;
    1338             : 
    1339         328 :         ac = talloc_get_type(req->context, struct map_context);
    1340         328 :         ldb = ldb_module_get_ctx(ac->module);
    1341             : 
    1342         328 :         if (!ares) {
    1343           0 :                 return ldb_module_done(ac->req, NULL, NULL,
    1344             :                                         LDB_ERR_OPERATIONS_ERROR);
    1345             :         }
    1346         328 :         if (ares->error != LDB_SUCCESS) {
    1347           0 :                 return ldb_module_done(ac->req, ares->controls,
    1348             :                                         ares->response, ares->error);
    1349             :         }
    1350             : 
    1351         328 :         switch (ares->type) {
    1352          97 :         case LDB_REPLY_ENTRY:
    1353             :                 /* We have already found a local record */
    1354          97 :                 if (ac->r_current->local) {
    1355           0 :                         talloc_free(ares);
    1356           0 :                         ldb_set_errstring(ldb, "ldb_map: Too many results!");
    1357           0 :                         return ldb_module_done(ac->req, NULL, NULL,
    1358             :                                                 LDB_ERR_OPERATIONS_ERROR);
    1359             :                 }
    1360             : 
    1361             :                 /* Store local result */
    1362          97 :                 ac->r_current->local = talloc_steal(ac->r_current, ares);
    1363             : 
    1364          97 :                 break;
    1365             : 
    1366           0 :         case LDB_REPLY_REFERRAL:
    1367             :                 /* ignore referrals */
    1368           0 :                 talloc_free(ares);
    1369           0 :                 break;
    1370             : 
    1371         231 :         case LDB_REPLY_DONE:
    1372             :                 /* We don't need the local 'ares', but we will use the remote one from below */
    1373         231 :                 talloc_free(ares);
    1374             : 
    1375             :                 /* No local record found, map and send remote record */
    1376         231 :                 if (ac->r_current->local != NULL) {
    1377             :                         /* Merge remote into local message */
    1378         194 :                         ret = ldb_msg_merge_local(ac->module,
    1379           0 :                                                   ac->r_current->local->message,
    1380          97 :                                                   ac->r_current->remote->message);
    1381          97 :                         if (ret == LDB_SUCCESS) {
    1382          97 :                                 ret = map_return_entry(ac, ac->r_current->local);
    1383             :                         }
    1384          97 :                         if (ret != LDB_SUCCESS) {
    1385           0 :                                 return ldb_module_done(ac->req, NULL, NULL,
    1386             :                                                         LDB_ERR_OPERATIONS_ERROR);
    1387             :                         }
    1388             :                 } else {
    1389         134 :                         ret = map_return_entry(ac, ac->r_current->remote);
    1390         134 :                         if (ret != LDB_SUCCESS) {
    1391           0 :                                 return ldb_module_done(ac->req,
    1392             :                                                         NULL, NULL, ret);
    1393             :                         }
    1394             :                 }
    1395             : 
    1396         231 :                 if (ac->r_current->next != NULL) {
    1397         159 :                         ac->r_current = ac->r_current->next;
    1398         159 :                         if (ac->r_current->remote->type == LDB_REPLY_ENTRY) {
    1399         159 :                                 ret = map_search_local(ac);
    1400         159 :                                 if (ret != LDB_SUCCESS) {
    1401           0 :                                         return ldb_module_done(ac->req,
    1402             :                                                                NULL, NULL, ret);
    1403             :                                 }
    1404           0 :                                 break;
    1405             :                         }
    1406             :                 }
    1407             : 
    1408             :                 /* ok we are done with all search, finally it is time to
    1409             :                  * finish operations for this module */
    1410          72 :                 return ldb_module_done(ac->req,
    1411           0 :                                         ac->remote_done_ares->controls,
    1412           0 :                                         ac->remote_done_ares->response,
    1413          72 :                                         ac->remote_done_ares->error);
    1414             :         }
    1415             : 
    1416           0 :         return LDB_SUCCESS;
    1417             : }

Generated by: LCOV version 1.13