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-%u", &start, &end) == 2) {
64 } else if (sscanf(p, ";range=%u-*", &start) == 1) {
65 end = (unsigned int)-1;
69 new_attr = talloc_strndup(orig_req,
70 orig_req->op.search.attrs[i],
71 (unsigned int)(p-orig_req->op.search.attrs[i]));
75 return LDB_ERR_OPERATIONS_ERROR;
77 el = ldb_msg_find_element(ares->message, new_attr);
78 talloc_free(new_attr);
83 ldb_asprintf_errstring(ldb, "range request error: start must not be greater than end");
84 return LDB_ERR_UNWILLING_TO_PERFORM;
86 if (end >= (el->num_values - 1)) {
87 /* Need to leave the requested attribute in
88 * there (so add an empty one to match) */
90 end = el->num_values - 1;
92 end_str = talloc_asprintf(el, "%u", end);
95 return LDB_ERR_OPERATIONS_ERROR;
98 /* If start is greater then where we noe find the end to be */
103 orig_values = el->values;
104 orig_num_values = el->num_values;
106 if ((start + end < start) || (start + end < end)) {
107 ldb_asprintf_errstring(ldb, "range request error: start or end would overflow!");
108 return LDB_ERR_UNWILLING_TO_PERFORM;
113 el->values = talloc_array(el, struct ldb_val, (end - start) + 1);
116 return LDB_ERR_OPERATIONS_ERROR;
118 for (j=start; j <= end; j++) {
119 el->values[el->num_values] = orig_values[j];
123 el->name = talloc_asprintf(el, "%s;range=%u-%s", el->name, start, end_str);
126 return LDB_ERR_OPERATIONS_ERROR;
130 return rr_context->orig_req->callback(ldb, rr_context->orig_req->context, ares);
135 static int rr_search(struct ldb_module *module, struct ldb_request *req)
138 unsigned int start, end;
139 const char **new_attrs = NULL;
140 struct rr_context *context;
141 bool found_rr = false;
143 /* Strip the range request from the attribute */
144 for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
146 new_attrs = talloc_realloc(req, new_attrs, const char *, i+2);
147 new_attrs[i] = req->op.search.attrs[i];
148 new_attrs[i+1] = NULL;
149 p = strchr(req->op.search.attrs[i], ';');
153 if (strncasecmp(p, ";range=", strlen(";range=")) != 0) {
156 if (sscanf(p, ";range=%u-%u", &start, &end) == 2) {
157 } else if (sscanf(p, ";range=%u-*", &start) == 1) {
158 end = (unsigned int)-1;
160 ldb_asprintf_errstring(module->ldb, "range request error: range requst malformed");
161 return LDB_ERR_UNWILLING_TO_PERFORM;
164 ldb_asprintf_errstring(module->ldb, "range request error: start must not be greater than end");
165 return LDB_ERR_UNWILLING_TO_PERFORM;
169 new_attrs[i] = talloc_strndup(new_attrs,
170 req->op.search.attrs[i],
171 (unsigned int)(p-req->op.search.attrs[i]));
174 ldb_oom(module->ldb);
175 return LDB_ERR_OPERATIONS_ERROR;
181 context = talloc(req, struct rr_context);
182 context->orig_req = req;
183 context->down_req = talloc(context, struct ldb_request);
184 *context->down_req = *req;
186 context->down_req->op.search.attrs = new_attrs;
188 context->down_req->callback = rr_search_callback;
189 context->down_req->context = context;
191 ret = ldb_next_request(module, context->down_req);
193 /* We don't need to implement our own 'wait' function, so pass the handle along */
194 if (ret == LDB_SUCCESS) {
195 req->handle = context->down_req->handle;
200 /* No change, just run the original request as if we were never here */
201 return ldb_next_request(module, req);
204 static const struct ldb_module_ops rr_ops = {
205 .name = "ranged_results",
209 int ldb_ranged_results_init(void)
211 return ldb_register_module(&rr_ops);