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 master 2f515e9b Lines: 314 404 77.7 %
Date: 2024-04-21 15:09:00 Functions: 14 15 93.3 %

          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           0 :         struct results_store *store;
      93           0 :         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        8033 :                         best = i;
     102        8033 :                         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      274180 : 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           0 :         struct ldb_dn *dn;
     147           0 :         struct ldb_request *req;
     148           0 :         struct ldb_result *res;
     149           0 :         int ret;
     150           0 :         struct GUID_txt_buf guid_str;
     151      274180 :         struct ldb_control **controls = ac->store->down_controls;
     152      274180 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     153             : 
     154      274180 :         dn = ldb_dn_new_fmt(ac, ldb, "<GUID=%s>",
     155             :                             GUID_buf_string(guid, &guid_str));
     156      274180 :         if (dn == NULL) {
     157           0 :                 return ldb_oom(ldb);
     158             :         }
     159             : 
     160      274180 :         res = talloc_zero(ac, struct ldb_result);
     161      274180 :         if (res == NULL) {
     162           0 :                 return ldb_oom(ldb);
     163             :         }
     164             : 
     165      274180 :         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      274180 :         if (ret != LDB_SUCCESS) {
     175           0 :                 talloc_free(res);
     176           0 :                 return ret;
     177             :         }
     178             : 
     179      274180 :         ret = ldb_request(ldb, req);
     180      274180 :         if (ret == LDB_SUCCESS) {
     181      274180 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
     182             :         }
     183             : 
     184      274180 :         talloc_free(req);
     185      274180 :         if (ret != LDB_SUCCESS) {
     186       35362 :                 talloc_free(res);
     187       35362 :                 return ret;
     188             :         }
     189             : 
     190      238818 :         *result = res;
     191      238818 :         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           0 :         int ret;
     218           0 :         struct referral_store *node;
     219        3388 :         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       48477 : static int vlv_value_compare(struct vlv_sort_context *target,
     235             :                              struct GUID *guid)
     236             : {
     237       48477 :         struct ldb_result *result = NULL;
     238       48477 :         struct ldb_message_element *el = NULL;
     239       48477 :         struct vlv_context *ac = target->ac;
     240           0 :         int ret;
     241       48477 :         const char *attrs[2] = {
     242       48477 :                 target->attr,
     243             :                 NULL
     244             :         };
     245             : 
     246       48477 :         ret = vlv_search_by_dn_guid(ac->module, ac, &result, guid, attrs);
     247             : 
     248       48477 :         if (ret != LDB_SUCCESS) {
     249           0 :                 target->status = ret;
     250             :                 /* returning 0 ends the search. */
     251           0 :                 return 0;
     252             :         }
     253             : 
     254       48477 :         el = ldb_msg_find_element(result->msgs[0], target->attr);
     255       48477 :         return target->comparison_fn(target->ldb, ac,
     256       48477 :                                      &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           0 :         struct ldb_context *ldb;
     290           0 :         const struct ldb_schema_attribute *a;
     291       16005 :         struct GUID *result = NULL;
     292           0 :         struct vlv_sort_context context;
     293       16005 :         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       64482 :                 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        4301 :                 return len;
     329             :         }
     330       11704 :         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           0 :         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       53028 :         struct ldb_extended *response = (ares != NULL ? ares->response : NULL);
     393           0 :         struct ldb_vlv_resp_control *vlv;
     394           0 :         unsigned int num_ctrls;
     395           0 :         int ret, i, first_i, last_i;
     396           0 :         struct ldb_vlv_req_control *vlv_details;
     397           0 :         struct ldb_server_sort_control *sort_details;
     398       53028 :         int target = 0;
     399             : 
     400       53028 :         if (ac->store == NULL) {
     401           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
     402           0 :                 return ldb_module_done(
     403             :                         ac->req, ac->controls, response, ret);
     404             :         }
     405             : 
     406       53028 :         if (ac->store->first_ref) {
     407             :                 /* There is no right place to put references in the sorted
     408             :                    results, so we send them as soon as possible.
     409             :                 */
     410         847 :                 ret = send_referrals(ac->store, ac->req);
     411         847 :                 if (ret != LDB_SUCCESS) {
     412             :                         /*
     413             :                          * send_referrals will have called ldb_module_done
     414             :                          * if there was an error.
     415             :                          */
     416           0 :                         return ret;
     417             :                 }
     418             :         }
     419             : 
     420       53028 :         vlv_details = ac->store->vlv_details;
     421       53028 :         sort_details = ac->store->sort_details;
     422             : 
     423       53028 :         if (ac->store->num_entries != 0) {
     424       46758 :                 if (vlv_details->type == 1) {
     425       16005 :                         target = vlv_gt_eq_to_index(ac, ac->store->results,
     426             :                                                     vlv_details,
     427             :                                                     sort_details, &ret);
     428       16005 :                         if (ret != LDB_SUCCESS) {
     429           0 :                                 return ldb_module_done(
     430             :                                         ac->req,
     431             :                                         ac->controls,
     432             :                                         response,
     433             :                                         ret);
     434             :                         }
     435             :                 } else {
     436       30753 :                         target = vlv_calc_real_offset(vlv_details->match.byOffset.offset,
     437             :                                                       vlv_details->match.byOffset.contentCount,
     438       30753 :                                                       ac->store->num_entries);
     439       30753 :                         if (target == -1) {
     440           0 :                                 ret = LDB_ERR_OPERATIONS_ERROR;
     441           0 :                                 return ldb_module_done(
     442             :                                         ac->req,
     443             :                                         ac->controls,
     444             :                                         response,
     445             :                                         ret);
     446             :                         }
     447             :                 }
     448             : 
     449             :                 /* send the results */
     450       46758 :                 first_i = MAX(target - vlv_details->beforeCount, 0);
     451       46758 :                 last_i = MIN(target + vlv_details->afterCount,
     452             :                              ac->store->num_entries - 1);
     453             : 
     454      272461 :                 for (i = first_i; i <= last_i; i++) {
     455      225703 :                         struct ldb_result *result = NULL;
     456      225703 :                         struct GUID *guid = &ac->store->results[i];
     457             : 
     458      451406 :                         ret = vlv_search_by_dn_guid(ac->module, ac, &result, guid,
     459      225703 :                                                     ac->req->op.search.attrs);
     460             : 
     461      225703 :                         if (ret == LDAP_NO_SUCH_OBJECT
     462      190341 :                             || result->count != 1) {
     463             :                                 /*
     464             :                                  * The thing isn't there, which we quietly
     465             :                                  * ignore and go on to send an extra one
     466             :                                  * instead.
     467             :                                  *
     468             :                                  * result->count == 0 or > 1 can only
     469             :                                  * happen if ASQ (which breaks all the
     470             :                                  * rules) is somehow invoked (as this
     471             :                                  * is a BASE search).
     472             :                                  *
     473             :                                  * (We skip the ASQ cookie for the
     474             :                                  * GUID searches)
     475             :                                  */
     476       35362 :                                 if (last_i < ac->store->num_entries - 1) {
     477       13403 :                                         last_i++;
     478             :                                 }
     479       35362 :                                 continue;
     480      190341 :                         } else if (ret != LDB_SUCCESS) {
     481           0 :                                 return ldb_module_done(
     482             :                                         ac->req,
     483             :                                         ac->controls,
     484             :                                         response,
     485             :                                         ret);
     486             :                         }
     487             : 
     488      190341 :                         ret = ldb_module_send_entry(ac->req, result->msgs[0],
     489             :                                                     NULL);
     490      190341 :                         if (ret != LDB_SUCCESS) {
     491             :                                 /*
     492             :                                  * ldb_module_send_entry will have called
     493             :                                  * ldb_module_done if there was an error
     494             :                                  */
     495           0 :                                 return ret;
     496             :                         }
     497             :                 }
     498             :         } else {
     499        6270 :                 target = -1;
     500             :         }
     501             : 
     502             :         /* return result done */
     503       53028 :         num_ctrls = 1;
     504       53028 :         i = 0;
     505             : 
     506       53028 :         if (ac->store->controls != NULL) {
     507           2 :                 while (ac->store->controls[i]){
     508           1 :                         i++; /* counting */
     509             :                 }
     510           1 :                 num_ctrls += i;
     511             :         }
     512             : 
     513       53028 :         ac->controls = talloc_array(ac, struct ldb_control *, num_ctrls + 1);
     514       53028 :         if (ac->controls == NULL) {
     515           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
     516           0 :                 return ldb_module_done(
     517             :                         ac->req, ac->controls, response, ret);
     518             :         }
     519       53028 :         ac->controls[num_ctrls] = NULL;
     520             : 
     521       53029 :         for (i = 0; i < (num_ctrls -1); i++) {
     522           1 :                 ac->controls[i] = talloc_reference(ac->controls, ac->store->controls[i]);
     523             :         }
     524             : 
     525       53028 :         ac->controls[i] = talloc(ac->controls, struct ldb_control);
     526       53028 :         if (ac->controls[i] == NULL) {
     527           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
     528           0 :                 return ldb_module_done(
     529             :                         ac->req, ac->controls, response, ret);
     530             :         }
     531             : 
     532       53028 :         ac->controls[i]->oid = talloc_strdup(ac->controls[i],
     533             :                                              LDB_CONTROL_VLV_RESP_OID);
     534       53028 :         if (ac->controls[i]->oid == NULL) {
     535           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
     536           0 :                 return ldb_module_done(
     537             :                         ac->req, ac->controls, response, ret);
     538             :         }
     539             : 
     540       53028 :         ac->controls[i]->critical = 0;
     541             : 
     542       53028 :         vlv = talloc(ac->controls[i], struct ldb_vlv_resp_control);
     543       53028 :         if (vlv == NULL) {
     544           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
     545           0 :                 return ldb_module_done(
     546             :                         ac->req, ac->controls, response, ret);
     547             :         }
     548       53028 :         ac->controls[i]->data = vlv;
     549             : 
     550       53028 :         ac->store->timestamp = time(NULL);
     551             : 
     552       53028 :         ac->store->contextId = ac->priv->next_free_id;
     553       53028 :         ac->priv->next_free_id++;
     554       53028 :         vlv->contextId = talloc_memdup(vlv, &ac->store->contextId, sizeof(uint32_t));
     555       53028 :         vlv->ctxid_len = sizeof(uint32_t);
     556       53028 :         vlv->vlv_result = 0;
     557       53028 :         vlv->contentCount = ac->store->num_entries;
     558       53028 :         if (target >= 0) {
     559       46758 :                 vlv->targetPosition = target + 1;
     560        6270 :         } else if (vlv_details->type == 1) {
     561        6270 :                 vlv->targetPosition = ac->store->num_entries + 1;
     562             :         } else {
     563           0 :                 vlv->targetPosition = 0;
     564             :         }
     565       53028 :         return LDB_SUCCESS;
     566             : }
     567             : 
     568             : 
     569             : /* vlv_search_callback() collects GUIDs found by the original search */
     570             : 
     571      575389 : static int vlv_search_callback(struct ldb_request *req, struct ldb_reply *ares)
     572             : {
     573           0 :         struct vlv_context *ac;
     574           0 :         struct results_store *store;
     575           0 :         int ret;
     576             : 
     577      575389 :         ac = talloc_get_type(req->context, struct vlv_context);
     578      575389 :         store = ac->store;
     579             : 
     580      575389 :         if (!ares) {
     581           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     582             :                                         LDB_ERR_OPERATIONS_ERROR);
     583             :         }
     584      575389 :         if (ares->error != LDB_SUCCESS) {
     585           0 :                 return ldb_module_done(ac->req, ares->controls,
     586             :                                         ares->response, ares->error);
     587             :         }
     588             : 
     589      575389 :         switch (ares->type) {
     590      565095 :         case LDB_REPLY_ENTRY:
     591      565095 :                 if (store->results == NULL) {
     592        7733 :                         store->num_entries = 0;
     593        7733 :                         store->result_array_size = 16;
     594        7733 :                         store->results = talloc_array(store, struct GUID,
     595             :                                                       store->result_array_size);
     596        7733 :                         if (store->results == NULL) {
     597           0 :                                 return ldb_module_done(ac->req, NULL, NULL,
     598             :                                                        LDB_ERR_OPERATIONS_ERROR);
     599             :                         }
     600      557362 :                 } else if (store->num_entries == store->result_array_size) {
     601       10977 :                         store->result_array_size *= 2;
     602       10977 :                         store->results = talloc_realloc(store, store->results,
     603             :                                                         struct GUID,
     604             :                                                         store->result_array_size);
     605       10977 :                         if (store->results == NULL) {
     606           0 :                                 return ldb_module_done(ac->req, NULL, NULL,
     607             :                                                        LDB_ERR_OPERATIONS_ERROR);
     608             :                         }
     609             :                 }
     610      565095 :                 store->results[store->num_entries] = \
     611      565095 :                         samdb_result_guid(ares->message, "objectGUID");
     612      565095 :                 store->num_entries++;
     613      565095 :                 break;
     614             : 
     615        2541 :         case LDB_REPLY_REFERRAL:
     616        2541 :                 ret = save_referral(store, ares->referral);
     617        2541 :                 if (ret != LDB_SUCCESS) {
     618           0 :                         return ldb_module_done(ac->req, NULL, NULL, ret);
     619             :                 }
     620        2541 :                 break;
     621             : 
     622        7753 :         case LDB_REPLY_DONE:
     623        7753 :                 if (store->num_entries != 0) {
     624        7733 :                         store->results = talloc_realloc(store, store->results,
     625             :                                                         struct GUID,
     626             :                                                         store->num_entries);
     627        7733 :                         if (store->results == NULL) {
     628           0 :                                 return ldb_module_done(ac->req, NULL, NULL,
     629             :                                                        LDB_ERR_OPERATIONS_ERROR);
     630             :                         }
     631             :                 }
     632        7753 :                 store->result_array_size = store->num_entries;
     633             : 
     634        7753 :                 ac->store->controls = talloc_move(ac->store, &ares->controls);
     635        7753 :                 ret = vlv_results(ac, ares);
     636        7753 :                 if (ret != LDB_SUCCESS) {
     637             :                         /* vlv_results will have called ldb_module_done
     638             :                          * if there was an error.
     639             :                          */
     640           0 :                         return ret;
     641             :                 }
     642        7753 :                 return ldb_module_done(ac->req, ac->controls,
     643             :                                         ares->response, ret);
     644             :         }
     645             : 
     646      567636 :         return LDB_SUCCESS;
     647             : }
     648             : 
     649       53028 : static int copy_search_details(struct results_store *store,
     650             :                                struct ldb_vlv_req_control *vlv_ctrl,
     651             :                                struct ldb_server_sort_control *sort_ctrl)
     652             : {
     653             :         /* free the old details which are no longer going to be reachable. */
     654       53028 :         if (store->vlv_details != NULL){
     655       45275 :                 TALLOC_FREE(store->vlv_details);
     656             :         }
     657             : 
     658       53028 :         if (store->sort_details != NULL){
     659       45275 :                 TALLOC_FREE(store->sort_details);
     660             :         }
     661             : 
     662       53028 :         store->vlv_details = talloc(store, struct ldb_vlv_req_control);
     663       53028 :         if (store->vlv_details == NULL) {
     664           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     665             :         }
     666       53028 :         *store->vlv_details = *vlv_ctrl;
     667       53028 :         store->vlv_details->contextId = talloc_memdup(store, vlv_ctrl->contextId,
     668             :                                                       vlv_ctrl->ctxid_len);
     669       53028 :         if (store->vlv_details->contextId == NULL) {
     670           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     671             :         }
     672             : 
     673       53028 :         if (vlv_ctrl->type == 1) {
     674       22275 :                 char *v = talloc_array(store, char,
     675             :                                        vlv_ctrl->match.gtOrEq.value_len + 1);
     676             : 
     677       22275 :                 if (v == NULL) {
     678           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     679             :                 }
     680             : 
     681       22275 :                 memcpy(v, vlv_ctrl->match.gtOrEq.value, vlv_ctrl->match.gtOrEq.value_len);
     682       22275 :                 v[vlv_ctrl->match.gtOrEq.value_len] = '\0';
     683             : 
     684       22275 :                 store->vlv_details->match.gtOrEq.value = v;
     685             :         }
     686             : 
     687       53028 :         store->sort_details = talloc(store, struct ldb_server_sort_control);
     688       53028 :         if (store->sort_details == NULL) {
     689           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     690             :         }
     691       53028 :         store->sort_details->attributeName = talloc_strdup(store,
     692             :                                                            sort_ctrl->attributeName);
     693       53028 :         if (store->sort_details->attributeName == NULL) {
     694           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     695             :         }
     696             : 
     697       53028 :         if (sort_ctrl->orderingRule == NULL) {
     698       53028 :                 store->sort_details->orderingRule = NULL;
     699             :         } else {
     700           0 :                 store->sort_details->orderingRule = talloc_strdup(store,
     701             :                                                                   sort_ctrl->orderingRule);
     702           0 :                 if (store->sort_details->orderingRule == NULL) {
     703           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     704             :                 }
     705             :         }
     706       53028 :         store->sort_details->reverse = sort_ctrl->reverse;
     707             : 
     708       53028 :         return LDB_SUCCESS;
     709             : }
     710             : 
     711             : 
     712             : static struct ldb_control **
     713        7753 : vlv_copy_down_controls(TALLOC_CTX *mem_ctx, struct ldb_control **controls)
     714             : {
     715             : 
     716           0 :         struct ldb_control **new_controls;
     717           0 :         unsigned int i, j, num_ctrls;
     718        7753 :         if (controls == NULL) {
     719           0 :                 return NULL;
     720             :         }
     721             : 
     722       31990 :         for (num_ctrls = 0; controls[num_ctrls]; num_ctrls++);
     723             : 
     724        7753 :         new_controls = talloc_array(mem_ctx, struct ldb_control *, num_ctrls);
     725        7753 :         if (new_controls == NULL) {
     726           0 :                 return NULL;
     727             :         }
     728             : 
     729       24238 :         for (j = 0, i = 0; i < (num_ctrls); i++) {
     730       24237 :                 struct ldb_control *control = controls[i];
     731       24237 :                 if (control->oid == NULL) {
     732        7752 :                         break;
     733             :                 }
     734             :                 /*
     735             :                  * Do not re-use VLV, nor the server-sort, both are
     736             :                  * already handled here.
     737             :                  */
     738       16485 :                 if (strcmp(control->oid, LDB_CONTROL_VLV_REQ_OID) == 0 ||
     739        8732 :                     strcmp(control->oid, LDB_CONTROL_SERVER_SORT_OID) == 0) {
     740       15506 :                         continue;
     741             :                 }
     742             :                 /*
     743             :                  * ASQ changes everything, do not copy it down for the
     744             :                  * per-GUID search
     745             :                  */
     746         979 :                 if (strcmp(control->oid, LDB_CONTROL_ASQ_OID) == 0) {
     747           1 :                         continue;
     748             :                 }
     749         978 :                 new_controls[j] = talloc_steal(new_controls, control);
     750             :                 /*
     751             :                  * Sadly the caller is not obliged to make this a
     752             :                  * proper talloc tree, so we do so here.
     753             :                  */
     754         978 :                 if (control->data) {
     755           1 :                         talloc_steal(control, control->data);
     756             :                 }
     757         978 :                 j++;
     758             :         }
     759        7753 :         new_controls[j] = NULL;
     760        7753 :         return new_controls;
     761             : }
     762             : 
     763    20015237 : static int vlv_search(struct ldb_module *module, struct ldb_request *req)
     764             : {
     765     1144549 :         struct ldb_context *ldb;
     766     1144549 :         struct ldb_control *control;
     767     1144549 :         struct ldb_control *sort_control;
     768     1144549 :         struct private_data *priv;
     769     1144549 :         struct ldb_vlv_req_control *vlv_ctrl;
     770     1144549 :         struct ldb_server_sort_control **sort_ctrl;
     771     1144549 :         struct ldb_request *search_req;
     772     1144549 :         struct vlv_context *ac;
     773     1144549 :         int ret, i, critical;
     774             : 
     775    20015237 :         ldb = ldb_module_get_ctx(module);
     776             : 
     777    20015237 :         control = ldb_request_get_control(req, LDB_CONTROL_VLV_REQ_OID);
     778    20015237 :         if (control == NULL) {
     779             :                 /* There is no VLV. go on */
     780    19962206 :                 return ldb_next_request(module, req);
     781             :         }
     782       53031 :         critical = control->critical;
     783       53031 :         control->critical = 0;
     784             : 
     785       53031 :         sort_control = ldb_request_get_control(req, LDB_CONTROL_SERVER_SORT_OID);
     786       53031 :         if (sort_control == NULL) {
     787             :                 /* VLV needs sort */
     788           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     789             :         }
     790             : 
     791       53031 :         vlv_ctrl = talloc_get_type(control->data, struct ldb_vlv_req_control);
     792       53031 :         if (vlv_ctrl == NULL) {
     793           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     794             :         }
     795             : 
     796       53031 :         sort_ctrl = talloc_get_type(sort_control->data, struct ldb_server_sort_control *);
     797       53031 :         if (sort_ctrl == NULL) {
     798           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     799             :         }
     800             : 
     801       53031 :         priv = talloc_get_type(ldb_module_get_private(module),
     802             :                                struct private_data);
     803             : 
     804       53031 :         ac = talloc_zero(req, struct vlv_context);
     805       53031 :         if (ac == NULL) {
     806           0 :                 ldb_set_errstring(ldb, "Out of Memory");
     807           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     808             :         }
     809             : 
     810       53031 :         ac->module = module;
     811       53031 :         ac->req = req;
     812       53031 :         ac->priv = priv;
     813             :         /* If there is no cookie, this is a new request, and we need to do the
     814             :          * search in the database. Otherwise we try to refer to a previously
     815             :          * saved search.
     816             :          */
     817       53031 :         if (vlv_ctrl->ctxid_len == 0) {
     818           0 :                 static const char * const attrs[2] = {
     819             :                         "objectGUID", NULL
     820             :                 };
     821             : 
     822        7753 :                 ac->store = new_store(priv);
     823        7753 :                 if (ac->store == NULL) {
     824           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     825             :                 }
     826             : 
     827        7753 :                 ret = copy_search_details(ac->store, vlv_ctrl, sort_ctrl[0]);
     828        7753 :                 if (ret != LDB_SUCCESS) {
     829           0 :                         return ret;
     830             :                 }
     831             : 
     832        7753 :                 ret = ldb_build_search_req_ex(&search_req, ldb, ac,
     833             :                                               req->op.search.base,
     834             :                                               req->op.search.scope,
     835             :                                               req->op.search.tree,
     836             :                                               attrs,
     837             :                                               req->controls,
     838             :                                               ac,
     839             :                                               vlv_search_callback,
     840             :                                               req);
     841        7753 :                 if (ret != LDB_SUCCESS) {
     842           0 :                         return ret;
     843             :                 }
     844             :                 /* save it locally and remove it from the list */
     845             :                 /* we do not need to replace them later as we
     846             :                  * are keeping the original req intact */
     847        7753 :                 if (!ldb_save_controls(control, search_req, NULL)) {
     848           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     849             :                 }
     850             : 
     851        7753 :                 ac->store->down_controls = vlv_copy_down_controls(ac->store,
     852             :                                                                   req->controls);
     853             : 
     854        7753 :                 if (ac->store->down_controls == NULL) {
     855           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     856             :                 }
     857             : 
     858        7753 :                 return ldb_next_request(module, search_req);
     859             : 
     860             :         } else {
     861       45278 :                 struct results_store *current = NULL;
     862       45278 :                 uint8_t *id = vlv_ctrl->contextId;
     863             : 
     864       45278 :                 if (vlv_ctrl->ctxid_len != sizeof(uint32_t)){
     865           0 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
     866             :                 }
     867             : 
     868      130319 :                 for (i = 0; i < priv->n_stores; i++) {
     869      130316 :                         current = priv->store[i];
     870      130316 :                         if (current == NULL) {
     871          10 :                                 continue;
     872             :                         }
     873      130306 :                         if (memcmp(&current->contextId, id, sizeof(uint32_t)) == 0) {
     874       45275 :                                 current->timestamp = time(NULL);
     875       45275 :                                 break;
     876             :                         }
     877             :                 }
     878       45278 :                 if (i == priv->n_stores) {
     879             :                         /* We were given a context id that we don't know about. */
     880           3 :                         if (critical) {
     881           2 :                                 return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
     882             :                         } else {
     883           1 :                                 return ldb_next_request(module, req);
     884             :                         }
     885             :                 }
     886             : 
     887       45275 :                 ac->store = current;
     888       45275 :                 ret = copy_search_details(ac->store, vlv_ctrl, sort_ctrl[0]);
     889       45275 :                 if (ret != LDB_SUCCESS) {
     890           0 :                         return ret;
     891             :                 }
     892             : 
     893       45275 :                 ret = vlv_results(ac, NULL);
     894       45275 :                 if (ret != LDB_SUCCESS) {
     895             :                         /*
     896             :                          * vlv_results() will have called ldb_module_done
     897             :                          * if there was an error.
     898             :                          */
     899           0 :                         return ret;
     900             :                 }
     901       45275 :                 return ldb_module_done(req, ac->controls, NULL,
     902             :                                        LDB_SUCCESS);
     903             :         }
     904             : }
     905             : 
     906             : 
     907      182004 : static int vlv_request_init(struct ldb_module *module)
     908             : {
     909        6016 :         struct ldb_context *ldb;
     910        6016 :         struct private_data *data;
     911        6016 :         int ret;
     912             : 
     913      182004 :         ldb = ldb_module_get_ctx(module);
     914             : 
     915      182004 :         data = talloc(module, struct private_data);
     916      182004 :         if (data == NULL) {
     917           0 :                 return LDB_ERR_OTHER;
     918             :         }
     919             : 
     920      182004 :         data->next_free_id = 1;
     921      182004 :         data->n_stores = VLV_N_SEARCHES;
     922      182004 :         data->store = talloc_zero_array(data, struct results_store *, data->n_stores);
     923             : 
     924      182004 :         ldb_module_set_private(module, data);
     925             : 
     926      182004 :         ret = ldb_mod_register_control(module, LDB_CONTROL_VLV_REQ_OID);
     927      182004 :         if (ret != LDB_SUCCESS) {
     928           0 :                 ldb_debug(ldb, LDB_DEBUG_WARNING,
     929             :                           "vlv:"
     930             :                           "Unable to register control with rootdse!");
     931             :         }
     932             : 
     933      182004 :         return ldb_next_init(module);
     934             : }
     935             : 
     936             : static const struct ldb_module_ops ldb_vlv_module_ops = {
     937             :         .name           = "vlv",
     938             :         .search         = vlv_search,
     939             :         .init_context   = vlv_request_init
     940             : };
     941             : 
     942        6040 : int ldb_vlv_init(const char *version)
     943             : {
     944        6040 :         LDB_MODULE_CHECK_VERSION(version);
     945        6040 :         return ldb_register_module(&ldb_vlv_module_ops);
     946             : }

Generated by: LCOV version 1.14