4 Copyright (C) Andrew Bartlett 2007
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.
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.
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/>.
23 * Component: ldb ranged results module
25 * Description: munge AD-style 'ranged results' requests into
26 * requests for all values in an attribute, then return the range to
29 * Author: Andrew Bartlett
32 #include "ldb_includes.h"
35 struct ldb_request *orig_req;
36 struct ldb_request *down_req;
39 static int rr_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
41 struct rr_context *rr_context = talloc_get_type(context, struct rr_context);
42 struct ldb_request *orig_req = rr_context->orig_req;
45 if (ares->type != LDB_REPLY_ENTRY) {
46 return rr_context->orig_req->callback(ldb, rr_context->orig_req->context, ares);
49 /* Find those that are range requests from the attribute list */
50 for (i = 0; orig_req->op.search.attrs[i]; i++) {
53 unsigned int start, end, orig_num_values;
54 struct ldb_message_element *el;
55 struct ldb_val *orig_values;
56 p = strchr(orig_req->op.search.attrs[i], ';');
60 if (strncasecmp(p, ";range=", strlen(";range=")) != 0) {
63 if (sscanf(p, ";range=%u-*", &start) == 1) {
64 end = (unsigned int)-1;
65 } else if (sscanf(p, ";range=%u-%u", &start, &end) != 2) {
68 new_attr = talloc_strndup(orig_req,
69 orig_req->op.search.attrs[i],
70 (unsigned int)(p-orig_req->op.search.attrs[i]));
74 return LDB_ERR_OPERATIONS_ERROR;
76 el = ldb_msg_find_element(ares->message, new_attr);
77 talloc_free(new_attr);
82 ldb_asprintf_errstring(ldb, "range request error: start must not be greater than end");
83 return LDB_ERR_UNWILLING_TO_PERFORM;
85 if (end >= el->num_values) {
86 /* Need to leave the requested attribute in
87 * there (so add an empty one to match) */
90 ret = ldb_msg_add_empty(ares->message, orig_req->op.search.attrs[i],
92 if (ret != LDB_SUCCESS) {
96 end_str = talloc_asprintf(el, "%u", end);
98 orig_values = el->values;
99 orig_num_values = el->num_values;
101 if ((start + end < start) || (start + end < end)) {
102 ldb_asprintf_errstring(ldb, "range request error: start or end would overflow!");
103 return LDB_ERR_UNWILLING_TO_PERFORM;
106 el->values = talloc_array(el, struct ldb_val, end - start);
111 return LDB_ERR_OPERATIONS_ERROR;
113 for (j=start; j < end; j++) {
114 el->values[el->num_values] = orig_values[j];
117 el->name = talloc_asprintf(el, "%s;Range=%u-%s", el->name, start, end_str);
120 return LDB_ERR_OPERATIONS_ERROR;
124 return rr_context->orig_req->callback(ldb, rr_context->orig_req->context, ares);
129 static int rr_search(struct ldb_module *module, struct ldb_request *req)
132 unsigned int start, end;
133 const char **new_attrs = NULL;
134 struct rr_context *context;
135 bool found_rr = false;
137 /* Strip the range request from the attribute */
138 for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
140 new_attrs = talloc_realloc(req, new_attrs, const char *, i+2);
141 new_attrs[i] = req->op.search.attrs[i];
142 new_attrs[i+1] = NULL;
143 p = strchr(req->op.search.attrs[i], ';');
147 if (strncasecmp(p, ";range=", strlen(";range=")) != 0) {
150 if (sscanf(p, ";range=%u-*", &start) == 1) {
151 } else if (sscanf(p, ";range=%u-%u", &start, &end) != 2) {
152 ldb_asprintf_errstring(module->ldb, "range request error: range requst malformed");
153 return LDB_ERR_UNWILLING_TO_PERFORM;
156 ldb_asprintf_errstring(module->ldb, "range request error: start must not be greater than end");
157 return LDB_ERR_UNWILLING_TO_PERFORM;
161 new_attrs[i] = talloc_strndup(new_attrs,
162 req->op.search.attrs[i],
163 (unsigned int)(p-req->op.search.attrs[i]));
166 ldb_oom(module->ldb);
167 return LDB_ERR_OPERATIONS_ERROR;
173 context = talloc(req, struct rr_context);
174 context->orig_req = req;
175 context->down_req = talloc(context, struct ldb_request);
176 *context->down_req = *req;
178 context->down_req->op.search.attrs = new_attrs;
180 context->down_req->callback = rr_search_callback;
181 context->down_req->context = context;
183 ret = ldb_next_request(module, context->down_req);
185 /* We don't need to implement our own 'wait' function, so pass the handle along */
186 if (ret == LDB_SUCCESS) {
187 req->handle = context->down_req->handle;
192 /* No change, just run the original request as if we were never here */
193 return ldb_next_request(module, req);
196 static const struct ldb_module_ops rr_ops = {
197 .name = "ranged_results",
201 int ldb_ranged_results_init(void)
203 return ldb_register_module(&rr_ops);