• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/lib/ldb/modules/
1/*
2   ldb database library
3
4   Copyright (C) Simo Sorce  2005-2008
5
6     ** NOTE! The following LGPL license applies to the ldb
7     ** library. This does NOT imply that all of Samba is released
8     ** under the LGPL
9
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.
14
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.
19
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/>.
22*/
23
24/*
25 *  Name: ldb
26 *
27 *  Component: ldb server side sort control module
28 *
29 *  Description: this module sorts the results of a search
30 *
31 *  Author: Simo Sorce
32 */
33
34#include "ldb_module.h"
35
36struct opaque {
37	struct ldb_context *ldb;
38	const struct ldb_attrib_handler *h;
39	const char *attribute;
40	int reverse;
41	int result;
42};
43
44struct sort_context {
45	struct ldb_module *module;
46
47	char *attributeName;
48	char *orderingRule;
49	int reverse;
50
51	struct ldb_request *req;
52	struct ldb_message **msgs;
53	char **referrals;
54	int num_msgs;
55	int num_refs;
56
57	const struct ldb_schema_attribute *a;
58	int sort_result;
59};
60
61static int build_response(void *mem_ctx, struct ldb_control ***ctrls, int result, const char *desc)
62{
63	struct ldb_control **controls;
64	struct ldb_sort_resp_control *resp;
65	int i;
66
67	if (*ctrls) {
68		controls = *ctrls;
69		for (i = 0; controls[i]; i++);
70		controls = talloc_realloc(mem_ctx, controls, struct ldb_control *, i + 2);
71	} else {
72		i = 0;
73		controls = talloc_array(mem_ctx, struct ldb_control *, 2);
74	}
75	if (! controls )
76		return LDB_ERR_OPERATIONS_ERROR;
77
78	*ctrls = controls;
79
80	controls[i+1] = NULL;
81	controls[i] = talloc(controls, struct ldb_control);
82	if (! controls[i] )
83		return LDB_ERR_OPERATIONS_ERROR;
84
85	controls[i]->oid = LDB_CONTROL_SORT_RESP_OID;
86	controls[i]->critical = 0;
87
88	resp = talloc(controls[i], struct ldb_sort_resp_control);
89	if (! resp )
90		return LDB_ERR_OPERATIONS_ERROR;
91
92	resp->result = result;
93	resp->attr_desc = talloc_strdup(resp, desc);
94
95	if (! resp->attr_desc )
96		return LDB_ERR_OPERATIONS_ERROR;
97
98	controls[i]->data = resp;
99
100	return LDB_SUCCESS;
101}
102
103static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, void *opaque)
104{
105	struct sort_context *ac = talloc_get_type(opaque, struct sort_context);
106	struct ldb_message_element *el1, *el2;
107	struct ldb_context *ldb;
108
109	ldb = ldb_module_get_ctx(ac->module);
110
111	if (ac->sort_result != 0) {
112		/* an error occurred previously,
113		 * let's exit the sorting by returning always 0 */
114		return 0;
115	}
116
117	el1 = ldb_msg_find_element(*msg1, ac->attributeName);
118	el2 = ldb_msg_find_element(*msg2, ac->attributeName);
119
120	if (!el1 && el2) {
121		return 1;
122	}
123	if (el1 && !el2) {
124		return -1;
125	}
126	if (!el1 && !el2) {
127		return 0;
128	}
129
130	if (ac->reverse)
131		return ac->a->syntax->comparison_fn(ldb, ac, &el2->values[0], &el1->values[0]);
132
133	return ac->a->syntax->comparison_fn(ldb, ac, &el1->values[0], &el2->values[0]);
134}
135
136static int server_sort_results(struct sort_context *ac)
137{
138	struct ldb_context *ldb;
139	struct ldb_reply *ares;
140	int i, ret;
141
142	ldb = ldb_module_get_ctx(ac->module);
143
144	ac->a = ldb_schema_attribute_by_name(ldb, ac->attributeName);
145	ac->sort_result = 0;
146
147	ldb_qsort(ac->msgs, ac->num_msgs,
148		  sizeof(struct ldb_message *),
149		  ac, (ldb_qsort_cmp_fn_t)sort_compare);
150
151	if (ac->sort_result != LDB_SUCCESS) {
152		return ac->sort_result;
153	}
154
155	for (i = 0; i < ac->num_msgs; i++) {
156		ares = talloc_zero(ac, struct ldb_reply);
157		if (!ares) {
158			return LDB_ERR_OPERATIONS_ERROR;
159		}
160
161		ares->type = LDB_REPLY_ENTRY;
162		ares->message = talloc_move(ares, &ac->msgs[i]);
163
164		ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
165		if (ret != LDB_SUCCESS) {
166			return ret;
167		}
168	}
169
170	for (i = 0; i < ac->num_refs; i++) {
171		ares = talloc_zero(ac, struct ldb_reply);
172		if (!ares) {
173			return LDB_ERR_OPERATIONS_ERROR;
174		}
175
176		ares->type = LDB_REPLY_REFERRAL;
177		ares->referral = talloc_move(ares, &ac->referrals[i]);
178
179		ret = ldb_module_send_referral(ac->req, ares->referral);
180		if (ret != LDB_SUCCESS) {
181			return ret;
182		}
183	}
184
185	return LDB_SUCCESS;
186}
187
188static int server_sort_search_callback(struct ldb_request *req, struct ldb_reply *ares)
189{
190	struct sort_context *ac;
191	struct ldb_context *ldb;
192	int ret;
193
194	ac = talloc_get_type(req->context, struct sort_context);
195	ldb = ldb_module_get_ctx(ac->module);
196
197	if (!ares) {
198		return ldb_module_done(ac->req, NULL, NULL,
199					LDB_ERR_OPERATIONS_ERROR);
200	}
201	if (ares->error != LDB_SUCCESS) {
202		return ldb_module_done(ac->req, ares->controls,
203					ares->response, ares->error);
204	}
205
206	switch (ares->type) {
207	case LDB_REPLY_ENTRY:
208		ac->msgs = talloc_realloc(ac, ac->msgs, struct ldb_message *, ac->num_msgs + 2);
209		if (! ac->msgs) {
210			talloc_free(ares);
211			ldb_oom(ldb);
212			return ldb_module_done(ac->req, NULL, NULL,
213						LDB_ERR_OPERATIONS_ERROR);
214		}
215
216		ac->msgs[ac->num_msgs] = talloc_steal(ac->msgs, ares->message);
217		ac->num_msgs++;
218		ac->msgs[ac->num_msgs] = NULL;
219
220		break;
221
222	case LDB_REPLY_REFERRAL:
223		ac->referrals = talloc_realloc(ac, ac->referrals, char *, ac->num_refs + 2);
224		if (! ac->referrals) {
225			talloc_free(ares);
226			ldb_oom(ldb);
227			return ldb_module_done(ac->req, NULL, NULL,
228						LDB_ERR_OPERATIONS_ERROR);
229		}
230
231		ac->referrals[ac->num_refs] = talloc_steal(ac->referrals, ares->referral);
232		ac->num_refs++;
233		ac->referrals[ac->num_refs] = NULL;
234
235		break;
236
237	case LDB_REPLY_DONE:
238
239		ret = server_sort_results(ac);
240		return ldb_module_done(ac->req, ares->controls,
241					ares->response, ret);
242	}
243
244	talloc_free(ares);
245	return LDB_SUCCESS;
246}
247
248static int server_sort_search(struct ldb_module *module, struct ldb_request *req)
249{
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;
257	int ret;
258
259	ldb = ldb_module_get_ctx(module);
260
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);
266	}
267
268	ac = talloc_zero(req, struct sort_context);
269	if (ac == NULL) {
270		ldb_oom(ldb);
271		return LDB_ERR_OPERATIONS_ERROR;
272	}
273
274	ac->module = module;
275	ac->req = req;
276
277	sort_ctrls = talloc_get_type(control->data, struct ldb_server_sort_control *);
278	if (!sort_ctrls) {
279		return LDB_ERR_PROTOCOL_ERROR;
280	}
281
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 */
284
285	if (sort_ctrls[1] != NULL) {
286		if (control->critical) {
287
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);
295			}
296
297			return ldb_module_done(req, controls, NULL, ret);
298		} else {
299			/* just pass the call down and don't do any sorting */
300			return ldb_next_request(module, req);
301		}
302	}
303
304	ac->attributeName = sort_ctrls[0]->attributeName;
305	ac->orderingRule = sort_ctrls[0]->orderingRule;
306	ac->reverse = sort_ctrls[0]->reverse;
307
308	ret = ldb_build_search_req_ex(&down_req, ldb, ac,
309					req->op.search.base,
310					req->op.search.scope,
311					req->op.search.tree,
312					req->op.search.attrs,
313					req->controls,
314					ac,
315					server_sort_search_callback,
316					req);
317	if (ret != LDB_SUCCESS) {
318		return LDB_ERR_OPERATIONS_ERROR;
319	}
320
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;
326	}
327
328	return ldb_next_request(module, down_req);
329}
330
331static int server_sort_init(struct ldb_module *module)
332{
333	struct ldb_context *ldb;
334	int ret;
335
336	ldb = ldb_module_get_ctx(module);
337
338	ret = ldb_mod_register_control(module, LDB_CONTROL_SERVER_SORT_OID);
339	if (ret != LDB_SUCCESS) {
340		ldb_debug(ldb, LDB_DEBUG_WARNING,
341			"server_sort:"
342			"Unable to register control with rootdse!");
343	}
344
345	return ldb_next_init(module);
346}
347
348const struct ldb_module_ops ldb_server_sort_module_ops = {
349	.name		   = "server_sort",
350	.search            = server_sort_search,
351	.init_context	   = server_sort_init
352};
353