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
33 #include "ldb_module.h"
36 struct ldb_module
*module
;
37 struct ldb_request
*req
;
40 static struct rr_context
*rr_init_context(struct ldb_module
*module
,
41 struct ldb_request
*req
)
43 struct rr_context
*ac
;
45 ac
= talloc_zero(req
, struct rr_context
);
47 ldb_set_errstring(ldb_module_get_ctx(module
), "Out of Memory");
57 static int rr_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
59 struct ldb_context
*ldb
;
60 struct rr_context
*ac
;
64 ac
= talloc_get_type(req
->context
, struct rr_context
);
65 ldb
= ldb_module_get_ctx(ac
->module
);
68 return ldb_module_done(ac
->req
, NULL
, NULL
,
69 LDB_ERR_OPERATIONS_ERROR
);
71 if (ares
->error
!= LDB_SUCCESS
) {
72 return ldb_module_done(ac
->req
, ares
->controls
,
73 ares
->response
, ares
->error
);
76 if (ares
->type
== LDB_REPLY_REFERRAL
) {
77 return ldb_module_send_referral(ac
->req
, ares
->referral
);
80 if (ares
->type
== LDB_REPLY_DONE
) {
81 return ldb_module_done(ac
->req
, ares
->controls
,
82 ares
->response
, ares
->error
);
87 temp_ctx
= talloc_new(ac
->req
);
89 ldb_module_oom(ac
->module
);
90 return ldb_module_done(ac
->req
, NULL
, NULL
,
91 LDB_ERR_OPERATIONS_ERROR
);
94 /* Find those that are range requests from the attribute list */
95 for (i
= 0; ac
->req
->op
.search
.attrs
[i
]; i
++) {
98 unsigned int start
, end
;
99 struct ldb_message_element
*el
;
100 struct ldb_val
*orig_values
;
102 p
= strchr(ac
->req
->op
.search
.attrs
[i
], ';');
106 if (strncasecmp(p
, ";range=", strlen(";range=")) != 0) {
109 if (sscanf(p
, ";range=%u-%u", &start
, &end
) != 2) {
110 if (sscanf(p
, ";range=%u-*", &start
) == 1) {
111 end
= (unsigned int)-1;
116 new_attr
= talloc_strndup(temp_ctx
,
117 ac
->req
->op
.search
.attrs
[i
],
118 (size_t)(p
- ac
->req
->op
.search
.attrs
[i
]));
122 return ldb_module_done(ac
->req
, NULL
, NULL
,
123 LDB_ERR_OPERATIONS_ERROR
);
125 el
= ldb_msg_find_element(ares
->message
, new_attr
);
126 talloc_free(new_attr
);
130 if (end
>= (el
->num_values
- 1)) {
131 /* Need to leave the requested attribute in
132 * there (so add an empty one to match) */
134 end
= el
->num_values
- 1;
136 end_str
= talloc_asprintf(temp_ctx
, "%u", end
);
139 return ldb_module_done(ac
->req
, NULL
, NULL
,
140 LDB_ERR_OPERATIONS_ERROR
);
143 /* If start is greater then where we are find the end to be */
148 orig_values
= el
->values
;
150 if ((start
+ end
< start
) || (start
+ end
< end
)) {
151 ldb_asprintf_errstring(ldb
,
152 "range request error: start or end would overflow!");
153 return ldb_module_done(ac
->req
, NULL
, NULL
,
154 LDB_ERR_UNWILLING_TO_PERFORM
);
159 el
->values
= talloc_array(ares
->message
->elements
,
164 return ldb_module_done(ac
->req
, NULL
, NULL
,
165 LDB_ERR_OPERATIONS_ERROR
);
167 for (j
=start
; j
<= end
; j
++) {
168 el
->values
[el
->num_values
] = orig_values
[j
];
172 el
->name
= talloc_asprintf(ares
->message
->elements
,
173 "%s;range=%u-%s", el
->name
, start
,
177 return ldb_module_done(ac
->req
, NULL
, NULL
,
178 LDB_ERR_OPERATIONS_ERROR
);
182 talloc_free(temp_ctx
);
184 return ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
188 static int rr_search(struct ldb_module
*module
, struct ldb_request
*req
)
190 struct ldb_context
*ldb
;
192 unsigned int start
, end
;
193 const char **new_attrs
= NULL
;
194 bool found_rr
= false;
195 struct ldb_request
*down_req
;
196 struct rr_context
*ac
;
199 ldb
= ldb_module_get_ctx(module
);
201 /* Strip the range request from the attribute */
202 for (i
= 0; req
->op
.search
.attrs
&& req
->op
.search
.attrs
[i
]; i
++) {
204 new_attrs
= talloc_realloc(req
, new_attrs
, const char *, i
+2);
205 new_attrs
[i
] = req
->op
.search
.attrs
[i
];
206 new_attrs
[i
+1] = NULL
;
207 p
= strchr(new_attrs
[i
], ';');
211 if (strncasecmp(p
, ";range=", strlen(";range=")) != 0) {
214 end
= (unsigned int)-1;
215 if (sscanf(p
, ";range=%u-*", &start
) != 1) {
216 if (sscanf(p
, ";range=%u-%u", &start
, &end
) != 2) {
217 ldb_asprintf_errstring(ldb
,
218 "range request error: "
219 "range request malformed");
220 return LDB_ERR_UNWILLING_TO_PERFORM
;
224 ldb_asprintf_errstring(ldb
, "range request error: start must not be greater than end");
225 return LDB_ERR_UNWILLING_TO_PERFORM
;
229 new_attrs
[i
] = talloc_strndup(new_attrs
, new_attrs
[i
],
230 (size_t)(p
- new_attrs
[i
]));
238 ac
= rr_init_context(module
, req
);
240 return ldb_operr(ldb
);
243 ret
= ldb_build_search_req_ex(&down_req
, ldb
, ac
,
245 req
->op
.search
.scope
,
249 ac
, rr_search_callback
,
251 LDB_REQ_SET_LOCATION(down_req
);
252 if (ret
!= LDB_SUCCESS
) {
255 return ldb_next_request(module
, down_req
);
258 /* No change, just run the original request as if we were never here */
259 talloc_free(new_attrs
);
260 return ldb_next_request(module
, req
);
263 static const struct ldb_module_ops ldb_ranged_results_module_ops
= {
264 .name
= "ranged_results",
268 int ldb_ranged_results_module_init(const char *version
)
270 LDB_MODULE_CHECK_VERSION(version
);
271 return ldb_register_module(&ldb_ranged_results_module_ops
);