LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - ranged_results.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 96 134 71.6 %
Date: 2024-04-21 15:09:00 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* 
       2             :    ldb database library
       3             : 
       4             :    Copyright (C) Andrew Bartlett 2007
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             :    
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             :    
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : /*
      21             :  *  Name: ldb
      22             :  *
      23             :  *  Component: ldb ranged results module
      24             :  *
      25             :  *  Description: munge AD-style 'ranged results' requests into
      26             :  *  requests for all values in an attribute, then return the range to
      27             :  *  the client.
      28             :  *
      29             :  *  Author: Andrew Bartlett
      30             :  */
      31             : 
      32             : #include "includes.h"
      33             : #include "ldb_module.h"
      34             : 
      35             : #undef strncasecmp
      36             : 
      37             : struct rr_context {
      38             :         struct ldb_module *module;
      39             :         struct ldb_request *req;
      40             :         bool dirsync_in_use;
      41             : };
      42             : 
      43          12 : static struct rr_context *rr_init_context(struct ldb_module *module,
      44             :                                           struct ldb_request *req)
      45             : {
      46          12 :         struct ldb_control *dirsync_control = NULL;
      47          12 :         struct rr_context *ac = talloc_zero(req, struct rr_context);
      48          12 :         if (ac == NULL) {
      49           0 :                 ldb_set_errstring(ldb_module_get_ctx(module), "Out of Memory");
      50           0 :                 return NULL;
      51             :         }
      52             : 
      53          12 :         ac->module = module;
      54          12 :         ac->req = req;
      55             : 
      56             :         /*
      57             :          * check if there's a dirsync control (as there is an
      58             :          * interaction between these modules)
      59             :          */
      60          12 :         dirsync_control = ldb_request_get_control(req,
      61             :                                                   LDB_CONTROL_DIRSYNC_OID);
      62          12 :         if (dirsync_control != NULL) {
      63           1 :                 ac->dirsync_in_use = true;
      64             :         }
      65             : 
      66          12 :         return ac;
      67             : }
      68             : 
      69          48 : static int rr_search_callback(struct ldb_request *req, struct ldb_reply *ares)
      70             : {
      71           0 :         struct ldb_context *ldb;
      72           0 :         struct rr_context *ac;
      73           0 :         unsigned int i, j;
      74           0 :         TALLOC_CTX *temp_ctx;
      75             : 
      76          48 :         ac = talloc_get_type(req->context, struct rr_context);
      77          48 :         ldb = ldb_module_get_ctx(ac->module);
      78             : 
      79          48 :         if (!ares) {
      80           0 :                 return ldb_module_done(ac->req, NULL, NULL,
      81             :                                         LDB_ERR_OPERATIONS_ERROR);
      82             :         }
      83          48 :         if (ares->error != LDB_SUCCESS) {
      84           0 :                 return ldb_module_done(ac->req, ares->controls,
      85             :                                         ares->response, ares->error);
      86             :         }
      87             : 
      88          48 :         if (ares->type == LDB_REPLY_REFERRAL) {
      89          27 :                 return ldb_module_send_referral(ac->req, ares->referral);
      90             :         }
      91             : 
      92          21 :         if (ares->type == LDB_REPLY_DONE) {
      93          12 :                 return ldb_module_done(ac->req, ares->controls,
      94             :                                         ares->response, ares->error);
      95             :         }
      96             : 
      97           9 :         if (ac->dirsync_in_use) {
      98             :                 /*
      99             :                  * We return full attribute values when mixed with
     100             :                  * dirsync
     101             :                  */
     102           1 :                 return ldb_module_send_entry(ac->req,
     103             :                                              ares->message,
     104             :                                              ares->controls);
     105             :         }
     106             :         /* LDB_REPLY_ENTRY */
     107             : 
     108           8 :         temp_ctx = talloc_new(ac->req);
     109           8 :         if (!temp_ctx) {
     110           0 :                 ldb_module_oom(ac->module);
     111           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     112             :                                        LDB_ERR_OPERATIONS_ERROR);
     113             :         }
     114             : 
     115             :         /* Find those that are range requests from the attribute list */
     116          16 :         for (i = 0; ac->req->op.search.attrs[i]; i++) {
     117           0 :                 char *p, *new_attr;
     118           0 :                 const char *end_str;
     119           0 :                 unsigned int start, end;
     120           0 :                 struct ldb_message_element *el;
     121           0 :                 struct ldb_val *orig_values;
     122             : 
     123           8 :                 p = strchr(ac->req->op.search.attrs[i], ';');
     124           8 :                 if (!p) {
     125           0 :                         continue;
     126             :                 }
     127           8 :                 if (strncasecmp(p, ";range=", strlen(";range=")) != 0) {
     128           0 :                         continue;
     129             :                 }
     130           8 :                 if (sscanf(p, ";range=%u-%u", &start, &end) != 2) {
     131           1 :                         if (sscanf(p, ";range=%u-*", &start) == 1) {
     132           1 :                                 end = (unsigned int)-1;
     133             :                         } else {
     134           0 :                                 continue;
     135             :                         }
     136             :                 }
     137           8 :                 new_attr = talloc_strndup(temp_ctx,
     138           8 :                                           ac->req->op.search.attrs[i],
     139           8 :                                           (size_t)(p - ac->req->op.search.attrs[i]));
     140             : 
     141           8 :                 if (!new_attr) {
     142           0 :                         ldb_oom(ldb);
     143           0 :                         return ldb_module_done(ac->req, NULL, NULL,
     144             :                                                 LDB_ERR_OPERATIONS_ERROR);
     145             :                 }
     146           8 :                 el = ldb_msg_find_element(ares->message, new_attr);
     147           8 :                 talloc_free(new_attr);
     148           8 :                 if (!el) {
     149           0 :                         continue;
     150             :                 }
     151           8 :                 if (end >= (el->num_values - 1)) {
     152             :                         /* Need to leave the requested attribute in
     153             :                          * there (so add an empty one to match) */
     154           6 :                         end_str = "*";
     155           6 :                         end = el->num_values - 1;
     156             :                 } else {
     157           2 :                         end_str = talloc_asprintf(temp_ctx, "%u", end);
     158           2 :                         if (!end_str) {
     159           0 :                                 ldb_oom(ldb);
     160           0 :                                 return ldb_module_done(ac->req, NULL, NULL,
     161             :                                                         LDB_ERR_OPERATIONS_ERROR);
     162             :                         }
     163             :                 }
     164             :                 /* If start is greater then where we are find the end to be */
     165           8 :                 if (start > end) {
     166           1 :                         el->num_values = 0;
     167           1 :                         el->values = NULL;
     168             :                 } else {
     169           7 :                         orig_values = el->values;
     170             :                         
     171           7 :                         if ((start + end < start) || (start + end < end)) {
     172           0 :                                 ldb_asprintf_errstring(ldb,
     173             :                                         "range request error: start or end would overflow!");
     174           0 :                                 return ldb_module_done(ac->req, NULL, NULL,
     175             :                                                         LDB_ERR_UNWILLING_TO_PERFORM);
     176             :                         }
     177             :                         
     178           7 :                         el->num_values = 0;
     179             :                         
     180           7 :                         el->values = talloc_array(ares->message->elements,
     181             :                                                   struct ldb_val,
     182             :                                                   (end - start) + 1);
     183           7 :                         if (!el->values) {
     184           0 :                                 ldb_oom(ldb);
     185           0 :                                 return ldb_module_done(ac->req, NULL, NULL,
     186             :                                                         LDB_ERR_OPERATIONS_ERROR);
     187             :                         }
     188         161 :                         for (j=start; j <= end; j++) {
     189         154 :                                 el->values[el->num_values] = orig_values[j];
     190         154 :                                 el->num_values++;
     191             :                         }
     192             :                 }
     193           8 :                 el->name = talloc_asprintf(ares->message->elements,
     194             :                                            "%s;range=%u-%s", el->name, start,
     195             :                                            end_str);
     196           8 :                 if (!el->name) {
     197           0 :                         ldb_oom(ldb);
     198           0 :                         return ldb_module_done(ac->req, NULL, NULL,
     199             :                                                 LDB_ERR_OPERATIONS_ERROR);
     200             :                 }
     201             :         }
     202             : 
     203           8 :         talloc_free(temp_ctx);
     204             : 
     205           8 :         return ldb_module_send_entry(ac->req, ares->message, ares->controls);
     206             : }
     207             : 
     208             : /* search */
     209    19969960 : static int rr_search(struct ldb_module *module, struct ldb_request *req)
     210             : {
     211     1144549 :         struct ldb_context *ldb;
     212     1144549 :         unsigned int i;
     213     1144549 :         unsigned int start, end;
     214    19969960 :         const char **new_attrs = NULL;
     215    19969960 :         bool found_rr = false;
     216     1144549 :         struct ldb_request *down_req;
     217     1144549 :         struct rr_context *ac;
     218     1144549 :         int ret;
     219             : 
     220    19969960 :         ldb = ldb_module_get_ctx(module);
     221             : 
     222             :         /* Strip the range request from the attribute */
     223    66554508 :         for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
     224     1386388 :                 char *p;
     225    45439999 :                 size_t range_len = strlen(";range=");
     226             : 
     227    45439999 :                 new_attrs = talloc_realloc(req, new_attrs, const char *, i+2);
     228    45439999 :                 new_attrs[i] = req->op.search.attrs[i];
     229    45439999 :                 new_attrs[i+1] = NULL;
     230    45439999 :                 p = strchr(new_attrs[i], ';');
     231    45439999 :                 if (!p) {
     232    45439987 :                         continue;
     233             :                 }
     234          12 :                 if (strncasecmp(p, ";range=", range_len) != 0) {
     235           0 :                         continue;
     236             :                 }
     237          12 :                 end = (unsigned int)-1;
     238          12 :                 if (sscanf(p + range_len, "%u-*", &start) != 1) {
     239           0 :                         if (sscanf(p + range_len, "%u-%u", &start, &end) != 2) {
     240           0 :                                 ldb_asprintf_errstring(ldb,
     241             :                                         "range request error: "
     242             :                                         "range request malformed");
     243           0 :                                 return LDB_ERR_UNWILLING_TO_PERFORM;
     244             :                         }
     245             :                 }
     246          12 :                 if (start > end) {
     247           0 :                         ldb_asprintf_errstring(ldb, "range request error: start must not be greater than end");
     248           0 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
     249             :                 }
     250             : 
     251          12 :                 found_rr = true;
     252          24 :                 new_attrs[i] = talloc_strndup(new_attrs, new_attrs[i],
     253          12 :                                               (size_t)(p - new_attrs[i]));
     254             : 
     255          12 :                 if (!new_attrs[i]) {
     256           0 :                         return ldb_oom(ldb);
     257             :                 }
     258             :         }
     259             : 
     260    19969960 :         if (found_rr) {
     261          12 :                 ac = rr_init_context(module, req);
     262          12 :                 if (!ac) {
     263           0 :                         return ldb_operr(ldb);
     264             :                 }
     265             : 
     266          12 :                 ret = ldb_build_search_req_ex(&down_req, ldb, ac,
     267             :                                               req->op.search.base,
     268             :                                               req->op.search.scope,
     269             :                                               req->op.search.tree,
     270             :                                               new_attrs,
     271             :                                               req->controls,
     272             :                                               ac, rr_search_callback,
     273             :                                               req);
     274          12 :                 LDB_REQ_SET_LOCATION(down_req);
     275          12 :                 if (ret != LDB_SUCCESS) {
     276           0 :                         return ret;
     277             :                 }
     278          12 :                 return ldb_next_request(module, down_req);
     279             :         }
     280             : 
     281             :         /* No change, just run the original request as if we were never here */
     282    19969948 :         talloc_free(new_attrs);
     283    19969948 :         return ldb_next_request(module, req);
     284             : }
     285             : 
     286             : static const struct ldb_module_ops ldb_ranged_results_module_ops = {
     287             :         .name              = "ranged_results",
     288             :         .search            = rr_search,
     289             : };
     290             : 
     291        6040 : int ldb_ranged_results_module_init(const char *version)
     292             : {
     293        6040 :         LDB_MODULE_CHECK_VERSION(version);
     294        6040 :         return ldb_register_module(&ldb_ranged_results_module_ops);
     295             : }

Generated by: LCOV version 1.14