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_module *module;
36 struct ldb_request *req;
39 static struct rr_context *rr_init_context(struct ldb_module *module,
40 struct ldb_request *req)
42 struct rr_context *ac;
44 ac = talloc_zero(req, struct rr_context);
46 ldb_set_errstring(module->ldb, "Out of Memory");
56 static int rr_search_callback(struct ldb_request *req, struct ldb_reply *ares)
58 struct rr_context *ac;
61 ac = talloc_get_type(req->context, struct rr_context);
64 return ldb_module_done(ac->req, NULL, NULL,
65 LDB_ERR_OPERATIONS_ERROR);
67 if (ares->error != LDB_SUCCESS) {
68 return ldb_module_done(ac->req, ares->controls,
69 ares->response, ares->error);
72 if (ares->type == LDB_REPLY_REFERRAL) {
73 return ldb_module_send_referral(ac->req, ares->referral);
76 if (ares->type == LDB_REPLY_DONE) {
77 return ldb_module_done(ac->req, ares->controls,
78 ares->response, ares->error);
83 /* Find those that are range requests from the attribute list */
84 for (i = 0; ac->req->op.search.attrs[i]; i++) {
87 unsigned int start, end, orig_num_values;
88 struct ldb_message_element *el;
89 struct ldb_val *orig_values;
90 p = strchr(ac->req->op.search.attrs[i], ';');
94 if (strncasecmp(p, ";range=", strlen(";range=")) != 0) {
97 if (sscanf(p, ";range=%u-%u", &start, &end) != 2) {
98 if (sscanf(p, ";range=%u-*", &start) == 1) {
99 end = (unsigned int)-1;
104 new_attr = talloc_strndup(ac->req,
105 ac->req->op.search.attrs[i],
106 (size_t)(p - ac->req->op.search.attrs[i]));
109 ldb_oom(ac->module->ldb);
110 return ldb_module_done(ac->req, NULL, NULL,
111 LDB_ERR_OPERATIONS_ERROR);
113 el = ldb_msg_find_element(ares->message, new_attr);
114 talloc_free(new_attr);
118 if (end >= (el->num_values - 1)) {
119 /* Need to leave the requested attribute in
120 * there (so add an empty one to match) */
122 end = el->num_values - 1;
124 end_str = talloc_asprintf(el, "%u", end);
126 ldb_oom(ac->module->ldb);
127 return ldb_module_done(ac->req, NULL, NULL,
128 LDB_ERR_OPERATIONS_ERROR);
131 /* If start is greater then where we are find the end to be */
136 orig_values = el->values;
137 orig_num_values = el->num_values;
139 if ((start + end < start) || (start + end < end)) {
140 ldb_asprintf_errstring(ac->module->ldb,
141 "range request error: start or end would overflow!");
142 return ldb_module_done(ac->req, NULL, NULL,
143 LDB_ERR_UNWILLING_TO_PERFORM);
148 el->values = talloc_array(el, struct ldb_val, (end - start) + 1);
150 ldb_oom(ac->module->ldb);
151 return ldb_module_done(ac->req, NULL, NULL,
152 LDB_ERR_OPERATIONS_ERROR);
154 for (j=start; j <= end; j++) {
155 el->values[el->num_values] = orig_values[j];
159 el->name = talloc_asprintf(el, "%s;range=%u-%s", el->name, start, end_str);
161 ldb_oom(ac->module->ldb);
162 return ldb_module_done(ac->req, NULL, NULL,
163 LDB_ERR_OPERATIONS_ERROR);
167 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
171 static int rr_search(struct ldb_module *module, struct ldb_request *req)
174 unsigned int start, end;
175 const char **new_attrs = NULL;
176 bool found_rr = false;
177 struct ldb_request *down_req;
178 struct rr_context *ac;
181 /* Strip the range request from the attribute */
182 for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
184 new_attrs = talloc_realloc(req, new_attrs, const char *, i+2);
185 new_attrs[i] = req->op.search.attrs[i];
186 new_attrs[i+1] = NULL;
187 p = strchr(new_attrs[i], ';');
191 if (strncasecmp(p, ";range=", strlen(";range=")) != 0) {
194 end = (unsigned int)-1;
195 if (sscanf(p, ";range=%u-*", &start) != 1) {
196 if (sscanf(p, ";range=%u-%u", &start, &end) != 2) {
197 ldb_asprintf_errstring(module->ldb,
198 "range request error: "
199 "range request malformed");
200 return LDB_ERR_UNWILLING_TO_PERFORM;
204 ldb_asprintf_errstring(module->ldb, "range request error: start must not be greater than end");
205 return LDB_ERR_UNWILLING_TO_PERFORM;
209 new_attrs[i] = talloc_strndup(new_attrs, new_attrs[i],
210 (size_t)(p - new_attrs[i]));
213 ldb_oom(module->ldb);
214 return LDB_ERR_OPERATIONS_ERROR;
219 ac = rr_init_context(module, req);
221 return LDB_ERR_OPERATIONS_ERROR;
224 ret = ldb_build_search_req_ex(&down_req, module->ldb, ac,
226 req->op.search.scope,
230 ac, rr_search_callback,
232 if (ret != LDB_SUCCESS) {
235 return ldb_next_request(module, down_req);
238 /* No change, just run the original request as if we were never here */
239 talloc_free(new_attrs);
240 return ldb_next_request(module, req);
243 const struct ldb_module_ops ldb_ranged_results_module_ops = {
244 .name = "ranged_results",