Line data Source code
1 : /*
2 : ldb database library
3 :
4 : Copyright (C) Simo Sorce 2005-2008
5 : Copyright (C) Catalyst IT 2016
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: vlv_pagination
27 : *
28 : * Component: ldb vlv pagination 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 : * Originally based on paged_results.c by Simo Sorce
34 : * Modified by Douglas Bagnall and Garming Sam for Catalyst.
35 : */
36 :
37 : #include "includes.h"
38 : #include "auth/auth.h"
39 : #include <ldb.h>
40 : #include "dsdb/samdb/samdb.h"
41 : #include "libcli/security/security.h"
42 : #include "libcli/ldap/ldap_errors.h"
43 : #include <ldb.h>
44 : #include "replace.h"
45 : #include "system/filesys.h"
46 : #include "system/time.h"
47 : #include "ldb_module.h"
48 : #include "dsdb/samdb/samdb.h"
49 :
50 : #include "dsdb/common/util.h"
51 : #include "lib/util/binsearch.h"
52 :
53 : /* This is the number of concurrent searches per connection to cache. */
54 : #define VLV_N_SEARCHES 5
55 :
56 :
57 : struct results_store {
58 : uint32_t contextId;
59 : time_t timestamp;
60 :
61 : struct GUID *results;
62 : size_t num_entries;
63 : size_t result_array_size;
64 :
65 : struct referral_store *first_ref;
66 : struct referral_store *last_ref;
67 :
68 : struct ldb_control **controls;
69 : struct ldb_control **down_controls;
70 : struct ldb_vlv_req_control *vlv_details;
71 : struct ldb_server_sort_control *sort_details;
72 : };
73 :
74 : struct private_data {
75 : uint32_t next_free_id;
76 : struct results_store **store;
77 : int n_stores;
78 : };
79 :
80 :
81 : struct vlv_context {
82 : struct ldb_module *module;
83 : struct ldb_request *req;
84 : struct results_store *store;
85 : struct ldb_control **controls;
86 : struct private_data *priv;
87 : };
88 :
89 :
90 7753 : static struct results_store *new_store(struct private_data *priv)
91 : {
92 : struct results_store *store;
93 : int i;
94 7753 : int best = 0;
95 7753 : time_t oldest = TIME_T_MAX;
96 46268 : for (i = 0; i < priv->n_stores; i++) {
97 38593 : if (priv->store[i] == NULL) {
98 78 : best = i;
99 78 : break;
100 38515 : } else if (priv->store[i]->timestamp < oldest){
101 8065 : best = i;
102 8065 : oldest = priv->store[i]->timestamp;
103 : }
104 : }
105 :
106 7753 : store = talloc_zero(priv, struct results_store);
107 7753 : if (store == NULL) {
108 0 : return NULL;
109 : }
110 7753 : if (priv->store[best] != NULL) {
111 7675 : TALLOC_FREE(priv->store[best]);
112 : }
113 7753 : priv->store[best] = store;
114 7753 : store->timestamp = time(NULL);
115 7753 : return store;
116 : }
117 :
118 :
119 : struct vlv_sort_context {
120 : struct ldb_context *ldb;
121 : ldb_attr_comparison_t comparison_fn;
122 : const char *attr;
123 : struct vlv_context *ac;
124 : int status;
125 : struct ldb_val value;
126 : };
127 :
128 :
129 : /* Referrals are temporarily stored in a linked list */
130 : struct referral_store {
131 : char *ref;
132 : struct referral_store *next;
133 : };
134 :
135 : /*
136 : search for attrs on one DN, by the GUID of the DN, with true
137 : LDB controls
138 : */
139 :
140 274133 : static int vlv_search_by_dn_guid(struct ldb_module *module,
141 : struct vlv_context *ac,
142 : struct ldb_result **result,
143 : const struct GUID *guid,
144 : const char * const *attrs)
145 : {
146 : struct ldb_dn *dn;
147 : struct ldb_request *req;
148 : struct ldb_result *res;
149 : int ret;
150 : struct GUID_txt_buf guid_str;
151 274133 : struct ldb_control **controls = ac->store->down_controls;
152 274133 : struct ldb_context *ldb = ldb_module_get_ctx(module);
153 :
154 274133 : dn = ldb_dn_new_fmt(ac, ldb, "<GUID=%s>",
155 : GUID_buf_string(guid, &guid_str));
156 274133 : if (dn == NULL) {
157 0 : return ldb_oom(ldb);
158 : }
159 :
160 274133 : res = talloc_zero(ac, struct ldb_result);
161 274133 : if (res == NULL) {
162 0 : return ldb_oom(ldb);
163 : }
164 :
165 274133 : ret = ldb_build_search_req(&req, ldb, ac,
166 : dn,
167 : LDB_SCOPE_BASE,
168 : NULL,
169 : attrs,
170 : controls,
171 : res,
172 : ldb_search_default_callback,
173 : ac->req);
174 274133 : if (ret != LDB_SUCCESS) {
175 0 : talloc_free(res);
176 0 : return ret;
177 : }
178 :
179 274133 : ret = ldb_request(ldb, req);
180 274133 : if (ret == LDB_SUCCESS) {
181 274133 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
182 : }
183 :
184 274133 : talloc_free(req);
185 274133 : if (ret != LDB_SUCCESS) {
186 35247 : talloc_free(res);
187 35247 : return ret;
188 : }
189 :
190 238886 : *result = res;
191 238886 : return ret;
192 : }
193 :
194 :
195 2541 : static int save_referral(struct results_store *store, char *ref)
196 : {
197 2541 : struct referral_store *node = talloc(store,
198 : struct referral_store);
199 2541 : if (node == NULL) {
200 0 : return LDB_ERR_OPERATIONS_ERROR;
201 : }
202 2541 : node->next = NULL;
203 2541 : node->ref = talloc_steal(node, ref);
204 :
205 2541 : if (store->first_ref == NULL) {
206 847 : store->first_ref = node;
207 : } else {
208 1694 : store->last_ref->next = node;
209 : }
210 2541 : store->last_ref = node;
211 2541 : return LDB_SUCCESS;
212 : }
213 :
214 847 : static int send_referrals(struct results_store *store,
215 : struct ldb_request *req)
216 : {
217 : int ret;
218 : struct referral_store *node;
219 4235 : while (store->first_ref != NULL) {
220 2541 : node = store->first_ref;
221 2541 : ret = ldb_module_send_referral(req, node->ref);
222 2541 : if (ret != LDB_SUCCESS) {
223 0 : return ret;
224 : }
225 2541 : store->first_ref = node->next;
226 2541 : talloc_free(node);
227 : }
228 847 : return LDB_SUCCESS;
229 : }
230 :
231 :
232 : /* vlv_value_compare() is used in a binary search */
233 :
234 48444 : static int vlv_value_compare(struct vlv_sort_context *target,
235 : struct GUID *guid)
236 : {
237 48444 : struct ldb_result *result = NULL;
238 48444 : struct ldb_message_element *el = NULL;
239 48444 : struct vlv_context *ac = target->ac;
240 : int ret;
241 48444 : const char *attrs[2] = {
242 48444 : target->attr,
243 : NULL
244 : };
245 :
246 48444 : ret = vlv_search_by_dn_guid(ac->module, ac, &result, guid, attrs);
247 :
248 48444 : if (ret != LDB_SUCCESS) {
249 0 : target->status = ret;
250 : /* returning 0 ends the search. */
251 0 : return 0;
252 : }
253 :
254 48444 : el = ldb_msg_find_element(result->msgs[0], target->attr);
255 96888 : return target->comparison_fn(target->ldb, ac,
256 48444 : &target->value, &el->values[0]);
257 :
258 : }
259 :
260 : /* The same as vlv_value_compare() but sorting in the opposite direction. */
261 0 : static int vlv_value_compare_rev(struct vlv_sort_context *target,
262 : struct GUID *guid)
263 : {
264 0 : return -vlv_value_compare(target, guid);
265 : }
266 :
267 :
268 :
269 : /* Convert a "greater than or equal to" VLV query into an index. This is
270 : zero-based, so one less than the equivalent VLV offset query.
271 :
272 : If the query value is greater than (or less than in the reverse case) all
273 : the items, An index just beyond the last position is used.
274 :
275 : If an error occurs during the search for the index, we stash it in the
276 : status argument.
277 : */
278 :
279 16005 : static int vlv_gt_eq_to_index(struct vlv_context *ac,
280 : struct GUID *guid_array,
281 : struct ldb_vlv_req_control *vlv_details,
282 : struct ldb_server_sort_control *sort_details,
283 : int *status)
284 : {
285 : /* this has a >= comparison string, which needs to be
286 : * converted into indices.
287 : */
288 16005 : size_t len = ac->store->num_entries;
289 : struct ldb_context *ldb;
290 : const struct ldb_schema_attribute *a;
291 16005 : struct GUID *result = NULL;
292 : struct vlv_sort_context context;
293 32010 : struct ldb_val value = {
294 16005 : .data = (uint8_t *)vlv_details->match.gtOrEq.value,
295 16005 : .length = vlv_details->match.gtOrEq.value_len
296 : };
297 16005 : ldb = ldb_module_get_ctx(ac->module);
298 16005 : a = ldb_schema_attribute_by_name(ldb, sort_details->attributeName);
299 :
300 16005 : context = (struct vlv_sort_context){
301 : .ldb = ldb,
302 16005 : .comparison_fn = a->syntax->comparison_fn,
303 16005 : .attr = sort_details->attributeName,
304 : .ac = ac,
305 : .status = LDB_SUCCESS,
306 : .value = value
307 : };
308 :
309 16005 : if (sort_details->reverse) {
310 : /* when the sort is reversed, "gtOrEq" means
311 : "less than or equal" */
312 0 : BINARY_ARRAY_SEARCH_GTE(guid_array, len, &context,
313 : vlv_value_compare_rev,
314 : result, result);
315 : } else {
316 16005 : BINARY_ARRAY_SEARCH_GTE(guid_array, len, &context,
317 : vlv_value_compare,
318 : result, result);
319 : }
320 16005 : if (context.status != LDB_SUCCESS) {
321 0 : *status = context.status;
322 0 : return len;
323 : }
324 16005 : *status = LDB_SUCCESS;
325 :
326 16005 : if (result == NULL) {
327 : /* the target is beyond the end of the array */
328 4246 : return len;
329 : }
330 11759 : return result - guid_array;
331 :
332 : }
333 :
334 : /* return the zero-based index into the sorted results, or -1 on error.
335 :
336 : The VLV index is one-base, so one greater than this.
337 : */
338 :
339 30753 : static int vlv_calc_real_offset(int offset, int denominator, int n_entries)
340 : {
341 : double fraction;
342 :
343 : /* An offset of 0 (or less) is an error, unless the denominator is
344 : also zero. */
345 30753 : if (offset <= 0 && denominator != 0) {
346 0 : return -1;
347 : }
348 :
349 : /* a denominator of zero means the server should use the estimated
350 : number of entries. */
351 30753 : if (denominator == 0) {
352 5956 : if (offset == 0) {
353 : /* 0/0 means the last one */
354 0 : return n_entries - 1;
355 : }
356 5956 : denominator = n_entries;
357 : }
358 :
359 30753 : if (denominator == 1) {
360 : /* The 1/1 case means the LAST index.
361 : Strangely, for n > 1, n/1 means the FIRST index.
362 : */
363 120 : if (offset == 1) {
364 40 : return n_entries - 1;
365 : }
366 80 : return 0;
367 : }
368 :
369 30633 : if (offset >= denominator) {
370 : /* we want the last one */
371 2457 : return n_entries - 1;
372 : }
373 : /* if the denominator is exactly the number of entries, the offset is
374 : already correct. */
375 :
376 28176 : if (denominator == n_entries) {
377 21336 : return offset - 1;
378 : }
379 :
380 : /* The following formula was discovered by probing Windows. */
381 6840 : fraction = (offset - 1.0) / (denominator - 1.0);
382 6840 : return (int)(fraction * (n_entries - 1.0) + 0.5);
383 : }
384 :
385 :
386 : /* vlv_results() is called when there is a valid contextID -- meaning the search
387 : has been prepared earlier and saved -- or by vlv_search_callback() when a
388 : search has just been completed. */
389 :
390 53028 : static int vlv_results(struct vlv_context *ac, struct ldb_reply *ares)
391 : {
392 : struct ldb_vlv_resp_control *vlv;
393 : unsigned int num_ctrls;
394 : int ret, i, first_i, last_i;
395 : struct ldb_vlv_req_control *vlv_details;
396 : struct ldb_server_sort_control *sort_details;
397 53028 : int target = 0;
398 :
399 53028 : if (ac->store == NULL) {
400 0 : ret = LDB_ERR_OPERATIONS_ERROR;
401 0 : return ldb_module_done(
402 : ac->req, ac->controls, ares->response, ret);
403 : }
404 :
405 53028 : if (ac->store->first_ref) {
406 : /* There is no right place to put references in the sorted
407 : results, so we send them as soon as possible.
408 : */
409 847 : ret = send_referrals(ac->store, ac->req);
410 847 : if (ret != LDB_SUCCESS) {
411 : /*
412 : * send_referrals will have called ldb_module_done
413 : * if there was an error.
414 : */
415 0 : return ret;
416 : }
417 : }
418 :
419 53028 : vlv_details = ac->store->vlv_details;
420 53028 : sort_details = ac->store->sort_details;
421 :
422 53028 : if (ac->store->num_entries != 0) {
423 46758 : if (vlv_details->type == 1) {
424 16005 : target = vlv_gt_eq_to_index(ac, ac->store->results,
425 : vlv_details,
426 : sort_details, &ret);
427 16005 : if (ret != LDB_SUCCESS) {
428 0 : return ldb_module_done(
429 : ac->req,
430 : ac->controls,
431 : ares->response,
432 : ret);
433 : }
434 : } else {
435 30753 : target = vlv_calc_real_offset(vlv_details->match.byOffset.offset,
436 : vlv_details->match.byOffset.contentCount,
437 30753 : ac->store->num_entries);
438 30753 : if (target == -1) {
439 0 : ret = LDB_ERR_OPERATIONS_ERROR;
440 0 : return ldb_module_done(
441 : ac->req,
442 : ac->controls,
443 : ares->response,
444 : ret);
445 : }
446 : }
447 :
448 : /* send the results */
449 46758 : first_i = MAX(target - vlv_details->beforeCount, 0);
450 46758 : last_i = MIN(target + vlv_details->afterCount,
451 : ac->store->num_entries - 1);
452 :
453 272447 : for (i = first_i; i <= last_i; i++) {
454 225689 : struct ldb_result *result = NULL;
455 225689 : struct GUID *guid = &ac->store->results[i];
456 :
457 225689 : ret = vlv_search_by_dn_guid(ac->module, ac, &result, guid,
458 225689 : ac->req->op.search.attrs);
459 :
460 225689 : if (ret == LDAP_NO_SUCH_OBJECT
461 190442 : || result->count != 1) {
462 : /*
463 : * The thing isn't there, which we quietly
464 : * ignore and go on to send an extra one
465 : * instead.
466 : *
467 : * result->count == 0 or > 1 can only
468 : * happen if ASQ (which breaks all the
469 : * rules) is somehow invoked (as this
470 : * is a BASE search).
471 : *
472 : * (We skip the ASQ cookie for the
473 : * GUID searches)
474 : */
475 35247 : if (last_i < ac->store->num_entries - 1) {
476 13342 : last_i++;
477 : }
478 35247 : continue;
479 190442 : } else if (ret != LDB_SUCCESS) {
480 0 : return ldb_module_done(
481 : ac->req,
482 : ac->controls,
483 : ares->response,
484 : ret);
485 : }
486 :
487 190442 : ret = ldb_module_send_entry(ac->req, result->msgs[0],
488 : NULL);
489 190442 : if (ret != LDB_SUCCESS) {
490 : /*
491 : * ldb_module_send_entry will have called
492 : * ldb_module_done if there was an error
493 : */
494 0 : return ret;
495 : }
496 : }
497 : } else {
498 6270 : target = -1;
499 : }
500 :
501 : /* return result done */
502 53028 : num_ctrls = 1;
503 53028 : i = 0;
504 :
505 53028 : if (ac->store->controls != NULL) {
506 3 : while (ac->store->controls[i]){
507 1 : i++; /* counting */
508 : }
509 1 : num_ctrls += i;
510 : }
511 :
512 53028 : ac->controls = talloc_array(ac, struct ldb_control *, num_ctrls + 1);
513 53028 : if (ac->controls == NULL) {
514 0 : ret = LDB_ERR_OPERATIONS_ERROR;
515 0 : return ldb_module_done(
516 : ac->req, ac->controls, ares->response, ret);
517 : }
518 53028 : ac->controls[num_ctrls] = NULL;
519 :
520 53029 : for (i = 0; i < (num_ctrls -1); i++) {
521 1 : ac->controls[i] = talloc_reference(ac->controls, ac->store->controls[i]);
522 : }
523 :
524 53028 : ac->controls[i] = talloc(ac->controls, struct ldb_control);
525 53028 : if (ac->controls[i] == NULL) {
526 0 : ret = LDB_ERR_OPERATIONS_ERROR;
527 0 : return ldb_module_done(
528 : ac->req, ac->controls, ares->response, ret);
529 : }
530 :
531 53028 : ac->controls[i]->oid = talloc_strdup(ac->controls[i],
532 : LDB_CONTROL_VLV_RESP_OID);
533 53028 : if (ac->controls[i]->oid == NULL) {
534 0 : ret = LDB_ERR_OPERATIONS_ERROR;
535 0 : return ldb_module_done(
536 : ac->req, ac->controls, ares->response, ret);
537 : }
538 :
539 53028 : ac->controls[i]->critical = 0;
540 :
541 53028 : vlv = talloc(ac->controls[i], struct ldb_vlv_resp_control);
542 53028 : if (vlv == NULL) {
543 0 : ret = LDB_ERR_OPERATIONS_ERROR;
544 0 : return ldb_module_done(
545 : ac->req, ac->controls, ares->response, ret);
546 : }
547 53028 : ac->controls[i]->data = vlv;
548 :
549 53028 : ac->store->timestamp = time(NULL);
550 :
551 53028 : ac->store->contextId = ac->priv->next_free_id;
552 53028 : ac->priv->next_free_id++;
553 53028 : vlv->contextId = talloc_memdup(vlv, &ac->store->contextId, sizeof(uint32_t));
554 53028 : vlv->ctxid_len = sizeof(uint32_t);
555 53028 : vlv->vlv_result = 0;
556 53028 : vlv->contentCount = ac->store->num_entries;
557 53028 : if (target >= 0) {
558 46758 : vlv->targetPosition = target + 1;
559 6270 : } else if (vlv_details->type == 1) {
560 6270 : vlv->targetPosition = ac->store->num_entries + 1;
561 : } else {
562 0 : vlv->targetPosition = 0;
563 : }
564 53028 : return LDB_SUCCESS;
565 : }
566 :
567 :
568 : /* vlv_search_callback() collects GUIDs found by the original search */
569 :
570 558449 : static int vlv_search_callback(struct ldb_request *req, struct ldb_reply *ares)
571 : {
572 : struct vlv_context *ac;
573 : struct results_store *store;
574 : int ret;
575 :
576 558449 : ac = talloc_get_type(req->context, struct vlv_context);
577 558449 : store = ac->store;
578 :
579 558449 : if (!ares) {
580 0 : return ldb_module_done(ac->req, NULL, NULL,
581 : LDB_ERR_OPERATIONS_ERROR);
582 : }
583 558449 : if (ares->error != LDB_SUCCESS) {
584 0 : return ldb_module_done(ac->req, ares->controls,
585 : ares->response, ares->error);
586 : }
587 :
588 558449 : switch (ares->type) {
589 548155 : case LDB_REPLY_ENTRY:
590 548155 : if (store->results == NULL) {
591 7733 : store->num_entries = 0;
592 7733 : store->result_array_size = 16;
593 7733 : store->results = talloc_array(store, struct GUID,
594 : store->result_array_size);
595 7733 : if (store->results == NULL) {
596 0 : return ldb_module_done(ac->req, NULL, NULL,
597 : LDB_ERR_OPERATIONS_ERROR);
598 : }
599 540422 : } else if (store->num_entries == store->result_array_size) {
600 10977 : store->result_array_size *= 2;
601 10977 : store->results = talloc_realloc(store, store->results,
602 : struct GUID,
603 : store->result_array_size);
604 10977 : if (store->results == NULL) {
605 0 : return ldb_module_done(ac->req, NULL, NULL,
606 : LDB_ERR_OPERATIONS_ERROR);
607 : }
608 : }
609 548155 : store->results[store->num_entries] = \
610 548155 : samdb_result_guid(ares->message, "objectGUID");
611 548155 : store->num_entries++;
612 548155 : break;
613 :
614 2541 : case LDB_REPLY_REFERRAL:
615 2541 : ret = save_referral(store, ares->referral);
616 2541 : if (ret != LDB_SUCCESS) {
617 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
618 : }
619 2541 : break;
620 :
621 7753 : case LDB_REPLY_DONE:
622 7753 : if (store->num_entries != 0) {
623 7733 : store->results = talloc_realloc(store, store->results,
624 : struct GUID,
625 : store->num_entries);
626 7733 : if (store->results == NULL) {
627 0 : return ldb_module_done(ac->req, NULL, NULL,
628 : LDB_ERR_OPERATIONS_ERROR);
629 : }
630 : }
631 7753 : store->result_array_size = store->num_entries;
632 :
633 7753 : ac->store->controls = talloc_move(ac->store, &ares->controls);
634 7753 : ret = vlv_results(ac, ares);
635 7753 : if (ret != LDB_SUCCESS) {
636 : /* vlv_results will have called ldb_module_done
637 : * if there was an error.
638 : */
639 0 : return ret;
640 : }
641 7753 : return ldb_module_done(ac->req, ac->controls,
642 : ares->response, ret);
643 : }
644 :
645 550696 : return LDB_SUCCESS;
646 : }
647 :
648 53028 : static int copy_search_details(struct results_store *store,
649 : struct ldb_vlv_req_control *vlv_ctrl,
650 : struct ldb_server_sort_control *sort_ctrl)
651 : {
652 : /* free the old details which are no longer going to be reachable. */
653 53028 : if (store->vlv_details != NULL){
654 45275 : TALLOC_FREE(store->vlv_details);
655 : }
656 :
657 53028 : if (store->sort_details != NULL){
658 45275 : TALLOC_FREE(store->sort_details);
659 : }
660 :
661 53028 : store->vlv_details = talloc(store, struct ldb_vlv_req_control);
662 53028 : if (store->vlv_details == NULL) {
663 0 : return LDB_ERR_OPERATIONS_ERROR;
664 : }
665 53028 : *store->vlv_details = *vlv_ctrl;
666 53028 : store->vlv_details->contextId = talloc_memdup(store, vlv_ctrl->contextId,
667 : vlv_ctrl->ctxid_len);
668 53028 : if (store->vlv_details->contextId == NULL) {
669 0 : return LDB_ERR_OPERATIONS_ERROR;
670 : }
671 :
672 53028 : if (vlv_ctrl->type == 1) {
673 22275 : char *v = talloc_array(store, char,
674 : vlv_ctrl->match.gtOrEq.value_len + 1);
675 :
676 22275 : if (v == NULL) {
677 0 : return LDB_ERR_OPERATIONS_ERROR;
678 : }
679 :
680 22275 : memcpy(v, vlv_ctrl->match.gtOrEq.value, vlv_ctrl->match.gtOrEq.value_len);
681 22275 : v[vlv_ctrl->match.gtOrEq.value_len] = '\0';
682 :
683 22275 : store->vlv_details->match.gtOrEq.value = v;
684 : }
685 :
686 53028 : store->sort_details = talloc(store, struct ldb_server_sort_control);
687 53028 : if (store->sort_details == NULL) {
688 0 : return LDB_ERR_OPERATIONS_ERROR;
689 : }
690 53028 : store->sort_details->attributeName = talloc_strdup(store,
691 : sort_ctrl->attributeName);
692 53028 : if (store->sort_details->attributeName == NULL) {
693 0 : return LDB_ERR_OPERATIONS_ERROR;
694 : }
695 :
696 53028 : if (sort_ctrl->orderingRule == NULL) {
697 53028 : store->sort_details->orderingRule = NULL;
698 : } else {
699 0 : store->sort_details->orderingRule = talloc_strdup(store,
700 : sort_ctrl->orderingRule);
701 0 : if (store->sort_details->orderingRule == NULL) {
702 0 : return LDB_ERR_OPERATIONS_ERROR;
703 : }
704 : }
705 53028 : store->sort_details->reverse = sort_ctrl->reverse;
706 :
707 53028 : return LDB_SUCCESS;
708 : }
709 :
710 :
711 : static struct ldb_control **
712 7753 : vlv_copy_down_controls(TALLOC_CTX *mem_ctx, struct ldb_control **controls)
713 : {
714 :
715 : struct ldb_control **new_controls;
716 : unsigned int i, j, num_ctrls;
717 7753 : if (controls == NULL) {
718 0 : return NULL;
719 : }
720 :
721 7753 : for (num_ctrls = 0; controls[num_ctrls]; num_ctrls++);
722 :
723 7753 : new_controls = talloc_array(mem_ctx, struct ldb_control *, num_ctrls);
724 7753 : if (new_controls == NULL) {
725 0 : return NULL;
726 : }
727 :
728 24238 : for (j = 0, i = 0; i < (num_ctrls); i++) {
729 24237 : struct ldb_control *control = controls[i];
730 24237 : if (control->oid == NULL) {
731 7752 : break;
732 : }
733 : /*
734 : * Do not re-use VLV, nor the server-sort, both are
735 : * already handled here.
736 : */
737 25217 : if (strcmp(control->oid, LDB_CONTROL_VLV_REQ_OID) == 0 ||
738 8732 : strcmp(control->oid, LDB_CONTROL_SERVER_SORT_OID) == 0) {
739 15506 : continue;
740 : }
741 : /*
742 : * ASQ changes everything, do not copy it down for the
743 : * per-GUID search
744 : */
745 979 : if (strcmp(control->oid, LDB_CONTROL_ASQ_OID) == 0) {
746 1 : continue;
747 : }
748 978 : new_controls[j] = talloc_steal(new_controls, control);
749 : /*
750 : * Sadly the caller is not obliged to make this a
751 : * proper talloc tree, so we do so here.
752 : */
753 978 : if (control->data) {
754 1 : talloc_steal(control, control->data);
755 : }
756 978 : j++;
757 : }
758 7753 : new_controls[j] = NULL;
759 7753 : return new_controls;
760 : }
761 :
762 14385816 : static int vlv_search(struct ldb_module *module, struct ldb_request *req)
763 : {
764 : struct ldb_context *ldb;
765 : struct ldb_control *control;
766 : struct ldb_control *sort_control;
767 : struct private_data *priv;
768 : struct ldb_vlv_req_control *vlv_ctrl;
769 : struct ldb_server_sort_control **sort_ctrl;
770 : struct ldb_request *search_req;
771 : struct vlv_context *ac;
772 : int ret, i, critical;
773 :
774 14385816 : ldb = ldb_module_get_ctx(module);
775 :
776 14385816 : control = ldb_request_get_control(req, LDB_CONTROL_VLV_REQ_OID);
777 14385816 : if (control == NULL) {
778 : /* There is no VLV. go on */
779 14332785 : return ldb_next_request(module, req);
780 : }
781 53031 : critical = control->critical;
782 53031 : control->critical = 0;
783 :
784 53031 : sort_control = ldb_request_get_control(req, LDB_CONTROL_SERVER_SORT_OID);
785 53031 : if (sort_control == NULL) {
786 : /* VLV needs sort */
787 0 : return LDB_ERR_OPERATIONS_ERROR;
788 : }
789 :
790 53031 : vlv_ctrl = talloc_get_type(control->data, struct ldb_vlv_req_control);
791 53031 : if (vlv_ctrl == NULL) {
792 0 : return LDB_ERR_OPERATIONS_ERROR;
793 : }
794 :
795 53031 : sort_ctrl = talloc_get_type(sort_control->data, struct ldb_server_sort_control *);
796 53031 : if (sort_ctrl == NULL) {
797 0 : return LDB_ERR_OPERATIONS_ERROR;
798 : }
799 :
800 53031 : priv = talloc_get_type(ldb_module_get_private(module),
801 : struct private_data);
802 :
803 53031 : ac = talloc_zero(req, struct vlv_context);
804 53031 : if (ac == NULL) {
805 0 : ldb_set_errstring(ldb, "Out of Memory");
806 0 : return LDB_ERR_OPERATIONS_ERROR;
807 : }
808 :
809 53031 : ac->module = module;
810 53031 : ac->req = req;
811 53031 : ac->priv = priv;
812 : /* If there is no cookie, this is a new request, and we need to do the
813 : * search in the database. Otherwise we try to refer to a previously
814 : * saved search.
815 : */
816 53031 : if (vlv_ctrl->ctxid_len == 0) {
817 : static const char * const attrs[2] = {
818 : "objectGUID", NULL
819 : };
820 :
821 7753 : ac->store = new_store(priv);
822 7753 : if (ac->store == NULL) {
823 0 : return LDB_ERR_OPERATIONS_ERROR;
824 : }
825 :
826 7753 : ret = copy_search_details(ac->store, vlv_ctrl, sort_ctrl[0]);
827 7753 : if (ret != LDB_SUCCESS) {
828 0 : return ret;
829 : }
830 :
831 7753 : ret = ldb_build_search_req_ex(&search_req, ldb, ac,
832 : req->op.search.base,
833 : req->op.search.scope,
834 : req->op.search.tree,
835 : attrs,
836 : req->controls,
837 : ac,
838 : vlv_search_callback,
839 : req);
840 7753 : if (ret != LDB_SUCCESS) {
841 0 : return ret;
842 : }
843 : /* save it locally and remove it from the list */
844 : /* we do not need to replace them later as we
845 : * are keeping the original req intact */
846 7753 : if (!ldb_save_controls(control, search_req, NULL)) {
847 0 : return LDB_ERR_OPERATIONS_ERROR;
848 : }
849 :
850 7753 : ac->store->down_controls = vlv_copy_down_controls(ac->store,
851 : req->controls);
852 :
853 7753 : if (ac->store->down_controls == NULL) {
854 0 : return LDB_ERR_OPERATIONS_ERROR;
855 : }
856 :
857 7753 : return ldb_next_request(module, search_req);
858 :
859 : } else {
860 45278 : struct results_store *current = NULL;
861 45278 : uint8_t *id = vlv_ctrl->contextId;
862 :
863 45278 : if (vlv_ctrl->ctxid_len != sizeof(uint32_t)){
864 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
865 : }
866 :
867 130569 : for (i = 0; i < priv->n_stores; i++) {
868 130566 : current = priv->store[i];
869 130566 : if (current == NULL) {
870 10 : continue;
871 : }
872 130556 : if (memcmp(¤t->contextId, id, sizeof(uint32_t)) == 0) {
873 45275 : current->timestamp = time(NULL);
874 45275 : break;
875 : }
876 : }
877 45278 : if (i == priv->n_stores) {
878 : /* We were given a context id that we don't know about. */
879 3 : if (critical) {
880 2 : return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
881 : } else {
882 1 : return ldb_next_request(module, req);
883 : }
884 : }
885 :
886 45275 : ac->store = current;
887 45275 : ret = copy_search_details(ac->store, vlv_ctrl, sort_ctrl[0]);
888 45275 : if (ret != LDB_SUCCESS) {
889 0 : return ret;
890 : }
891 :
892 45275 : ret = vlv_results(ac, NULL);
893 45275 : if (ret != LDB_SUCCESS) {
894 0 : return ret;
895 : }
896 45275 : return ldb_module_done(req, ac->controls, NULL,
897 : LDB_SUCCESS);
898 : }
899 : }
900 :
901 :
902 132453 : static int vlv_request_init(struct ldb_module *module)
903 : {
904 : struct ldb_context *ldb;
905 : struct private_data *data;
906 : int ret;
907 :
908 132453 : ldb = ldb_module_get_ctx(module);
909 :
910 132453 : data = talloc(module, struct private_data);
911 132453 : if (data == NULL) {
912 0 : return LDB_ERR_OTHER;
913 : }
914 :
915 132453 : data->next_free_id = 1;
916 132453 : data->n_stores = VLV_N_SEARCHES;
917 132453 : data->store = talloc_zero_array(data, struct results_store *, data->n_stores);
918 :
919 132453 : ldb_module_set_private(module, data);
920 :
921 132453 : ret = ldb_mod_register_control(module, LDB_CONTROL_VLV_REQ_OID);
922 132453 : if (ret != LDB_SUCCESS) {
923 0 : ldb_debug(ldb, LDB_DEBUG_WARNING,
924 : "vlv:"
925 : "Unable to register control with rootdse!");
926 : }
927 :
928 132453 : return ldb_next_init(module);
929 : }
930 :
931 : static const struct ldb_module_ops ldb_vlv_module_ops = {
932 : .name = "vlv",
933 : .search = vlv_search,
934 : .init_context = vlv_request_init
935 : };
936 :
937 5536 : int ldb_vlv_init(const char *version)
938 : {
939 5536 : LDB_MODULE_CHECK_VERSION(version);
940 5536 : return ldb_register_module(&ldb_vlv_module_ops);
941 : }
|