4 Copyright (C) Simo Sorce 2005-2008
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb server side sort control module
29 * Description: this module sorts the results of a search
34 #include "ldb_module.h"
37 struct ldb_context *ldb;
38 const struct ldb_attrib_handler *h;
39 const char *attribute;
45 struct ldb_module *module;
51 struct ldb_request *req;
52 struct ldb_message **msgs;
57 const struct ldb_schema_attribute *a;
61 static int build_response(void *mem_ctx, struct ldb_control ***ctrls, int result, const char *desc)
63 struct ldb_control **controls;
64 struct ldb_sort_resp_control *resp;
69 for (i = 0; controls[i]; i++);
70 controls = talloc_realloc(mem_ctx, controls, struct ldb_control *, i + 2);
73 controls = talloc_array(mem_ctx, struct ldb_control *, 2);
76 return LDB_ERR_OPERATIONS_ERROR;
81 controls[i] = talloc(controls, struct ldb_control);
83 return LDB_ERR_OPERATIONS_ERROR;
85 controls[i]->oid = LDB_CONTROL_SORT_RESP_OID;
86 controls[i]->critical = 0;
88 resp = talloc(controls[i], struct ldb_sort_resp_control);
90 return LDB_ERR_OPERATIONS_ERROR;
92 resp->result = result;
93 resp->attr_desc = talloc_strdup(resp, desc);
95 if (! resp->attr_desc )
96 return LDB_ERR_OPERATIONS_ERROR;
98 controls[i]->data = resp;
103 static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, void *opaque)
105 struct sort_context *ac = talloc_get_type(opaque, struct sort_context);
106 struct ldb_message_element *el1, *el2;
107 struct ldb_context *ldb;
109 ldb = ldb_module_get_ctx(ac->module);
111 if (ac->sort_result != 0) {
112 /* an error occurred previously,
113 * let's exit the sorting by returning always 0 */
117 el1 = ldb_msg_find_element(*msg1, ac->attributeName);
118 el2 = ldb_msg_find_element(*msg2, ac->attributeName);
131 return ac->a->syntax->comparison_fn(ldb, ac, &el2->values[0], &el1->values[0]);
133 return ac->a->syntax->comparison_fn(ldb, ac, &el1->values[0], &el2->values[0]);
136 static int server_sort_results(struct sort_context *ac)
138 struct ldb_context *ldb;
139 struct ldb_reply *ares;
142 ldb = ldb_module_get_ctx(ac->module);
144 ac->a = ldb_schema_attribute_by_name(ldb, ac->attributeName);
147 ldb_qsort(ac->msgs, ac->num_msgs,
148 sizeof(struct ldb_message *),
149 ac, (ldb_qsort_cmp_fn_t)sort_compare);
151 if (ac->sort_result != LDB_SUCCESS) {
152 return ac->sort_result;
155 for (i = 0; i < ac->num_msgs; i++) {
156 ares = talloc_zero(ac, struct ldb_reply);
158 return LDB_ERR_OPERATIONS_ERROR;
161 ares->type = LDB_REPLY_ENTRY;
162 ares->message = talloc_move(ares, &ac->msgs[i]);
164 ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
165 if (ret != LDB_SUCCESS) {
170 for (i = 0; i < ac->num_refs; i++) {
171 ares = talloc_zero(ac, struct ldb_reply);
173 return LDB_ERR_OPERATIONS_ERROR;
176 ares->type = LDB_REPLY_REFERRAL;
177 ares->referral = talloc_move(ares, &ac->referrals[i]);
179 ret = ldb_module_send_referral(ac->req, ares->referral);
180 if (ret != LDB_SUCCESS) {
188 static int server_sort_search_callback(struct ldb_request *req, struct ldb_reply *ares)
190 struct sort_context *ac;
191 struct ldb_context *ldb;
194 ac = talloc_get_type(req->context, struct sort_context);
195 ldb = ldb_module_get_ctx(ac->module);
198 return ldb_module_done(ac->req, NULL, NULL,
199 LDB_ERR_OPERATIONS_ERROR);
201 if (ares->error != LDB_SUCCESS) {
202 return ldb_module_done(ac->req, ares->controls,
203 ares->response, ares->error);
206 switch (ares->type) {
207 case LDB_REPLY_ENTRY:
208 ac->msgs = talloc_realloc(ac, ac->msgs, struct ldb_message *, ac->num_msgs + 2);
212 return ldb_module_done(ac->req, NULL, NULL,
213 LDB_ERR_OPERATIONS_ERROR);
216 ac->msgs[ac->num_msgs] = talloc_steal(ac->msgs, ares->message);
218 ac->msgs[ac->num_msgs] = NULL;
222 case LDB_REPLY_REFERRAL:
223 ac->referrals = talloc_realloc(ac, ac->referrals, char *, ac->num_refs + 2);
224 if (! ac->referrals) {
227 return ldb_module_done(ac->req, NULL, NULL,
228 LDB_ERR_OPERATIONS_ERROR);
231 ac->referrals[ac->num_refs] = talloc_steal(ac->referrals, ares->referral);
233 ac->referrals[ac->num_refs] = NULL;
239 ret = server_sort_results(ac);
240 return ldb_module_done(ac->req, ares->controls,
241 ares->response, ret);
248 static int server_sort_search(struct ldb_module *module, struct ldb_request *req)
250 struct ldb_control *control;
251 struct ldb_server_sort_control **sort_ctrls;
252 struct ldb_control **saved_controls;
253 struct ldb_control **controls;
254 struct ldb_request *down_req;
255 struct sort_context *ac;
256 struct ldb_context *ldb;
259 ldb = ldb_module_get_ctx(module);
261 /* check if there's a server sort control */
262 control = ldb_request_get_control(req, LDB_CONTROL_SERVER_SORT_OID);
263 if (control == NULL) {
264 /* not found go on */
265 return ldb_next_request(module, req);
268 ac = talloc_zero(req, struct sort_context);
271 return LDB_ERR_OPERATIONS_ERROR;
277 sort_ctrls = talloc_get_type(control->data, struct ldb_server_sort_control *);
279 return LDB_ERR_PROTOCOL_ERROR;
282 /* FIXME: we do not support more than one attribute for sorting right now */
283 /* FIXME: we need to check if the attribute type exist or return an error */
285 if (sort_ctrls[1] != NULL) {
286 if (control->critical) {
288 /* callback immediately */
289 ret = build_response(req, &controls,
290 LDB_ERR_UNWILLING_TO_PERFORM,
291 "sort control is not complete yet");
292 if (ret != LDB_SUCCESS) {
293 return ldb_module_done(req, NULL, NULL,
294 LDB_ERR_OPERATIONS_ERROR);
297 return ldb_module_done(req, controls, NULL, ret);
299 /* just pass the call down and don't do any sorting */
300 return ldb_next_request(module, req);
304 ac->attributeName = sort_ctrls[0]->attributeName;
305 ac->orderingRule = sort_ctrls[0]->orderingRule;
306 ac->reverse = sort_ctrls[0]->reverse;
308 ret = ldb_build_search_req_ex(&down_req, ldb, ac,
310 req->op.search.scope,
312 req->op.search.attrs,
315 server_sort_search_callback,
317 if (ret != LDB_SUCCESS) {
318 return LDB_ERR_OPERATIONS_ERROR;
321 /* save it locally and remove it from the list */
322 /* we do not need to replace them later as we
323 * are keeping the original req intact */
324 if (!save_controls(control, down_req, &saved_controls)) {
325 return LDB_ERR_OPERATIONS_ERROR;
328 return ldb_next_request(module, down_req);
331 static int server_sort_init(struct ldb_module *module)
333 struct ldb_context *ldb;
336 ldb = ldb_module_get_ctx(module);
338 ret = ldb_mod_register_control(module, LDB_CONTROL_SERVER_SORT_OID);
339 if (ret != LDB_SUCCESS) {
340 ldb_debug(ldb, LDB_DEBUG_WARNING,
342 "Unable to register control with rootdse!");
345 return ldb_next_init(module);
348 const struct ldb_module_ops ldb_server_sort_module_ops = {
349 .name = "server_sort",
350 .search = server_sort_search,
351 .init_context = server_sort_init