4 Copyright (C) Simo Sorce 2005
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, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb server side sort control module
30 * Description: this module sorts the results of a search
36 #include "ldb/include/includes.h"
39 struct ldb_context
*ldb
;
40 const struct ldb_attrib_handler
*h
;
41 const char *attribute
;
47 struct ldb_module
*module
;
49 int (*up_callback
)(struct ldb_context
*, void *, struct ldb_reply
*);
55 struct ldb_request
*req
;
56 struct ldb_message
**msgs
;
58 struct ldb_control
**controls
;
62 const struct ldb_attrib_handler
*h
;
66 static struct ldb_handle
*init_handle(void *mem_ctx
, struct ldb_module
*module
,
68 int (*callback
)(struct ldb_context
*, void *, struct ldb_reply
*))
70 struct sort_context
*ac
;
73 h
= talloc_zero(mem_ctx
, struct ldb_handle
);
75 ldb_set_errstring(module
->ldb
, "Out of Memory");
81 ac
= talloc_zero(h
, struct sort_context
);
83 ldb_set_errstring(module
->ldb
, "Out of Memory");
88 h
->private_data
= (void *)ac
;
90 h
->state
= LDB_ASYNC_INIT
;
91 h
->status
= LDB_SUCCESS
;
94 ac
->up_context
= context
;
95 ac
->up_callback
= callback
;
100 static int build_response(void *mem_ctx
, struct ldb_control
***ctrls
, int result
, const char *desc
)
102 struct ldb_control
**controls
;
103 struct ldb_sort_resp_control
*resp
;
108 for (i
= 0; controls
[i
]; i
++);
109 controls
= talloc_realloc(mem_ctx
, controls
, struct ldb_control
*, i
+ 2);
112 controls
= talloc_array(mem_ctx
, struct ldb_control
*, 2);
115 return LDB_ERR_OPERATIONS_ERROR
;
119 controls
[i
+1] = NULL
;
120 controls
[i
] = talloc(controls
, struct ldb_control
);
122 return LDB_ERR_OPERATIONS_ERROR
;
124 controls
[i
]->oid
= LDB_CONTROL_SORT_RESP_OID
;
125 controls
[i
]->critical
= 0;
127 resp
= talloc(controls
[i
], struct ldb_sort_resp_control
);
129 return LDB_ERR_OPERATIONS_ERROR
;
131 resp
->result
= result
;
132 resp
->attr_desc
= talloc_strdup(resp
, desc
);
134 if (! resp
->attr_desc
)
135 return LDB_ERR_OPERATIONS_ERROR
;
137 controls
[i
]->data
= resp
;
142 static int sort_compare(struct ldb_message
**msg1
, struct ldb_message
**msg2
, void *opaque
)
144 struct sort_context
*ac
= talloc_get_type(opaque
, struct sort_context
);
145 struct ldb_message_element
*el1
, *el2
;
147 if (ac
->sort_result
!= 0) {
148 /* an error occurred previously,
149 * let's exit the sorting by returning always 0 */
153 el1
= ldb_msg_find_element(*msg1
, ac
->attributeName
);
154 el2
= ldb_msg_find_element(*msg2
, ac
->attributeName
);
157 /* the attribute was not found return and
159 ac
->sort_result
= 53;
164 return ac
->h
->comparison_fn(ac
->module
->ldb
, ac
, &el2
->values
[0], &el1
->values
[0]);
166 return ac
->h
->comparison_fn(ac
->module
->ldb
, ac
, &el1
->values
[0], &el2
->values
[0]);
169 static int server_sort_search_callback(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
171 struct sort_context
*ac
= NULL
;
173 if (!context
|| !ares
) {
174 ldb_set_errstring(ldb
, "NULL Context or Result in callback");
178 ac
= talloc_get_type(context
, struct sort_context
);
180 if (ares
->type
== LDB_REPLY_ENTRY
) {
181 ac
->msgs
= talloc_realloc(ac
, ac
->msgs
, struct ldb_message
*, ac
->num_msgs
+ 2);
186 ac
->msgs
[ac
->num_msgs
+ 1] = NULL
;
188 ac
->msgs
[ac
->num_msgs
] = talloc_move(ac
->msgs
, &ares
->message
);
192 if (ares
->type
== LDB_REPLY_REFERRAL
) {
193 ac
->referrals
= talloc_realloc(ac
, ac
->referrals
, char *, ac
->num_refs
+ 2);
194 if (! ac
->referrals
) {
198 ac
->referrals
[ac
->num_refs
+ 1] = NULL
;
199 ac
->referrals
[ac
->num_refs
] = talloc_move(ac
->referrals
, &ares
->referral
);
204 if (ares
->type
== LDB_REPLY_DONE
) {
205 ac
->controls
= talloc_move(ac
, &ares
->controls
);
213 return LDB_ERR_OPERATIONS_ERROR
;
216 static int server_sort_search(struct ldb_module
*module
, struct ldb_request
*req
)
218 struct ldb_control
*control
;
219 struct ldb_server_sort_control
**sort_ctrls
;
220 struct ldb_control
**saved_controls
;
221 struct sort_context
*ac
;
222 struct ldb_handle
*h
;
225 /* check if there's a paged request control */
226 control
= get_control_from_list(req
->controls
, LDB_CONTROL_SERVER_SORT_OID
);
227 if (control
== NULL
) {
228 /* not found go on */
229 return ldb_next_request(module
, req
);
234 if (!req
->callback
|| !req
->context
) {
235 ldb_set_errstring(module
->ldb
,
236 "Async interface called with NULL callback function or NULL context");
237 return LDB_ERR_OPERATIONS_ERROR
;
240 h
= init_handle(req
, module
, req
->context
, req
->callback
);
242 return LDB_ERR_OPERATIONS_ERROR
;
244 ac
= talloc_get_type(h
->private_data
, struct sort_context
);
246 sort_ctrls
= talloc_get_type(control
->data
, struct ldb_server_sort_control
*);
248 return LDB_ERR_PROTOCOL_ERROR
;
251 /* FIXME: we do not support more than one attribute for sorting right now */
252 /* FIXME: we need to check if the attribute type exist or return an error */
254 if (sort_ctrls
[1] != NULL
) {
255 if (control
->critical
) {
256 struct ldb_reply
*ares
;
258 ares
= talloc_zero(req
, struct ldb_reply
);
260 return LDB_ERR_OPERATIONS_ERROR
;
262 /* 53 = unwilling to perform */
263 ares
->type
= LDB_REPLY_DONE
;
264 if ((ret
= build_response(ares
, &ares
->controls
, 53, "sort control is not complete yet")) != LDB_SUCCESS
) {
268 h
->status
= LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION
;
269 h
->state
= LDB_ASYNC_DONE
;
270 ret
= ac
->up_callback(module
->ldb
, ac
->up_context
, ares
);
274 /* just pass the call down and don't do any sorting */
275 ldb_next_request(module
, req
);
279 ac
->attributeName
= sort_ctrls
[0]->attributeName
;
280 ac
->orderingRule
= sort_ctrls
[0]->orderingRule
;
281 ac
->reverse
= sort_ctrls
[0]->reverse
;
283 ac
->req
= talloc(req
, struct ldb_request
);
285 return LDB_ERR_OPERATIONS_ERROR
;
287 ac
->req
->operation
= req
->operation
;
288 ac
->req
->op
.search
.base
= req
->op
.search
.base
;
289 ac
->req
->op
.search
.scope
= req
->op
.search
.scope
;
290 ac
->req
->op
.search
.tree
= req
->op
.search
.tree
;
291 ac
->req
->op
.search
.attrs
= req
->op
.search
.attrs
;
292 ac
->req
->controls
= req
->controls
;
294 /* save it locally and remove it from the list */
295 /* we do not need to replace them later as we
296 * are keeping the original req intact */
297 if (!save_controls(control
, ac
->req
, &saved_controls
)) {
298 return LDB_ERR_OPERATIONS_ERROR
;
301 ac
->req
->context
= ac
;
302 ac
->req
->callback
= server_sort_search_callback
;
303 ldb_set_timeout_from_prev_req(module
->ldb
, req
, ac
->req
);
307 return ldb_next_request(module
, ac
->req
);
310 static int server_sort_results(struct ldb_handle
*handle
)
312 struct sort_context
*ac
;
313 struct ldb_reply
*ares
;
316 ac
= talloc_get_type(handle
->private_data
, struct sort_context
);
318 ac
->h
= ldb_attrib_handler(ac
->module
->ldb
, ac
->attributeName
);
321 ldb_qsort(ac
->msgs
, ac
->num_msgs
,
322 sizeof(struct ldb_message
*),
323 ac
, (ldb_qsort_cmp_fn_t
)sort_compare
);
325 for (i
= 0; i
< ac
->num_msgs
; i
++) {
326 ares
= talloc_zero(ac
, struct ldb_reply
);
328 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
329 return handle
->status
;
332 ares
->type
= LDB_REPLY_ENTRY
;
333 ares
->message
= talloc_move(ares
, &ac
->msgs
[i
]);
335 handle
->status
= ac
->up_callback(ac
->module
->ldb
, ac
->up_context
, ares
);
336 if (handle
->status
!= LDB_SUCCESS
) {
337 return handle
->status
;
341 for (i
= 0; i
< ac
->num_refs
; i
++) {
342 ares
= talloc_zero(ac
, struct ldb_reply
);
344 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
345 return handle
->status
;
348 ares
->type
= LDB_REPLY_REFERRAL
;
349 ares
->referral
= talloc_move(ares
, &ac
->referrals
[i
]);
351 handle
->status
= ac
->up_callback(ac
->module
->ldb
, ac
->up_context
, ares
);
352 if (handle
->status
!= LDB_SUCCESS
) {
353 return handle
->status
;
357 ares
= talloc_zero(ac
, struct ldb_reply
);
359 handle
->status
= LDB_ERR_OPERATIONS_ERROR
;
360 return handle
->status
;
363 ares
->type
= LDB_REPLY_DONE
;
364 ares
->controls
= talloc_move(ares
, &ac
->controls
);
366 handle
->status
= ac
->up_callback(ac
->module
->ldb
, ac
->up_context
, ares
);
367 if (handle
->status
!= LDB_SUCCESS
) {
368 return handle
->status
;
371 if ((ret
= build_response(ac
, &ac
->controls
, ac
->sort_result
, "sort control is not complete yet")) != LDB_SUCCESS
) {
378 static int server_sort_wait(struct ldb_handle
*handle
, enum ldb_wait_type type
)
380 struct sort_context
*ac
;
383 if (!handle
|| !handle
->private_data
) {
384 return LDB_ERR_OPERATIONS_ERROR
;
387 ac
= talloc_get_type(handle
->private_data
, struct sort_context
);
389 ret
= ldb_wait(ac
->req
->handle
, type
);
391 if (ret
!= LDB_SUCCESS
) {
392 handle
->status
= ret
;
396 handle
->state
= ac
->req
->handle
->state
;
397 handle
->status
= ac
->req
->handle
->status
;
399 if (handle
->status
!= LDB_SUCCESS
) {
400 return handle
->status
;
403 if (handle
->state
== LDB_ASYNC_DONE
) {
404 ret
= server_sort_results(handle
);
410 static int server_sort_init(struct ldb_module
*module
)
412 struct ldb_request
*req
;
415 req
= talloc(module
, struct ldb_request
);
417 return LDB_ERR_OPERATIONS_ERROR
;
420 req
->operation
= LDB_REQ_REGISTER_CONTROL
;
421 req
->op
.reg_control
.oid
= LDB_CONTROL_SERVER_SORT_OID
;
422 req
->controls
= NULL
;
424 ret
= ldb_request(module
->ldb
, req
);
425 if (ret
!= LDB_SUCCESS
) {
426 ldb_debug(module
->ldb
, LDB_DEBUG_WARNING
, "server_sort: Unable to register control with rootdse!\n");
430 return ldb_next_init(module
);
433 static const struct ldb_module_ops server_sort_ops
= {
434 .name
= "server_sort",
435 .search
= server_sort_search
,
436 .wait
= server_sort_wait
,
437 .init_context
= server_sort_init
440 int ldb_sort_init(void)
442 return ldb_register_module(&server_sort_ops
);