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

Generated by: LCOV version 1.14