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
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
37 #include "ldb_module.h"
39 #define PS_DEFAULT_PAGE_SIZE 500
40 /* 500 objects per query seem to be a decent compromise
41 * the default AD limit per request is 1000 entries */
49 struct ldb_module
*module
;
50 struct ldb_request
*req
;
54 char **saved_referrals
;
55 unsigned int num_referrals
;
57 struct ldb_request
*down_req
;
60 static int check_ps_continuation(struct ps_context
*ac
, struct ldb_request
*req
, struct ldb_reply
*ares
)
62 struct ldb_context
*ldb
;
63 struct ldb_control
*rep_control
, *req_control
;
64 struct ldb_paged_control
*paged_rep_control
= NULL
, *paged_req_control
= NULL
;
65 ldb
= ldb_module_get_ctx(ac
->module
);
67 rep_control
= ldb_reply_get_control(ares
, LDB_CONTROL_PAGED_RESULTS_OID
);
69 paged_rep_control
= talloc_get_type(rep_control
->data
, struct ldb_paged_control
);
72 req_control
= ldb_request_get_control(req
, LDB_CONTROL_PAGED_RESULTS_OID
);
73 paged_req_control
= talloc_get_type(req_control
->data
, struct ldb_paged_control
);
75 if (!rep_control
|| !paged_rep_control
) {
76 if (paged_req_control
->cookie
) {
77 /* something wrong here - why give us a control back befre, but not one now? */
78 ldb_set_errstring(ldb
, "paged_searches: ERROR: We got back a control from a previous page, but this time no control was returned!");
79 return LDB_ERR_OPERATIONS_ERROR
;
81 /* No cookie received yet, valid to just return the full data set */
89 if (paged_rep_control
->cookie_len
== 0) {
95 /* more processing required */
96 /* let's fill in the request control with the new cookie */
97 /* if there's a reply control we must find a request
98 * control matching it */
100 if (paged_req_control
->cookie
) {
101 talloc_free(paged_req_control
->cookie
);
104 paged_req_control
->cookie
= talloc_memdup(req_control
,
105 paged_rep_control
->cookie
,
106 paged_rep_control
->cookie_len
);
107 paged_req_control
->cookie_len
= paged_rep_control
->cookie_len
;
113 static int store_referral(struct ps_context
*ac
, char *referral
)
115 ac
->saved_referrals
= talloc_realloc(ac
, ac
->saved_referrals
, char *, ac
->num_referrals
+ 2);
116 if (!ac
->saved_referrals
) {
117 return LDB_ERR_OPERATIONS_ERROR
;
120 ac
->saved_referrals
[ac
->num_referrals
] = talloc_strdup(ac
->saved_referrals
, referral
);
121 if (!ac
->saved_referrals
[ac
->num_referrals
]) {
122 return LDB_ERR_OPERATIONS_ERROR
;
126 ac
->saved_referrals
[ac
->num_referrals
] = NULL
;
131 static int send_referrals(struct ps_context
*ac
)
133 struct ldb_reply
*ares
;
137 for (i
= 0; i
< ac
->num_referrals
; i
++) {
138 ares
= talloc_zero(ac
->req
, struct ldb_reply
);
140 return LDB_ERR_OPERATIONS_ERROR
;
143 ares
->type
= LDB_REPLY_REFERRAL
;
144 ares
->referral
= ac
->saved_referrals
[i
];
146 ret
= ldb_module_send_referral(ac
->req
, ares
->referral
);
147 if (ret
!= LDB_SUCCESS
) {
155 static int ps_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
157 struct ps_context
*ac
;
160 ac
= talloc_get_type(req
->context
, struct ps_context
);
163 return ldb_module_done(ac
->req
, NULL
, NULL
,
164 LDB_ERR_OPERATIONS_ERROR
);
166 if (ares
->error
!= LDB_SUCCESS
) {
167 return ldb_module_done(ac
->req
, ares
->controls
,
168 ares
->response
, ares
->error
);
171 switch (ares
->type
) {
172 case LDB_REPLY_ENTRY
:
173 ret
= ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
174 if (ret
!= LDB_SUCCESS
) {
175 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
179 case LDB_REPLY_REFERRAL
:
180 ret
= store_referral(ac
, ares
->referral
);
181 if (ret
!= LDB_SUCCESS
) {
182 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
188 ret
= check_ps_continuation(ac
, req
, ares
);
189 if (ret
!= LDB_SUCCESS
) {
190 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
195 ret
= ldb_next_request(ac
->module
, ac
->down_req
);
197 if (ret
!= LDB_SUCCESS
) {
198 return ldb_module_done(ac
->req
,
205 ret
= send_referrals(ac
);
206 if (ret
!= LDB_SUCCESS
) {
207 return ldb_module_done(ac
->req
,
211 /* send REPLY_DONE */
212 return ldb_module_done(ac
->req
, ares
->controls
,
213 ares
->response
, LDB_SUCCESS
);
222 static int ps_search(struct ldb_module
*module
, struct ldb_request
*req
)
224 struct ldb_context
*ldb
;
225 struct private_data
*private_data
;
226 struct ps_context
*ac
;
227 struct ldb_paged_control
*control
;
230 private_data
= talloc_get_type(ldb_module_get_private(module
), struct private_data
);
231 ldb
= ldb_module_get_ctx(module
);
233 /* check if paging is supported */
234 if (!private_data
|| !private_data
->paged_supported
) {
235 /* do not touch this request paged controls not
237 * are just not setup yet */
238 return ldb_next_request(module
, req
);
241 ac
= talloc_zero(req
, struct ps_context
);
244 return LDB_ERR_OPERATIONS_ERROR
;
250 ac
->saved_referrals
= NULL
;
251 ac
->num_referrals
= 0;
253 ldb
= ldb_module_get_ctx(ac
->module
);
255 control
= talloc(ac
, struct ldb_paged_control
);
257 return LDB_ERR_OPERATIONS_ERROR
;
260 control
->size
= PS_DEFAULT_PAGE_SIZE
;
261 control
->cookie
= NULL
;
262 control
->cookie_len
= 0;
264 ret
= ldb_build_search_req_ex(&ac
->down_req
, ldb
, ac
,
265 ac
->req
->op
.search
.base
,
266 ac
->req
->op
.search
.scope
,
267 ac
->req
->op
.search
.tree
,
268 ac
->req
->op
.search
.attrs
,
273 if (ret
!= LDB_SUCCESS
) {
277 ret
= ldb_request_add_control(ac
->down_req
, LDB_CONTROL_PAGED_RESULTS_OID
,
279 if (ret
!= LDB_SUCCESS
) {
283 talloc_steal(ac
->down_req
, control
);
285 return ldb_next_request(ac
->module
, ac
->down_req
);
288 static int check_supported_paged(struct ldb_request
*req
,
289 struct ldb_reply
*ares
)
291 struct private_data
*data
;
293 data
= talloc_get_type(req
->context
, struct private_data
);
296 return ldb_request_done(req
, LDB_ERR_OPERATIONS_ERROR
);
298 if (ares
->error
!= LDB_SUCCESS
) {
299 return ldb_request_done(req
, LDB_ERR_OPERATIONS_ERROR
);
302 switch (ares
->type
) {
303 case LDB_REPLY_ENTRY
:
304 if (ldb_msg_check_string_attribute(ares
->message
,
306 LDB_CONTROL_PAGED_RESULTS_OID
)) {
307 data
->paged_supported
= true;
311 case LDB_REPLY_REFERRAL
:
316 return ldb_request_done(req
, LDB_SUCCESS
);
323 static int ps_init(struct ldb_module
*module
)
325 struct ldb_context
*ldb
;
326 static const char *attrs
[] = { "supportedControl", NULL
};
327 struct private_data
*data
;
330 struct ldb_request
*req
;
332 ldb
= ldb_module_get_ctx(module
);
334 data
= talloc(module
, struct private_data
);
337 return LDB_ERR_OPERATIONS_ERROR
;
339 data
->paged_supported
= false;
341 ldb_module_set_private(module
, data
);
343 base
= ldb_dn_new(module
, ldb
, "");
346 return LDB_ERR_OPERATIONS_ERROR
;
348 ret
= ldb_build_search_req(&req
, ldb
, module
,
349 base
, LDB_SCOPE_BASE
,
352 data
, check_supported_paged
,
354 if (ret
!= LDB_SUCCESS
) {
358 ret
= ldb_next_request(module
, req
);
359 if (ret
== LDB_SUCCESS
) {
360 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
362 if (ret
!= LDB_SUCCESS
) {
369 return ldb_next_init(module
);
372 _PUBLIC_
const struct ldb_module_ops ldb_paged_searches_module_ops
= {
373 .name
= "paged_searches",
375 .init_context
= ps_init