LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - vlv_pagination.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 301 366 82.2 %
Date: 2021-09-23 10:06:22 Functions: 14 18 77.8 %

          Line data    Source code
       1             : /*
       2             :    ldb database library
       3             : 
       4             :    Copyright (C) Simo Sorce  2005-2008
       5             :    Copyright (C) Catalyst IT 2016
       6             : 
       7             :      ** NOTE! The following LGPL license applies to the ldb
       8             :      ** library. This does NOT imply that all of Samba is released
       9             :      ** under the LGPL
      10             : 
      11             :    This library is free software; you can redistribute it and/or
      12             :    modify it under the terms of the GNU Lesser General Public
      13             :    License as published by the Free Software Foundation; either
      14             :    version 3 of the License, or (at your option) any later version.
      15             : 
      16             :    This library is distributed in the hope that it will be useful,
      17             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      19             :    Lesser General Public License for more details.
      20             : 
      21             :    You should have received a copy of the GNU Lesser General Public
      22             :    License along with this library; if not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : /*
      26             :  *  Name: vlv_pagination
      27             :  *
      28             :  *  Component: ldb vlv pagination control module
      29             :  *
      30             :  *  Description: this module caches a complete search and sends back
      31             :  *               results in chunks as asked by the client
      32             :  *
      33             :  *  Originally based on paged_results.c by Simo Sorce
      34             :  *  Modified by Douglas Bagnall and Garming Sam for Catalyst.
      35             :  */
      36             : 
      37             : #include "includes.h"
      38             : #include "auth/auth.h"
      39             : #include <ldb.h>
      40             : #include "dsdb/samdb/samdb.h"
      41             : #include "libcli/security/security.h"
      42             : #include "libcli/ldap/ldap_errors.h"
      43             : #include <ldb.h>
      44             : #include "replace.h"
      45             : #include "system/filesys.h"
      46             : #include "system/time.h"
      47             : #include "ldb_module.h"
      48             : #include "dsdb/samdb/samdb.h"
      49             : 
      50             : #include "dsdb/common/util.h"
      51             : #include "lib/util/binsearch.h"
      52             : 
      53             : /* This is the number of concurrent searches per connection to cache. */
      54             : #define VLV_N_SEARCHES 5
      55             : 
      56             : 
      57             : struct results_store {
      58             :         uint32_t contextId;
      59             :         time_t timestamp;
      60             : 
      61             :         struct GUID *results;
      62             :         size_t num_entries;
      63             :         size_t result_array_size;
      64             : 
      65             :         struct referral_store *first_ref;
      66             :         struct referral_store *last_ref;
      67             : 
      68             :         struct ldb_control **controls;
      69             :         struct ldb_control **down_controls;
      70             :         struct ldb_vlv_req_control *vlv_details;
      71             :         struct ldb_server_sort_control *sort_details;
      72             : };
      73             : 
      74             : struct private_data {
      75             :         uint32_t next_free_id;
      76             :         struct results_store **store;
      77             :         int n_stores;
      78             : };
      79             : 
      80             : 
      81             : struct vlv_context {
      82             :         struct ldb_module *module;
      83             :         struct ldb_request *req;
      84             :         struct results_store *store;
      85             :         struct ldb_control **controls;
      86             :         struct private_data *priv;
      87             : };
      88             : 
      89             : 
      90        7753 : static struct results_store *new_store(struct private_data *priv)
      91             : {
      92             :         struct results_store *store;
      93             :         int i;
      94        7753 :         int best = 0;
      95        7753 :         time_t oldest = TIME_T_MAX;
      96       46268 :         for (i = 0; i < priv->n_stores; i++) {
      97       38593 :                 if (priv->store[i] == NULL) {
      98          78 :                         best = i;
      99          78 :                         break;
     100       38515 :                 } else if (priv->store[i]->timestamp < oldest){
     101        8065 :                         best = i;
     102        8065 :                         oldest = priv->store[i]->timestamp;
     103             :                 }
     104             :         }
     105             : 
     106        7753 :         store = talloc_zero(priv, struct results_store);
     107        7753 :         if (store == NULL) {
     108           0 :                 return NULL;
     109             :         }
     110        7753 :         if (priv->store[best] != NULL) {
     111        7675 :                 TALLOC_FREE(priv->store[best]);
     112             :         }
     113        7753 :         priv->store[best] = store;
     114        7753 :         store->timestamp = time(NULL);
     115        7753 :         return store;
     116             : }
     117             : 
     118             : 
     119             : struct vlv_sort_context {
     120             :         struct ldb_context *ldb;
     121             :         ldb_attr_comparison_t comparison_fn;
     122             :         const char *attr;
     123             :         struct vlv_context *ac;
     124             :         int status;
     125             :         struct ldb_val value;
     126             : };
     127             : 
     128             : 
     129             : /* Referrals are temporarily stored in a linked list */
     130             : struct referral_store {
     131             :         char *ref;
     132             :         struct referral_store *next;
     133             : };
     134             : 
     135             : /*
     136             :   search for attrs on one DN, by the GUID of the DN, with true
     137             :   LDB controls
     138             :  */
     139             : 
     140      274133 : static int vlv_search_by_dn_guid(struct ldb_module *module,
     141             :                                  struct vlv_context *ac,
     142             :                                  struct ldb_result **result,
     143             :                                  const struct GUID *guid,
     144             :                                  const char * const *attrs)
     145             : {
     146             :         struct ldb_dn *dn;
     147             :         struct ldb_request *req;
     148             :         struct ldb_result *res;
     149             :         int ret;
     150             :         struct GUID_txt_buf guid_str;
     151      274133 :         struct ldb_control **controls = ac->store->down_controls;
     152      274133 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     153             : 
     154      274133 :         dn = ldb_dn_new_fmt(ac, ldb, "<GUID=%s>",
     155             :                             GUID_buf_string(guid, &guid_str));
     156      274133 :         if (dn == NULL) {
     157           0 :                 return ldb_oom(ldb);
     158             :         }
     159             : 
     160      274133 :         res = talloc_zero(ac, struct ldb_result);
     161      274133 :         if (res == NULL) {
     162           0 :                 return ldb_oom(ldb);
     163             :         }
     164             : 
     165      274133 :         ret = ldb_build_search_req(&req, ldb, ac,
     166             :                                    dn,
     167             :                                    LDB_SCOPE_BASE,
     168             :                                    NULL,
     169             :                                    attrs,
     170             :                                    controls,
     171             :                                    res,
     172             :                                    ldb_search_default_callback,
     173             :                                    ac->req);
     174      274133 :         if (ret != LDB_SUCCESS) {
     175           0 :                 talloc_free(res);
     176           0 :                 return ret;
     177             :         }
     178             : 
     179      274133 :         ret = ldb_request(ldb, req);
     180      274133 :         if (ret == LDB_SUCCESS) {
     181      274133 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
     182             :         }
     183             : 
     184      274133 :         talloc_free(req);
     185      274133 :         if (ret != LDB_SUCCESS) {
     186       35247 :                 talloc_free(res);
     187       35247 :                 return ret;
     188             :         }
     189             : 
     190      238886 :         *result = res;
     191      238886 :         return ret;
     192             : }
     193             : 
     194             : 
     195        2541 : static int save_referral(struct results_store *store, char *ref)
     196             : {
     197        2541 :         struct referral_store *node = talloc(store,
     198             :                                              struct referral_store);
     199        2541 :         if (node == NULL) {
     200           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     201             :         }
     202        2541 :         node->next = NULL;
     203        2541 :         node->ref = talloc_steal(node, ref);
     204             : 
     205        2541 :         if (store->first_ref == NULL) {
     206         847 :                 store->first_ref = node;
     207             :         } else {
     208        1694 :                 store->last_ref->next = node;
     209             :         }
     210        2541 :         store->last_ref = node;
     211        2541 :         return LDB_SUCCESS;
     212             : }
     213             : 
     214         847 : static int send_referrals(struct results_store *store,
     215             :                           struct ldb_request *req)
     216             : {
     217             :         int ret;
     218             :         struct referral_store *node;
     219        4235 :         while (store->first_ref != NULL) {
     220        2541 :                 node = store->first_ref;
     221        2541 :                 ret = ldb_module_send_referral(req, node->ref);
     222        2541 :                 if (ret != LDB_SUCCESS) {
     223           0 :                         return ret;
     224             :                 }
     225        2541 :                 store->first_ref = node->next;
     226        2541 :                 talloc_free(node);
     227             :         }
     228         847 :         return LDB_SUCCESS;
     229             : }
     230             : 
     231             : 
     232             : /* vlv_value_compare() is used in a binary search */
     233             : 
     234       48444 : static int vlv_value_compare(struct vlv_sort_context *target,
     235             :                              struct GUID *guid)
     236             : {
     237       48444 :         struct ldb_result *result = NULL;
     238       48444 :         struct ldb_message_element *el = NULL;
     239       48444 :         struct vlv_context *ac = target->ac;
     240             :         int ret;
     241       48444 :         const char *attrs[2] = {
     242       48444 :                 target->attr,
     243             :                 NULL
     244             :         };
     245             : 
     246       48444 :         ret = vlv_search_by_dn_guid(ac->module, ac, &result, guid, attrs);
     247             : 
     248       48444 :         if (ret != LDB_SUCCESS) {
     249           0 :                 target->status = ret;
     250             :                 /* returning 0 ends the search. */
     251           0 :                 return 0;
     252             :         }
     253             : 
     254       48444 :         el = ldb_msg_find_element(result->msgs[0], target->attr);
     255       96888 :         return target->comparison_fn(target->ldb, ac,
     256       48444 :                                      &target->value, &el->values[0]);
     257             : 
     258             : }
     259             : 
     260             : /* The same as vlv_value_compare() but sorting in the opposite direction. */
     261           0 : static int vlv_value_compare_rev(struct vlv_sort_context *target,
     262             :                              struct GUID *guid)
     263             : {
     264           0 :         return -vlv_value_compare(target, guid);
     265             : }
     266             : 
     267             : 
     268             : 
     269             : /* Convert a "greater than or equal to" VLV query into an index. This is
     270             :    zero-based, so one less than the equivalent VLV offset query.
     271             : 
     272             :    If the query value is greater than (or less than in the reverse case) all
     273             :    the items, An index just beyond the last position is used.
     274             : 
     275             :    If an error occurs during the search for the index, we stash it in the
     276             :    status argument.
     277             :  */
     278             : 
     279       16005 : static int vlv_gt_eq_to_index(struct vlv_context *ac,
     280             :                               struct GUID *guid_array,
     281             :                               struct ldb_vlv_req_control *vlv_details,
     282             :                               struct ldb_server_sort_control *sort_details,
     283             :                               int *status)
     284             : {
     285             :         /* this has a >= comparison string, which needs to be
     286             :          * converted into indices.
     287             :          */
     288       16005 :         size_t len = ac->store->num_entries;
     289             :         struct ldb_context *ldb;
     290             :         const struct ldb_schema_attribute *a;
     291       16005 :         struct GUID *result = NULL;
     292             :         struct vlv_sort_context context;
     293       32010 :         struct ldb_val value = {
     294       16005 :                 .data = (uint8_t *)vlv_details->match.gtOrEq.value,
     295       16005 :                 .length = vlv_details->match.gtOrEq.value_len
     296             :         };
     297       16005 :         ldb = ldb_module_get_ctx(ac->module);
     298       16005 :         a = ldb_schema_attribute_by_name(ldb, sort_details->attributeName);
     299             : 
     300       16005 :         context = (struct vlv_sort_context){
     301             :                 .ldb = ldb,
     302       16005 :                 .comparison_fn = a->syntax->comparison_fn,
     303       16005 :                 .attr = sort_details->attributeName,
     304             :                 .ac = ac,
     305             :                 .status = LDB_SUCCESS,
     306             :                 .value = value
     307             :         };
     308             : 
     309       16005 :         if (sort_details->reverse) {
     310             :                 /* when the sort is reversed, "gtOrEq" means
     311             :                    "less than or equal" */
     312           0 :                 BINARY_ARRAY_SEARCH_GTE(guid_array, len, &context,
     313             :                                         vlv_value_compare_rev,
     314             :                                         result, result);
     315             :         } else {
     316       16005 :                 BINARY_ARRAY_SEARCH_GTE(guid_array, len, &context,
     317             :                                         vlv_value_compare,
     318             :                                         result, result);
     319             :         }
     320       16005 :         if (context.status != LDB_SUCCESS) {
     321           0 :                 *status = context.status;
     322           0 :                 return len;
     323             :         }
     324       16005 :         *status = LDB_SUCCESS;
     325             : 
     326       16005 :         if (result == NULL) {
     327             :                 /* the target is beyond the end of the array */
     328        4246 :                 return len;
     329             :         }
     330       11759 :         return result - guid_array;
     331             : 
     332             : }
     333             : 
     334             : /* return the zero-based index into the sorted results, or -1 on error.
     335             : 
     336             :    The VLV index is one-base, so one greater than this.
     337             :  */
     338             : 
     339       30753 : static int vlv_calc_real_offset(int offset, int denominator, int n_entries)
     340             : {
     341             :         double fraction;
     342             : 
     343             :         /* An offset of 0 (or less) is an error, unless the denominator is
     344             :            also zero. */
     345       30753 :         if (offset <= 0 && denominator != 0) {
     346           0 :                 return -1;
     347             :         }
     348             : 
     349             :         /* a denominator of zero means the server should use the estimated
     350             :            number of entries. */
     351       30753 :         if (denominator == 0) {
     352        5956 :                 if (offset == 0) {
     353             :                         /* 0/0 means the last one */
     354           0 :                         return n_entries - 1;
     355             :                 }
     356        5956 :                 denominator = n_entries;
     357             :         }
     358             : 
     359       30753 :         if (denominator == 1) {
     360             :                 /* The 1/1 case means the LAST index.
     361             :                    Strangely, for n > 1, n/1 means the FIRST index.
     362             :                 */
     363         120 :                 if (offset == 1) {
     364          40 :                         return n_entries - 1;
     365             :                 }
     366          80 :                 return 0;
     367             :         }
     368             : 
     369       30633 :         if (offset >= denominator) {
     370             :                 /* we want the last one */
     371        2457 :                 return n_entries - 1;
     372             :         }
     373             :         /* if the denominator is exactly the number of entries, the offset is
     374             :            already correct. */
     375             : 
     376       28176 :         if (denominator == n_entries) {
     377       21336 :                 return offset - 1;
     378             :         }
     379             : 
     380             :         /* The following formula was discovered by probing Windows. */
     381        6840 :         fraction = (offset - 1.0) / (denominator - 1.0);
     382        6840 :         return (int)(fraction * (n_entries - 1.0) + 0.5);
     383             : }
     384             : 
     385             : 
     386             : /* vlv_results() is called when there is a valid contextID -- meaning the search
     387             :    has been prepared earlier and saved -- or by vlv_search_callback() when a
     388             :    search has just been completed. */
     389             : 
     390       53028 : static int vlv_results(struct vlv_context *ac, struct ldb_reply *ares)
     391             : {
     392             :         struct ldb_vlv_resp_control *vlv;
     393             :         unsigned int num_ctrls;
     394             :         int ret, i, first_i, last_i;
     395             :         struct ldb_vlv_req_control *vlv_details;
     396             :         struct ldb_server_sort_control *sort_details;
     397       53028 :         int target = 0;
     398             : 
     399       53028 :         if (ac->store == NULL) {
     400           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
     401           0 :                 return ldb_module_done(
     402             :                         ac->req, ac->controls, ares->response, ret);
     403             :         }
     404             : 
     405       53028 :         if (ac->store->first_ref) {
     406             :                 /* There is no right place to put references in the sorted
     407             :                    results, so we send them as soon as possible.
     408             :                 */
     409         847 :                 ret = send_referrals(ac->store, ac->req);
     410         847 :                 if (ret != LDB_SUCCESS) {
     411             :                         /*
     412             :                          * send_referrals will have called ldb_module_done
     413             :                          * if there was an error.
     414             :                          */
     415           0 :                         return ret;
     416             :                 }
     417             :         }
     418             : 
     419       53028 :         vlv_details = ac->store->vlv_details;
     420       53028 :         sort_details = ac->store->sort_details;
     421             : 
     422       53028 :         if (ac->store->num_entries != 0) {
     423       46758 :                 if (vlv_details->type == 1) {
     424       16005 :                         target = vlv_gt_eq_to_index(ac, ac->store->results,
     425             :                                                     vlv_details,
     426             :                                                     sort_details, &ret);
     427       16005 :                         if (ret != LDB_SUCCESS) {
     428           0 :                                 return ldb_module_done(
     429             :                                         ac->req,
     430             :                                         ac->controls,
     431             :                                         ares->response,
     432             :                                         ret);
     433             :                         }
     434             :                 } else {
     435       30753 :                         target = vlv_calc_real_offset(vlv_details->match.byOffset.offset,
     436             :                                                       vlv_details->match.byOffset.contentCount,
     437       30753 :                                                       ac->store->num_entries);
     438       30753 :                         if (target == -1) {
     439           0 :                                 ret = LDB_ERR_OPERATIONS_ERROR;
     440           0 :                                 return ldb_module_done(
     441             :                                         ac->req,
     442             :                                         ac->controls,
     443             :                                         ares->response,
     444             :                                         ret);
     445             :                         }
     446             :                 }
     447             : 
     448             :                 /* send the results */
     449       46758 :                 first_i = MAX(target - vlv_details->beforeCount, 0);
     450       46758 :                 last_i = MIN(target + vlv_details->afterCount,
     451             :                              ac->store->num_entries - 1);
     452             : 
     453      272447 :                 for (i = first_i; i <= last_i; i++) {
     454      225689 :                         struct ldb_result *result = NULL;
     455      225689 :                         struct GUID *guid = &ac->store->results[i];
     456             : 
     457      225689 :                         ret = vlv_search_by_dn_guid(ac->module, ac, &result, guid,
     458      225689 :                                                     ac->req->op.search.attrs);
     459             : 
     460      225689 :                         if (ret == LDAP_NO_SUCH_OBJECT
     461      190442 :                             || result->count != 1) {
     462             :                                 /*
     463             :                                  * The thing isn't there, which we quietly
     464             :                                  * ignore and go on to send an extra one
     465             :                                  * instead.
     466             :                                  *
     467             :                                  * result->count == 0 or > 1 can only
     468             :                                  * happen if ASQ (which breaks all the
     469             :                                  * rules) is somehow invoked (as this
     470             :                                  * is a BASE search).
     471             :                                  *
     472             :                                  * (We skip the ASQ cookie for the
     473             :                                  * GUID searches)
     474             :                                  */
     475       35247 :                                 if (last_i < ac->store->num_entries - 1) {
     476       13342 :                                         last_i++;
     477             :                                 }
     478       35247 :                                 continue;
     479      190442 :                         } else if (ret != LDB_SUCCESS) {
     480           0 :                                 return ldb_module_done(
     481             :                                         ac->req,
     482             :                                         ac->controls,
     483             :                                         ares->response,
     484             :                                         ret);
     485             :                         }
     486             : 
     487      190442 :                         ret = ldb_module_send_entry(ac->req, result->msgs[0],
     488             :                                                     NULL);
     489      190442 :                         if (ret != LDB_SUCCESS) {
     490             :                                 /*
     491             :                                  * ldb_module_send_entry will have called
     492             :                                  * ldb_module_done if there was an error
     493             :                                  */
     494           0 :                                 return ret;
     495             :                         }
     496             :                 }
     497             :         } else {
     498        6270 :                 target = -1;
     499             :         }
     500             : 
     501             :         /* return result done */
     502       53028 :         num_ctrls = 1;
     503       53028 :         i = 0;
     504             : 
     505       53028 :         if (ac->store->controls != NULL) {
     506           3 :                 while (ac->store->controls[i]){
     507           1 :                         i++; /* counting */
     508             :                 }
     509           1 :                 num_ctrls += i;
     510             :         }
     511             : 
     512       53028 :         ac->controls = talloc_array(ac, struct ldb_control *, num_ctrls + 1);
     513       53028 :         if (ac->controls == NULL) {
     514           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
     515           0 :                 return ldb_module_done(
     516             :                         ac->req, ac->controls, ares->response, ret);
     517             :         }
     518       53028 :         ac->controls[num_ctrls] = NULL;
     519             : 
     520       53029 :         for (i = 0; i < (num_ctrls -1); i++) {
     521           1 :                 ac->controls[i] = talloc_reference(ac->controls, ac->store->controls[i]);
     522             :         }
     523             : 
     524       53028 :         ac->controls[i] = talloc(ac->controls, struct ldb_control);
     525       53028 :         if (ac->controls[i] == NULL) {
     526           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
     527           0 :                 return ldb_module_done(
     528             :                         ac->req, ac->controls, ares->response, ret);
     529             :         }
     530             : 
     531       53028 :         ac->controls[i]->oid = talloc_strdup(ac->controls[i],
     532             :                                              LDB_CONTROL_VLV_RESP_OID);
     533       53028 :         if (ac->controls[i]->oid == NULL) {
     534           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
     535           0 :                 return ldb_module_done(
     536             :                         ac->req, ac->controls, ares->response, ret);
     537             :         }
     538             : 
     539       53028 :         ac->controls[i]->critical = 0;
     540             : 
     541       53028 :         vlv = talloc(ac->controls[i], struct ldb_vlv_resp_control);
     542       53028 :         if (vlv == NULL) {
     543           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
     544           0 :                 return ldb_module_done(
     545             :                         ac->req, ac->controls, ares->response, ret);
     546             :         }
     547       53028 :         ac->controls[i]->data = vlv;
     548             : 
     549       53028 :         ac->store->timestamp = time(NULL);
     550             : 
     551       53028 :         ac->store->contextId = ac->priv->next_free_id;
     552       53028 :         ac->priv->next_free_id++;
     553       53028 :         vlv->contextId = talloc_memdup(vlv, &ac->store->contextId, sizeof(uint32_t));
     554       53028 :         vlv->ctxid_len = sizeof(uint32_t);
     555       53028 :         vlv->vlv_result = 0;
     556       53028 :         vlv->contentCount = ac->store->num_entries;
     557       53028 :         if (target >= 0) {
     558       46758 :                 vlv->targetPosition = target + 1;
     559        6270 :         } else if (vlv_details->type == 1) {
     560        6270 :                 vlv->targetPosition = ac->store->num_entries + 1;
     561             :         } else {
     562           0 :                 vlv->targetPosition = 0;
     563             :         }
     564       53028 :         return LDB_SUCCESS;
     565             : }
     566             : 
     567             : 
     568             : /* vlv_search_callback() collects GUIDs found by the original search */
     569             : 
     570      558449 : static int vlv_search_callback(struct ldb_request *req, struct ldb_reply *ares)
     571             : {
     572             :         struct vlv_context *ac;
     573             :         struct results_store *store;
     574             :         int ret;
     575             : 
     576      558449 :         ac = talloc_get_type(req->context, struct vlv_context);
     577      558449 :         store = ac->store;
     578             : 
     579      558449 :         if (!ares) {
     580           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     581             :                                         LDB_ERR_OPERATIONS_ERROR);
     582             :         }
     583      558449 :         if (ares->error != LDB_SUCCESS) {
     584           0 :                 return ldb_module_done(ac->req, ares->controls,
     585             :                                         ares->response, ares->error);
     586             :         }
     587             : 
     588      558449 :         switch (ares->type) {
     589      548155 :         case LDB_REPLY_ENTRY:
     590      548155 :                 if (store->results == NULL) {
     591        7733 :                         store->num_entries = 0;
     592        7733 :                         store->result_array_size = 16;
     593        7733 :                         store->results = talloc_array(store, struct GUID,
     594             :                                                       store->result_array_size);
     595        7733 :                         if (store->results == NULL) {
     596           0 :                                 return ldb_module_done(ac->req, NULL, NULL,
     597             :                                                        LDB_ERR_OPERATIONS_ERROR);
     598             :                         }
     599      540422 :                 } else if (store->num_entries == store->result_array_size) {
     600       10977 :                         store->result_array_size *= 2;
     601       10977 :                         store->results = talloc_realloc(store, store->results,
     602             :                                                         struct GUID,
     603             :                                                         store->result_array_size);
     604       10977 :                         if (store->results == NULL) {
     605           0 :                                 return ldb_module_done(ac->req, NULL, NULL,
     606             :                                                        LDB_ERR_OPERATIONS_ERROR);
     607             :                         }
     608             :                 }
     609      548155 :                 store->results[store->num_entries] = \
     610      548155 :                         samdb_result_guid(ares->message, "objectGUID");
     611      548155 :                 store->num_entries++;
     612      548155 :                 break;
     613             : 
     614        2541 :         case LDB_REPLY_REFERRAL:
     615        2541 :                 ret = save_referral(store, ares->referral);
     616        2541 :                 if (ret != LDB_SUCCESS) {
     617           0 :                         return ldb_module_done(ac->req, NULL, NULL, ret);
     618             :                 }
     619        2541 :                 break;
     620             : 
     621        7753 :         case LDB_REPLY_DONE:
     622        7753 :                 if (store->num_entries != 0) {
     623        7733 :                         store->results = talloc_realloc(store, store->results,
     624             :                                                         struct GUID,
     625             :                                                         store->num_entries);
     626        7733 :                         if (store->results == NULL) {
     627           0 :                                 return ldb_module_done(ac->req, NULL, NULL,
     628             :                                                        LDB_ERR_OPERATIONS_ERROR);
     629             :                         }
     630             :                 }
     631        7753 :                 store->result_array_size = store->num_entries;
     632             : 
     633        7753 :                 ac->store->controls = talloc_move(ac->store, &ares->controls);
     634        7753 :                 ret = vlv_results(ac, ares);
     635        7753 :                 if (ret != LDB_SUCCESS) {
     636             :                         /* vlv_results will have called ldb_module_done
     637             :                          * if there was an error.
     638             :                          */
     639           0 :                         return ret;
     640             :                 }
     641        7753 :                 return ldb_module_done(ac->req, ac->controls,
     642             :                                         ares->response, ret);
     643             :         }
     644             : 
     645      550696 :         return LDB_SUCCESS;
     646             : }
     647             : 
     648       53028 : static int copy_search_details(struct results_store *store,
     649             :                                struct ldb_vlv_req_control *vlv_ctrl,
     650             :                                struct ldb_server_sort_control *sort_ctrl)
     651             : {
     652             :         /* free the old details which are no longer going to be reachable. */
     653       53028 :         if (store->vlv_details != NULL){
     654       45275 :                 TALLOC_FREE(store->vlv_details);
     655             :         }
     656             : 
     657       53028 :         if (store->sort_details != NULL){
     658       45275 :                 TALLOC_FREE(store->sort_details);
     659             :         }
     660             : 
     661       53028 :         store->vlv_details = talloc(store, struct ldb_vlv_req_control);
     662       53028 :         if (store->vlv_details == NULL) {
     663           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     664             :         }
     665       53028 :         *store->vlv_details = *vlv_ctrl;
     666       53028 :         store->vlv_details->contextId = talloc_memdup(store, vlv_ctrl->contextId,
     667             :                                                       vlv_ctrl->ctxid_len);
     668       53028 :         if (store->vlv_details->contextId == NULL) {
     669           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     670             :         }
     671             : 
     672       53028 :         if (vlv_ctrl->type == 1) {
     673       22275 :                 char *v = talloc_array(store, char,
     674             :                                        vlv_ctrl->match.gtOrEq.value_len + 1);
     675             : 
     676       22275 :                 if (v == NULL) {
     677           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     678             :                 }
     679             : 
     680       22275 :                 memcpy(v, vlv_ctrl->match.gtOrEq.value, vlv_ctrl->match.gtOrEq.value_len);
     681       22275 :                 v[vlv_ctrl->match.gtOrEq.value_len] = '\0';
     682             : 
     683       22275 :                 store->vlv_details->match.gtOrEq.value = v;
     684             :         }
     685             : 
     686       53028 :         store->sort_details = talloc(store, struct ldb_server_sort_control);
     687       53028 :         if (store->sort_details == NULL) {
     688           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     689             :         }
     690       53028 :         store->sort_details->attributeName = talloc_strdup(store,
     691             :                                                            sort_ctrl->attributeName);
     692       53028 :         if (store->sort_details->attributeName == NULL) {
     693           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     694             :         }
     695             : 
     696       53028 :         if (sort_ctrl->orderingRule == NULL) {
     697       53028 :                 store->sort_details->orderingRule = NULL;
     698             :         } else {
     699           0 :                 store->sort_details->orderingRule = talloc_strdup(store,
     700             :                                                                   sort_ctrl->orderingRule);
     701           0 :                 if (store->sort_details->orderingRule == NULL) {
     702           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     703             :                 }
     704             :         }
     705       53028 :         store->sort_details->reverse = sort_ctrl->reverse;
     706             : 
     707       53028 :         return LDB_SUCCESS;
     708             : }
     709             : 
     710             : 
     711             : static struct ldb_control **
     712        7753 : vlv_copy_down_controls(TALLOC_CTX *mem_ctx, struct ldb_control **controls)
     713             : {
     714             : 
     715             :         struct ldb_control **new_controls;
     716             :         unsigned int i, j, num_ctrls;
     717        7753 :         if (controls == NULL) {
     718           0 :                 return NULL;
     719             :         }
     720             : 
     721        7753 :         for (num_ctrls = 0; controls[num_ctrls]; num_ctrls++);
     722             : 
     723        7753 :         new_controls = talloc_array(mem_ctx, struct ldb_control *, num_ctrls);
     724        7753 :         if (new_controls == NULL) {
     725           0 :                 return NULL;
     726             :         }
     727             : 
     728       24238 :         for (j = 0, i = 0; i < (num_ctrls); i++) {
     729       24237 :                 struct ldb_control *control = controls[i];
     730       24237 :                 if (control->oid == NULL) {
     731        7752 :                         break;
     732             :                 }
     733             :                 /*
     734             :                  * Do not re-use VLV, nor the server-sort, both are
     735             :                  * already handled here.
     736             :                  */
     737       25217 :                 if (strcmp(control->oid, LDB_CONTROL_VLV_REQ_OID) == 0 ||
     738        8732 :                     strcmp(control->oid, LDB_CONTROL_SERVER_SORT_OID) == 0) {
     739       15506 :                         continue;
     740             :                 }
     741             :                 /*
     742             :                  * ASQ changes everything, do not copy it down for the
     743             :                  * per-GUID search
     744             :                  */
     745         979 :                 if (strcmp(control->oid, LDB_CONTROL_ASQ_OID) == 0) {
     746           1 :                         continue;
     747             :                 }
     748         978 :                 new_controls[j] = talloc_steal(new_controls, control);
     749             :                 /*
     750             :                  * Sadly the caller is not obliged to make this a
     751             :                  * proper talloc tree, so we do so here.
     752             :                  */
     753         978 :                 if (control->data) {
     754           1 :                         talloc_steal(control, control->data);
     755             :                 }
     756         978 :                 j++;
     757             :         }
     758        7753 :         new_controls[j] = NULL;
     759        7753 :         return new_controls;
     760             : }
     761             : 
     762    14385816 : static int vlv_search(struct ldb_module *module, struct ldb_request *req)
     763             : {
     764             :         struct ldb_context *ldb;
     765             :         struct ldb_control *control;
     766             :         struct ldb_control *sort_control;
     767             :         struct private_data *priv;
     768             :         struct ldb_vlv_req_control *vlv_ctrl;
     769             :         struct ldb_server_sort_control **sort_ctrl;
     770             :         struct ldb_request *search_req;
     771             :         struct vlv_context *ac;
     772             :         int ret, i, critical;
     773             : 
     774    14385816 :         ldb = ldb_module_get_ctx(module);
     775             : 
     776    14385816 :         control = ldb_request_get_control(req, LDB_CONTROL_VLV_REQ_OID);
     777    14385816 :         if (control == NULL) {
     778             :                 /* There is no VLV. go on */
     779    14332785 :                 return ldb_next_request(module, req);
     780             :         }
     781       53031 :         critical = control->critical;
     782       53031 :         control->critical = 0;
     783             : 
     784       53031 :         sort_control = ldb_request_get_control(req, LDB_CONTROL_SERVER_SORT_OID);
     785       53031 :         if (sort_control == NULL) {
     786             :                 /* VLV needs sort */
     787           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     788             :         }
     789             : 
     790       53031 :         vlv_ctrl = talloc_get_type(control->data, struct ldb_vlv_req_control);
     791       53031 :         if (vlv_ctrl == NULL) {
     792           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     793             :         }
     794             : 
     795       53031 :         sort_ctrl = talloc_get_type(sort_control->data, struct ldb_server_sort_control *);
     796       53031 :         if (sort_ctrl == NULL) {
     797           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     798             :         }
     799             : 
     800       53031 :         priv = talloc_get_type(ldb_module_get_private(module),
     801             :                                struct private_data);
     802             : 
     803       53031 :         ac = talloc_zero(req, struct vlv_context);
     804       53031 :         if (ac == NULL) {
     805           0 :                 ldb_set_errstring(ldb, "Out of Memory");
     806           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     807             :         }
     808             : 
     809       53031 :         ac->module = module;
     810       53031 :         ac->req = req;
     811       53031 :         ac->priv = priv;
     812             :         /* If there is no cookie, this is a new request, and we need to do the
     813             :          * search in the database. Otherwise we try to refer to a previously
     814             :          * saved search.
     815             :          */
     816       53031 :         if (vlv_ctrl->ctxid_len == 0) {
     817             :                 static const char * const attrs[2] = {
     818             :                         "objectGUID", NULL
     819             :                 };
     820             : 
     821        7753 :                 ac->store = new_store(priv);
     822        7753 :                 if (ac->store == NULL) {
     823           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     824             :                 }
     825             : 
     826        7753 :                 ret = copy_search_details(ac->store, vlv_ctrl, sort_ctrl[0]);
     827        7753 :                 if (ret != LDB_SUCCESS) {
     828           0 :                         return ret;
     829             :                 }
     830             : 
     831        7753 :                 ret = ldb_build_search_req_ex(&search_req, ldb, ac,
     832             :                                               req->op.search.base,
     833             :                                               req->op.search.scope,
     834             :                                               req->op.search.tree,
     835             :                                               attrs,
     836             :                                               req->controls,
     837             :                                               ac,
     838             :                                               vlv_search_callback,
     839             :                                               req);
     840        7753 :                 if (ret != LDB_SUCCESS) {
     841           0 :                         return ret;
     842             :                 }
     843             :                 /* save it locally and remove it from the list */
     844             :                 /* we do not need to replace them later as we
     845             :                  * are keeping the original req intact */
     846        7753 :                 if (!ldb_save_controls(control, search_req, NULL)) {
     847           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     848             :                 }
     849             : 
     850        7753 :                 ac->store->down_controls = vlv_copy_down_controls(ac->store,
     851             :                                                                   req->controls);
     852             : 
     853        7753 :                 if (ac->store->down_controls == NULL) {
     854           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     855             :                 }
     856             : 
     857        7753 :                 return ldb_next_request(module, search_req);
     858             : 
     859             :         } else {
     860       45278 :                 struct results_store *current = NULL;
     861       45278 :                 uint8_t *id = vlv_ctrl->contextId;
     862             : 
     863       45278 :                 if (vlv_ctrl->ctxid_len != sizeof(uint32_t)){
     864           0 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
     865             :                 }
     866             : 
     867      130569 :                 for (i = 0; i < priv->n_stores; i++) {
     868      130566 :                         current = priv->store[i];
     869      130566 :                         if (current == NULL) {
     870          10 :                                 continue;
     871             :                         }
     872      130556 :                         if (memcmp(&current->contextId, id, sizeof(uint32_t)) == 0) {
     873       45275 :                                 current->timestamp = time(NULL);
     874       45275 :                                 break;
     875             :                         }
     876             :                 }
     877       45278 :                 if (i == priv->n_stores) {
     878             :                         /* We were given a context id that we don't know about. */
     879           3 :                         if (critical) {
     880           2 :                                 return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
     881             :                         } else {
     882           1 :                                 return ldb_next_request(module, req);
     883             :                         }
     884             :                 }
     885             : 
     886       45275 :                 ac->store = current;
     887       45275 :                 ret = copy_search_details(ac->store, vlv_ctrl, sort_ctrl[0]);
     888       45275 :                 if (ret != LDB_SUCCESS) {
     889           0 :                         return ret;
     890             :                 }
     891             : 
     892       45275 :                 ret = vlv_results(ac, NULL);
     893       45275 :                 if (ret != LDB_SUCCESS) {
     894           0 :                         return ret;
     895             :                 }
     896       45275 :                 return ldb_module_done(req, ac->controls, NULL,
     897             :                                        LDB_SUCCESS);
     898             :         }
     899             : }
     900             : 
     901             : 
     902      132453 : static int vlv_request_init(struct ldb_module *module)
     903             : {
     904             :         struct ldb_context *ldb;
     905             :         struct private_data *data;
     906             :         int ret;
     907             : 
     908      132453 :         ldb = ldb_module_get_ctx(module);
     909             : 
     910      132453 :         data = talloc(module, struct private_data);
     911      132453 :         if (data == NULL) {
     912           0 :                 return LDB_ERR_OTHER;
     913             :         }
     914             : 
     915      132453 :         data->next_free_id = 1;
     916      132453 :         data->n_stores = VLV_N_SEARCHES;
     917      132453 :         data->store = talloc_zero_array(data, struct results_store *, data->n_stores);
     918             : 
     919      132453 :         ldb_module_set_private(module, data);
     920             : 
     921      132453 :         ret = ldb_mod_register_control(module, LDB_CONTROL_VLV_REQ_OID);
     922      132453 :         if (ret != LDB_SUCCESS) {
     923           0 :                 ldb_debug(ldb, LDB_DEBUG_WARNING,
     924             :                           "vlv:"
     925             :                           "Unable to register control with rootdse!");
     926             :         }
     927             : 
     928      132453 :         return ldb_next_init(module);
     929             : }
     930             : 
     931             : static const struct ldb_module_ops ldb_vlv_module_ops = {
     932             :         .name           = "vlv",
     933             :         .search         = vlv_search,
     934             :         .init_context   = vlv_request_init
     935             : };
     936             : 
     937        5536 : int ldb_vlv_init(const char *version)
     938             : {
     939        5536 :         LDB_MODULE_CHECK_VERSION(version);
     940        5536 :         return ldb_register_module(&ldb_vlv_module_ops);
     941             : }

Generated by: LCOV version 1.13