root/source4/dsdb/samdb/ldb_modules/ranged_results.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rr_init_context
  2. rr_search_callback
  3. rr_search

   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 struct rr_context {
  36         struct ldb_module *module;
  37         struct ldb_request *req;
  38 };
  39 
  40 static struct rr_context *rr_init_context(struct ldb_module *module,
     /* [<][>][^][v][top][bottom][index][help] */
  41                                           struct ldb_request *req)
  42 {
  43         struct rr_context *ac;
  44 
  45         ac = talloc_zero(req, struct rr_context);
  46         if (ac == NULL) {
  47                 ldb_set_errstring(ldb_module_get_ctx(module), "Out of Memory");
  48                 return NULL;
  49         }
  50 
  51         ac->module = module;
  52         ac->req = req;
  53 
  54         return ac;
  55 }
  56 
  57 static int rr_search_callback(struct ldb_request *req, struct ldb_reply *ares)
     /* [<][>][^][v][top][bottom][index][help] */
  58 {
  59         struct ldb_context *ldb;
  60         struct rr_context *ac;
  61         int i, j;
  62 
  63         ac = talloc_get_type(req->context, struct rr_context);
  64         ldb = ldb_module_get_ctx(ac->module);
  65 
  66         if (!ares) {
  67                 return ldb_module_done(ac->req, NULL, NULL,
  68                                         LDB_ERR_OPERATIONS_ERROR);
  69         }
  70         if (ares->error != LDB_SUCCESS) {
  71                 return ldb_module_done(ac->req, ares->controls,
  72                                         ares->response, ares->error);
  73         }
  74 
  75         if (ares->type == LDB_REPLY_REFERRAL) {
  76                 return ldb_module_send_referral(ac->req, ares->referral);
  77         }
  78 
  79         if (ares->type == LDB_REPLY_DONE) {
  80                 return ldb_module_done(ac->req, ares->controls,
  81                                         ares->response, ares->error);
  82         }
  83 
  84         /* LDB_REPLY_ENTRY */
  85 
  86         /* Find those that are range requests from the attribute list */
  87         for (i = 0; ac->req->op.search.attrs[i]; i++) {
  88                 char *p, *new_attr;
  89                 const char *end_str;
  90                 unsigned int start, end, orig_num_values;
  91                 struct ldb_message_element *el;
  92                 struct ldb_val *orig_values;
  93                 p = strchr(ac->req->op.search.attrs[i], ';');
  94                 if (!p) {
  95                         continue;
  96                 }
  97                 if (strncasecmp(p, ";range=", strlen(";range=")) != 0) {
  98                         continue;
  99                 }
 100                 if (sscanf(p, ";range=%u-%u", &start, &end) != 2) {
 101                         if (sscanf(p, ";range=%u-*", &start) == 1) {
 102                                 end = (unsigned int)-1;
 103                         } else {
 104                                 continue;
 105                         }
 106                 }
 107                 new_attr = talloc_strndup(ac->req,
 108                                           ac->req->op.search.attrs[i],
 109                                           (size_t)(p - ac->req->op.search.attrs[i]));
 110 
 111                 if (!new_attr) {
 112                         ldb_oom(ldb);
 113                         return ldb_module_done(ac->req, NULL, NULL,
 114                                                 LDB_ERR_OPERATIONS_ERROR);
 115                 }
 116                 el = ldb_msg_find_element(ares->message, new_attr);
 117                 talloc_free(new_attr);
 118                 if (!el) {
 119                         continue;
 120                 }
 121                 if (end >= (el->num_values - 1)) {
 122                         /* Need to leave the requested attribute in
 123                          * there (so add an empty one to match) */
 124                         end_str = "*";
 125                         end = el->num_values - 1;
 126                 } else {
 127                         end_str = talloc_asprintf(el, "%u", end);
 128                         if (!end_str) {
 129                                 ldb_oom(ldb);
 130                                 return ldb_module_done(ac->req, NULL, NULL,
 131                                                         LDB_ERR_OPERATIONS_ERROR);
 132                         }
 133                 }
 134                 /* If start is greater then where we are find the end to be */
 135                 if (start > end) {
 136                         el->num_values = 0;
 137                         el->values = NULL;
 138                 } else {
 139                         orig_values = el->values;
 140                         orig_num_values = el->num_values;
 141                         
 142                         if ((start + end < start) || (start + end < end)) {
 143                                 ldb_asprintf_errstring(ldb,
 144                                         "range request error: start or end would overflow!");
 145                                 return ldb_module_done(ac->req, NULL, NULL,
 146                                                         LDB_ERR_UNWILLING_TO_PERFORM);
 147                         }
 148                         
 149                         el->num_values = 0;
 150                         
 151                         el->values = talloc_array(el, struct ldb_val, (end - start) + 1);
 152                         if (!el->values) {
 153                                 ldb_oom(ldb);
 154                                 return ldb_module_done(ac->req, NULL, NULL,
 155                                                         LDB_ERR_OPERATIONS_ERROR);
 156                         }
 157                         for (j=start; j <= end; j++) {
 158                                 el->values[el->num_values] = orig_values[j];
 159                                 el->num_values++;
 160                         }
 161                 }
 162                 el->name = talloc_asprintf(el, "%s;range=%u-%s", el->name, start, end_str);
 163                 if (!el->name) {
 164                         ldb_oom(ldb);
 165                         return ldb_module_done(ac->req, NULL, NULL,
 166                                                 LDB_ERR_OPERATIONS_ERROR);
 167                 }
 168         }
 169 
 170         return ldb_module_send_entry(ac->req, ares->message, ares->controls);
 171 }
 172 
 173 /* search */
 174 static int rr_search(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 175 {
 176         struct ldb_context *ldb;
 177         int i;
 178         unsigned int start, end;
 179         const char **new_attrs = NULL;
 180         bool found_rr = false;
 181         struct ldb_request *down_req;
 182         struct rr_context *ac;
 183         int ret;
 184 
 185         ldb = ldb_module_get_ctx(module);
 186 
 187         /* Strip the range request from the attribute */
 188         for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
 189                 char *p;
 190                 new_attrs = talloc_realloc(req, new_attrs, const char *, i+2);
 191                 new_attrs[i] = req->op.search.attrs[i];
 192                 new_attrs[i+1] = NULL;
 193                 p = strchr(new_attrs[i], ';');
 194                 if (!p) {
 195                         continue;
 196                 }
 197                 if (strncasecmp(p, ";range=", strlen(";range=")) != 0) {
 198                         continue;
 199                 }
 200                 end = (unsigned int)-1;
 201                 if (sscanf(p, ";range=%u-*", &start) != 1) {
 202                         if (sscanf(p, ";range=%u-%u", &start, &end) != 2) {
 203                                 ldb_asprintf_errstring(ldb,
 204                                         "range request error: "
 205                                         "range request malformed");
 206                                 return LDB_ERR_UNWILLING_TO_PERFORM;
 207                         }
 208                 }
 209                 if (start > end) {
 210                         ldb_asprintf_errstring(ldb, "range request error: start must not be greater than end");
 211                         return LDB_ERR_UNWILLING_TO_PERFORM;
 212                 }
 213 
 214                 found_rr = true;
 215                 new_attrs[i] = talloc_strndup(new_attrs, new_attrs[i],
 216                                               (size_t)(p - new_attrs[i]));
 217 
 218                 if (!new_attrs[i]) {
 219                         ldb_oom(ldb);
 220                         return LDB_ERR_OPERATIONS_ERROR;
 221                 }
 222         }
 223 
 224         if (found_rr) {
 225                 ac = rr_init_context(module, req);
 226                 if (!ac) {
 227                         return LDB_ERR_OPERATIONS_ERROR;
 228                 }
 229 
 230                 ret = ldb_build_search_req_ex(&down_req, ldb, ac,
 231                                               req->op.search.base,
 232                                               req->op.search.scope,
 233                                               req->op.search.tree,
 234                                               new_attrs,
 235                                               req->controls,
 236                                               ac, rr_search_callback,
 237                                               req);
 238                 if (ret != LDB_SUCCESS) {
 239                         return ret;
 240                 }
 241                 return ldb_next_request(module, down_req);
 242         }
 243 
 244         /* No change, just run the original request as if we were never here */
 245         talloc_free(new_attrs);
 246         return ldb_next_request(module, req);
 247 }
 248 
 249 const struct ldb_module_ops ldb_ranged_results_module_ops = {
 250         .name              = "ranged_results",
 251         .search            = rr_search,
 252 };

/* [<][>][^][v][top][bottom][index][help] */