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
, orig_num_values
;
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
;
149 orig_num_values
= el
->num_values
;
151 if ((start
+ end
< start
) || (start
+ end
< end
)) {
152 ldb_asprintf_errstring(ldb
,
153 "range request error: start or end would overflow!");
154 return ldb_module_done(ac
->req
, NULL
, NULL
,
155 LDB_ERR_UNWILLING_TO_PERFORM
);
160 el
->values
= talloc_array(ares
->message
->elements
,
165 return ldb_module_done(ac
->req
, NULL
, NULL
,
166 LDB_ERR_OPERATIONS_ERROR
);
168 for (j
=start
; j
<= end
; j
++) {
169 el
->values
[el
->num_values
] = orig_values
[j
];
173 el
->name
= talloc_asprintf(ares
->message
->elements
,
174 "%s;range=%u-%s", el
->name
, start
,
178 return ldb_module_done(ac
->req
, NULL
, NULL
,
179 LDB_ERR_OPERATIONS_ERROR
);
183 talloc_free(temp_ctx
);
185 return ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
189 static int rr_search(struct ldb_module
*module
, struct ldb_request
*req
)
191 struct ldb_context
*ldb
;
193 unsigned int start
, end
;
194 const char **new_attrs
= NULL
;
195 bool found_rr
= false;
196 struct ldb_request
*down_req
;
197 struct rr_context
*ac
;
200 ldb
= ldb_module_get_ctx(module
);
202 /* Strip the range request from the attribute */
203 for (i
= 0; req
->op
.search
.attrs
&& req
->op
.search
.attrs
[i
]; i
++) {
205 new_attrs
= talloc_realloc(req
, new_attrs
, const char *, i
+2);
206 new_attrs
[i
] = req
->op
.search
.attrs
[i
];
207 new_attrs
[i
+1] = NULL
;
208 p
= strchr(new_attrs
[i
], ';');
212 if (strncasecmp(p
, ";range=", strlen(";range=")) != 0) {
215 end
= (unsigned int)-1;
216 if (sscanf(p
, ";range=%u-*", &start
) != 1) {
217 if (sscanf(p
, ";range=%u-%u", &start
, &end
) != 2) {
218 ldb_asprintf_errstring(ldb
,
219 "range request error: "
220 "range request malformed");
221 return LDB_ERR_UNWILLING_TO_PERFORM
;
225 ldb_asprintf_errstring(ldb
, "range request error: start must not be greater than end");
226 return LDB_ERR_UNWILLING_TO_PERFORM
;
230 new_attrs
[i
] = talloc_strndup(new_attrs
, new_attrs
[i
],
231 (size_t)(p
- new_attrs
[i
]));
239 ac
= rr_init_context(module
, req
);
241 return ldb_operr(ldb
);
244 ret
= ldb_build_search_req_ex(&down_req
, ldb
, ac
,
246 req
->op
.search
.scope
,
250 ac
, rr_search_callback
,
252 LDB_REQ_SET_LOCATION(down_req
);
253 if (ret
!= LDB_SUCCESS
) {
256 return ldb_next_request(module
, down_req
);
259 /* No change, just run the original request as if we were never here */
260 talloc_free(new_attrs
);
261 return ldb_next_request(module
, req
);
264 static const struct ldb_module_ops ldb_ranged_results_module_ops
= {
265 .name
= "ranged_results",
269 int ldb_ranged_results_module_init(const char *version
)
271 LDB_MODULE_CHECK_VERSION(version
);
272 return ldb_register_module(&ldb_ranged_results_module_ops
);