dcerpc: use anon creds for unknown transport
[samba.git] / source4 / dsdb / samdb / ldb_modules / paged_results.c
1 /*
2    ldb database library
3
4    Copyright (C) Simo Sorce  2005-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
6
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
10
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.
15
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.
20
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/>.
23 */
24
25 /*
26  *  Name: paged_result
27  *
28  *  Component: ldb paged results control module
29  *
30  *  Description: this module caches a complete search and sends back
31  *               results in chunks as asked by the client
32  *
33  *  Author: Garming Sam and Aaron Haslett
34  *
35  *  Note: Based on the original paged_results.c by Simo Sorce and
36  *        vlv_pagination.c by Douglas Bagnall and Garming Sam.
37  */
38
39 #include "includes.h"
40 #include "auth/auth.h"
41 #include <ldb.h>
42 #include "dsdb/samdb/samdb.h"
43 #include "libcli/security/security.h"
44 #include "libcli/ldap/ldap_errors.h"
45 #include "replace.h"
46 #include "system/filesys.h"
47 #include "system/time.h"
48 #include "ldb_module.h"
49 #include "dsdb/samdb/samdb.h"
50
51 #include "dsdb/common/util.h"
52 #include "lib/util/dlinklist.h"
53
54 /* Referrals are temporarily stored in a linked list */
55 struct referral_store {
56         char *ref;
57         struct referral_store *next;
58 };
59
60 struct private_data;
61
62 struct results_store {
63         struct results_store *prev, *next;
64
65         struct private_data *priv;
66
67         char *cookie;
68         time_t timestamp;
69
70         struct referral_store *first_ref;
71         struct referral_store *last_ref;
72
73         struct ldb_control **controls;
74
75         /* from VLV */
76         struct GUID *results;
77         size_t num_entries;
78         size_t result_array_size;
79
80         struct ldb_control **down_controls;
81         const char * const *attrs;
82
83         unsigned last_i;
84         struct ldb_parse_tree *expr;
85         char *expr_str;
86 };
87
88 struct private_data {
89         uint32_t next_free_id;
90         size_t num_stores;
91         struct results_store *store;
92 };
93
94 static int store_destructor(struct results_store *del)
95 {
96         struct private_data *priv = del->priv;
97         DLIST_REMOVE(priv->store, del);
98
99         priv->num_stores -= 1;
100
101         return 0;
102 }
103
104 static struct results_store *new_store(struct private_data *priv)
105 {
106         struct results_store *newr;
107         uint32_t new_id = priv->next_free_id++;
108
109         /* TODO: we should have a limit on the number of
110          * outstanding paged searches
111          */
112
113         newr = talloc_zero(priv, struct results_store);
114         if (!newr) return NULL;
115
116         newr->priv = priv;
117
118         newr->cookie = talloc_asprintf(newr, "%d", new_id);
119         if (!newr->cookie) {
120                 talloc_free(newr);
121                 return NULL;
122         }
123
124         newr->timestamp = time(NULL);
125
126         DLIST_ADD(priv->store, newr);
127
128         priv->num_stores += 1;
129
130         talloc_set_destructor(newr, store_destructor);
131
132         if (priv->num_stores > 10) {
133                 struct results_store *last;
134                 /*
135                  * 10 is the default for MaxResultSetsPerConn --
136                  * possibly need to parameterize it.
137                  */
138                 last = DLIST_TAIL(priv->store);
139                 TALLOC_FREE(last);
140         }
141
142         return newr;
143 }
144
145 struct paged_context {
146         struct ldb_module *module;
147         struct ldb_request *req;
148
149         struct results_store *store;
150         int size;
151         struct ldb_control **controls;
152 };
153
154 static int send_referrals(struct results_store *store,
155                           struct ldb_request *req)
156 {
157         int ret;
158         struct referral_store *node;
159         while (store->first_ref != NULL) {
160                 node = store->first_ref;
161                 ret = ldb_module_send_referral(req, node->ref);
162                 if (ret != LDB_SUCCESS) {
163                         return ret;
164                 }
165                 store->first_ref = node->next;
166                 talloc_free(node);
167         }
168         return LDB_SUCCESS;
169 }
170
171 /* Start an ldb request for a single object by GUID */
172 static int paged_search_by_dn_guid(struct ldb_module *module,
173                                  struct paged_context *ac,
174                                  struct ldb_result **result,
175                                  const struct GUID *guid,
176                                  const char * const *attrs,
177                                  struct ldb_parse_tree *expr)
178 {
179         struct ldb_dn *dn;
180         struct ldb_request *req;
181         struct ldb_result *res;
182         int ret;
183         struct GUID_txt_buf guid_str;
184
185         /* Use controls passed in on the downreq */
186         struct ldb_control **controls = ac->store->down_controls;
187
188         struct ldb_context *ldb = ldb_module_get_ctx(module);
189
190         dn = ldb_dn_new_fmt(ac, ldb, "<GUID=%s>",
191                             GUID_buf_string(guid, &guid_str));
192         if (dn == NULL) {
193                 return ldb_oom(ldb);
194         }
195
196         res = talloc_zero(ac, struct ldb_result);
197         if (res == NULL) {
198                 TALLOC_FREE(dn);
199                 return ldb_oom(ldb);
200         }
201
202         ret = ldb_build_search_req_ex(&req, ldb, ac,
203                                    dn,
204                                    LDB_SCOPE_BASE,
205                                    expr,
206                                    attrs,
207                                    controls,
208                                    res,
209                                    ldb_search_default_callback,
210                                    ac->req);
211         if (ret != LDB_SUCCESS) {
212                 TALLOC_FREE(dn);
213                 TALLOC_FREE(res);
214                 return ret;
215         }
216
217         /*
218          * Ensure the dn lasts only as long as the request,
219          * as we will have a lot of these (one per object
220          * being returned)
221          */
222
223         talloc_steal(req, dn);
224
225         ret = ldb_request(ldb, req);
226         if (ret == LDB_SUCCESS) {
227                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
228         }
229
230         talloc_free(req);
231         if (ret != LDB_SUCCESS) {
232                 talloc_free(res);
233                 return ret;
234         }
235
236         *result = res;
237         return ret;
238 }
239
240 static int paged_results(struct paged_context *ac)
241 {
242         struct ldb_paged_control *paged;
243         unsigned int i, num_ctrls;
244         int ret;
245
246         if (ac->store == NULL) {
247                 return LDB_ERR_OPERATIONS_ERROR;
248         }
249
250         while (ac->store->last_i < ac->store->num_entries && ac->size > 0) {
251                 struct GUID *guid = &ac->store->results[ac->store->last_i++];
252                 struct ldb_result *result = NULL;
253
254                 ac->size--;
255
256                 /*
257                  * Note: In the case that an object has been moved to a
258                  * different place in the LDAP tree, we might expect the object
259                  * to disappear from paged results.  If we were going to
260                  * implement that behaviour, we would do it here by passing
261                  * down the original container DN to the search.
262                  * However, testing shows that, on Windows, the moved object
263                  * remains in the paged results. So, we are matching Windows
264                  * behaviour here by leaving out the scope.
265                  */
266                 ret = paged_search_by_dn_guid(ac->module, ac, &result, guid,
267                                             ac->req->op.search.attrs,
268                                             ac->store->expr);
269                 if (ret == LDAP_NO_SUCH_OBJECT ||
270                     (ret == LDB_SUCCESS && result->count == 0)) {
271                         /* The thing isn't there TODO, which we quietly
272                            ignore and go on to send an extra one
273                            instead. */
274                         continue;
275                 } else if (ret != LDB_SUCCESS) {
276                         return ret;
277                 }
278
279                 ret = ldb_module_send_entry(ac->req, result->msgs[0],
280                                             NULL);
281                 if (ret != LDB_SUCCESS) {
282                         return ret;
283                 }
284         }
285
286         if (ac->store->first_ref) {
287                 /* There is no right place to put references in the sorted
288                    results, so we send them as soon as possible.
289                 */
290                 ret = send_referrals(ac->store, ac->req);
291                 if (ret != LDB_SUCCESS) {
292                         return ret;
293                 }
294         }
295
296         /* return result done */
297         num_ctrls = 1;
298         i = 0;
299
300         if (ac->store->controls != NULL) {
301                 while (ac->store->controls[i]) i++; /* counting */
302
303                 num_ctrls += i;
304         }
305
306         ac->controls = talloc_array(ac, struct ldb_control *, num_ctrls +1);
307         if (ac->controls == NULL) {
308                 return LDB_ERR_OPERATIONS_ERROR;
309         }
310         ac->controls[num_ctrls] = NULL;
311
312         for (i = 0; i < (num_ctrls -1); i++) {
313                 ac->controls[i] = talloc_reference(ac->controls,
314                                                    ac->store->controls[i]);
315         }
316
317         ac->controls[i] = talloc(ac->controls, struct ldb_control);
318         if (ac->controls[i] == NULL) {
319                 return LDB_ERR_OPERATIONS_ERROR;
320         }
321
322         ac->controls[i]->oid = talloc_strdup(ac->controls[i],
323                                                 LDB_CONTROL_PAGED_RESULTS_OID);
324         if (ac->controls[i]->oid == NULL) {
325                 return LDB_ERR_OPERATIONS_ERROR;
326         }
327
328         ac->controls[i]->critical = 0;
329
330         paged = talloc(ac->controls[i], struct ldb_paged_control);
331         if (paged == NULL) {
332                 return LDB_ERR_OPERATIONS_ERROR;
333         }
334
335         ac->controls[i]->data = paged;
336
337         if (ac->size > 0) {
338                 paged->size = 0;
339                 paged->cookie = NULL;
340                 paged->cookie_len = 0;
341         } else {
342                 paged->size = ac->store->num_entries;
343                 paged->cookie = talloc_strdup(paged, ac->store->cookie);
344                 paged->cookie_len = strlen(paged->cookie) + 1;
345         }
346
347         return LDB_SUCCESS;
348 }
349
350 static int save_referral(struct results_store *store, char *ref)
351 {
352         struct referral_store *node = talloc(store,
353                                              struct referral_store);
354         if (node == NULL) {
355                 return LDB_ERR_OPERATIONS_ERROR;
356         }
357         node->next = NULL;
358         node->ref = talloc_steal(node, ref);
359
360         if (store->first_ref == NULL) {
361                 store->first_ref = node;
362         } else {
363                 store->last_ref->next = node;
364         }
365         store->last_ref = node;
366         return LDB_SUCCESS;
367 }
368
369 static int paged_search_callback(struct ldb_request *req,
370                                  struct ldb_reply *ares)
371 {
372         struct paged_context *ac;
373         struct results_store *store;
374         int ret;
375         const struct ldb_val *guid_blob;
376         struct GUID guid;
377         NTSTATUS status;
378
379         ac = talloc_get_type(req->context, struct paged_context);
380         store = ac->store;
381
382         if (!ares) {
383                 return ldb_module_done(ac->req, NULL, NULL,
384                                         LDB_ERR_OPERATIONS_ERROR);
385         }
386         if (ares->error != LDB_SUCCESS) {
387                 return ldb_module_done(ac->req, ares->controls,
388                                         ares->response, ares->error);
389         }
390
391         switch (ares->type) {
392         case LDB_REPLY_ENTRY:
393                 if (store->results == NULL) {
394                         store->num_entries = 0;
395                         store->result_array_size = 16;
396                         store->results = talloc_array(store, struct GUID,
397                                                      store->result_array_size);
398                         if (store->results == NULL) {
399                                 return ldb_module_done(ac->req, NULL, NULL,
400                                                      LDB_ERR_OPERATIONS_ERROR);
401                         }
402                 } else if (store->num_entries == store->result_array_size) {
403                         if (store->result_array_size > INT_MAX/2) {
404                                 return ldb_module_done(ac->req, NULL, NULL,
405                                                      LDB_ERR_OPERATIONS_ERROR);
406                         }
407                         store->result_array_size *= 2;
408                         store->results = talloc_realloc(store, store->results,
409                                                         struct GUID,
410                                                 store->result_array_size);
411                         if (store->results == NULL) {
412                                 return ldb_module_done(ac->req, NULL, NULL,
413                                                      LDB_ERR_OPERATIONS_ERROR);
414                         }
415                 }
416
417                 guid_blob = ldb_dn_get_extended_component(ares->message->dn,
418                                                           "GUID");
419                 status = GUID_from_ndr_blob(guid_blob, &guid);
420                 if (!NT_STATUS_IS_OK(status)) {
421                         return ldb_module_done(ac->req, NULL, NULL,
422                                                LDB_ERR_OPERATIONS_ERROR);
423                 }
424
425                 /* Redundant paranoid check */
426                 if (store->num_entries > store->result_array_size) {
427                         return ldb_module_done(ac->req, NULL, NULL,
428                                                LDB_ERR_OPERATIONS_ERROR);
429                 }
430
431                 store->results[store->num_entries] = guid;
432                 store->num_entries++;
433                 break;
434
435         case LDB_REPLY_REFERRAL:
436                 ret = save_referral(store, ares->referral);
437                 if (ret != LDB_SUCCESS) {
438                         return ldb_module_done(ac->req, NULL, NULL, ret);
439                 }
440                 break;
441
442         case LDB_REPLY_DONE:
443                 if (store->num_entries != 0) {
444                         store->results = talloc_realloc(store, store->results,
445                                                         struct GUID,
446                                                         store->num_entries);
447                         if (store->results == NULL) {
448                                 return ldb_module_done(ac->req, NULL, NULL,
449                                                      LDB_ERR_OPERATIONS_ERROR);
450                         }
451                 }
452                 store->result_array_size = store->num_entries;
453
454                 ac->store->controls = talloc_move(ac->store, &ares->controls);
455                 ret = paged_results(ac);
456                 return ldb_module_done(ac->req, ac->controls,
457                                         ares->response, ret);
458         }
459
460         return LDB_SUCCESS;
461 }
462
463 static struct ldb_control **
464 paged_results_copy_down_controls(TALLOC_CTX *mem_ctx,
465                                  struct ldb_control **controls)
466 {
467
468         struct ldb_control **new_controls;
469         unsigned int i, j, num_ctrls;
470         if (controls == NULL) {
471                 return NULL;
472         }
473
474         for (num_ctrls = 0; controls[num_ctrls]; num_ctrls++);
475
476         new_controls = talloc_array(mem_ctx, struct ldb_control *, num_ctrls);
477         if (new_controls == NULL) {
478                 return NULL;
479         }
480
481         for (j = 0, i = 0; i < (num_ctrls); i++) {
482                 struct ldb_control *control = controls[i];
483                 if (control->oid == NULL) {
484                         continue;
485                 }
486                 if (strncmp(control->oid, LDB_CONTROL_PAGED_RESULTS_OID,
487                     sizeof(LDB_CONTROL_PAGED_RESULTS_OID)) == 0) {
488                         continue;
489                 }
490                 new_controls[j] = talloc_steal(new_controls, control);
491                 j++;
492         }
493         new_controls[j] = NULL;
494         return new_controls;
495 }
496
497 static const char * const *paged_copy_attrs(TALLOC_CTX *mem_ctx,
498                                             const char * const *attrs) {
499         int i;
500         const char **new_attrs;
501         if (attrs == NULL) {
502                 return NULL;
503         }
504         new_attrs = ldb_attr_list_copy(mem_ctx, attrs);
505
506         for (i=0; attrs[i] != NULL; i++) {
507                 new_attrs[i] = talloc_strdup(mem_ctx, attrs[i]);
508         }
509         new_attrs[i] = NULL;
510         return new_attrs;
511 }
512
513 /*
514  * Check if two sets of controls are the same except for the paged results
515  * control in the request controls.  This function is messy because request
516  * control lists can contain controls that were NULL'd by the rootdse.  We
517  * must ignore those entries.  This function is not portable.
518  */
519 static bool paged_controls_same(struct ldb_request *req,
520                                 struct ldb_control **down_controls) {
521         int i;
522         unsigned int num_down_controls, num_non_null_req_controls;
523         struct ldb_control *ctrl;
524
525         num_down_controls = 0;
526         for (i=0; down_controls[i] != NULL; i++) {
527                 num_down_controls++;
528
529                 ctrl = ldb_request_get_control(req, down_controls[i]->oid);
530                 if (ctrl == NULL) {
531                         return false;
532                 }
533         }
534
535         num_non_null_req_controls = 0;
536         for (i=0; req->controls[i] != NULL; i++) {
537                 if (req->controls[i]->oid != NULL) {
538                         num_non_null_req_controls++;
539                 }
540         }
541
542         /* At this point we have the number of non-null entries for both
543          * control lists and we know that:
544          * 1. down_controls does not contain the paged control
545          *      (because paged_results_copy_down_controls excludes it)
546          * 2. req->controls does contain the paged control
547          *      (because this function is only called if this is true)
548          * 3. down_controls is a subset of non-null controls in req->controls
549          *      (checked above)
550          * So to confirm that the two lists are identical except for the paged
551          * control, all we need to check is: */
552         if (num_non_null_req_controls == num_down_controls + 1) {
553                 return true;
554         }
555         return false;
556 }
557
558 static bool paged_attrs_same(const char * const *attrs_1,
559                              const char * const *attrs_2) {
560         int i;
561         if (attrs_1 == NULL || attrs_2 == NULL) {
562                 if (attrs_1 == NULL && attrs_2 == NULL) {
563                         return true;
564                 }
565                 return false;
566         }
567
568         for (i=0; attrs_1[i] != NULL; i++) {
569                if (!ldb_attr_in_list(attrs_2, attrs_1[i])) {
570                        return false;
571                }
572         }
573         return true;
574 }
575
576 static int paged_search(struct ldb_module *module, struct ldb_request *req)
577 {
578         struct ldb_context *ldb;
579         struct ldb_control *control;
580         struct private_data *private_data;
581         struct ldb_paged_control *paged_ctrl;
582         struct ldb_request *search_req;
583         struct paged_context *ac;
584         int ret;
585
586         ldb = ldb_module_get_ctx(module);
587
588         /* check if there's a paged request control */
589         control = ldb_request_get_control(req, LDB_CONTROL_PAGED_RESULTS_OID);
590         if (control == NULL) {
591                 /* not found go on */
592                 return ldb_next_request(module, req);
593         }
594
595         paged_ctrl = talloc_get_type(control->data, struct ldb_paged_control);
596         if (!paged_ctrl) {
597                 return LDB_ERR_PROTOCOL_ERROR;
598         }
599
600         private_data = talloc_get_type(ldb_module_get_private(module),
601                                         struct private_data);
602
603         ac = talloc_zero(req, struct paged_context);
604         if (ac == NULL) {
605                 ldb_set_errstring(ldb, "Out of Memory");
606                 return LDB_ERR_OPERATIONS_ERROR;
607         }
608
609         ac->module = module;
610         ac->req = req;
611         ac->size = paged_ctrl->size;
612         if (ac->size < 0) {
613                 /*
614                  * Apparently some clients send more than 2^31. This
615                  * violates the ldap standard, but we need to cope.
616                  * In the future, if maximum result sizes are implemented in
617                  * Samba, we should also clamp the page size to the maximum
618                  * result size.
619                  */
620                 ac->size = 0x7FFFFFFF;
621         }
622
623         /* check if it is a continuation search the store */
624         if (paged_ctrl->cookie_len == 0) {
625                 struct ldb_control *ext_ctrl;
626                 struct ldb_control **controls;
627                 static const char * const attrs[1] = { NULL };
628
629                 if (paged_ctrl->size == 0) {
630                         return LDB_ERR_OPERATIONS_ERROR;
631                 }
632
633                 ac->store = new_store(private_data);
634                 if (ac->store == NULL) {
635                         return LDB_ERR_OPERATIONS_ERROR;
636                 }
637
638                 controls = req->controls;
639                 ext_ctrl = ldb_request_get_control(req,
640                                         LDB_CONTROL_EXTENDED_DN_OID);
641                 if (ext_ctrl == NULL) {
642                         /*
643                          * Add extended_dn control to the request if there
644                          * isn't already one.  We'll get the GUID out of it in
645                          * the callback.  This is a workaround for the case
646                          * where ntsecuritydescriptor forbids fetching GUIDs
647                          * for the current user.
648                          */
649                         struct ldb_request *req_extended_dn;
650                         struct ldb_extended_dn_control *ext_ctrl_data;
651                         req_extended_dn = talloc_zero(req, struct ldb_request);
652                         req_extended_dn->controls = req->controls;
653                         ext_ctrl_data = talloc_zero(req,
654                                         struct ldb_extended_dn_control);
655                         ext_ctrl_data->type = 1;
656
657                         ret = ldb_request_add_control(req_extended_dn,
658                                               LDB_CONTROL_EXTENDED_DN_OID,
659                                                       true,
660                                                       ext_ctrl_data);
661                         if (ret != LDB_SUCCESS) {
662                                 return ret;
663                         }
664                         controls = req_extended_dn->controls;
665                 }
666
667                 ret = ldb_build_search_req_ex(&search_req, ldb, ac,
668                                                 req->op.search.base,
669                                                 req->op.search.scope,
670                                                 req->op.search.tree,
671                                                 attrs,
672                                                 controls,
673                                                 ac,
674                                                 paged_search_callback,
675                                                 req);
676                 if (ret != LDB_SUCCESS) {
677                         return ret;
678                 }
679
680                 ac->store->expr = talloc_steal(ac->store, req->op.search.tree);
681                 ac->store->expr_str = ldb_filter_from_tree(ac->store,
682                                                           req->op.search.tree);
683                 ac->store->attrs = paged_copy_attrs(ac->store,
684                                                     req->op.search.attrs);
685
686                 /* save it locally and remove it from the list */
687                 /* we do not need to replace them later as we
688                  * are keeping the original req intact */
689                 if (!ldb_save_controls(control, search_req, NULL)) {
690                         return LDB_ERR_OPERATIONS_ERROR;
691                 }
692                 ac->store->down_controls =
693                     paged_results_copy_down_controls(ac->store, req->controls);
694                 if (ac->store->down_controls == NULL) {
695                         return LDB_ERR_OPERATIONS_ERROR;
696                 }
697
698                 return ldb_next_request(module, search_req);
699
700         } else {
701                 struct results_store *current = NULL;
702                 char *expr_str;
703                 bool bool_ret;
704
705                 /* TODO: age out old outstanding requests */
706                 for (current = private_data->store; current != NULL;
707                      current = current->next) {
708                         if (strcmp(current->cookie, paged_ctrl->cookie) == 0) {
709                                 current->timestamp = time(NULL);
710                                 break;
711                         }
712                 }
713                 if (current == NULL) {
714                         return LDB_ERR_UNWILLING_TO_PERFORM;
715                 }
716
717                 /* Get the expression string and make sure it didn't change */
718                 expr_str = ldb_filter_from_tree(ac, req->op.search.tree);
719                 if (expr_str == NULL) {
720                         return LDB_ERR_OPERATIONS_ERROR;
721                 }
722
723                 ret = strcmp(current->expr_str, expr_str);
724                 if (ret != 0) {
725                         return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
726                 }
727
728                 bool_ret = paged_controls_same(req, current->down_controls);
729                 if (bool_ret == false) {
730                         return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
731                 }
732
733                 bool_ret = paged_attrs_same(req->op.search.attrs,
734                                             current->attrs);
735                 if (bool_ret == false) {
736                         return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
737                 }
738
739                 DLIST_PROMOTE(private_data->store, current);
740
741                 ac->store = current;
742
743                 /* check if it is an abandon */
744                 if (ac->size == 0) {
745                         return ldb_module_done(req, NULL, NULL,
746                                                                 LDB_SUCCESS);
747                 }
748
749                 ret = paged_results(ac);
750                 if (ret != LDB_SUCCESS) {
751                         return ldb_module_done(req, NULL, NULL, ret);
752                 }
753                 return ldb_module_done(req, ac->controls, NULL, LDB_SUCCESS);
754         }
755 }
756
757 static int paged_request_init(struct ldb_module *module)
758 {
759         struct ldb_context *ldb;
760         struct private_data *data;
761         int ret;
762
763         ldb = ldb_module_get_ctx(module);
764
765         data = talloc(module, struct private_data);
766         if (data == NULL) {
767                 return LDB_ERR_OTHER;
768         }
769
770         data->next_free_id = 1;
771         data->num_stores = 0;
772         data->store = NULL;
773         ldb_module_set_private(module, data);
774
775         ret = ldb_mod_register_control(module, LDB_CONTROL_PAGED_RESULTS_OID);
776         if (ret != LDB_SUCCESS) {
777                 ldb_debug(ldb, LDB_DEBUG_WARNING,
778                         "paged_results:"
779                         "Unable to register control with rootdse!");
780         }
781
782         return ldb_next_init(module);
783 }
784
785 static const struct ldb_module_ops ldb_paged_results_module_ops = {
786         .name           = "dsdb_paged_results",
787         .search         = paged_search,
788         .init_context   = paged_request_init
789 };
790
791 int ldb_dsdb_paged_results_init(const char *version)
792 {
793         LDB_MODULE_CHECK_VERSION(version);
794         return ldb_register_module(&ldb_paged_results_module_ops);
795 }