1/* search.c - search operation */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2000-2011 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16 17#include "portable.h" 18 19#include <stdio.h> 20#include <ac/string.h> 21 22#include "back-bdb.h" 23#include "idl.h" 24 25static int base_candidate( 26 BackendDB *be, 27 Entry *e, 28 ID *ids ); 29 30static int search_candidates( 31 Operation *op, 32 SlapReply *rs, 33 Entry *e, 34 DB_TXN *txn, 35 ID *ids, 36 ID *scopes ); 37 38static int parse_paged_cookie( Operation *op, SlapReply *rs ); 39 40static void send_paged_response( 41 Operation *op, 42 SlapReply *rs, 43 ID *lastid, 44 int tentries ); 45 46/* Dereference aliases for a single alias entry. Return the final 47 * dereferenced entry on success, NULL on any failure. 48 */ 49static Entry * deref_base ( 50 Operation *op, 51 SlapReply *rs, 52 Entry *e, 53 Entry **matched, 54 DB_TXN *txn, 55 DB_LOCK *lock, 56 ID *tmp, 57 ID *visited ) 58{ 59 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 60 struct berval ndn; 61 EntryInfo *ei; 62 DB_LOCK lockr; 63 64 rs->sr_err = LDAP_ALIAS_DEREF_PROBLEM; 65 rs->sr_text = "maximum deref depth exceeded"; 66 67 for (;;) { 68 /* Remember the last entry we looked at, so we can 69 * report broken links 70 */ 71 *matched = e; 72 73 if (BDB_IDL_N(tmp) >= op->o_bd->be_max_deref_depth) { 74 e = NULL; 75 break; 76 } 77 78 /* If this is part of a subtree or onelevel search, 79 * have we seen this ID before? If so, quit. 80 */ 81 if ( visited && bdb_idl_insert( visited, e->e_id ) ) { 82 e = NULL; 83 break; 84 } 85 86 /* If we've seen this ID during this deref iteration, 87 * we've hit a loop. 88 */ 89 if ( bdb_idl_insert( tmp, e->e_id ) ) { 90 rs->sr_err = LDAP_ALIAS_PROBLEM; 91 rs->sr_text = "circular alias"; 92 e = NULL; 93 break; 94 } 95 96 /* If there was a problem getting the aliasedObjectName, 97 * get_alias_dn will have set the error status. 98 */ 99 if ( get_alias_dn(e, &ndn, &rs->sr_err, &rs->sr_text) ) { 100 e = NULL; 101 break; 102 } 103 104 rs->sr_err = bdb_dn2entry( op, txn, &ndn, &ei, 105 0, &lockr ); 106 if ( rs->sr_err == DB_LOCK_DEADLOCK ) 107 return NULL; 108 109 if ( ei ) { 110 e = ei->bei_e; 111 } else { 112 e = NULL; 113 } 114 115 if (!e) { 116 rs->sr_err = LDAP_ALIAS_PROBLEM; 117 rs->sr_text = "aliasedObject not found"; 118 break; 119 } 120 121 /* Free the previous entry, continue to work with the 122 * one we just retrieved. 123 */ 124 bdb_cache_return_entry_r( bdb, *matched, lock); 125 *lock = lockr; 126 127 /* We found a regular entry. Return this to the caller. The 128 * entry is still locked for Read. 129 */ 130 if (!is_entry_alias(e)) { 131 rs->sr_err = LDAP_SUCCESS; 132 rs->sr_text = NULL; 133 break; 134 } 135 } 136 return e; 137} 138 139/* Look for and dereference all aliases within the search scope. Adds 140 * the dereferenced entries to the "ids" list. Requires "stack" to be 141 * able to hold 8 levels of DB_SIZE IDLs. Of course we're hardcoded to 142 * require a minimum of 8 UM_SIZE IDLs so this is never a problem. 143 */ 144static int search_aliases( 145 Operation *op, 146 SlapReply *rs, 147 Entry *e, 148 DB_TXN *txn, 149 ID *ids, 150 ID *scopes, 151 ID *stack ) 152{ 153 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 154 ID *aliases, *curscop, *subscop, *visited, *newsubs, *oldsubs, *tmp; 155 ID cursora, ida, cursoro, ido, *subscop2; 156 Entry *matched, *a; 157 EntryInfo *ei; 158 struct berval bv_alias = BER_BVC( "alias" ); 159 AttributeAssertion aa_alias = ATTRIBUTEASSERTION_INIT; 160 Filter af; 161 DB_LOCK locka, lockr; 162 int first = 1; 163 164 aliases = stack; /* IDL of all aliases in the database */ 165 curscop = aliases + BDB_IDL_DB_SIZE; /* Aliases in the current scope */ 166 subscop = curscop + BDB_IDL_DB_SIZE; /* The current scope */ 167 visited = subscop + BDB_IDL_DB_SIZE; /* IDs we've seen in this search */ 168 newsubs = visited + BDB_IDL_DB_SIZE; /* New subtrees we've added */ 169 oldsubs = newsubs + BDB_IDL_DB_SIZE; /* Subtrees added previously */ 170 tmp = oldsubs + BDB_IDL_DB_SIZE; /* Scratch space for deref_base() */ 171 172 /* A copy of subscop, because subscop gets clobbered by 173 * the bdb_idl_union/intersection routines 174 */ 175 subscop2 = tmp + BDB_IDL_DB_SIZE; 176 177 af.f_choice = LDAP_FILTER_EQUALITY; 178 af.f_ava = &aa_alias; 179 af.f_av_desc = slap_schema.si_ad_objectClass; 180 af.f_av_value = bv_alias; 181 af.f_next = NULL; 182 183 /* Find all aliases in database */ 184 BDB_IDL_ZERO( aliases ); 185 rs->sr_err = bdb_filter_candidates( op, txn, &af, aliases, 186 curscop, visited ); 187 if (rs->sr_err != LDAP_SUCCESS) { 188 return rs->sr_err; 189 } 190 oldsubs[0] = 1; 191 oldsubs[1] = e->e_id; 192 193 BDB_IDL_ZERO( ids ); 194 BDB_IDL_ZERO( visited ); 195 BDB_IDL_ZERO( newsubs ); 196 197 cursoro = 0; 198 ido = bdb_idl_first( oldsubs, &cursoro ); 199 200 for (;;) { 201 /* Set curscop to only the aliases in the current scope. Start with 202 * all the aliases, obtain the IDL for the current scope, and then 203 * get the intersection of these two IDLs. Add the current scope 204 * to the cumulative list of candidates. 205 */ 206 BDB_IDL_CPY( curscop, aliases ); 207 rs->sr_err = bdb_dn2idl( op, txn, &e->e_nname, BEI(e), subscop, 208 subscop2+BDB_IDL_DB_SIZE ); 209 210 if (first) { 211 first = 0; 212 } else { 213 bdb_cache_return_entry_r (bdb, e, &locka); 214 } 215 if ( rs->sr_err == DB_LOCK_DEADLOCK ) 216 return rs->sr_err; 217 218 BDB_IDL_CPY(subscop2, subscop); 219 rs->sr_err = bdb_idl_intersection(curscop, subscop); 220 bdb_idl_union( ids, subscop2 ); 221 222 /* Dereference all of the aliases in the current scope. */ 223 cursora = 0; 224 for (ida = bdb_idl_first(curscop, &cursora); ida != NOID; 225 ida = bdb_idl_next(curscop, &cursora)) 226 { 227 ei = NULL; 228retry1: 229 rs->sr_err = bdb_cache_find_id(op, txn, 230 ida, &ei, 0, &lockr ); 231 if (rs->sr_err != LDAP_SUCCESS) { 232 if ( rs->sr_err == DB_LOCK_DEADLOCK ) 233 return rs->sr_err; 234 if ( rs->sr_err == DB_LOCK_NOTGRANTED ) 235 goto retry1; 236 continue; 237 } 238 a = ei->bei_e; 239 240 /* This should only happen if the curscop IDL has maxed out and 241 * turned into a range that spans IDs indiscriminately 242 */ 243 if (!is_entry_alias(a)) { 244 bdb_cache_return_entry_r (bdb, a, &lockr); 245 continue; 246 } 247 248 /* Actually dereference the alias */ 249 BDB_IDL_ZERO(tmp); 250 a = deref_base( op, rs, a, &matched, txn, &lockr, 251 tmp, visited ); 252 if (a) { 253 /* If the target was not already in our current candidates, 254 * make note of it in the newsubs list. Also 255 * set it in the scopes list so that bdb_search 256 * can check it. 257 */ 258 if (bdb_idl_insert(ids, a->e_id) == 0) { 259 bdb_idl_insert(newsubs, a->e_id); 260 bdb_idl_insert(scopes, a->e_id); 261 } 262 bdb_cache_return_entry_r( bdb, a, &lockr); 263 264 } else if ( rs->sr_err == DB_LOCK_DEADLOCK ) { 265 return rs->sr_err; 266 } else if (matched) { 267 /* Alias could not be dereferenced, or it deref'd to 268 * an ID we've already seen. Ignore it. 269 */ 270 bdb_cache_return_entry_r( bdb, matched, &lockr ); 271 rs->sr_text = NULL; 272 } 273 } 274 /* If this is a OneLevel search, we're done; oldsubs only had one 275 * ID in it. For a Subtree search, oldsubs may be a list of scope IDs. 276 */ 277 if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) break; 278nextido: 279 ido = bdb_idl_next( oldsubs, &cursoro ); 280 281 /* If we're done processing the old scopes, did we add any new 282 * scopes in this iteration? If so, go back and do those now. 283 */ 284 if (ido == NOID) { 285 if (BDB_IDL_IS_ZERO(newsubs)) break; 286 BDB_IDL_CPY(oldsubs, newsubs); 287 BDB_IDL_ZERO(newsubs); 288 cursoro = 0; 289 ido = bdb_idl_first( oldsubs, &cursoro ); 290 } 291 292 /* Find the entry corresponding to the next scope. If it can't 293 * be found, ignore it and move on. This should never happen; 294 * we should never see the ID of an entry that doesn't exist. 295 * Set the name so that the scope's IDL can be retrieved. 296 */ 297 ei = NULL; 298sameido: 299 rs->sr_err = bdb_cache_find_id(op, txn, ido, &ei, 300 0, &locka ); 301 if ( rs->sr_err != LDAP_SUCCESS ) { 302 if ( rs->sr_err == DB_LOCK_DEADLOCK ) 303 return rs->sr_err; 304 if ( rs->sr_err == DB_LOCK_NOTGRANTED ) 305 goto sameido; 306 goto nextido; 307 } 308 e = ei->bei_e; 309 } 310 return rs->sr_err; 311} 312 313/* Get the next ID from the DB. Used if the candidate list is 314 * a range and simple iteration hits missing entryIDs 315 */ 316static int 317bdb_get_nextid(struct bdb_info *bdb, DB_TXN *ltid, ID *cursor) 318{ 319 DBC *curs; 320 DBT key, data; 321 ID id, nid; 322 int rc; 323 324 id = *cursor + 1; 325 BDB_ID2DISK( id, &nid ); 326 rc = bdb->bi_id2entry->bdi_db->cursor( 327 bdb->bi_id2entry->bdi_db, ltid, &curs, bdb->bi_db_opflags ); 328 if ( rc ) 329 return rc; 330 key.data = &nid; 331 key.size = key.ulen = sizeof(ID); 332 key.flags = DB_DBT_USERMEM; 333 data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; 334 data.dlen = data.ulen = 0; 335 rc = curs->c_get( curs, &key, &data, DB_SET_RANGE ); 336 curs->c_close( curs ); 337 if ( rc ) 338 return rc; 339 BDB_DISK2ID( &nid, cursor ); 340 return 0; 341} 342 343int 344bdb_search( Operation *op, SlapReply *rs ) 345{ 346 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 347 ID id, cursor; 348 ID lastid = NOID; 349 ID candidates[BDB_IDL_UM_SIZE]; 350 ID scopes[BDB_IDL_DB_SIZE]; 351 Entry *e = NULL, base, *e_root; 352 Entry *matched = NULL; 353 EntryInfo *ei; 354 AttributeName *attrs; 355 struct berval realbase = BER_BVNULL; 356 slap_mask_t mask; 357 time_t stoptime; 358 int manageDSAit; 359 int tentries = 0; 360 unsigned nentries = 0; 361 int idflag = 0; 362 363 DB_LOCK lock; 364 struct bdb_op_info *opinfo = NULL; 365 DB_TXN *ltid = NULL; 366 OpExtra *oex; 367 368 Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_search) "\n", 0, 0, 0); 369 attrs = op->oq_search.rs_attrs; 370 371 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { 372 if ( oex->oe_key == bdb ) 373 break; 374 } 375 opinfo = (struct bdb_op_info *) oex; 376 377 manageDSAit = get_manageDSAit( op ); 378 379 if ( opinfo && opinfo->boi_txn ) { 380 ltid = opinfo->boi_txn; 381 } else { 382 rs->sr_err = bdb_reader_get( op, bdb->bi_dbenv, <id ); 383 384 switch(rs->sr_err) { 385 case 0: 386 break; 387 default: 388 send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); 389 return rs->sr_err; 390 } 391 } 392 393 e_root = bdb->bi_cache.c_dntree.bei_e; 394 if ( op->o_req_ndn.bv_len == 0 ) { 395 /* DIT root special case */ 396 ei = e_root->e_private; 397 rs->sr_err = LDAP_SUCCESS; 398 } else { 399 if ( op->ors_deref & LDAP_DEREF_FINDING ) { 400 BDB_IDL_ZERO(candidates); 401 } 402dn2entry_retry: 403 /* get entry with reader lock */ 404 rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 405 1, &lock ); 406 } 407 408 switch(rs->sr_err) { 409 case DB_NOTFOUND: 410 matched = ei->bei_e; 411 break; 412 case 0: 413 e = ei->bei_e; 414 break; 415 case DB_LOCK_DEADLOCK: 416 if ( !opinfo ) { 417 ltid->flags &= ~TXN_DEADLOCK; 418 goto dn2entry_retry; 419 } 420 opinfo->boi_err = rs->sr_err; 421 /* FALLTHRU */ 422 case LDAP_BUSY: 423 send_ldap_error( op, rs, LDAP_BUSY, "ldap server busy" ); 424 return LDAP_BUSY; 425 case DB_LOCK_NOTGRANTED: 426 goto dn2entry_retry; 427 default: 428 send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); 429 return rs->sr_err; 430 } 431 432 if ( op->ors_deref & LDAP_DEREF_FINDING ) { 433 if ( matched && is_entry_alias( matched )) { 434 struct berval stub; 435 436 stub.bv_val = op->o_req_ndn.bv_val; 437 stub.bv_len = op->o_req_ndn.bv_len - matched->e_nname.bv_len - 1; 438 e = deref_base( op, rs, matched, &matched, ltid, &lock, 439 candidates, NULL ); 440 if ( e ) { 441 build_new_dn( &op->o_req_ndn, &e->e_nname, &stub, 442 op->o_tmpmemctx ); 443 bdb_cache_return_entry_r (bdb, e, &lock); 444 matched = NULL; 445 goto dn2entry_retry; 446 } 447 } else if ( e && is_entry_alias( e )) { 448 e = deref_base( op, rs, e, &matched, ltid, &lock, 449 candidates, NULL ); 450 } 451 } 452 453 if ( e == NULL ) { 454 struct berval matched_dn = BER_BVNULL; 455 456 if ( matched != NULL ) { 457 BerVarray erefs = NULL; 458 459 /* return referral only if "disclose" 460 * is granted on the object */ 461 if ( ! access_allowed( op, matched, 462 slap_schema.si_ad_entry, 463 NULL, ACL_DISCLOSE, NULL ) ) 464 { 465 rs->sr_err = LDAP_NO_SUCH_OBJECT; 466 467 } else { 468 ber_dupbv( &matched_dn, &matched->e_name ); 469 470 erefs = is_entry_referral( matched ) 471 ? get_entry_referrals( op, matched ) 472 : NULL; 473 if ( rs->sr_err == DB_NOTFOUND ) 474 rs->sr_err = LDAP_REFERRAL; 475 rs->sr_matched = matched_dn.bv_val; 476 } 477 478#ifdef SLAP_ZONE_ALLOC 479 slap_zn_runlock(bdb->bi_cache.c_zctx, matched); 480#endif 481 bdb_cache_return_entry_r (bdb, matched, &lock); 482 matched = NULL; 483 484 if ( erefs ) { 485 rs->sr_ref = referral_rewrite( erefs, &matched_dn, 486 &op->o_req_dn, op->oq_search.rs_scope ); 487 ber_bvarray_free( erefs ); 488 } 489 490 } else { 491#ifdef SLAP_ZONE_ALLOC 492 slap_zn_runlock(bdb->bi_cache.c_zctx, matched); 493#endif 494 rs->sr_ref = referral_rewrite( default_referral, 495 NULL, &op->o_req_dn, op->oq_search.rs_scope ); 496 rs->sr_err = rs->sr_ref != NULL ? LDAP_REFERRAL : LDAP_NO_SUCH_OBJECT; 497 } 498 499 send_ldap_result( op, rs ); 500 501 if ( rs->sr_ref ) { 502 ber_bvarray_free( rs->sr_ref ); 503 rs->sr_ref = NULL; 504 } 505 if ( !BER_BVISNULL( &matched_dn ) ) { 506 ber_memfree( matched_dn.bv_val ); 507 rs->sr_matched = NULL; 508 } 509 return rs->sr_err; 510 } 511 512 /* NOTE: __NEW__ "search" access is required 513 * on searchBase object */ 514 if ( ! access_allowed_mask( op, e, slap_schema.si_ad_entry, 515 NULL, ACL_SEARCH, NULL, &mask ) ) 516 { 517 if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) { 518 rs->sr_err = LDAP_NO_SUCH_OBJECT; 519 } else { 520 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 521 } 522 523#ifdef SLAP_ZONE_ALLOC 524 slap_zn_runlock(bdb->bi_cache.c_zctx, e); 525#endif 526 if ( e != e_root ) { 527 bdb_cache_return_entry_r(bdb, e, &lock); 528 } 529 send_ldap_result( op, rs ); 530 return rs->sr_err; 531 } 532 533 if ( !manageDSAit && e != e_root && is_entry_referral( e ) ) { 534 /* entry is a referral, don't allow add */ 535 struct berval matched_dn = BER_BVNULL; 536 BerVarray erefs = NULL; 537 538 ber_dupbv( &matched_dn, &e->e_name ); 539 erefs = get_entry_referrals( op, e ); 540 541 rs->sr_err = LDAP_REFERRAL; 542 543#ifdef SLAP_ZONE_ALLOC 544 slap_zn_runlock(bdb->bi_cache.c_zctx, e); 545#endif 546 bdb_cache_return_entry_r( bdb, e, &lock ); 547 e = NULL; 548 549 if ( erefs ) { 550 rs->sr_ref = referral_rewrite( erefs, &matched_dn, 551 &op->o_req_dn, op->oq_search.rs_scope ); 552 ber_bvarray_free( erefs ); 553 554 if ( !rs->sr_ref ) { 555 rs->sr_text = "bad_referral object"; 556 } 557 } 558 559 Debug( LDAP_DEBUG_TRACE, 560 LDAP_XSTRING(bdb_search) ": entry is referral\n", 561 0, 0, 0 ); 562 563 rs->sr_matched = matched_dn.bv_val; 564 send_ldap_result( op, rs ); 565 566 ber_bvarray_free( rs->sr_ref ); 567 rs->sr_ref = NULL; 568 ber_memfree( matched_dn.bv_val ); 569 rs->sr_matched = NULL; 570 return 1; 571 } 572 573 if ( get_assert( op ) && 574 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE )) 575 { 576 rs->sr_err = LDAP_ASSERTION_FAILED; 577#ifdef SLAP_ZONE_ALLOC 578 slap_zn_runlock(bdb->bi_cache.c_zctx, e); 579#endif 580 if ( e != e_root ) { 581 bdb_cache_return_entry_r(bdb, e, &lock); 582 } 583 send_ldap_result( op, rs ); 584 return 1; 585 } 586 587 /* compute it anyway; root does not use it */ 588 stoptime = op->o_time + op->ors_tlimit; 589 590 /* need normalized dn below */ 591 ber_dupbv( &realbase, &e->e_nname ); 592 593 /* Copy info to base, must free entry before accessing the database 594 * in search_candidates, to avoid deadlocks. 595 */ 596 base.e_private = e->e_private; 597 base.e_nname = realbase; 598 base.e_id = e->e_id; 599 600#ifdef SLAP_ZONE_ALLOC 601 slap_zn_runlock(bdb->bi_cache.c_zctx, e); 602#endif 603 if ( e != e_root ) { 604 bdb_cache_return_entry_r(bdb, e, &lock); 605 } 606 e = NULL; 607 608 /* select candidates */ 609 if ( op->oq_search.rs_scope == LDAP_SCOPE_BASE ) { 610 rs->sr_err = base_candidate( op->o_bd, &base, candidates ); 611 612 } else { 613cand_retry: 614 BDB_IDL_ZERO( candidates ); 615 BDB_IDL_ZERO( scopes ); 616 rs->sr_err = search_candidates( op, rs, &base, 617 ltid, candidates, scopes ); 618 if ( rs->sr_err == DB_LOCK_DEADLOCK ) { 619 if ( !opinfo ) { 620 ltid->flags &= ~TXN_DEADLOCK; 621 goto cand_retry; 622 } 623 opinfo->boi_err = rs->sr_err; 624 send_ldap_error( op, rs, LDAP_BUSY, "ldap server busy" ); 625 return LDAP_BUSY; 626 } 627 } 628 629 /* start cursor at beginning of candidates. 630 */ 631 cursor = 0; 632 633 if ( candidates[0] == 0 ) { 634 Debug( LDAP_DEBUG_TRACE, 635 LDAP_XSTRING(bdb_search) ": no candidates\n", 636 0, 0, 0 ); 637 638 goto nochange; 639 } 640 641 /* if not root and candidates exceed to-be-checked entries, abort */ 642 if ( op->ors_limit /* isroot == FALSE */ && 643 op->ors_limit->lms_s_unchecked != -1 && 644 BDB_IDL_N(candidates) > (unsigned) op->ors_limit->lms_s_unchecked ) 645 { 646 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; 647 send_ldap_result( op, rs ); 648 rs->sr_err = LDAP_SUCCESS; 649 goto done; 650 } 651 652 if ( op->ors_limit == NULL /* isroot == TRUE */ || 653 !op->ors_limit->lms_s_pr_hide ) 654 { 655 tentries = BDB_IDL_N(candidates); 656 } 657 658 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { 659 PagedResultsState *ps = op->o_pagedresults_state; 660 /* deferred cookie parsing */ 661 rs->sr_err = parse_paged_cookie( op, rs ); 662 if ( rs->sr_err != LDAP_SUCCESS ) { 663 send_ldap_result( op, rs ); 664 goto done; 665 } 666 667 cursor = (ID) ps->ps_cookie; 668 if ( cursor && ps->ps_size == 0 ) { 669 rs->sr_err = LDAP_SUCCESS; 670 rs->sr_text = "search abandoned by pagedResult size=0"; 671 send_ldap_result( op, rs ); 672 goto done; 673 } 674 id = bdb_idl_first( candidates, &cursor ); 675 if ( id == NOID ) { 676 Debug( LDAP_DEBUG_TRACE, 677 LDAP_XSTRING(bdb_search) 678 ": no paged results candidates\n", 679 0, 0, 0 ); 680 send_paged_response( op, rs, &lastid, 0 ); 681 682 rs->sr_err = LDAP_OTHER; 683 goto done; 684 } 685 nentries = ps->ps_count; 686 if ( id == (ID)ps->ps_cookie ) 687 id = bdb_idl_next( candidates, &cursor ); 688 goto loop_begin; 689 } 690 691 for ( id = bdb_idl_first( candidates, &cursor ); 692 id != NOID ; id = bdb_idl_next( candidates, &cursor ) ) 693 { 694 int scopeok; 695 696loop_begin: 697 698 /* check for abandon */ 699 if ( op->o_abandon ) { 700 rs->sr_err = SLAPD_ABANDON; 701 send_ldap_result( op, rs ); 702 goto done; 703 } 704 705 /* mostly needed by internal searches, 706 * e.g. related to syncrepl, for whom 707 * abandon does not get set... */ 708 if ( slapd_shutdown ) { 709 rs->sr_err = LDAP_UNAVAILABLE; 710 send_ldap_disconnect( op, rs ); 711 goto done; 712 } 713 714 /* check time limit */ 715 if ( op->ors_tlimit != SLAP_NO_LIMIT 716 && slap_get_time() > stoptime ) 717 { 718 rs->sr_err = LDAP_TIMELIMIT_EXCEEDED; 719 rs->sr_ref = rs->sr_v2ref; 720 send_ldap_result( op, rs ); 721 rs->sr_err = LDAP_SUCCESS; 722 goto done; 723 } 724 725 /* If we inspect more entries than will 726 * fit into the entry cache, stop caching 727 * any subsequent entries 728 */ 729 nentries++; 730 if ( nentries > bdb->bi_cache.c_maxsize && !idflag ) { 731 idflag = ID_NOCACHE; 732 } 733 734fetch_entry_retry: 735 /* get the entry with reader lock */ 736 ei = NULL; 737 rs->sr_err = bdb_cache_find_id( op, ltid, 738 id, &ei, idflag, &lock ); 739 740 if (rs->sr_err == LDAP_BUSY) { 741 rs->sr_text = "ldap server busy"; 742 send_ldap_result( op, rs ); 743 goto done; 744 745 } else if ( rs->sr_err == DB_LOCK_DEADLOCK ) { 746 if ( !opinfo ) { 747 ltid->flags &= ~TXN_DEADLOCK; 748 goto fetch_entry_retry; 749 } 750txnfail: 751 opinfo->boi_err = rs->sr_err; 752 send_ldap_error( op, rs, LDAP_BUSY, "ldap server busy" ); 753 goto done; 754 755 } else if ( rs->sr_err == DB_LOCK_NOTGRANTED ) 756 { 757 goto fetch_entry_retry; 758 } else if ( rs->sr_err == LDAP_OTHER ) { 759 rs->sr_text = "internal error"; 760 send_ldap_result( op, rs ); 761 goto done; 762 } 763 764 if ( ei && rs->sr_err == LDAP_SUCCESS ) { 765 e = ei->bei_e; 766 } else { 767 e = NULL; 768 } 769 770 if ( e == NULL ) { 771 if( !BDB_IDL_IS_RANGE(candidates) ) { 772 /* only complain for non-range IDLs */ 773 Debug( LDAP_DEBUG_TRACE, 774 LDAP_XSTRING(bdb_search) 775 ": candidate %ld not found\n", 776 (long) id, 0, 0 ); 777 } else { 778 /* get the next ID from the DB */ 779id_retry: 780 rs->sr_err = bdb_get_nextid( bdb, ltid, &cursor ); 781 if ( rs->sr_err == DB_NOTFOUND ) { 782 break; 783 } else if ( rs->sr_err == DB_LOCK_DEADLOCK ) { 784 if ( opinfo ) 785 goto txnfail; 786 ltid->flags &= ~TXN_DEADLOCK; 787 goto id_retry; 788 } else if ( rs->sr_err == DB_LOCK_NOTGRANTED ) { 789 goto id_retry; 790 } 791 if ( rs->sr_err ) { 792 rs->sr_err = LDAP_OTHER; 793 rs->sr_text = "internal error in get_nextid"; 794 send_ldap_result( op, rs ); 795 goto done; 796 } 797 cursor--; 798 } 799 800 goto loop_continue; 801 } 802 803 if ( is_entry_subentry( e ) ) { 804 if( op->oq_search.rs_scope != LDAP_SCOPE_BASE ) { 805 if(!get_subentries_visibility( op )) { 806 /* only subentries are visible */ 807 goto loop_continue; 808 } 809 810 } else if ( get_subentries( op ) && 811 !get_subentries_visibility( op )) 812 { 813 /* only subentries are visible */ 814 goto loop_continue; 815 } 816 817 } else if ( get_subentries_visibility( op )) { 818 /* only subentries are visible */ 819 goto loop_continue; 820 } 821 822 /* Does this candidate actually satisfy the search scope? 823 * 824 * Note that we don't lock access to the bei_parent pointer. 825 * Since only leaf nodes can be deleted, the parent of any 826 * node will always be a valid node. Also since we have 827 * a Read lock on the data, it cannot be renamed out of the 828 * scope while we are looking at it, and unless we're using 829 * BDB_HIER, its parents cannot be moved either. 830 */ 831 scopeok = 0; 832 switch( op->ors_scope ) { 833 case LDAP_SCOPE_BASE: 834 /* This is always true, yes? */ 835 if ( id == base.e_id ) scopeok = 1; 836 break; 837 838 case LDAP_SCOPE_ONELEVEL: 839 if ( ei->bei_parent->bei_id == base.e_id ) scopeok = 1; 840 break; 841 842#ifdef LDAP_SCOPE_CHILDREN 843 case LDAP_SCOPE_CHILDREN: 844 if ( id == base.e_id ) break; 845 /* Fall-thru */ 846#endif 847 case LDAP_SCOPE_SUBTREE: { 848 EntryInfo *tmp; 849 for ( tmp = BEI(e); tmp; tmp = tmp->bei_parent ) { 850 if ( tmp->bei_id == base.e_id ) { 851 scopeok = 1; 852 break; 853 } 854 } 855 } break; 856 } 857 858 /* aliases were already dereferenced in candidate list */ 859 if ( op->ors_deref & LDAP_DEREF_SEARCHING ) { 860 /* but if the search base is an alias, and we didn't 861 * deref it when finding, return it. 862 */ 863 if ( is_entry_alias(e) && 864 ((op->ors_deref & LDAP_DEREF_FINDING) || 865 !bvmatch(&e->e_nname, &op->o_req_ndn))) 866 { 867 goto loop_continue; 868 } 869 870 /* scopes is only non-empty for onelevel or subtree */ 871 if ( !scopeok && BDB_IDL_N(scopes) ) { 872 unsigned x; 873 if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) { 874 x = bdb_idl_search( scopes, e->e_id ); 875 if ( scopes[x] == e->e_id ) scopeok = 1; 876 } else { 877 /* subtree, walk up the tree */ 878 EntryInfo *tmp = BEI(e); 879 for (;tmp->bei_parent; tmp=tmp->bei_parent) { 880 x = bdb_idl_search( scopes, tmp->bei_id ); 881 if ( scopes[x] == tmp->bei_id ) { 882 scopeok = 1; 883 break; 884 } 885 } 886 } 887 } 888 } 889 890 /* Not in scope, ignore it */ 891 if ( !scopeok ) 892 { 893 Debug( LDAP_DEBUG_TRACE, 894 LDAP_XSTRING(bdb_search) 895 ": %ld scope not okay\n", 896 (long) id, 0, 0 ); 897 goto loop_continue; 898 } 899 900 /* 901 * if it's a referral, add it to the list of referrals. only do 902 * this for non-base searches, and don't check the filter 903 * explicitly here since it's only a candidate anyway. 904 */ 905 if ( !manageDSAit && op->oq_search.rs_scope != LDAP_SCOPE_BASE 906 && is_entry_referral( e ) ) 907 { 908 struct bdb_op_info bois; 909 struct bdb_lock_info blis; 910 BerVarray erefs = get_entry_referrals( op, e ); 911 rs->sr_ref = referral_rewrite( erefs, &e->e_name, NULL, 912 op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL 913 ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE ); 914 915 /* Must set lockinfo so that entry_release will work */ 916 if (!opinfo) { 917 bois.boi_oe.oe_key = bdb; 918 bois.boi_txn = NULL; 919 bois.boi_err = 0; 920 bois.boi_acl_cache = op->o_do_not_cache; 921 bois.boi_flag = BOI_DONTFREE; 922 bois.boi_locks = &blis; 923 blis.bli_next = NULL; 924 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &bois.boi_oe, 925 oe_next ); 926 } else { 927 blis.bli_next = opinfo->boi_locks; 928 opinfo->boi_locks = &blis; 929 } 930 blis.bli_id = e->e_id; 931 blis.bli_lock = lock; 932 blis.bli_flag = BLI_DONTFREE; 933 934 rs->sr_entry = e; 935 rs->sr_flags = REP_ENTRY_MUSTRELEASE; 936 937 send_search_reference( op, rs ); 938 939 if ( blis.bli_flag ) { 940#ifdef SLAP_ZONE_ALLOC 941 slap_zn_runlock(bdb->bi_cache.c_zctx, e); 942#endif 943 bdb_cache_return_entry_r(bdb, e, &lock); 944 if ( opinfo ) { 945 opinfo->boi_locks = blis.bli_next; 946 } else { 947 LDAP_SLIST_REMOVE( &op->o_extra, &bois.boi_oe, 948 OpExtra, oe_next ); 949 } 950 } 951 rs->sr_entry = NULL; 952 e = NULL; 953 954 ber_bvarray_free( rs->sr_ref ); 955 ber_bvarray_free( erefs ); 956 rs->sr_ref = NULL; 957 958 goto loop_continue; 959 } 960 961 if ( !manageDSAit && is_entry_glue( e )) { 962 goto loop_continue; 963 } 964 965 /* if it matches the filter and scope, send it */ 966 rs->sr_err = test_filter( op, e, op->oq_search.rs_filter ); 967 968 if ( rs->sr_err == LDAP_COMPARE_TRUE ) { 969 /* check size limit */ 970 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { 971 if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size ) { 972#ifdef SLAP_ZONE_ALLOC 973 slap_zn_runlock(bdb->bi_cache.c_zctx, e); 974#endif 975 bdb_cache_return_entry_r( bdb, e, &lock ); 976 e = NULL; 977 send_paged_response( op, rs, &lastid, tentries ); 978 goto done; 979 } 980 lastid = id; 981 } 982 983 if (e) { 984 struct bdb_op_info bois; 985 struct bdb_lock_info blis; 986 987 /* Must set lockinfo so that entry_release will work */ 988 if (!opinfo) { 989 bois.boi_oe.oe_key = bdb; 990 bois.boi_txn = NULL; 991 bois.boi_err = 0; 992 bois.boi_acl_cache = op->o_do_not_cache; 993 bois.boi_flag = BOI_DONTFREE; 994 bois.boi_locks = &blis; 995 blis.bli_next = NULL; 996 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &bois.boi_oe, 997 oe_next ); 998 } else { 999 blis.bli_next = opinfo->boi_locks; 1000 opinfo->boi_locks = &blis; 1001 } 1002 blis.bli_id = e->e_id; 1003 blis.bli_lock = lock; 1004 blis.bli_flag = BLI_DONTFREE; 1005 1006 /* safe default */ 1007 rs->sr_attrs = op->oq_search.rs_attrs; 1008 rs->sr_operational_attrs = NULL; 1009 rs->sr_ctrls = NULL; 1010 rs->sr_entry = e; 1011 RS_ASSERT( e->e_private != NULL ); 1012 rs->sr_flags = REP_ENTRY_MUSTRELEASE; 1013 rs->sr_err = LDAP_SUCCESS; 1014 rs->sr_err = send_search_entry( op, rs ); 1015 rs->sr_attrs = NULL; 1016 rs->sr_entry = NULL; 1017 1018 /* send_search_entry will usually free it. 1019 * an overlay might leave its own copy here; 1020 * bli_flag will be 0 if lock was already released. 1021 */ 1022 if ( blis.bli_flag ) { 1023#ifdef SLAP_ZONE_ALLOC 1024 slap_zn_runlock(bdb->bi_cache.c_zctx, e); 1025#endif 1026 bdb_cache_return_entry_r(bdb, e, &lock); 1027 if ( opinfo ) { 1028 opinfo->boi_locks = blis.bli_next; 1029 } else { 1030 LDAP_SLIST_REMOVE( &op->o_extra, &bois.boi_oe, 1031 OpExtra, oe_next ); 1032 } 1033 } 1034 e = NULL; 1035 1036 switch ( rs->sr_err ) { 1037 case LDAP_SUCCESS: /* entry sent ok */ 1038 break; 1039 default: /* entry not sent */ 1040 break; 1041 case LDAP_UNAVAILABLE: 1042 case LDAP_SIZELIMIT_EXCEEDED: 1043 if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) { 1044 rs->sr_ref = rs->sr_v2ref; 1045 send_ldap_result( op, rs ); 1046 rs->sr_err = LDAP_SUCCESS; 1047 1048 } else { 1049 rs->sr_err = LDAP_OTHER; 1050 } 1051 goto done; 1052 } 1053 } 1054 1055 } else { 1056 Debug( LDAP_DEBUG_TRACE, 1057 LDAP_XSTRING(bdb_search) 1058 ": %ld does not match filter\n", 1059 (long) id, 0, 0 ); 1060 } 1061 1062loop_continue: 1063 if( e != NULL ) { 1064 /* free reader lock */ 1065#ifdef SLAP_ZONE_ALLOC 1066 slap_zn_runlock(bdb->bi_cache.c_zctx, e); 1067#endif 1068 bdb_cache_return_entry_r( bdb, e , &lock ); 1069 RS_ASSERT( rs->sr_entry == NULL ); 1070 e = NULL; 1071 rs->sr_entry = NULL; 1072 } 1073 } 1074 1075nochange: 1076 rs->sr_ctrls = NULL; 1077 rs->sr_ref = rs->sr_v2ref; 1078 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS : LDAP_REFERRAL; 1079 rs->sr_rspoid = NULL; 1080 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { 1081 send_paged_response( op, rs, NULL, 0 ); 1082 } else { 1083 send_ldap_result( op, rs ); 1084 } 1085 1086 rs->sr_err = LDAP_SUCCESS; 1087 1088done: 1089 if( rs->sr_v2ref ) { 1090 ber_bvarray_free( rs->sr_v2ref ); 1091 rs->sr_v2ref = NULL; 1092 } 1093 if( realbase.bv_val ) ch_free( realbase.bv_val ); 1094 1095 return rs->sr_err; 1096} 1097 1098 1099static int base_candidate( 1100 BackendDB *be, 1101 Entry *e, 1102 ID *ids ) 1103{ 1104 Debug(LDAP_DEBUG_ARGS, "base_candidates: base: \"%s\" (0x%08lx)\n", 1105 e->e_nname.bv_val, (long) e->e_id, 0); 1106 1107 ids[0] = 1; 1108 ids[1] = e->e_id; 1109 return 0; 1110} 1111 1112/* Look for "objectClass Present" in this filter. 1113 * Also count depth of filter tree while we're at it. 1114 */ 1115static int oc_filter( 1116 Filter *f, 1117 int cur, 1118 int *max ) 1119{ 1120 int rc = 0; 1121 1122 assert( f != NULL ); 1123 1124 if( cur > *max ) *max = cur; 1125 1126 switch( f->f_choice ) { 1127 case LDAP_FILTER_PRESENT: 1128 if (f->f_desc == slap_schema.si_ad_objectClass) { 1129 rc = 1; 1130 } 1131 break; 1132 1133 case LDAP_FILTER_AND: 1134 case LDAP_FILTER_OR: 1135 cur++; 1136 for ( f=f->f_and; f; f=f->f_next ) { 1137 (void) oc_filter(f, cur, max); 1138 } 1139 break; 1140 1141 default: 1142 break; 1143 } 1144 return rc; 1145} 1146 1147static void search_stack_free( void *key, void *data ) 1148{ 1149 ber_memfree_x(data, NULL); 1150} 1151 1152static void *search_stack( Operation *op ) 1153{ 1154 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 1155 void *ret = NULL; 1156 1157 if ( op->o_threadctx ) { 1158 ldap_pvt_thread_pool_getkey( op->o_threadctx, (void *)search_stack, 1159 &ret, NULL ); 1160 } else { 1161 ret = bdb->bi_search_stack; 1162 } 1163 1164 if ( !ret ) { 1165 ret = ch_malloc( bdb->bi_search_stack_depth * BDB_IDL_UM_SIZE 1166 * sizeof( ID ) ); 1167 if ( op->o_threadctx ) { 1168 ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)search_stack, 1169 ret, search_stack_free, NULL, NULL ); 1170 } else { 1171 bdb->bi_search_stack = ret; 1172 } 1173 } 1174 return ret; 1175} 1176 1177static int search_candidates( 1178 Operation *op, 1179 SlapReply *rs, 1180 Entry *e, 1181 DB_TXN *txn, 1182 ID *ids, 1183 ID *scopes ) 1184{ 1185 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 1186 int rc, depth = 1; 1187 Filter f, rf, xf, nf; 1188 ID *stack; 1189 AttributeAssertion aa_ref = ATTRIBUTEASSERTION_INIT; 1190 Filter sf; 1191 AttributeAssertion aa_subentry = ATTRIBUTEASSERTION_INIT; 1192 1193 /* 1194 * This routine takes as input a filter (user-filter) 1195 * and rewrites it as follows: 1196 * (&(scope=DN)[(objectClass=subentry)] 1197 * (|[(objectClass=referral)(objectClass=alias)](user-filter)) 1198 */ 1199 1200 Debug(LDAP_DEBUG_TRACE, 1201 "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n", 1202 e->e_nname.bv_val, (long) e->e_id, op->oq_search.rs_scope ); 1203 1204 xf.f_or = op->oq_search.rs_filter; 1205 xf.f_choice = LDAP_FILTER_OR; 1206 xf.f_next = NULL; 1207 1208 /* If the user's filter uses objectClass=*, 1209 * these clauses are redundant. 1210 */ 1211 if (!oc_filter(op->oq_search.rs_filter, 1, &depth) 1212 && !get_subentries_visibility(op)) { 1213 if( !get_manageDSAit(op) && !get_domainScope(op) ) { 1214 /* match referral objects */ 1215 struct berval bv_ref = BER_BVC( "referral" ); 1216 rf.f_choice = LDAP_FILTER_EQUALITY; 1217 rf.f_ava = &aa_ref; 1218 rf.f_av_desc = slap_schema.si_ad_objectClass; 1219 rf.f_av_value = bv_ref; 1220 rf.f_next = xf.f_or; 1221 xf.f_or = &rf; 1222 depth++; 1223 } 1224 } 1225 1226 f.f_next = NULL; 1227 f.f_choice = LDAP_FILTER_AND; 1228 f.f_and = &nf; 1229 /* Dummy; we compute scope separately now */ 1230 nf.f_choice = SLAPD_FILTER_COMPUTED; 1231 nf.f_result = LDAP_SUCCESS; 1232 nf.f_next = ( xf.f_or == op->oq_search.rs_filter ) 1233 ? op->oq_search.rs_filter : &xf ; 1234 /* Filter depth increased again, adding dummy clause */ 1235 depth++; 1236 1237 if( get_subentries_visibility( op ) ) { 1238 struct berval bv_subentry = BER_BVC( "subentry" ); 1239 sf.f_choice = LDAP_FILTER_EQUALITY; 1240 sf.f_ava = &aa_subentry; 1241 sf.f_av_desc = slap_schema.si_ad_objectClass; 1242 sf.f_av_value = bv_subentry; 1243 sf.f_next = nf.f_next; 1244 nf.f_next = &sf; 1245 } 1246 1247 /* Allocate IDL stack, plus 1 more for former tmp */ 1248 if ( depth+1 > bdb->bi_search_stack_depth ) { 1249 stack = ch_malloc( (depth + 1) * BDB_IDL_UM_SIZE * sizeof( ID ) ); 1250 } else { 1251 stack = search_stack( op ); 1252 } 1253 1254 if( op->ors_deref & LDAP_DEREF_SEARCHING ) { 1255 rc = search_aliases( op, rs, e, txn, ids, scopes, stack ); 1256 } else { 1257 rc = bdb_dn2idl( op, txn, &e->e_nname, BEI(e), ids, stack ); 1258 } 1259 1260 if ( rc == LDAP_SUCCESS ) { 1261 rc = bdb_filter_candidates( op, txn, &f, ids, 1262 stack, stack+BDB_IDL_UM_SIZE ); 1263 } 1264 1265 if ( depth+1 > bdb->bi_search_stack_depth ) { 1266 ch_free( stack ); 1267 } 1268 1269 if( rc ) { 1270 Debug(LDAP_DEBUG_TRACE, 1271 "bdb_search_candidates: failed (rc=%d)\n", 1272 rc, NULL, NULL ); 1273 1274 } else { 1275 Debug(LDAP_DEBUG_TRACE, 1276 "bdb_search_candidates: id=%ld first=%ld last=%ld\n", 1277 (long) ids[0], 1278 (long) BDB_IDL_FIRST(ids), 1279 (long) BDB_IDL_LAST(ids) ); 1280 } 1281 1282 return rc; 1283} 1284 1285static int 1286parse_paged_cookie( Operation *op, SlapReply *rs ) 1287{ 1288 int rc = LDAP_SUCCESS; 1289 PagedResultsState *ps = op->o_pagedresults_state; 1290 1291 /* this function must be invoked only if the pagedResults 1292 * control has been detected, parsed and partially checked 1293 * by the frontend */ 1294 assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ); 1295 1296 /* cookie decoding/checks deferred to backend... */ 1297 if ( ps->ps_cookieval.bv_len ) { 1298 PagedResultsCookie reqcookie; 1299 if( ps->ps_cookieval.bv_len != sizeof( reqcookie ) ) { 1300 /* bad cookie */ 1301 rs->sr_text = "paged results cookie is invalid"; 1302 rc = LDAP_PROTOCOL_ERROR; 1303 goto done; 1304 } 1305 1306 AC_MEMCPY( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie )); 1307 1308 if ( reqcookie > ps->ps_cookie ) { 1309 /* bad cookie */ 1310 rs->sr_text = "paged results cookie is invalid"; 1311 rc = LDAP_PROTOCOL_ERROR; 1312 goto done; 1313 1314 } else if ( reqcookie < ps->ps_cookie ) { 1315 rs->sr_text = "paged results cookie is invalid or old"; 1316 rc = LDAP_UNWILLING_TO_PERFORM; 1317 goto done; 1318 } 1319 1320 } else { 1321 /* we're going to use ps_cookie */ 1322 op->o_conn->c_pagedresults_state.ps_cookie = 0; 1323 } 1324 1325done:; 1326 1327 return rc; 1328} 1329 1330static void 1331send_paged_response( 1332 Operation *op, 1333 SlapReply *rs, 1334 ID *lastid, 1335 int tentries ) 1336{ 1337 LDAPControl *ctrls[2]; 1338 BerElementBuffer berbuf; 1339 BerElement *ber = (BerElement *)&berbuf; 1340 PagedResultsCookie respcookie; 1341 struct berval cookie; 1342 1343 Debug(LDAP_DEBUG_ARGS, 1344 "send_paged_response: lastid=0x%08lx nentries=%d\n", 1345 lastid ? *lastid : 0, rs->sr_nentries, NULL ); 1346 1347 ctrls[1] = NULL; 1348 1349 ber_init2( ber, NULL, LBER_USE_DER ); 1350 1351 if ( lastid ) { 1352 respcookie = ( PagedResultsCookie )(*lastid); 1353 cookie.bv_len = sizeof( respcookie ); 1354 cookie.bv_val = (char *)&respcookie; 1355 1356 } else { 1357 respcookie = ( PagedResultsCookie )0; 1358 BER_BVSTR( &cookie, "" ); 1359 } 1360 1361 op->o_conn->c_pagedresults_state.ps_cookie = respcookie; 1362 op->o_conn->c_pagedresults_state.ps_count = 1363 ((PagedResultsState *)op->o_pagedresults_state)->ps_count + 1364 rs->sr_nentries; 1365 1366 /* return size of 0 -- no estimate */ 1367 ber_printf( ber, "{iO}", 0, &cookie ); 1368 1369 ctrls[0] = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx ); 1370 if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) { 1371 goto done; 1372 } 1373 1374 ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS; 1375 ctrls[0]->ldctl_iscritical = 0; 1376 1377 slap_add_ctrls( op, rs, ctrls ); 1378 rs->sr_err = LDAP_SUCCESS; 1379 send_ldap_result( op, rs ); 1380 1381done: 1382 (void) ber_free_buf( ber ); 1383} 1384