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