Fix the mess with ldb includes.
[Samba/ekacnet.git] / source4 / dsdb / samdb / ldb_modules / ranged_results.c
blob8f36baa7d6382e654a75c0c26c26748c6c6dc94b
1 /*
2 ldb database library
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/>.
21 * Name: ldb
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
27 * the client.
29 * Author: Andrew Bartlett
32 #include "ldb_module.h"
34 struct rr_context {
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);
45 if (ac == NULL) {
46 ldb_set_errstring(ldb_module_get_ctx(module), "Out of Memory");
47 return NULL;
50 ac->module = module;
51 ac->req = req;
53 return ac;
56 static int rr_search_callback(struct ldb_request *req, struct ldb_reply *ares)
58 struct ldb_context *ldb;
59 struct rr_context *ac;
60 int i, j;
62 ac = talloc_get_type(req->context, struct rr_context);
63 ldb = ldb_module_get_ctx(ac->module);
65 if (!ares) {
66 return ldb_module_done(ac->req, NULL, NULL,
67 LDB_ERR_OPERATIONS_ERROR);
69 if (ares->error != LDB_SUCCESS) {
70 return ldb_module_done(ac->req, ares->controls,
71 ares->response, ares->error);
74 if (ares->type == LDB_REPLY_REFERRAL) {
75 return ldb_module_send_referral(ac->req, ares->referral);
78 if (ares->type == LDB_REPLY_DONE) {
79 return ldb_module_done(ac->req, ares->controls,
80 ares->response, ares->error);
83 /* LDB_REPLY_ENTRY */
85 /* Find those that are range requests from the attribute list */
86 for (i = 0; ac->req->op.search.attrs[i]; i++) {
87 char *p, *new_attr;
88 const char *end_str;
89 unsigned int start, end, orig_num_values;
90 struct ldb_message_element *el;
91 struct ldb_val *orig_values;
92 p = strchr(ac->req->op.search.attrs[i], ';');
93 if (!p) {
94 continue;
96 if (strncasecmp(p, ";range=", strlen(";range=")) != 0) {
97 continue;
99 if (sscanf(p, ";range=%u-%u", &start, &end) != 2) {
100 if (sscanf(p, ";range=%u-*", &start) == 1) {
101 end = (unsigned int)-1;
102 } else {
103 continue;
106 new_attr = talloc_strndup(ac->req,
107 ac->req->op.search.attrs[i],
108 (size_t)(p - ac->req->op.search.attrs[i]));
110 if (!new_attr) {
111 ldb_oom(ldb);
112 return ldb_module_done(ac->req, NULL, NULL,
113 LDB_ERR_OPERATIONS_ERROR);
115 el = ldb_msg_find_element(ares->message, new_attr);
116 talloc_free(new_attr);
117 if (!el) {
118 continue;
120 if (end >= (el->num_values - 1)) {
121 /* Need to leave the requested attribute in
122 * there (so add an empty one to match) */
123 end_str = "*";
124 end = el->num_values - 1;
125 } else {
126 end_str = talloc_asprintf(el, "%u", end);
127 if (!end_str) {
128 ldb_oom(ldb);
129 return ldb_module_done(ac->req, NULL, NULL,
130 LDB_ERR_OPERATIONS_ERROR);
133 /* If start is greater then where we are find the end to be */
134 if (start > end) {
135 el->num_values = 0;
136 el->values = NULL;
137 } else {
138 orig_values = el->values;
139 orig_num_values = el->num_values;
141 if ((start + end < start) || (start + end < end)) {
142 ldb_asprintf_errstring(ldb,
143 "range request error: start or end would overflow!");
144 return ldb_module_done(ac->req, NULL, NULL,
145 LDB_ERR_UNWILLING_TO_PERFORM);
148 el->num_values = 0;
150 el->values = talloc_array(el, struct ldb_val, (end - start) + 1);
151 if (!el->values) {
152 ldb_oom(ldb);
153 return ldb_module_done(ac->req, NULL, NULL,
154 LDB_ERR_OPERATIONS_ERROR);
156 for (j=start; j <= end; j++) {
157 el->values[el->num_values] = orig_values[j];
158 el->num_values++;
161 el->name = talloc_asprintf(el, "%s;range=%u-%s", el->name, start, end_str);
162 if (!el->name) {
163 ldb_oom(ldb);
164 return ldb_module_done(ac->req, NULL, NULL,
165 LDB_ERR_OPERATIONS_ERROR);
169 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
172 /* search */
173 static int rr_search(struct ldb_module *module, struct ldb_request *req)
175 struct ldb_context *ldb;
176 int i;
177 unsigned int start, end;
178 const char **new_attrs = NULL;
179 bool found_rr = false;
180 struct ldb_request *down_req;
181 struct rr_context *ac;
182 int ret;
184 ldb = ldb_module_get_ctx(module);
186 /* Strip the range request from the attribute */
187 for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
188 char *p;
189 new_attrs = talloc_realloc(req, new_attrs, const char *, i+2);
190 new_attrs[i] = req->op.search.attrs[i];
191 new_attrs[i+1] = NULL;
192 p = strchr(new_attrs[i], ';');
193 if (!p) {
194 continue;
196 if (strncasecmp(p, ";range=", strlen(";range=")) != 0) {
197 continue;
199 end = (unsigned int)-1;
200 if (sscanf(p, ";range=%u-*", &start) != 1) {
201 if (sscanf(p, ";range=%u-%u", &start, &end) != 2) {
202 ldb_asprintf_errstring(ldb,
203 "range request error: "
204 "range request malformed");
205 return LDB_ERR_UNWILLING_TO_PERFORM;
208 if (start > end) {
209 ldb_asprintf_errstring(ldb, "range request error: start must not be greater than end");
210 return LDB_ERR_UNWILLING_TO_PERFORM;
213 found_rr = true;
214 new_attrs[i] = talloc_strndup(new_attrs, new_attrs[i],
215 (size_t)(p - new_attrs[i]));
217 if (!new_attrs[i]) {
218 ldb_oom(ldb);
219 return LDB_ERR_OPERATIONS_ERROR;
223 if (found_rr) {
224 ac = rr_init_context(module, req);
225 if (!ac) {
226 return LDB_ERR_OPERATIONS_ERROR;
229 ret = ldb_build_search_req_ex(&down_req, ldb, ac,
230 req->op.search.base,
231 req->op.search.scope,
232 req->op.search.tree,
233 new_attrs,
234 req->controls,
235 ac, rr_search_callback,
236 req);
237 if (ret != LDB_SUCCESS) {
238 return ret;
240 return ldb_next_request(module, down_req);
243 /* No change, just run the original request as if we were never here */
244 talloc_free(new_attrs);
245 return ldb_next_request(module, req);
248 const struct ldb_module_ops ldb_ranged_results_module_ops = {
249 .name = "ranged_results",
250 .search = rr_search,