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
35 #include "system/filesys.h"
36 #include "system/time.h"
37 #include "ldb_module.h"
40 struct ldb_context
*ldb
;
41 const struct ldb_attrib_handler
*h
;
42 const char *attribute
;
48 struct ldb_module
*module
;
50 const char *attributeName
;
51 const char *orderingRule
;
54 struct ldb_request
*req
;
55 struct ldb_message
**msgs
;
57 unsigned int num_msgs
;
58 unsigned int num_refs
;
59 const char *extra_sort_key
;
61 const struct ldb_schema_attribute
*a
;
65 static int build_response(void *mem_ctx
, struct ldb_control
***ctrls
, int result
, const char *desc
)
67 struct ldb_control
**controls
;
68 struct ldb_sort_resp_control
*resp
;
73 for (i
= 0; controls
[i
]; i
++);
74 controls
= talloc_realloc(mem_ctx
, controls
, struct ldb_control
*, i
+ 2);
77 controls
= talloc_array(mem_ctx
, struct ldb_control
*, 2);
80 return LDB_ERR_OPERATIONS_ERROR
;
85 controls
[i
] = talloc(controls
, struct ldb_control
);
87 return LDB_ERR_OPERATIONS_ERROR
;
89 controls
[i
]->oid
= LDB_CONTROL_SORT_RESP_OID
;
90 controls
[i
]->critical
= 0;
92 resp
= talloc(controls
[i
], struct ldb_sort_resp_control
);
94 return LDB_ERR_OPERATIONS_ERROR
;
96 resp
->result
= result
;
97 resp
->attr_desc
= talloc_strdup(resp
, desc
);
99 if (! resp
->attr_desc
)
100 return LDB_ERR_OPERATIONS_ERROR
;
102 controls
[i
]->data
= resp
;
107 static int sort_compare(struct ldb_message
**msg1
, struct ldb_message
**msg2
, void *opaque
)
109 struct sort_context
*ac
= talloc_get_type(opaque
, struct sort_context
);
110 struct ldb_message_element
*el1
, *el2
;
111 struct ldb_context
*ldb
;
113 ldb
= ldb_module_get_ctx(ac
->module
);
115 if (ac
->sort_result
!= 0) {
116 /* an error occurred previously,
117 * let's exit the sorting by returning always 0 */
121 el1
= ldb_msg_find_element(*msg1
, ac
->attributeName
);
122 el2
= ldb_msg_find_element(*msg2
, ac
->attributeName
);
125 * NULL and empty elements sort at the end (regardless of ac->reverse flag).
126 * NULL elements come after empty ones.
137 if (unlikely(el1
->num_values
== 0 && el2
->num_values
== 0)) {
140 if (unlikely(el1
->num_values
== 0)) {
143 if (unlikely(el2
->num_values
== 0)) {
148 return ac
->a
->syntax
->comparison_fn(ldb
, ac
, &el2
->values
[0], &el1
->values
[0]);
150 return ac
->a
->syntax
->comparison_fn(ldb
, ac
, &el1
->values
[0], &el2
->values
[0]);
153 static int server_sort_results(struct sort_context
*ac
)
155 struct ldb_context
*ldb
;
156 struct ldb_reply
*ares
;
160 ldb
= ldb_module_get_ctx(ac
->module
);
162 ac
->a
= ldb_schema_attribute_by_name(ldb
, ac
->attributeName
);
165 LDB_TYPESAFE_QSORT(ac
->msgs
, ac
->num_msgs
, ac
, sort_compare
);
167 if (ac
->sort_result
!= LDB_SUCCESS
) {
168 return ac
->sort_result
;
171 for (i
= 0; i
< ac
->num_msgs
; i
++) {
172 ares
= talloc_zero(ac
, struct ldb_reply
);
174 return LDB_ERR_OPERATIONS_ERROR
;
177 ares
->type
= LDB_REPLY_ENTRY
;
178 ares
->message
= talloc_move(ares
, &ac
->msgs
[i
]);
179 if (ac
->extra_sort_key
) {
180 ldb_msg_remove_attr(ares
->message
, ac
->extra_sort_key
);
182 ret
= ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
183 if (ret
!= LDB_SUCCESS
) {
188 for (i
= 0; i
< ac
->num_refs
; i
++) {
189 ares
= talloc_zero(ac
, struct ldb_reply
);
191 return LDB_ERR_OPERATIONS_ERROR
;
194 ares
->type
= LDB_REPLY_REFERRAL
;
195 ares
->referral
= talloc_move(ares
, &ac
->referrals
[i
]);
197 ret
= ldb_module_send_referral(ac
->req
, ares
->referral
);
198 if (ret
!= LDB_SUCCESS
) {
206 static int server_sort_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
208 struct sort_context
*ac
;
209 struct ldb_context
*ldb
;
212 ac
= talloc_get_type(req
->context
, struct sort_context
);
213 ldb
= ldb_module_get_ctx(ac
->module
);
216 return ldb_module_done(ac
->req
, NULL
, NULL
,
217 LDB_ERR_OPERATIONS_ERROR
);
219 if (ares
->error
!= LDB_SUCCESS
) {
220 return ldb_module_done(ac
->req
, ares
->controls
,
221 ares
->response
, ares
->error
);
224 switch (ares
->type
) {
225 case LDB_REPLY_ENTRY
:
226 ac
->msgs
= talloc_realloc(ac
, ac
->msgs
, struct ldb_message
*, ac
->num_msgs
+ 2);
230 return ldb_module_done(ac
->req
, NULL
, NULL
,
231 LDB_ERR_OPERATIONS_ERROR
);
234 ac
->msgs
[ac
->num_msgs
] = talloc_steal(ac
->msgs
, ares
->message
);
236 ac
->msgs
[ac
->num_msgs
] = NULL
;
240 case LDB_REPLY_REFERRAL
:
241 ac
->referrals
= talloc_realloc(ac
, ac
->referrals
, char *, ac
->num_refs
+ 2);
242 if (! ac
->referrals
) {
245 return ldb_module_done(ac
->req
, NULL
, NULL
,
246 LDB_ERR_OPERATIONS_ERROR
);
249 ac
->referrals
[ac
->num_refs
] = talloc_steal(ac
->referrals
, ares
->referral
);
251 ac
->referrals
[ac
->num_refs
] = NULL
;
257 ret
= server_sort_results(ac
);
258 return ldb_module_done(ac
->req
, ares
->controls
,
259 ares
->response
, ret
);
266 static int server_sort_search(struct ldb_module
*module
, struct ldb_request
*req
)
268 struct ldb_control
*control
;
269 struct ldb_server_sort_control
**sort_ctrls
;
270 struct ldb_control
**saved_controls
;
271 struct ldb_request
*down_req
;
272 struct sort_context
*ac
;
273 struct ldb_context
*ldb
;
275 const char * const *attrs
;
277 const char *sort_attr
;
279 ldb
= ldb_module_get_ctx(module
);
281 /* check if there's a server sort control */
282 control
= ldb_request_get_control(req
, LDB_CONTROL_SERVER_SORT_OID
);
283 if (control
== NULL
) {
284 /* not found go on */
285 return ldb_next_request(module
, req
);
288 ac
= talloc_zero(req
, struct sort_context
);
291 return LDB_ERR_OPERATIONS_ERROR
;
297 sort_ctrls
= talloc_get_type(control
->data
, struct ldb_server_sort_control
*);
299 return LDB_ERR_PROTOCOL_ERROR
;
302 /* FIXME: we do not support more than one attribute for sorting right now */
303 /* FIXME: we need to check if the attribute type exist or return an error */
305 if (sort_ctrls
[1] != NULL
) {
306 if (control
->critical
) {
307 struct ldb_control
**controls
= NULL
;
309 /* callback immediately */
310 ret
= build_response(req
, &controls
,
311 LDB_ERR_UNWILLING_TO_PERFORM
,
312 "sort control is not complete yet");
313 if (ret
!= LDB_SUCCESS
) {
314 return ldb_module_done(req
, NULL
, NULL
,
315 LDB_ERR_OPERATIONS_ERROR
);
318 return ldb_module_done(req
, controls
, NULL
, ret
);
320 /* just pass the call down and don't do any sorting */
321 return ldb_next_request(module
, req
);
325 control
->critical
= 0;
327 /* We are asked to sort on an attribute, and if that attribute is not
328 already in the search attributes we need to add it (and later
329 remove it on the return journey).
331 sort_attr
= sort_ctrls
[0]->attributeName
;
332 if (req
->op
.search
.attrs
== NULL
) {
333 /* This means all non-operational attributes, which means
334 there's nothing to add. */
338 while (req
->op
.search
.attrs
[n_attrs
] != NULL
) {
340 strcmp(req
->op
.search
.attrs
[n_attrs
], sort_attr
) == 0) {
346 if (sort_attr
== NULL
) {
347 attrs
= req
->op
.search
.attrs
;
349 const char **tmp
= talloc_array(ac
, const char *, n_attrs
+ 2);
351 for (i
= 0; i
< n_attrs
; i
++) {
352 tmp
[i
] = req
->op
.search
.attrs
[i
];
354 ac
->extra_sort_key
= sort_attr
;
355 tmp
[n_attrs
] = sort_attr
;
356 tmp
[n_attrs
+ 1] = NULL
;
361 ac
->attributeName
= sort_ctrls
[0]->attributeName
;
362 ac
->orderingRule
= sort_ctrls
[0]->orderingRule
;
363 ac
->reverse
= sort_ctrls
[0]->reverse
;
365 ret
= ldb_build_search_req_ex(&down_req
, ldb
, ac
,
367 req
->op
.search
.scope
,
372 server_sort_search_callback
,
374 if (ret
!= LDB_SUCCESS
) {
378 /* save it locally and remove it from the list */
379 /* we do not need to replace them later as we
380 * are keeping the original req intact */
381 if (!ldb_save_controls(control
, down_req
, &saved_controls
)) {
382 return LDB_ERR_OPERATIONS_ERROR
;
385 return ldb_next_request(module
, down_req
);
388 static int server_sort_init(struct ldb_module
*module
)
390 struct ldb_context
*ldb
;
393 ldb
= ldb_module_get_ctx(module
);
395 ret
= ldb_mod_register_control(module
, LDB_CONTROL_SERVER_SORT_OID
);
396 if (ret
!= LDB_SUCCESS
) {
397 ldb_debug(ldb
, LDB_DEBUG_WARNING
,
399 "Unable to register control with rootdse!");
402 return ldb_next_init(module
);
405 static const struct ldb_module_ops ldb_server_sort_module_ops
= {
406 .name
= "server_sort",
407 .search
= server_sort_search
,
408 .init_context
= server_sort_init
411 int ldb_server_sort_init(const char *version
)
413 LDB_MODULE_CHECK_VERSION(version
);
414 return ldb_register_module(&ldb_server_sort_module_ops
);