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