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 0 : struct results_store *store;
93 0 : 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 8033 : best = i;
102 8033 : 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 274180 : 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 0 : struct ldb_dn *dn;
147 0 : struct ldb_request *req;
148 0 : struct ldb_result *res;
149 0 : int ret;
150 0 : struct GUID_txt_buf guid_str;
151 274180 : struct ldb_control **controls = ac->store->down_controls;
152 274180 : struct ldb_context *ldb = ldb_module_get_ctx(module);
153 :
154 274180 : dn = ldb_dn_new_fmt(ac, ldb, "<GUID=%s>",
155 : GUID_buf_string(guid, &guid_str));
156 274180 : if (dn == NULL) {
157 0 : return ldb_oom(ldb);
158 : }
159 :
160 274180 : res = talloc_zero(ac, struct ldb_result);
161 274180 : if (res == NULL) {
162 0 : return ldb_oom(ldb);
163 : }
164 :
165 274180 : 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 274180 : if (ret != LDB_SUCCESS) {
175 0 : talloc_free(res);
176 0 : return ret;
177 : }
178 :
179 274180 : ret = ldb_request(ldb, req);
180 274180 : if (ret == LDB_SUCCESS) {
181 274180 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
182 : }
183 :
184 274180 : talloc_free(req);
185 274180 : if (ret != LDB_SUCCESS) {
186 35362 : talloc_free(res);
187 35362 : return ret;
188 : }
189 :
190 238818 : *result = res;
191 238818 : 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 0 : int ret;
218 0 : struct referral_store *node;
219 3388 : 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 48477 : static int vlv_value_compare(struct vlv_sort_context *target,
235 : struct GUID *guid)
236 : {
237 48477 : struct ldb_result *result = NULL;
238 48477 : struct ldb_message_element *el = NULL;
239 48477 : struct vlv_context *ac = target->ac;
240 0 : int ret;
241 48477 : const char *attrs[2] = {
242 48477 : target->attr,
243 : NULL
244 : };
245 :
246 48477 : ret = vlv_search_by_dn_guid(ac->module, ac, &result, guid, attrs);
247 :
248 48477 : if (ret != LDB_SUCCESS) {
249 0 : target->status = ret;
250 : /* returning 0 ends the search. */
251 0 : return 0;
252 : }
253 :
254 48477 : el = ldb_msg_find_element(result->msgs[0], target->attr);
255 48477 : return target->comparison_fn(target->ldb, ac,
256 48477 : &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 0 : struct ldb_context *ldb;
290 0 : const struct ldb_schema_attribute *a;
291 16005 : struct GUID *result = NULL;
292 0 : struct vlv_sort_context context;
293 16005 : 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 64482 : 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 4301 : return len;
329 : }
330 11704 : 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 0 : 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 53028 : struct ldb_extended *response = (ares != NULL ? ares->response : NULL);
393 0 : struct ldb_vlv_resp_control *vlv;
394 0 : unsigned int num_ctrls;
395 0 : int ret, i, first_i, last_i;
396 0 : struct ldb_vlv_req_control *vlv_details;
397 0 : struct ldb_server_sort_control *sort_details;
398 53028 : int target = 0;
399 :
400 53028 : if (ac->store == NULL) {
401 0 : ret = LDB_ERR_OPERATIONS_ERROR;
402 0 : return ldb_module_done(
403 : ac->req, ac->controls, response, ret);
404 : }
405 :
406 53028 : if (ac->store->first_ref) {
407 : /* There is no right place to put references in the sorted
408 : results, so we send them as soon as possible.
409 : */
410 847 : ret = send_referrals(ac->store, ac->req);
411 847 : if (ret != LDB_SUCCESS) {
412 : /*
413 : * send_referrals will have called ldb_module_done
414 : * if there was an error.
415 : */
416 0 : return ret;
417 : }
418 : }
419 :
420 53028 : vlv_details = ac->store->vlv_details;
421 53028 : sort_details = ac->store->sort_details;
422 :
423 53028 : if (ac->store->num_entries != 0) {
424 46758 : if (vlv_details->type == 1) {
425 16005 : target = vlv_gt_eq_to_index(ac, ac->store->results,
426 : vlv_details,
427 : sort_details, &ret);
428 16005 : if (ret != LDB_SUCCESS) {
429 0 : return ldb_module_done(
430 : ac->req,
431 : ac->controls,
432 : response,
433 : ret);
434 : }
435 : } else {
436 30753 : target = vlv_calc_real_offset(vlv_details->match.byOffset.offset,
437 : vlv_details->match.byOffset.contentCount,
438 30753 : ac->store->num_entries);
439 30753 : if (target == -1) {
440 0 : ret = LDB_ERR_OPERATIONS_ERROR;
441 0 : return ldb_module_done(
442 : ac->req,
443 : ac->controls,
444 : response,
445 : ret);
446 : }
447 : }
448 :
449 : /* send the results */
450 46758 : first_i = MAX(target - vlv_details->beforeCount, 0);
451 46758 : last_i = MIN(target + vlv_details->afterCount,
452 : ac->store->num_entries - 1);
453 :
454 272461 : for (i = first_i; i <= last_i; i++) {
455 225703 : struct ldb_result *result = NULL;
456 225703 : struct GUID *guid = &ac->store->results[i];
457 :
458 451406 : ret = vlv_search_by_dn_guid(ac->module, ac, &result, guid,
459 225703 : ac->req->op.search.attrs);
460 :
461 225703 : if (ret == LDAP_NO_SUCH_OBJECT
462 190341 : || result->count != 1) {
463 : /*
464 : * The thing isn't there, which we quietly
465 : * ignore and go on to send an extra one
466 : * instead.
467 : *
468 : * result->count == 0 or > 1 can only
469 : * happen if ASQ (which breaks all the
470 : * rules) is somehow invoked (as this
471 : * is a BASE search).
472 : *
473 : * (We skip the ASQ cookie for the
474 : * GUID searches)
475 : */
476 35362 : if (last_i < ac->store->num_entries - 1) {
477 13403 : last_i++;
478 : }
479 35362 : continue;
480 190341 : } else if (ret != LDB_SUCCESS) {
481 0 : return ldb_module_done(
482 : ac->req,
483 : ac->controls,
484 : response,
485 : ret);
486 : }
487 :
488 190341 : ret = ldb_module_send_entry(ac->req, result->msgs[0],
489 : NULL);
490 190341 : if (ret != LDB_SUCCESS) {
491 : /*
492 : * ldb_module_send_entry will have called
493 : * ldb_module_done if there was an error
494 : */
495 0 : return ret;
496 : }
497 : }
498 : } else {
499 6270 : target = -1;
500 : }
501 :
502 : /* return result done */
503 53028 : num_ctrls = 1;
504 53028 : i = 0;
505 :
506 53028 : if (ac->store->controls != NULL) {
507 2 : while (ac->store->controls[i]){
508 1 : i++; /* counting */
509 : }
510 1 : num_ctrls += i;
511 : }
512 :
513 53028 : ac->controls = talloc_array(ac, struct ldb_control *, num_ctrls + 1);
514 53028 : if (ac->controls == NULL) {
515 0 : ret = LDB_ERR_OPERATIONS_ERROR;
516 0 : return ldb_module_done(
517 : ac->req, ac->controls, response, ret);
518 : }
519 53028 : ac->controls[num_ctrls] = NULL;
520 :
521 53029 : for (i = 0; i < (num_ctrls -1); i++) {
522 1 : ac->controls[i] = talloc_reference(ac->controls, ac->store->controls[i]);
523 : }
524 :
525 53028 : ac->controls[i] = talloc(ac->controls, struct ldb_control);
526 53028 : if (ac->controls[i] == NULL) {
527 0 : ret = LDB_ERR_OPERATIONS_ERROR;
528 0 : return ldb_module_done(
529 : ac->req, ac->controls, response, ret);
530 : }
531 :
532 53028 : ac->controls[i]->oid = talloc_strdup(ac->controls[i],
533 : LDB_CONTROL_VLV_RESP_OID);
534 53028 : if (ac->controls[i]->oid == NULL) {
535 0 : ret = LDB_ERR_OPERATIONS_ERROR;
536 0 : return ldb_module_done(
537 : ac->req, ac->controls, response, ret);
538 : }
539 :
540 53028 : ac->controls[i]->critical = 0;
541 :
542 53028 : vlv = talloc(ac->controls[i], struct ldb_vlv_resp_control);
543 53028 : if (vlv == NULL) {
544 0 : ret = LDB_ERR_OPERATIONS_ERROR;
545 0 : return ldb_module_done(
546 : ac->req, ac->controls, response, ret);
547 : }
548 53028 : ac->controls[i]->data = vlv;
549 :
550 53028 : ac->store->timestamp = time(NULL);
551 :
552 53028 : ac->store->contextId = ac->priv->next_free_id;
553 53028 : ac->priv->next_free_id++;
554 53028 : vlv->contextId = talloc_memdup(vlv, &ac->store->contextId, sizeof(uint32_t));
555 53028 : vlv->ctxid_len = sizeof(uint32_t);
556 53028 : vlv->vlv_result = 0;
557 53028 : vlv->contentCount = ac->store->num_entries;
558 53028 : if (target >= 0) {
559 46758 : vlv->targetPosition = target + 1;
560 6270 : } else if (vlv_details->type == 1) {
561 6270 : vlv->targetPosition = ac->store->num_entries + 1;
562 : } else {
563 0 : vlv->targetPosition = 0;
564 : }
565 53028 : return LDB_SUCCESS;
566 : }
567 :
568 :
569 : /* vlv_search_callback() collects GUIDs found by the original search */
570 :
571 575389 : static int vlv_search_callback(struct ldb_request *req, struct ldb_reply *ares)
572 : {
573 0 : struct vlv_context *ac;
574 0 : struct results_store *store;
575 0 : int ret;
576 :
577 575389 : ac = talloc_get_type(req->context, struct vlv_context);
578 575389 : store = ac->store;
579 :
580 575389 : if (!ares) {
581 0 : return ldb_module_done(ac->req, NULL, NULL,
582 : LDB_ERR_OPERATIONS_ERROR);
583 : }
584 575389 : if (ares->error != LDB_SUCCESS) {
585 0 : return ldb_module_done(ac->req, ares->controls,
586 : ares->response, ares->error);
587 : }
588 :
589 575389 : switch (ares->type) {
590 565095 : case LDB_REPLY_ENTRY:
591 565095 : if (store->results == NULL) {
592 7733 : store->num_entries = 0;
593 7733 : store->result_array_size = 16;
594 7733 : store->results = talloc_array(store, struct GUID,
595 : store->result_array_size);
596 7733 : if (store->results == NULL) {
597 0 : return ldb_module_done(ac->req, NULL, NULL,
598 : LDB_ERR_OPERATIONS_ERROR);
599 : }
600 557362 : } else if (store->num_entries == store->result_array_size) {
601 10977 : store->result_array_size *= 2;
602 10977 : store->results = talloc_realloc(store, store->results,
603 : struct GUID,
604 : store->result_array_size);
605 10977 : if (store->results == NULL) {
606 0 : return ldb_module_done(ac->req, NULL, NULL,
607 : LDB_ERR_OPERATIONS_ERROR);
608 : }
609 : }
610 565095 : store->results[store->num_entries] = \
611 565095 : samdb_result_guid(ares->message, "objectGUID");
612 565095 : store->num_entries++;
613 565095 : break;
614 :
615 2541 : case LDB_REPLY_REFERRAL:
616 2541 : ret = save_referral(store, ares->referral);
617 2541 : if (ret != LDB_SUCCESS) {
618 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
619 : }
620 2541 : break;
621 :
622 7753 : case LDB_REPLY_DONE:
623 7753 : if (store->num_entries != 0) {
624 7733 : store->results = talloc_realloc(store, store->results,
625 : struct GUID,
626 : store->num_entries);
627 7733 : if (store->results == NULL) {
628 0 : return ldb_module_done(ac->req, NULL, NULL,
629 : LDB_ERR_OPERATIONS_ERROR);
630 : }
631 : }
632 7753 : store->result_array_size = store->num_entries;
633 :
634 7753 : ac->store->controls = talloc_move(ac->store, &ares->controls);
635 7753 : ret = vlv_results(ac, ares);
636 7753 : if (ret != LDB_SUCCESS) {
637 : /* vlv_results will have called ldb_module_done
638 : * if there was an error.
639 : */
640 0 : return ret;
641 : }
642 7753 : return ldb_module_done(ac->req, ac->controls,
643 : ares->response, ret);
644 : }
645 :
646 567636 : return LDB_SUCCESS;
647 : }
648 :
649 53028 : static int copy_search_details(struct results_store *store,
650 : struct ldb_vlv_req_control *vlv_ctrl,
651 : struct ldb_server_sort_control *sort_ctrl)
652 : {
653 : /* free the old details which are no longer going to be reachable. */
654 53028 : if (store->vlv_details != NULL){
655 45275 : TALLOC_FREE(store->vlv_details);
656 : }
657 :
658 53028 : if (store->sort_details != NULL){
659 45275 : TALLOC_FREE(store->sort_details);
660 : }
661 :
662 53028 : store->vlv_details = talloc(store, struct ldb_vlv_req_control);
663 53028 : if (store->vlv_details == NULL) {
664 0 : return LDB_ERR_OPERATIONS_ERROR;
665 : }
666 53028 : *store->vlv_details = *vlv_ctrl;
667 53028 : store->vlv_details->contextId = talloc_memdup(store, vlv_ctrl->contextId,
668 : vlv_ctrl->ctxid_len);
669 53028 : if (store->vlv_details->contextId == NULL) {
670 0 : return LDB_ERR_OPERATIONS_ERROR;
671 : }
672 :
673 53028 : if (vlv_ctrl->type == 1) {
674 22275 : char *v = talloc_array(store, char,
675 : vlv_ctrl->match.gtOrEq.value_len + 1);
676 :
677 22275 : if (v == NULL) {
678 0 : return LDB_ERR_OPERATIONS_ERROR;
679 : }
680 :
681 22275 : memcpy(v, vlv_ctrl->match.gtOrEq.value, vlv_ctrl->match.gtOrEq.value_len);
682 22275 : v[vlv_ctrl->match.gtOrEq.value_len] = '\0';
683 :
684 22275 : store->vlv_details->match.gtOrEq.value = v;
685 : }
686 :
687 53028 : store->sort_details = talloc(store, struct ldb_server_sort_control);
688 53028 : if (store->sort_details == NULL) {
689 0 : return LDB_ERR_OPERATIONS_ERROR;
690 : }
691 53028 : store->sort_details->attributeName = talloc_strdup(store,
692 : sort_ctrl->attributeName);
693 53028 : if (store->sort_details->attributeName == NULL) {
694 0 : return LDB_ERR_OPERATIONS_ERROR;
695 : }
696 :
697 53028 : if (sort_ctrl->orderingRule == NULL) {
698 53028 : store->sort_details->orderingRule = NULL;
699 : } else {
700 0 : store->sort_details->orderingRule = talloc_strdup(store,
701 : sort_ctrl->orderingRule);
702 0 : if (store->sort_details->orderingRule == NULL) {
703 0 : return LDB_ERR_OPERATIONS_ERROR;
704 : }
705 : }
706 53028 : store->sort_details->reverse = sort_ctrl->reverse;
707 :
708 53028 : return LDB_SUCCESS;
709 : }
710 :
711 :
712 : static struct ldb_control **
713 7753 : vlv_copy_down_controls(TALLOC_CTX *mem_ctx, struct ldb_control **controls)
714 : {
715 :
716 0 : struct ldb_control **new_controls;
717 0 : unsigned int i, j, num_ctrls;
718 7753 : if (controls == NULL) {
719 0 : return NULL;
720 : }
721 :
722 31990 : for (num_ctrls = 0; controls[num_ctrls]; num_ctrls++);
723 :
724 7753 : new_controls = talloc_array(mem_ctx, struct ldb_control *, num_ctrls);
725 7753 : if (new_controls == NULL) {
726 0 : return NULL;
727 : }
728 :
729 24238 : for (j = 0, i = 0; i < (num_ctrls); i++) {
730 24237 : struct ldb_control *control = controls[i];
731 24237 : if (control->oid == NULL) {
732 7752 : break;
733 : }
734 : /*
735 : * Do not re-use VLV, nor the server-sort, both are
736 : * already handled here.
737 : */
738 16485 : if (strcmp(control->oid, LDB_CONTROL_VLV_REQ_OID) == 0 ||
739 8732 : strcmp(control->oid, LDB_CONTROL_SERVER_SORT_OID) == 0) {
740 15506 : continue;
741 : }
742 : /*
743 : * ASQ changes everything, do not copy it down for the
744 : * per-GUID search
745 : */
746 979 : if (strcmp(control->oid, LDB_CONTROL_ASQ_OID) == 0) {
747 1 : continue;
748 : }
749 978 : new_controls[j] = talloc_steal(new_controls, control);
750 : /*
751 : * Sadly the caller is not obliged to make this a
752 : * proper talloc tree, so we do so here.
753 : */
754 978 : if (control->data) {
755 1 : talloc_steal(control, control->data);
756 : }
757 978 : j++;
758 : }
759 7753 : new_controls[j] = NULL;
760 7753 : return new_controls;
761 : }
762 :
763 20015237 : static int vlv_search(struct ldb_module *module, struct ldb_request *req)
764 : {
765 1144549 : struct ldb_context *ldb;
766 1144549 : struct ldb_control *control;
767 1144549 : struct ldb_control *sort_control;
768 1144549 : struct private_data *priv;
769 1144549 : struct ldb_vlv_req_control *vlv_ctrl;
770 1144549 : struct ldb_server_sort_control **sort_ctrl;
771 1144549 : struct ldb_request *search_req;
772 1144549 : struct vlv_context *ac;
773 1144549 : int ret, i, critical;
774 :
775 20015237 : ldb = ldb_module_get_ctx(module);
776 :
777 20015237 : control = ldb_request_get_control(req, LDB_CONTROL_VLV_REQ_OID);
778 20015237 : if (control == NULL) {
779 : /* There is no VLV. go on */
780 19962206 : return ldb_next_request(module, req);
781 : }
782 53031 : critical = control->critical;
783 53031 : control->critical = 0;
784 :
785 53031 : sort_control = ldb_request_get_control(req, LDB_CONTROL_SERVER_SORT_OID);
786 53031 : if (sort_control == NULL) {
787 : /* VLV needs sort */
788 0 : return LDB_ERR_OPERATIONS_ERROR;
789 : }
790 :
791 53031 : vlv_ctrl = talloc_get_type(control->data, struct ldb_vlv_req_control);
792 53031 : if (vlv_ctrl == NULL) {
793 0 : return LDB_ERR_OPERATIONS_ERROR;
794 : }
795 :
796 53031 : sort_ctrl = talloc_get_type(sort_control->data, struct ldb_server_sort_control *);
797 53031 : if (sort_ctrl == NULL) {
798 0 : return LDB_ERR_OPERATIONS_ERROR;
799 : }
800 :
801 53031 : priv = talloc_get_type(ldb_module_get_private(module),
802 : struct private_data);
803 :
804 53031 : ac = talloc_zero(req, struct vlv_context);
805 53031 : if (ac == NULL) {
806 0 : ldb_set_errstring(ldb, "Out of Memory");
807 0 : return LDB_ERR_OPERATIONS_ERROR;
808 : }
809 :
810 53031 : ac->module = module;
811 53031 : ac->req = req;
812 53031 : ac->priv = priv;
813 : /* If there is no cookie, this is a new request, and we need to do the
814 : * search in the database. Otherwise we try to refer to a previously
815 : * saved search.
816 : */
817 53031 : if (vlv_ctrl->ctxid_len == 0) {
818 0 : static const char * const attrs[2] = {
819 : "objectGUID", NULL
820 : };
821 :
822 7753 : ac->store = new_store(priv);
823 7753 : if (ac->store == NULL) {
824 0 : return LDB_ERR_OPERATIONS_ERROR;
825 : }
826 :
827 7753 : ret = copy_search_details(ac->store, vlv_ctrl, sort_ctrl[0]);
828 7753 : if (ret != LDB_SUCCESS) {
829 0 : return ret;
830 : }
831 :
832 7753 : ret = ldb_build_search_req_ex(&search_req, ldb, ac,
833 : req->op.search.base,
834 : req->op.search.scope,
835 : req->op.search.tree,
836 : attrs,
837 : req->controls,
838 : ac,
839 : vlv_search_callback,
840 : req);
841 7753 : if (ret != LDB_SUCCESS) {
842 0 : return ret;
843 : }
844 : /* save it locally and remove it from the list */
845 : /* we do not need to replace them later as we
846 : * are keeping the original req intact */
847 7753 : if (!ldb_save_controls(control, search_req, NULL)) {
848 0 : return LDB_ERR_OPERATIONS_ERROR;
849 : }
850 :
851 7753 : ac->store->down_controls = vlv_copy_down_controls(ac->store,
852 : req->controls);
853 :
854 7753 : if (ac->store->down_controls == NULL) {
855 0 : return LDB_ERR_OPERATIONS_ERROR;
856 : }
857 :
858 7753 : return ldb_next_request(module, search_req);
859 :
860 : } else {
861 45278 : struct results_store *current = NULL;
862 45278 : uint8_t *id = vlv_ctrl->contextId;
863 :
864 45278 : if (vlv_ctrl->ctxid_len != sizeof(uint32_t)){
865 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
866 : }
867 :
868 130319 : for (i = 0; i < priv->n_stores; i++) {
869 130316 : current = priv->store[i];
870 130316 : if (current == NULL) {
871 10 : continue;
872 : }
873 130306 : if (memcmp(¤t->contextId, id, sizeof(uint32_t)) == 0) {
874 45275 : current->timestamp = time(NULL);
875 45275 : break;
876 : }
877 : }
878 45278 : if (i == priv->n_stores) {
879 : /* We were given a context id that we don't know about. */
880 3 : if (critical) {
881 2 : return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
882 : } else {
883 1 : return ldb_next_request(module, req);
884 : }
885 : }
886 :
887 45275 : ac->store = current;
888 45275 : ret = copy_search_details(ac->store, vlv_ctrl, sort_ctrl[0]);
889 45275 : if (ret != LDB_SUCCESS) {
890 0 : return ret;
891 : }
892 :
893 45275 : ret = vlv_results(ac, NULL);
894 45275 : if (ret != LDB_SUCCESS) {
895 : /*
896 : * vlv_results() will have called ldb_module_done
897 : * if there was an error.
898 : */
899 0 : return ret;
900 : }
901 45275 : return ldb_module_done(req, ac->controls, NULL,
902 : LDB_SUCCESS);
903 : }
904 : }
905 :
906 :
907 182004 : static int vlv_request_init(struct ldb_module *module)
908 : {
909 6016 : struct ldb_context *ldb;
910 6016 : struct private_data *data;
911 6016 : int ret;
912 :
913 182004 : ldb = ldb_module_get_ctx(module);
914 :
915 182004 : data = talloc(module, struct private_data);
916 182004 : if (data == NULL) {
917 0 : return LDB_ERR_OTHER;
918 : }
919 :
920 182004 : data->next_free_id = 1;
921 182004 : data->n_stores = VLV_N_SEARCHES;
922 182004 : data->store = talloc_zero_array(data, struct results_store *, data->n_stores);
923 :
924 182004 : ldb_module_set_private(module, data);
925 :
926 182004 : ret = ldb_mod_register_control(module, LDB_CONTROL_VLV_REQ_OID);
927 182004 : if (ret != LDB_SUCCESS) {
928 0 : ldb_debug(ldb, LDB_DEBUG_WARNING,
929 : "vlv:"
930 : "Unable to register control with rootdse!");
931 : }
932 :
933 182004 : return ldb_next_init(module);
934 : }
935 :
936 : static const struct ldb_module_ops ldb_vlv_module_ops = {
937 : .name = "vlv",
938 : .search = vlv_search,
939 : .init_context = vlv_request_init
940 : };
941 :
942 6040 : int ldb_vlv_init(const char *version)
943 : {
944 6040 : LDB_MODULE_CHECK_VERSION(version);
945 6040 : return ldb_register_module(&ldb_vlv_module_ops);
946 : }
|