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);
121
/* the attribute was not found return and
123
ac->sort_result = LDB_ERR_UNWILLING_TO_PERFORM;
128
return ac->a->syntax->comparison_fn(ldb, ac, &el2->values[0], &el1->values[0]);
130
return ac->a->syntax->comparison_fn(ldb, ac, &el1->values[0], &el2->values[0]);
133
static int server_sort_results(struct sort_context *ac)
135
struct ldb_context *ldb;
136
struct ldb_reply *ares;
139
ldb = ldb_module_get_ctx(ac->module);
141
ac->a = ldb_schema_attribute_by_name(ldb, ac->attributeName);
144
ldb_qsort(ac->msgs, ac->num_msgs,
145
sizeof(struct ldb_message *),
146
ac, (ldb_qsort_cmp_fn_t)sort_compare);
148
if (ac->sort_result != LDB_SUCCESS) {
149
return ac->sort_result;
152
for (i = 0; i < ac->num_msgs; i++) {
153
ares = talloc_zero(ac, struct ldb_reply);
155
return LDB_ERR_OPERATIONS_ERROR;
158
ares->type = LDB_REPLY_ENTRY;
159
ares->message = talloc_move(ares, &ac->msgs[i]);
161
ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
162
if (ret != LDB_SUCCESS) {
167
for (i = 0; i < ac->num_refs; i++) {
168
ares = talloc_zero(ac, struct ldb_reply);
170
return LDB_ERR_OPERATIONS_ERROR;
173
ares->type = LDB_REPLY_REFERRAL;
174
ares->referral = talloc_move(ares, &ac->referrals[i]);
176
ret = ldb_module_send_referral(ac->req, ares->referral);
177
if (ret != LDB_SUCCESS) {
185
static int server_sort_search_callback(struct ldb_request *req, struct ldb_reply *ares)
187
struct sort_context *ac;
188
struct ldb_context *ldb;
191
ac = talloc_get_type(req->context, struct sort_context);
192
ldb = ldb_module_get_ctx(ac->module);
195
return ldb_module_done(ac->req, NULL, NULL,
196
LDB_ERR_OPERATIONS_ERROR);
198
if (ares->error != LDB_SUCCESS) {
199
return ldb_module_done(ac->req, ares->controls,
200
ares->response, ares->error);
203
switch (ares->type) {
204
case LDB_REPLY_ENTRY:
205
ac->msgs = talloc_realloc(ac, ac->msgs, struct ldb_message *, ac->num_msgs + 2);
209
return ldb_module_done(ac->req, NULL, NULL,
210
LDB_ERR_OPERATIONS_ERROR);
213
ac->msgs[ac->num_msgs] = talloc_steal(ac->msgs, ares->message);
215
ac->msgs[ac->num_msgs] = NULL;
219
case LDB_REPLY_REFERRAL:
220
ac->referrals = talloc_realloc(ac, ac->referrals, char *, ac->num_refs + 2);
221
if (! ac->referrals) {
224
return ldb_module_done(ac->req, NULL, NULL,
225
LDB_ERR_OPERATIONS_ERROR);
228
ac->referrals[ac->num_refs] = talloc_steal(ac->referrals, ares->referral);
230
ac->referrals[ac->num_refs] = NULL;
236
ret = server_sort_results(ac);
237
return ldb_module_done(ac->req, ares->controls,
238
ares->response, ret);
245
static int server_sort_search(struct ldb_module *module, struct ldb_request *req)
247
struct ldb_control *control;
248
struct ldb_server_sort_control **sort_ctrls;
249
struct ldb_control **saved_controls;
250
struct ldb_control **controls;
251
struct ldb_request *down_req;
252
struct sort_context *ac;
253
struct ldb_context *ldb;
256
ldb = ldb_module_get_ctx(module);
258
/* check if there's a paged request control */
259
control = ldb_request_get_control(req, LDB_CONTROL_SERVER_SORT_OID);
260
if (control == NULL) {
261
/* not found go on */
262
return ldb_next_request(module, req);
265
ac = talloc_zero(req, struct sort_context);
268
return LDB_ERR_OPERATIONS_ERROR;
274
sort_ctrls = talloc_get_type(control->data, struct ldb_server_sort_control *);
276
return LDB_ERR_PROTOCOL_ERROR;
279
/* FIXME: we do not support more than one attribute for sorting right now */
280
/* FIXME: we need to check if the attribute type exist or return an error */
282
if (sort_ctrls[1] != NULL) {
283
if (control->critical) {
285
/* callback immediately */
286
ret = build_response(req, &controls,
287
LDB_ERR_UNWILLING_TO_PERFORM,
288
"sort control is not complete yet");
289
if (ret != LDB_SUCCESS) {
290
return ldb_module_done(req, NULL, NULL,
291
LDB_ERR_OPERATIONS_ERROR);
294
return ldb_module_done(req, controls, NULL, ret);
296
/* just pass the call down and don't do any sorting */
297
return ldb_next_request(module, req);
301
ac->attributeName = sort_ctrls[0]->attributeName;
302
ac->orderingRule = sort_ctrls[0]->orderingRule;
303
ac->reverse = sort_ctrls[0]->reverse;
305
ret = ldb_build_search_req_ex(&down_req, ldb, ac,
307
req->op.search.scope,
309
req->op.search.attrs,
312
server_sort_search_callback,
314
if (ret != LDB_SUCCESS) {
315
return LDB_ERR_OPERATIONS_ERROR;
318
/* save it locally and remove it from the list */
319
/* we do not need to replace them later as we
320
* are keeping the original req intact */
321
if (!save_controls(control, down_req, &saved_controls)) {
322
return LDB_ERR_OPERATIONS_ERROR;
325
return ldb_next_request(module, down_req);
328
static int server_sort_init(struct ldb_module *module)
330
struct ldb_context *ldb;
333
ldb = ldb_module_get_ctx(module);
335
ret = ldb_mod_register_control(module, LDB_CONTROL_SERVER_SORT_OID);
336
if (ret != LDB_SUCCESS) {
337
ldb_debug(ldb, LDB_DEBUG_WARNING,
339
"Unable to register control with rootdse!\n");
342
return ldb_next_init(module);
345
const struct ldb_module_ops ldb_server_sort_module_ops = {
346
.name = "server_sort",
347
.search = server_sort_search,
348
.init_context = server_sort_init