s3:smbd: also log the "offline" flag when debugging the dos-mode
[Samba/gebeck_regimport.git] / lib / ldb / modules / paged_searches.c
blob68eeb4c76e30fd046683e510d3f6344015aea83c
1 /*
2 ldb database library
4 Copyright (C) Simo Sorce 2005-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
7 ** NOTE! The following LGPL license applies to the ldb
8 ** library. This does NOT imply that all of Samba is released
9 ** under the LGPL
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 * Name: paged_searches
28 * Component: ldb paged searches module
30 * Description: this module detects if the remote ldap server supports
31 * paged results and use them to transparently access all objects
33 * Author: Simo Sorce
36 #include "replace.h"
37 #include "system/filesys.h"
38 #include "system/time.h"
39 #include "ldb_module.h"
41 #define PS_DEFAULT_PAGE_SIZE 500
42 /* 500 objects per query seem to be a decent compromise
43 * the default AD limit per request is 1000 entries */
45 struct private_data {
47 bool paged_supported;
50 struct ps_context {
51 struct ldb_module *module;
52 struct ldb_request *req;
54 bool pending;
56 char **saved_referrals;
57 unsigned int num_referrals;
59 struct ldb_request *down_req;
62 static int check_ps_continuation(struct ps_context *ac, struct ldb_request *req, struct ldb_reply *ares)
64 struct ldb_context *ldb;
65 struct ldb_control *rep_control, *req_control;
66 struct ldb_paged_control *paged_rep_control = NULL, *paged_req_control = NULL;
67 ldb = ldb_module_get_ctx(ac->module);
69 rep_control = ldb_reply_get_control(ares, LDB_CONTROL_PAGED_RESULTS_OID);
70 if (rep_control) {
71 paged_rep_control = talloc_get_type(rep_control->data, struct ldb_paged_control);
74 req_control = ldb_request_get_control(req, LDB_CONTROL_PAGED_RESULTS_OID);
75 paged_req_control = talloc_get_type(req_control->data, struct ldb_paged_control);
77 if (!rep_control || !paged_rep_control) {
78 if (paged_req_control->cookie) {
79 /* something wrong here - why give us a control back befre, but not one now? */
80 ldb_set_errstring(ldb, "paged_searches: ERROR: We got back a control from a previous page, but this time no control was returned!");
81 return LDB_ERR_OPERATIONS_ERROR;
82 } else {
83 /* No cookie received yet, valid to just return the full data set */
85 /* we are done */
86 ac->pending = false;
87 return LDB_SUCCESS;
91 if (paged_rep_control->cookie_len == 0) {
92 /* we are done */
93 ac->pending = false;
94 return LDB_SUCCESS;
97 /* more processing required */
98 /* let's fill in the request control with the new cookie */
99 /* if there's a reply control we must find a request
100 * control matching it */
102 if (paged_req_control->cookie) {
103 talloc_free(paged_req_control->cookie);
106 paged_req_control->cookie = talloc_memdup(req_control,
107 paged_rep_control->cookie,
108 paged_rep_control->cookie_len);
109 paged_req_control->cookie_len = paged_rep_control->cookie_len;
111 ac->pending = true;
112 return LDB_SUCCESS;
115 static int store_referral(struct ps_context *ac, char *referral)
117 ac->saved_referrals = talloc_realloc(ac, ac->saved_referrals, char *, ac->num_referrals + 2);
118 if (!ac->saved_referrals) {
119 return LDB_ERR_OPERATIONS_ERROR;
122 ac->saved_referrals[ac->num_referrals] = talloc_strdup(ac->saved_referrals, referral);
123 if (!ac->saved_referrals[ac->num_referrals]) {
124 return LDB_ERR_OPERATIONS_ERROR;
127 ac->num_referrals++;
128 ac->saved_referrals[ac->num_referrals] = NULL;
130 return LDB_SUCCESS;
133 static int send_referrals(struct ps_context *ac)
135 struct ldb_reply *ares;
136 int ret;
137 unsigned int i;
139 for (i = 0; i < ac->num_referrals; i++) {
140 ares = talloc_zero(ac->req, struct ldb_reply);
141 if (!ares) {
142 return LDB_ERR_OPERATIONS_ERROR;
145 ares->type = LDB_REPLY_REFERRAL;
146 ares->referral = ac->saved_referrals[i];
148 ret = ldb_module_send_referral(ac->req, ares->referral);
149 if (ret != LDB_SUCCESS) {
150 return ret;
154 return LDB_SUCCESS;
157 static int ps_callback(struct ldb_request *req, struct ldb_reply *ares)
159 struct ps_context *ac;
160 int ret;
162 ac = talloc_get_type(req->context, struct ps_context);
164 if (!ares) {
165 return ldb_module_done(ac->req, NULL, NULL,
166 LDB_ERR_OPERATIONS_ERROR);
168 if (ares->error != LDB_SUCCESS) {
169 return ldb_module_done(ac->req, ares->controls,
170 ares->response, ares->error);
173 switch (ares->type) {
174 case LDB_REPLY_ENTRY:
175 ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
176 if (ret != LDB_SUCCESS) {
177 return ldb_module_done(ac->req, NULL, NULL, ret);
179 break;
181 case LDB_REPLY_REFERRAL:
182 ret = store_referral(ac, ares->referral);
183 if (ret != LDB_SUCCESS) {
184 return ldb_module_done(ac->req, NULL, NULL, ret);
186 break;
188 case LDB_REPLY_DONE:
190 ret = check_ps_continuation(ac, req, ares);
191 if (ret != LDB_SUCCESS) {
192 return ldb_module_done(ac->req, NULL, NULL, ret);
195 if (ac->pending) {
197 ret = ldb_next_request(ac->module, ac->down_req);
199 if (ret != LDB_SUCCESS) {
200 return ldb_module_done(ac->req,
201 NULL, NULL, ret);
204 } else {
206 /* send referrals */
207 ret = send_referrals(ac);
208 if (ret != LDB_SUCCESS) {
209 return ldb_module_done(ac->req,
210 NULL, NULL, ret);
213 /* send REPLY_DONE */
214 return ldb_module_done(ac->req, ares->controls,
215 ares->response, LDB_SUCCESS);
217 break;
220 talloc_free(ares);
221 return LDB_SUCCESS;
224 static int ps_search(struct ldb_module *module, struct ldb_request *req)
226 struct ldb_context *ldb;
227 struct private_data *private_data;
228 struct ps_context *ac;
229 struct ldb_paged_control *control;
230 int ret;
232 private_data = talloc_get_type(ldb_module_get_private(module), struct private_data);
233 ldb = ldb_module_get_ctx(module);
235 /* check if paging is supported */
236 if (!private_data || !private_data->paged_supported) {
237 /* do not touch this request paged controls not
238 * supported or we
239 * are just not setup yet */
240 return ldb_next_request(module, req);
243 ac = talloc_zero(req, struct ps_context);
244 if (ac == NULL) {
245 ldb_oom(ldb);
246 return LDB_ERR_OPERATIONS_ERROR;
249 ac->module = module;
250 ac->req = req;
251 ac->pending = false;
252 ac->saved_referrals = NULL;
253 ac->num_referrals = 0;
255 ldb = ldb_module_get_ctx(ac->module);
257 control = talloc(ac, struct ldb_paged_control);
258 if (!control) {
259 return LDB_ERR_OPERATIONS_ERROR;
262 control->size = PS_DEFAULT_PAGE_SIZE;
263 control->cookie = NULL;
264 control->cookie_len = 0;
266 ret = ldb_build_search_req_ex(&ac->down_req, ldb, ac,
267 ac->req->op.search.base,
268 ac->req->op.search.scope,
269 ac->req->op.search.tree,
270 ac->req->op.search.attrs,
271 ac->req->controls,
273 ps_callback,
274 ac->req);
275 LDB_REQ_SET_LOCATION(ac->down_req);
276 if (ret != LDB_SUCCESS) {
277 return ret;
280 ret = ldb_request_add_control(ac->down_req, LDB_CONTROL_PAGED_RESULTS_OID,
281 true, control);
282 if (ret != LDB_SUCCESS) {
283 return ret;
286 talloc_steal(ac->down_req, control);
288 return ldb_next_request(ac->module, ac->down_req);
291 static int check_supported_paged(struct ldb_request *req,
292 struct ldb_reply *ares)
294 struct private_data *data;
296 data = talloc_get_type(req->context, struct private_data);
298 if (!ares) {
299 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
301 if (ares->error != LDB_SUCCESS) {
302 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
305 switch (ares->type) {
306 case LDB_REPLY_ENTRY:
307 if (ldb_msg_check_string_attribute(ares->message,
308 "supportedControl",
309 LDB_CONTROL_PAGED_RESULTS_OID)) {
310 data->paged_supported = true;
312 break;
314 case LDB_REPLY_REFERRAL:
315 /* ignore */
316 break;
318 case LDB_REPLY_DONE:
319 return ldb_request_done(req, LDB_SUCCESS);
322 talloc_free(ares);
323 return LDB_SUCCESS;
326 static int ps_init(struct ldb_module *module)
328 struct ldb_context *ldb;
329 static const char *attrs[] = { "supportedControl", NULL };
330 struct private_data *data;
331 struct ldb_dn *base;
332 int ret;
333 struct ldb_request *req;
335 ldb = ldb_module_get_ctx(module);
337 data = talloc(module, struct private_data);
338 if (data == NULL) {
339 ldb_oom(ldb);
340 return LDB_ERR_OPERATIONS_ERROR;
342 data->paged_supported = false;
344 ldb_module_set_private(module, data);
346 base = ldb_dn_new(module, ldb, "");
347 if (base == NULL) {
348 ldb_oom(ldb);
349 return LDB_ERR_OPERATIONS_ERROR;
351 ret = ldb_build_search_req(&req, ldb, module,
352 base, LDB_SCOPE_BASE,
353 "(objectClass=*)",
354 attrs, NULL,
355 data, check_supported_paged,
356 NULL);
357 LDB_REQ_SET_LOCATION(req);
358 if (ret != LDB_SUCCESS) {
359 return ret;
362 ret = ldb_next_request(module, req);
363 if (ret == LDB_SUCCESS) {
364 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
366 if (ret != LDB_SUCCESS) {
367 return ret;
370 talloc_free(base);
371 talloc_free(req);
373 return ldb_next_init(module);
376 static const struct ldb_module_ops ldb_paged_searches_module_ops = {
377 .name = "paged_searches",
378 .search = ps_search,
379 .init_context = ps_init
382 int ldb_paged_searches_init(const char *version)
384 LDB_MODULE_CHECK_VERSION(version);
385 return ldb_register_module(&ldb_paged_searches_module_ops);