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 v4-17-test 1498b464 Lines: 0 685 0.0 %
Date: 2024-06-13 04:01:37 Functions: 0 28 0.0 %

          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           0 : static const char **map_attrs_select_local(struct ldb_module *module, void *mem_ctx, const char * const *attrs)
      40             : {
      41           0 :         const struct ldb_map_context *data = map_get_context(module);
      42             :         const char **result;
      43             :         unsigned int i, last;
      44             : 
      45           0 :         if (attrs == NULL)
      46           0 :                 return NULL;
      47             : 
      48           0 :         last = 0;
      49           0 :         result = talloc_array(mem_ctx, const char *, 1);
      50           0 :         if (result == NULL) {
      51           0 :                 goto failed;
      52             :         }
      53           0 :         result[0] = NULL;
      54             : 
      55           0 :         for (i = 0; attrs[i]; i++) {
      56             :                 /* Wildcards and ignored attributes are kept locally */
      57           0 :                 if ((ldb_attr_cmp(attrs[i], "*") == 0) ||
      58           0 :                     (!map_attr_check_remote(data, attrs[i]))) {
      59           0 :                         result = talloc_realloc(mem_ctx, result, const char *, last+2);
      60           0 :                         if (result == NULL) {
      61           0 :                                 goto failed;
      62             :                         }
      63             : 
      64           0 :                         result[last] = talloc_strdup(result, attrs[i]);
      65           0 :                         result[last+1] = NULL;
      66           0 :                         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           0 : static const char **map_attrs_collect_remote(struct ldb_module *module, void *mem_ctx, 
      80             :                                              const char * const *attrs)
      81             : {
      82           0 :         const struct ldb_map_context *data = map_get_context(module);
      83             :         const char **result;
      84             :         const struct ldb_map_attribute *map;
      85           0 :         const char *name=NULL;
      86             :         unsigned int i, j, last;
      87             :         int ret;
      88             : 
      89           0 :         last = 0;
      90           0 :         result = talloc_array(mem_ctx, const char *, 1);
      91           0 :         if (result == NULL) {
      92           0 :                 goto failed;
      93             :         }
      94           0 :         result[0] = NULL;
      95             : 
      96           0 :         for (i = 0; attrs[i]; i++) {
      97             :                 /* Wildcards are kept remotely, too */
      98           0 :                 if (ldb_attr_cmp(attrs[i], "*") == 0) {
      99           0 :                         const char **new_attrs = NULL;
     100           0 :                         ret = map_attrs_merge(module, mem_ctx, &new_attrs, attrs);
     101           0 :                         if (ret != LDB_SUCCESS) {
     102           0 :                                 goto failed;
     103             :                         }
     104           0 :                         ret = map_attrs_merge(module, mem_ctx, &new_attrs, data->wildcard_attributes);
     105           0 :                         if (ret != LDB_SUCCESS) {
     106           0 :                                 goto failed;
     107             :                         }
     108             : 
     109           0 :                         attrs = new_attrs;
     110           0 :                         break;
     111             :                 }
     112             :         }
     113             : 
     114           0 :         for (i = 0; attrs[i]; i++) {
     115             :                 /* Wildcards are kept remotely, too */
     116           0 :                 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           0 :                 map = map_attr_find_local(data, attrs[i]);
     124           0 :                 if (map == NULL) {
     125           0 :                         continue;
     126             :                 }
     127             : 
     128           0 :                 switch (map->type) {
     129           0 :                 case LDB_MAP_IGNORE:
     130           0 :                         continue;
     131             : 
     132           0 :                 case LDB_MAP_KEEP:
     133           0 :                         name = attrs[i];
     134           0 :                         goto named;
     135             : 
     136           0 :                 case LDB_MAP_RENAME:
     137             :                 case LDB_MAP_RENDROP:
     138             :                 case LDB_MAP_CONVERT:
     139           0 :                         name = map->u.rename.remote_name;
     140           0 :                         goto named;
     141             : 
     142           0 :                 case LDB_MAP_GENERATE:
     143             :                         /* Add all remote names of "generate" attrs */
     144           0 :                         for (j = 0; map->u.generate.remote_names[j]; j++) {
     145           0 :                                 result = talloc_realloc(mem_ctx, result, const char *, last+2);
     146           0 :                                 if (result == NULL) {
     147           0 :                                         goto failed;
     148             :                                 }
     149             : 
     150           0 :                                 result[last] = talloc_strdup(result, map->u.generate.remote_names[j]);
     151           0 :                                 result[last+1] = NULL;
     152           0 :                                 last++;
     153             :                         }
     154           0 :                         continue;
     155             :                 }
     156             : 
     157           0 :         named:  /* We found a single remote name, add that */
     158           0 :                 result = talloc_realloc(mem_ctx, result, const char *, last+2);
     159           0 :                 if (result == NULL) {
     160           0 :                         goto failed;
     161             :                 }
     162             : 
     163           0 :                 result[last] = talloc_strdup(result, name);
     164           0 :                 result[last+1] = NULL;
     165           0 :                 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           0 :         *local_attrs = map_attrs_select_local(module, mem_ctx, attrs);
     181           0 :         *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           0 : 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           0 :         old = ldb_msg_find_element(msg, el->name);
     195             : 
     196             :         /* no local result, add as new element */
     197           0 :         if (old == NULL) {
     198           0 :                 if (ldb_msg_add_empty(msg, el->name, 0, &old) != 0) {
     199           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     200             :                 }
     201             :         }
     202             :         else {
     203           0 :                 talloc_free(old->values);
     204             :         }
     205             : 
     206           0 :         old->values = talloc_array(msg->elements, struct ldb_val, el->num_values);
     207           0 :         old->num_values = el->num_values;
     208           0 :         if (old->values == NULL) {
     209           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     210             :         }
     211             :         /* copy the values into the element */
     212           0 :         for (j=0;j<el->num_values;j++) {
     213           0 :                 old->values[j] = ldb_val_dup(old->values, &el->values[j]);
     214           0 :                 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           0 : 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           0 :         const struct ldb_map_context *data = map_get_context(module);
     230           0 :         const char *local_attr_name = attr_name;
     231             :         struct ldb_message_element *el;
     232             :         unsigned int i;
     233             : 
     234           0 :         el = talloc_zero(mem_ctx, struct ldb_message_element);
     235           0 :         if (el == NULL) {
     236           0 :                 map_oom(module);
     237           0 :                 return NULL;
     238             :         }
     239             : 
     240           0 :         el->values = talloc_array(el, struct ldb_val, old->num_values);
     241           0 :         if (el->values == NULL) {
     242           0 :                 talloc_free(el);
     243           0 :                 map_oom(module);
     244           0 :                 return NULL;
     245             :         }
     246             : 
     247           0 :         for (i = 0; data->attribute_maps[i].local_name; i++) {
     248           0 :                 struct ldb_map_attribute *am = &data->attribute_maps[i];
     249           0 :                 if (((am->type == LDB_MAP_RENAME || am->type == LDB_MAP_RENDROP) &&
     250           0 :                         !strcmp(am->u.rename.remote_name, attr_name))
     251           0 :                     || (am->type == LDB_MAP_CONVERT &&
     252           0 :                         !strcmp(am->u.convert.remote_name, attr_name))) {
     253             : 
     254           0 :                         local_attr_name = am->local_name;
     255           0 :                         break;
     256             :                 }
     257             :         }
     258             : 
     259           0 :         el->name = talloc_strdup(el, local_attr_name);
     260           0 :         if (el->name == NULL) {
     261           0 :                 talloc_free(el);
     262           0 :                 map_oom(module);
     263           0 :                 return NULL;
     264             :         }
     265             : 
     266           0 :         for (i = 0; i < old->num_values; i++) {
     267           0 :                 el->values[i] = ldb_val_map_remote(module, el->values, map, &old->values[i]);
     268             :                 /* Conversions might fail, in which case bail */
     269           0 :                 if (!el->values[i].data) {
     270           0 :                         talloc_free(el);
     271           0 :                         return NULL;
     272             :                 }
     273           0 :                 el->num_values++;
     274             :         }
     275             : 
     276           0 :         return el;
     277             : }
     278             : 
     279             : /* Merge a remote message element into a local message. */
     280           0 : 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           0 :         const struct ldb_map_context *data = map_get_context(module);
     284             :         const struct ldb_map_attribute *map;
     285           0 :         struct ldb_message_element *old, *el=NULL;
     286           0 :         const char *remote_name = NULL;
     287             :         struct ldb_context *ldb;
     288             : 
     289           0 :         ldb = ldb_module_get_ctx(module);
     290             : 
     291             :         /* We handle wildcards in ldb_msg_el_merge_wildcard */
     292           0 :         if (ldb_attr_cmp(attr_name, "*") == 0) {
     293           0 :                 return LDB_SUCCESS;
     294             :         }
     295             : 
     296           0 :         map = map_attr_find_local(data, attr_name);
     297             : 
     298             :         /* Unknown attribute in remote message:
     299             :          * skip, attribute was probably auto-generated */
     300           0 :         if (map == NULL) {
     301           0 :                 return LDB_SUCCESS;
     302             :         }
     303             : 
     304           0 :         switch (map->type) {
     305           0 :         case LDB_MAP_IGNORE:
     306           0 :                 break;
     307           0 :         case LDB_MAP_CONVERT:
     308           0 :                 remote_name = map->u.convert.remote_name;
     309           0 :                 break;
     310           0 :         case LDB_MAP_KEEP:
     311           0 :                 remote_name = attr_name;
     312           0 :                 break;
     313           0 :         case LDB_MAP_RENAME:
     314             :         case LDB_MAP_RENDROP:
     315           0 :                 remote_name = map->u.rename.remote_name;
     316           0 :                 break;
     317           0 :         case LDB_MAP_GENERATE:
     318           0 :                 break;
     319             :         }
     320             : 
     321           0 :         switch (map->type) {
     322           0 :         case LDB_MAP_IGNORE:
     323           0 :                 return LDB_SUCCESS;
     324             : 
     325           0 :         case LDB_MAP_CONVERT:
     326           0 :                 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           0 :                 old = ldb_msg_find_element(remote, remote_name);
     339           0 :                 if (old) {
     340           0 :                         el = ldb_msg_el_map_remote(module, local, map, attr_name, old);
     341             :                 } else {
     342           0 :                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
     343             :                 }
     344           0 :                 break;
     345             : 
     346           0 :         case LDB_MAP_GENERATE:
     347           0 :                 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           0 :                 el = map->u.generate.generate_local(module, local, attr_name, remote);
     356           0 :                 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           0 :         if (el == NULL) {
     364           0 :                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
     365             :         }
     366             : 
     367           0 :         return ldb_msg_replace(local, el);
     368             : }
     369             : 
     370             : /* Handle wildcard parts of merging a remote message element into a local message. */
     371           0 : static int ldb_msg_el_merge_wildcard(struct ldb_module *module, struct ldb_message *local, 
     372             :                                      struct ldb_message *remote)
     373             : {
     374           0 :         const struct ldb_map_context *data = map_get_context(module);
     375           0 :         const struct ldb_map_attribute *map = map_attr_find_local(data, "*");
     376           0 :         struct ldb_message_element *el=NULL;
     377             :         unsigned int i;
     378             :         int ret;
     379             : 
     380             :         /* Perhaps we have a mapping for "*" */
     381           0 :         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           0 :         for (i = 0; data->attribute_maps[i].local_name; i++) {
     400           0 :                 ret = ldb_msg_el_merge(module, local, remote, 
     401           0 :                                        data->attribute_maps[i].local_name);
     402           0 :                 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
     403           0 :                         continue;
     404           0 :                 } else if (ret) {
     405           0 :                         return ret;
     406             :                 } else {
     407           0 :                         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           0 :         for (i = 0; i < msg2->num_elements; i++) {
     424           0 :                 ret = ldb_msg_replace(msg1, &msg2->elements[i]);
     425           0 :                 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           0 : 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           0 :         const char * const *attrs = ac->all_attrs;
     440           0 :         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           0 :         for (i = 0; attrs && attrs[i]; i++) {
     448           0 :                 if (ldb_attr_cmp(attrs[i], "*") == 0) {
     449           0 :                         ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
     450           0 :                         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           0 :         for (i = 0; attrs && attrs[i]; i++) {
     461           0 :                 ret = ldb_msg_el_merge(ac->module, local, remote, 
     462           0 :                                        attrs[i]);
     463           0 :                 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
     464           0 :                 } 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           0 : 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           0 :         if (ares->type != LDB_REPLY_ENTRY) {
     484           0 :                 return 0;
     485             :         }
     486             : 
     487             :         /* Create a new result message */
     488           0 :         msg = ldb_msg_new(ares);
     489           0 :         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           0 :         ret = ldb_msg_merge_remote(ac, msg, ares->message);
     496           0 :         if (ret) {
     497           0 :                 talloc_free(msg);
     498           0 :                 return ret;
     499             :         }
     500             : 
     501             :         /* Create corresponding local DN */
     502           0 :         dn = ldb_dn_map_rebase_remote(ac->module, msg, ares->message->dn);
     503           0 :         if (dn == NULL) {
     504           0 :                 talloc_free(msg);
     505           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     506             :         }
     507           0 :         msg->dn = dn;
     508             : 
     509             :         /* Store new message with new DN as the result */
     510           0 :         talloc_free(ares->message);
     511           0 :         ares->message = msg;
     512             : 
     513           0 :         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           0 :         const struct ldb_parse_tree *subtree = tree;
     523           0 :         bool negate = false;
     524             : 
     525           0 :         while (subtree) {
     526           0 :                 switch (subtree->operation) {
     527           0 :                 case LDB_OP_NOT:
     528           0 :                         negate = !negate;
     529           0 :                         subtree = subtree->u.isnot.child;
     530           0 :                         continue;
     531             : 
     532           0 :                 case LDB_OP_AND:
     533           0 :                         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           0 : 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           0 :         if (tree == NULL) {
     554           0 :                 return 0;
     555             :         }
     556             : 
     557           0 :         switch (tree->operation) {
     558           0 :         case LDB_OP_OR:
     559             :         case LDB_OP_AND:                /* attributes stored in list of subtrees */
     560           0 :                 for (i = 0; i < tree->u.list.num_elements; i++) {
     561           0 :                         ret = ldb_parse_tree_collect_attrs(module, mem_ctx, 
     562           0 :                                                            attrs, tree->u.list.elements[i]);
     563           0 :                         if (ret) {
     564           0 :                                 return ret;
     565             :                         }
     566             :                 }
     567           0 :                 return 0;
     568             : 
     569           0 :         case LDB_OP_NOT:                /* attributes stored in single subtree */
     570           0 :                 return ldb_parse_tree_collect_attrs(module, mem_ctx, attrs, tree->u.isnot.child);
     571             : 
     572           0 :         default:                        /* single attribute in tree */
     573           0 :                 new_attrs = ldb_attr_list_copy_add(mem_ctx, *attrs, tree->u.equality.attr);
     574           0 :                 talloc_free(*attrs);
     575           0 :                 *attrs = new_attrs;
     576           0 :                 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           0 : 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           0 :         *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
     590           0 :         if (*new == NULL) {
     591           0 :                 map_oom(module);
     592           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     593             :         }
     594             : 
     595             :         /* Generate new subtree */
     596           0 :         ret = map_subtree_select_local(module, *new, &child, tree->u.isnot.child);
     597           0 :         if (ret) {
     598           0 :                 talloc_free(*new);
     599           0 :                 return ret;
     600             :         }
     601             : 
     602             :         /* Prune tree without subtree */
     603           0 :         if (child == NULL) {
     604           0 :                 talloc_free(*new);
     605           0 :                 *new = NULL;
     606           0 :                 return 0;
     607             :         }
     608             : 
     609           0 :         (*new)->u.isnot.child = child;
     610             : 
     611           0 :         return ret;
     612             : }
     613             : 
     614             : /* Select a list of subtrees that query attributes in the local partition */
     615           0 : 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           0 :         int ret=0;
     619             : 
     620             :         /* Prepare new tree */
     621           0 :         *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
     622           0 :         if (*new == NULL) {
     623           0 :                 map_oom(module);
     624           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     625             :         }
     626             : 
     627             :         /* Prepare list of subtrees */
     628           0 :         (*new)->u.list.num_elements = 0;
     629           0 :         (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
     630           0 :         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           0 :         for (i = 0; i < tree->u.list.num_elements; i++) {
     639           0 :                 struct ldb_parse_tree *child = NULL;
     640           0 :                 ret = map_subtree_select_local(module, *new, &child, tree->u.list.elements[i]);
     641           0 :                 if (ret) {
     642           0 :                         talloc_free(*new);
     643           0 :                         return ret;
     644             :                 }
     645             : 
     646           0 :                 if (child) {
     647           0 :                         (*new)->u.list.elements[j] = child;
     648           0 :                         j++;
     649             :                 }
     650             :         }
     651             : 
     652             :         /* Prune tree without subtrees */
     653           0 :         if (j == 0) {
     654           0 :                 talloc_free(*new);
     655           0 :                 *new = NULL;
     656           0 :                 return 0;
     657             :         }
     658             : 
     659             :         /* Fix subtree list size */
     660           0 :         (*new)->u.list.num_elements = j;
     661           0 :         (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
     662             : 
     663           0 :         return ret;
     664             : }
     665             : 
     666             : /* Select a simple subtree that queries attributes in the local partition */
     667           0 : 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           0 :         *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
     671           0 :         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           0 : 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           0 :         const struct ldb_map_context *data = map_get_context(module);
     683             : 
     684           0 :         if (tree == NULL) {
     685           0 :                 return 0;
     686             :         }
     687             : 
     688           0 :         if (tree->operation == LDB_OP_NOT) {
     689           0 :                 return map_subtree_select_local_not(module, mem_ctx, new, tree);
     690             :         }
     691             : 
     692           0 :         if (tree->operation == LDB_OP_AND || tree->operation == LDB_OP_OR) {
     693           0 :                 return map_subtree_select_local_list(module, mem_ctx, new, tree);
     694             :         }
     695             : 
     696           0 :         if (map_attr_check_remote(data, tree->u.equality.attr)) {
     697           0 :                 *new = NULL;
     698           0 :                 return 0;
     699             :         }
     700             : 
     701           0 :         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           0 : 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           0 :         *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
     714           0 :         if (*new == NULL) {
     715           0 :                 map_oom(module);
     716           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     717             :         }
     718             : 
     719             :         /* Generate new subtree */
     720           0 :         ret = map_subtree_collect_remote(module, *new, &child, tree->u.isnot.child);
     721           0 :         if (ret) {
     722           0 :                 talloc_free(*new);
     723           0 :                 return ret;
     724             :         }
     725             : 
     726             :         /* Prune tree without subtree */
     727           0 :         if (child == NULL) {
     728           0 :                 talloc_free(*new);
     729           0 :                 *new = NULL;
     730           0 :                 return 0;
     731             :         }
     732             : 
     733           0 :         (*new)->u.isnot.child = child;
     734             : 
     735           0 :         return ret;
     736             : }
     737             : 
     738             : /* Collect a list of subtrees that query attributes in the remote partition */
     739           0 : 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           0 :         int ret=0;
     743             : 
     744             :         /* Prepare new tree */
     745           0 :         *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
     746           0 :         if (*new == NULL) {
     747           0 :                 map_oom(module);
     748           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     749             :         }
     750             : 
     751             :         /* Prepare list of subtrees */
     752           0 :         (*new)->u.list.num_elements = 0;
     753           0 :         (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
     754           0 :         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           0 :         for (i = 0; i < tree->u.list.num_elements; i++) {
     763             :                 struct ldb_parse_tree *child;
     764           0 :                 ret = map_subtree_collect_remote(module, *new, &child, tree->u.list.elements[i]);
     765           0 :                 if (ret) {
     766           0 :                         talloc_free(*new);
     767           0 :                         return ret;
     768             :                 }
     769             : 
     770           0 :                 if (child) {
     771           0 :                         (*new)->u.list.elements[j] = child;
     772           0 :                         j++;
     773             :                 }
     774             :         }
     775             : 
     776             :         /* Prune tree without subtrees */
     777           0 :         if (j == 0) {
     778           0 :                 talloc_free(*new);
     779           0 :                 *new = NULL;
     780           0 :                 return 0;
     781             :         }
     782             : 
     783             :         /* Fix subtree list size */
     784           0 :         (*new)->u.list.num_elements = j;
     785           0 :         (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
     786             : 
     787           0 :         return ret;
     788             : }
     789             : 
     790             : /* Collect a simple subtree that queries attributes in the remote partition */
     791           0 : 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           0 :         *new = talloc(mem_ctx, struct ldb_parse_tree);
     797           0 :         if (*new == NULL) {
     798           0 :                 map_oom(module);
     799           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     800             :         }
     801           0 :         **new = *tree;
     802             :         
     803           0 :         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           0 :         switch (tree->operation) {
     810           0 :         case LDB_OP_PRESENT:
     811           0 :                 attr = map_attr_map_local(*new, map, tree->u.present.attr);
     812           0 :                 (*new)->u.present.attr = attr;
     813           0 :                 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           0 :         case LDB_OP_EQUALITY:
     821           0 :                 attr = map_attr_map_local(*new, map, tree->u.equality.attr);
     822           0 :                 (*new)->u.equality.attr = attr;
     823           0 :                 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           0 :         if (attr == NULL) {
     840           0 :                 talloc_free(*new);
     841           0 :                 *new = NULL;
     842           0 :                 return 0;
     843             :         }
     844             : 
     845           0 :         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           0 :         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           0 :         case LDB_OP_EQUALITY:
     878           0 :                 (*new)->u.equality.value = ldb_val_map_local(module, *new, map, &tree->u.equality.value);
     879           0 :                 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           0 : 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           0 :         const struct ldb_map_context *data = map_get_context(module);
     901             :         const struct ldb_map_attribute *map;
     902             :         struct ldb_context *ldb;
     903             : 
     904           0 :         ldb = ldb_module_get_ctx(module);
     905             : 
     906           0 :         if (tree == NULL) {
     907           0 :                 return 0;
     908             :         }
     909             : 
     910           0 :         if (tree->operation == LDB_OP_NOT) {
     911           0 :                 return map_subtree_collect_remote_not(module, mem_ctx, new, tree);
     912             :         }
     913             : 
     914           0 :         if ((tree->operation == LDB_OP_AND) || (tree->operation == LDB_OP_OR)) {
     915           0 :                 return map_subtree_collect_remote_list(module, mem_ctx, new, tree);
     916             :         }
     917             : 
     918           0 :         if (!map_attr_check_remote(data, tree->u.equality.attr)) {
     919           0 :                 *new = NULL;
     920           0 :                 return 0;
     921             :         }
     922             : 
     923           0 :         map = map_attr_find_local(data, tree->u.equality.attr);
     924           0 :         if (map == NULL) {
     925           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     926             :         }
     927           0 :         if (map->convert_operator) {
     928           0 :                 return map->convert_operator(module, mem_ctx, new, tree);
     929             :         }
     930             : 
     931           0 :         if (map->type == LDB_MAP_GENERATE) {
     932           0 :                 ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
     933             :                           "Skipping attribute '%s': "
     934             :                           "'convert_operator' not set",
     935           0 :                           tree->u.equality.attr);
     936           0 :                 *new = NULL;
     937           0 :                 return 0;
     938             :         }
     939             : 
     940           0 :         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           0 : 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           0 :         *local_tree = NULL;
     954           0 :         *remote_tree = NULL;
     955             : 
     956             :         /* No original tree */
     957           0 :         if (tree == NULL) {
     958           0 :                 return 0;
     959             :         }
     960             : 
     961             :         /* Generate local tree */
     962           0 :         ret = map_subtree_select_local(module, mem_ctx, local_tree, tree);
     963           0 :         if (ret) {
     964           0 :                 return ret;
     965             :         }
     966             : 
     967             :         /* Generate remote tree */
     968           0 :         ret = map_subtree_collect_remote(module, mem_ctx, remote_tree, tree);
     969           0 :         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           0 : 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           0 :         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           0 :         tmp_ctx = talloc_new(ac);
    1004           0 :         if (tmp_ctx == NULL) {
    1005           0 :                 goto oom;
    1006             :         }
    1007             : 
    1008             :         /* Prepare list of attributes from tree */
    1009           0 :         tree_attrs = talloc_array(tmp_ctx, const char *, 1);
    1010           0 :         if (tree_attrs == NULL) {
    1011           0 :                 talloc_free(tmp_ctx);
    1012           0 :                 goto oom;
    1013             :         }
    1014           0 :         tree_attrs[0] = NULL;
    1015             : 
    1016             :         /* Collect attributes from tree */
    1017           0 :         ret = ldb_parse_tree_collect_attrs(module, tmp_ctx, &tree_attrs, tree);
    1018           0 :         if (ret) {
    1019           0 :                 goto done;
    1020             :         }
    1021             : 
    1022             :         /* Merge attributes from search operation */
    1023           0 :         ret = map_attrs_merge(module, tmp_ctx, &tree_attrs, search_attrs);
    1024           0 :         if (ret) {
    1025           0 :                 goto done;
    1026             :         }
    1027             : 
    1028             :         /* Split local from remote attributes */
    1029           0 :         ret = map_attrs_partition(module, ac, &local_attrs, 
    1030             :                                   &remote_attrs, tree_attrs);
    1031             :         
    1032           0 :         if (ret == 0) {
    1033           0 :                 ac->local_attrs = local_attrs;
    1034           0 :                 ac->remote_attrs = remote_attrs;
    1035           0 :                 talloc_steal(ac, tree_attrs);
    1036           0 :                 ac->all_attrs = tree_attrs;
    1037             :         }
    1038           0 : done:
    1039             :         /* Free temporary memory */
    1040           0 :         talloc_free(tmp_ctx);
    1041           0 :         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           0 : static int map_save_entry(struct map_context *ac, struct ldb_reply *ares)
    1059             : {
    1060             :         struct map_reply *mr;
    1061             : 
    1062           0 :         mr = talloc_zero(ac, struct map_reply);
    1063           0 :         if (mr == NULL) {
    1064           0 :                 map_oom(ac->module);
    1065           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1066             :         }
    1067           0 :         mr->remote = talloc_steal(mr, ares);
    1068           0 :         if (ac->r_current) {
    1069           0 :                 ac->r_current->next = mr;
    1070             :         } else {
    1071             :                 /* first entry */
    1072           0 :                 ac->r_list = mr;
    1073             :         }
    1074           0 :         ac->r_current = mr;
    1075             : 
    1076           0 :         return LDB_SUCCESS;
    1077             : }
    1078             : 
    1079             : /* Pass a merged search result up the callback chain. */
    1080           0 : 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           0 :         ldb = ldb_module_get_ctx(ac->module);
    1090             : 
    1091             :         /* Merged result doesn't match original query, skip */
    1092           0 :         ret = ldb_match_msg_error(ldb, ares->message,
    1093           0 :                                   ac->req->op.search.tree,
    1094           0 :                                   ac->req->op.search.base,
    1095           0 :                                   ac->req->op.search.scope,
    1096             :                                   &matched);
    1097           0 :         if (ret != LDB_SUCCESS) return ret;
    1098           0 :         if (!matched) {
    1099           0 :                 ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_map: "
    1100             :                           "Skipping record '%s': "
    1101             :                           "doesn't match original search",
    1102           0 :                           ldb_dn_get_linearized(ares->message->dn));
    1103           0 :                 return LDB_SUCCESS;
    1104             :         }
    1105             : 
    1106             :         /* Limit result to requested attrs */
    1107           0 :         if (ac->req->op.search.attrs &&
    1108           0 :             (! ldb_attr_in_list(ac->req->op.search.attrs, "*"))) {
    1109             : 
    1110           0 :                 attrs = ac->req->op.search.attrs;
    1111           0 :                 i = 0;
    1112             : 
    1113           0 :                 while (i < ares->message->num_elements) {
    1114             : 
    1115           0 :                         el = &ares->message->elements[i];
    1116           0 :                         if ( ! ldb_attr_in_list(attrs, el->name)) {
    1117           0 :                                 ldb_msg_remove_element(ares->message, el);
    1118             :                         } else {
    1119           0 :                                 i++;
    1120             :                         }
    1121             :                 }
    1122             :         }
    1123             : 
    1124           0 :         return ldb_module_send_entry(ac->req, ares->message, ares->controls);
    1125             : }
    1126             : 
    1127             : /* Search a record. */
    1128           0 : 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           0 :         const char *wildcard[] = { "*", NULL };
    1138             :         const char * const *attrs;
    1139             : 
    1140           0 :         ldb = ldb_module_get_ctx(module);
    1141             : 
    1142             :         /* if we're not yet initialized, go to the next module */
    1143           0 :         if (!ldb_module_get_private(module))
    1144           0 :                 return ldb_next_request(module, req);
    1145             : 
    1146             :         /* Do not manipulate our control entries */
    1147           0 :         if (ldb_dn_is_special(req->op.search.base)) {
    1148           0 :                 return ldb_next_request(module, req);
    1149             :         }
    1150             : 
    1151             :         /* No mapping requested, skip to next module */
    1152           0 :         if ((req->op.search.base) && (!ldb_dn_check_local(module, req->op.search.base))) {
    1153           0 :                 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           0 :         ac = map_init_context(module, req);
    1161           0 :         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           0 :         attrs = req->op.search.attrs;
    1168           0 :         if (attrs == NULL) {
    1169           0 :                 attrs = wildcard;
    1170             :         }
    1171             : 
    1172             :         /* Split local from remote attrs */
    1173           0 :         ret = map_attrs_collect_and_partition(module, ac, 
    1174           0 :                                               attrs, req->op.search.tree);
    1175           0 :         if (ret) {
    1176           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1177             :         }
    1178             : 
    1179             :         /* Split local from remote tree */
    1180           0 :         ret = ldb_parse_tree_partition(module, ac,
    1181             :                                        &local_tree, &remote_tree,
    1182           0 :                                        req->op.search.tree);
    1183           0 :         if (ret) {
    1184           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1185             :         }
    1186             : 
    1187           0 :         if (((local_tree != NULL) && (remote_tree != NULL)) &&
    1188           0 :             (!ldb_parse_tree_check_splittable(req->op.search.tree))) {
    1189             :                 /* The query can't safely be split, enumerate the remote partition */
    1190           0 :                 local_tree = NULL;
    1191           0 :                 remote_tree = NULL;
    1192             :         }
    1193             : 
    1194           0 :         if (local_tree == NULL) {
    1195             :                 /* Construct default local parse tree */
    1196           0 :                 local_tree = talloc_zero(ac, struct ldb_parse_tree);
    1197           0 :                 if (local_tree == NULL) {
    1198           0 :                         map_oom(ac->module);
    1199           0 :                         return LDB_ERR_OPERATIONS_ERROR;
    1200             :                 }
    1201             : 
    1202           0 :                 local_tree->operation = LDB_OP_PRESENT;
    1203           0 :                 local_tree->u.present.attr = talloc_strdup(local_tree, IS_MAPPED);
    1204             :         }
    1205           0 :         if (remote_tree == NULL) {
    1206             :                 /* Construct default remote parse tree */
    1207           0 :                 remote_tree = ldb_parse_tree(ac, NULL);
    1208           0 :                 if (remote_tree == NULL) {
    1209           0 :                         return LDB_ERR_OPERATIONS_ERROR;
    1210             :                 }
    1211             :         }
    1212             : 
    1213           0 :         ac->local_tree = local_tree;
    1214             : 
    1215             :         /* Prepare the remote operation */
    1216           0 :         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           0 :         LDB_REQ_SET_LOCATION(remote_req);
    1225           0 :         if (ret != LDB_SUCCESS) {
    1226           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1227             :         }
    1228             : 
    1229           0 :         return ldb_next_remote_request(module, remote_req);
    1230             : }
    1231             : 
    1232             : /* Now, search the local part of a remote search result. */
    1233           0 : 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           0 :         ac = talloc_get_type(req->context, struct map_context);
    1240             : 
    1241           0 :         if (!ares) {
    1242           0 :                 return ldb_module_done(ac->req, NULL, NULL,
    1243             :                                         LDB_ERR_OPERATIONS_ERROR);
    1244             :         }
    1245           0 :         if (ares->error != LDB_SUCCESS) {
    1246           0 :                 return ldb_module_done(ac->req, ares->controls,
    1247             :                                         ares->response, ares->error);
    1248             :         }
    1249             : 
    1250           0 :         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           0 :         case LDB_REPLY_ENTRY:
    1258             : 
    1259             :                 /* Map result record into a local message */
    1260           0 :                 ret = map_reply_remote(ac, ares);
    1261           0 :                 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           0 :                 if ( ! map_check_local_db(ac->module)) {
    1271           0 :                         ret = map_return_entry(ac, ares);
    1272             :                 } else {
    1273           0 :                         ret = map_save_entry(ac,ares);
    1274             :                 }
    1275             : 
    1276           0 :                 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           0 :         case LDB_REPLY_DONE:
    1283             : 
    1284           0 :                 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           0 :                 ac->r_current = ac->r_list;
    1291             : 
    1292             :                 /* no entry just return */
    1293           0 :                 if (ac->r_current == NULL) {
    1294           0 :                         ret = ldb_module_done(ac->req, ares->controls,
    1295             :                                                 ares->response, LDB_SUCCESS);
    1296           0 :                         talloc_free(ares);
    1297           0 :                         return ret;
    1298             :                 }
    1299             : 
    1300           0 :                 ac->remote_done_ares = talloc_steal(ac, ares);
    1301             : 
    1302           0 :                 ret = map_search_local(ac);
    1303           0 :                 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           0 : static int map_search_local(struct map_context *ac)
    1312             : {
    1313             :         struct ldb_request *search_req;
    1314             : 
    1315           0 :         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           0 :         search_req = map_search_base_req(ac,
    1322           0 :                                          ac->r_current->remote->message->dn,
    1323             :                                          NULL, NULL,
    1324             :                                          ac, map_local_merge_callback);
    1325           0 :         if (search_req == NULL) {
    1326           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1327             :         }
    1328             : 
    1329           0 :         return ldb_next_request(ac->module, search_req);
    1330             : }
    1331             : 
    1332             : /* Merge the remote and local parts of a search result. */
    1333           0 : 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           0 :         ac = talloc_get_type(req->context, struct map_context);
    1340           0 :         ldb = ldb_module_get_ctx(ac->module);
    1341             : 
    1342           0 :         if (!ares) {
    1343           0 :                 return ldb_module_done(ac->req, NULL, NULL,
    1344             :                                         LDB_ERR_OPERATIONS_ERROR);
    1345             :         }
    1346           0 :         if (ares->error != LDB_SUCCESS) {
    1347           0 :                 return ldb_module_done(ac->req, ares->controls,
    1348             :                                         ares->response, ares->error);
    1349             :         }
    1350             : 
    1351           0 :         switch (ares->type) {
    1352           0 :         case LDB_REPLY_ENTRY:
    1353             :                 /* We have already found a local record */
    1354           0 :                 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           0 :                 ac->r_current->local = talloc_steal(ac->r_current, ares);
    1363             : 
    1364           0 :                 break;
    1365             : 
    1366           0 :         case LDB_REPLY_REFERRAL:
    1367             :                 /* ignore referrals */
    1368           0 :                 talloc_free(ares);
    1369           0 :                 break;
    1370             : 
    1371           0 :         case LDB_REPLY_DONE:
    1372             :                 /* We don't need the local 'ares', but we will use the remote one from below */
    1373           0 :                 talloc_free(ares);
    1374             : 
    1375             :                 /* No local record found, map and send remote record */
    1376           0 :                 if (ac->r_current->local != NULL) {
    1377             :                         /* Merge remote into local message */
    1378           0 :                         ret = ldb_msg_merge_local(ac->module,
    1379           0 :                                                   ac->r_current->local->message,
    1380           0 :                                                   ac->r_current->remote->message);
    1381           0 :                         if (ret == LDB_SUCCESS) {
    1382           0 :                                 ret = map_return_entry(ac, ac->r_current->local);
    1383             :                         }
    1384           0 :                         if (ret != LDB_SUCCESS) {
    1385           0 :                                 return ldb_module_done(ac->req, NULL, NULL,
    1386             :                                                         LDB_ERR_OPERATIONS_ERROR);
    1387             :                         }
    1388             :                 } else {
    1389           0 :                         ret = map_return_entry(ac, ac->r_current->remote);
    1390           0 :                         if (ret != LDB_SUCCESS) {
    1391           0 :                                 return ldb_module_done(ac->req,
    1392             :                                                         NULL, NULL, ret);
    1393             :                         }
    1394             :                 }
    1395             : 
    1396           0 :                 if (ac->r_current->next != NULL) {
    1397           0 :                         ac->r_current = ac->r_current->next;
    1398           0 :                         if (ac->r_current->remote->type == LDB_REPLY_ENTRY) {
    1399           0 :                                 ret = map_search_local(ac);
    1400           0 :                                 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           0 :                 return ldb_module_done(ac->req,
    1411           0 :                                         ac->remote_done_ares->controls,
    1412           0 :                                         ac->remote_done_ares->response,
    1413           0 :                                         ac->remote_done_ares->error);
    1414             :         }
    1415             : 
    1416           0 :         return LDB_SUCCESS;
    1417             : }

Generated by: LCOV version 1.13