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/>.
25 * Name: paged_searches
27 * Component: ldb paged searches module
29 * Description: this module detects if the remote ldap server supports
30 * paged results and use them to transparently access all objects
36 #include "ldb_module.h"
38 #define PS_DEFAULT_PAGE_SIZE 500
39 /* 500 objects per query seem to be a decent compromise
40 * the default AD limit per request is 1000 entries */
48 struct ldb_module
*module
;
49 struct ldb_request
*req
;
53 char **saved_referrals
;
57 static int check_ps_continuation(struct ldb_request
*req
, struct ldb_reply
*ares
)
59 struct ps_context
*ac
;
60 struct ldb_paged_control
*rep_control
, *req_control
;
62 ac
= talloc_get_type(req
->context
, struct ps_context
);
64 /* look up our paged control */
65 if (!ares
->controls
|| strcmp(LDB_CONTROL_PAGED_RESULTS_OID
, ares
->controls
[0]->oid
) != 0) {
66 /* something wrong here */
67 return LDB_ERR_OPERATIONS_ERROR
;
70 rep_control
= talloc_get_type(ares
->controls
[0]->data
, struct ldb_paged_control
);
71 if (rep_control
->cookie_len
== 0) {
77 /* more processing required */
78 /* let's fill in the request control with the new cookie */
79 /* if there's a reply control we must find a request
80 * control matching it */
82 if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID
, req
->controls
[0]->oid
) != 0) {
83 /* something wrong here */
84 return LDB_ERR_OPERATIONS_ERROR
;
87 req_control
= talloc_get_type(req
->controls
[0]->data
, struct ldb_paged_control
);
89 if (req_control
->cookie
) {
90 talloc_free(req_control
->cookie
);
93 req_control
->cookie
= talloc_memdup(req_control
,
95 rep_control
->cookie_len
);
96 req_control
->cookie_len
= rep_control
->cookie_len
;
102 static int store_referral(struct ps_context
*ac
, char *referral
)
104 ac
->saved_referrals
= talloc_realloc(ac
, ac
->saved_referrals
, char *, ac
->num_referrals
+ 2);
105 if (!ac
->saved_referrals
) {
106 return LDB_ERR_OPERATIONS_ERROR
;
109 ac
->saved_referrals
[ac
->num_referrals
] = talloc_strdup(ac
->saved_referrals
, referral
);
110 if (!ac
->saved_referrals
[ac
->num_referrals
]) {
111 return LDB_ERR_OPERATIONS_ERROR
;
115 ac
->saved_referrals
[ac
->num_referrals
] = NULL
;
120 static int send_referrals(struct ps_context
*ac
)
122 struct ldb_reply
*ares
;
126 for (i
= 0; i
< ac
->num_referrals
; i
++) {
127 ares
= talloc_zero(ac
->req
, struct ldb_reply
);
129 return LDB_ERR_OPERATIONS_ERROR
;
132 ares
->type
= LDB_REPLY_REFERRAL
;
133 ares
->referral
= ac
->saved_referrals
[i
];
135 ret
= ldb_module_send_referral(ac
->req
, ares
->referral
);
136 if (ret
!= LDB_SUCCESS
) {
144 static int ps_next_request(struct ps_context
*ac
);
146 static int ps_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
148 struct ps_context
*ac
;
151 ac
= talloc_get_type(req
->context
, struct ps_context
);
154 return ldb_module_done(ac
->req
, NULL
, NULL
,
155 LDB_ERR_OPERATIONS_ERROR
);
157 if (ares
->error
!= LDB_SUCCESS
) {
158 return ldb_module_done(ac
->req
, ares
->controls
,
159 ares
->response
, ares
->error
);
162 switch (ares
->type
) {
163 case LDB_REPLY_ENTRY
:
164 ret
= ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
165 if (ret
!= LDB_SUCCESS
) {
166 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
170 case LDB_REPLY_REFERRAL
:
171 ret
= store_referral(ac
, ares
->referral
);
172 if (ret
!= LDB_SUCCESS
) {
173 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
179 ret
= check_ps_continuation(req
, ares
);
180 if (ret
!= LDB_SUCCESS
) {
181 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
186 ret
= ps_next_request(ac
);
187 if (ret
!= LDB_SUCCESS
) {
188 return ldb_module_done(ac
->req
,
195 ret
= send_referrals(ac
);
196 if (ret
!= LDB_SUCCESS
) {
197 return ldb_module_done(ac
->req
,
201 /* send REPLY_DONE */
202 return ldb_module_done(ac
->req
, ares
->controls
,
203 ares
->response
, LDB_SUCCESS
);
212 static int ps_search(struct ldb_module
*module
, struct ldb_request
*req
)
214 struct ldb_context
*ldb
;
215 struct private_data
*private_data
;
216 struct ps_context
*ac
;
218 private_data
= talloc_get_type(ldb_module_get_private(module
), struct private_data
);
219 ldb
= ldb_module_get_ctx(module
);
221 /* check if paging is supported and if there is a any control */
222 if (!private_data
|| !private_data
->paged_supported
|| req
->controls
) {
223 /* do not touch this request paged controls not
224 * supported or explicit controls have been set or we
225 * are just not setup yet */
226 return ldb_next_request(module
, req
);
229 ac
= talloc_zero(req
, struct ps_context
);
232 return LDB_ERR_OPERATIONS_ERROR
;
238 ac
->saved_referrals
= NULL
;
239 ac
->num_referrals
= 0;
241 return ps_next_request(ac
);
244 static int ps_next_request(struct ps_context
*ac
) {
246 struct ldb_context
*ldb
;
247 struct ldb_paged_control
*control
;
248 struct ldb_control
**controls
;
249 struct ldb_request
*new_req
;
252 ldb
= ldb_module_get_ctx(ac
->module
);
254 controls
= talloc_array(ac
, struct ldb_control
*, 2);
256 return LDB_ERR_OPERATIONS_ERROR
;
259 controls
[0] = talloc(controls
, struct ldb_control
);
261 return LDB_ERR_OPERATIONS_ERROR
;
264 control
= talloc(controls
[0], struct ldb_paged_control
);
266 return LDB_ERR_OPERATIONS_ERROR
;
269 control
->size
= PS_DEFAULT_PAGE_SIZE
;
270 control
->cookie
= NULL
;
271 control
->cookie_len
= 0;
273 controls
[0]->oid
= LDB_CONTROL_PAGED_RESULTS_OID
;
274 controls
[0]->critical
= 1;
275 controls
[0]->data
= control
;
278 ret
= ldb_build_search_req_ex(&new_req
, ldb
, ac
,
279 ac
->req
->op
.search
.base
,
280 ac
->req
->op
.search
.scope
,
281 ac
->req
->op
.search
.tree
,
282 ac
->req
->op
.search
.attrs
,
287 if (ret
!= LDB_SUCCESS
) {
290 talloc_steal(new_req
, controls
);
292 return ldb_next_request(ac
->module
, new_req
);
295 static int check_supported_paged(struct ldb_request
*req
,
296 struct ldb_reply
*ares
)
298 struct private_data
*data
;
300 data
= talloc_get_type(req
->context
, struct private_data
);
303 return ldb_request_done(req
, LDB_ERR_OPERATIONS_ERROR
);
305 if (ares
->error
!= LDB_SUCCESS
) {
306 return ldb_request_done(req
, LDB_ERR_OPERATIONS_ERROR
);
309 switch (ares
->type
) {
310 case LDB_REPLY_ENTRY
:
311 if (ldb_msg_check_string_attribute(ares
->message
,
313 LDB_CONTROL_PAGED_RESULTS_OID
)) {
314 data
->paged_supported
= true;
318 case LDB_REPLY_REFERRAL
:
323 return ldb_request_done(req
, LDB_SUCCESS
);
330 static int ps_init(struct ldb_module
*module
)
332 struct ldb_context
*ldb
;
333 static const char *attrs
[] = { "supportedControl", NULL
};
334 struct private_data
*data
;
337 struct ldb_request
*req
;
339 ldb
= ldb_module_get_ctx(module
);
341 data
= talloc(module
, struct private_data
);
344 return LDB_ERR_OPERATIONS_ERROR
;
346 data
->paged_supported
= false;
348 ldb_module_set_private(module
, data
);
350 base
= ldb_dn_new(module
, ldb
, "");
353 return LDB_ERR_OPERATIONS_ERROR
;
355 ret
= ldb_build_search_req(&req
, ldb
, module
,
356 base
, LDB_SCOPE_BASE
,
359 data
, check_supported_paged
,
361 if (ret
!= LDB_SUCCESS
) {
365 ret
= ldb_next_request(module
, req
);
366 if (ret
== LDB_SUCCESS
) {
367 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
369 if (ret
!= LDB_SUCCESS
) {
376 return ldb_next_init(module
);
379 _PUBLIC_
const struct ldb_module_ops ldb_paged_searches_module_ops
= {
380 .name
= "paged_searches",
382 .init_context
= ps_init