X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-bdb%2Fsearch.c;h=59f81ff9207b5035d1d8cdebfd2edad00309a651;hb=0af1940f3fb59fe57b2281ef253fe1341c505c2c;hp=2e5d868c83056f8bcbbf8ca738f6417680959cea;hpb=d5be4896a36d2b2b8e81873ea10eb5d73000a7a8;p=openldap diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index 2e5d868c83..59f81ff920 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -1,8 +1,17 @@ /* search.c - search operation */ /* $OpenLDAP$ */ -/* - * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved. - * COPYING RESTRICTIONS APPLY, see COPYRIGHT file +/* This work is part of OpenLDAP Software . + * + * Copyright 2000-2006 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . */ #include "portable.h" @@ -12,24 +21,26 @@ #include "back-bdb.h" #include "idl.h" -#include "external.h" static int base_candidate( BackendDB *be, Entry *e, ID *ids ); + static int search_candidates( - Operation *stackop, /* op with the current threadctx/slab cache */ - Operation *sop, /* search op */ + Operation *op, SlapReply *rs, Entry *e, u_int32_t locker, ID *ids, ID *scopes ); -static void send_pagerequest_response( + +static int parse_paged_cookie( Operation *op, SlapReply *rs ); + +static void send_paged_response( Operation *op, SlapReply *rs, - ID lastid, + ID *lastid, int tentries ); /* Dereference aliases for a single alias entry. Return the final @@ -53,13 +64,17 @@ static Entry * deref_base ( rs->sr_err = LDAP_ALIAS_DEREF_PROBLEM; rs->sr_text = "maximum deref depth exceeded"; - while (BDB_IDL_N(tmp) < op->o_bd->be_max_deref_depth) { - + for (;;) { /* Remember the last entry we looked at, so we can * report broken links */ *matched = e; + if (BDB_IDL_N(tmp) >= op->o_bd->be_max_deref_depth) { + e = NULL; + break; + } + /* If this is part of a subtree or onelevel search, * have we seen this ID before? If so, quit. */ @@ -89,8 +104,11 @@ static Entry * deref_base ( rs->sr_err = bdb_dn2entry( op, NULL, &ndn, &ei, 0, locker, &lockr ); - if ( ei ) e = ei->bei_e; - else e = NULL; + if ( ei ) { + e = ei->bei_e; + } else { + e = NULL; + } if (!e) { rs->sr_err = LDAP_ALIAS_PROBLEM; @@ -129,16 +147,19 @@ static int search_aliases( u_int32_t locker, ID *ids, ID *scopes, - ID *stack -) + ID *stack ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; ID *aliases, *curscop, *subscop, *visited, *newsubs, *oldsubs, *tmp; ID cursora, ida, cursoro, ido, *subscop2; Entry *matched, *a; EntryInfo *ei; - struct berval bv_alias = { sizeof("alias")-1, "alias" }; - AttributeAssertion aa_alias; + struct berval bv_alias = BER_BVC( "alias" ); +#ifdef LDAP_COMP_MATCH + AttributeAssertion aa_alias = { NULL, BER_BVNULL, NULL }; +#else + AttributeAssertion aa_alias = { NULL, BER_BVNULL }; +#endif Filter af; DB_LOCK locka, lockr; int first = 1; @@ -187,7 +208,7 @@ static int search_aliases( */ BDB_IDL_CPY( curscop, aliases ); rs->sr_err = bdb_dn2idl( op, e, subscop, - subscop2+BDB_IDL_DB_SIZE ); + subscop2+BDB_IDL_DB_SIZE ); if (first) { first = 0; } else { @@ -203,9 +224,12 @@ static int search_aliases( ida = bdb_idl_next(curscop, &cursora)) { ei = NULL; +retry1: rs->sr_err = bdb_cache_find_id(op, NULL, ida, &ei, 0, locker, &lockr ); if (rs->sr_err != LDAP_SUCCESS) { + if ( rs->sr_err == DB_LOCK_DEADLOCK || + rs->sr_err == DB_LOCK_NOTGRANTED ) goto retry1; continue; } a = ei->bei_e; @@ -248,7 +272,7 @@ static int search_aliases( /* If this is a OneLevel search, we're done; oldsubs only had one * ID in it. For a Subtree search, oldsubs may be a list of scope IDs. */ - if (op->ors_scope != LDAP_SCOPE_SUBTREE) break; + if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) break; nextido: ido = bdb_idl_next( oldsubs, &cursoro ); @@ -269,278 +293,255 @@ nextido: * Set the name so that the scope's IDL can be retrieved. */ ei = NULL; +sameido: rs->sr_err = bdb_cache_find_id(op, NULL, ido, &ei, 0, locker, &locka ); - if (rs->sr_err != LDAP_SUCCESS) goto nextido; + if ( rs->sr_err != LDAP_SUCCESS ) { + if ( rs->sr_err == DB_LOCK_DEADLOCK || + rs->sr_err == DB_LOCK_NOTGRANTED ) + goto sameido; + goto nextido; + } e = ei->bei_e; } return rs->sr_err; } -static -int is_sync_protocol( Operation *op ) -{ - if ( op->o_sync_mode & SLAP_SYNC_REFRESH_AND_PERSIST ) - return 1; - return 0; -} - -#define IS_BDB_REPLACE(type) (( type == LDAP_PSEARCH_BY_DELETE ) || \ - ( type == LDAP_PSEARCH_BY_SCOPEOUT )) -#define IS_PSEARCH (op != sop) - -int -bdb_abandon( Operation *op, SlapReply *rs ) -{ - Operation *ps_list; - struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; - - LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) { - if ( ps_list->o_connid == op->o_connid ) { - if ( ps_list->o_msgid == op->oq_abandon.rs_msgid ) { - ps_list->o_abandon = 1; - LDAP_LIST_REMOVE( ps_list, o_ps_link ); - slap_op_free ( ps_list ); - return LDAP_SUCCESS; - } - } - } - return LDAP_UNAVAILABLE; -} - -int -bdb_cancel( Operation *op, SlapReply *rs ) -{ - Operation *ps_list; - struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; - - LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) { - if ( ps_list->o_connid == op->o_connid ) { - if ( ps_list->o_msgid == op->oq_cancel.rs_msgid ) { - ps_list->o_cancel = SLAP_CANCEL_DONE; - LDAP_LIST_REMOVE( ps_list, o_ps_link ); - - rs->sr_err = LDAP_CANCELLED; - send_ldap_result( ps_list, rs ); - - if ( ps_list->o_tmpmemctx ) { - sl_mem_destroy( NULL, ps_list->o_tmpmemctx ); - } - - slap_op_free ( ps_list ); - return LDAP_SUCCESS; - } - } - } - return LDAP_UNAVAILABLE; -} - -int bdb_search( Operation *op, SlapReply *rs ) -{ - return bdb_do_search( op, rs, op, NULL, 0 ); -} - -/* For persistent searches, op is the currently executing operation, - * sop is the persistent search. For regular searches, sop = op. - */ int -bdb_do_search( Operation *op, SlapReply *rs, Operation *sop, - Entry *ps_e, int ps_type ) +bdb_search( Operation *op, SlapReply *rs ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; time_t stoptime; ID id, cursor; ID candidates[BDB_IDL_UM_SIZE]; ID scopes[BDB_IDL_DB_SIZE]; - Entry *e = NULL, base; - Entry *matched = NULL; - EntryInfo *ei; - struct berval realbase = { 0, NULL }; + Entry *e = NULL, base, e_root = {0}; + Entry *matched = NULL; + EntryInfo *ei, ei_root = {0}; + struct berval realbase = BER_BVNULL; +#ifdef SLAP_ACL_HONOR_DISCLOSE + slap_mask_t mask; +#endif int manageDSAit; int tentries = 0; ID lastid = NOID; AttributeName *attrs; - Filter contextcsnand, contextcsnle, cookief, csnfnot, csnfeq, csnfand, csnfge; - Filter omitcsnf, omitcsnfle; - AttributeAssertion aa_ge, aa_eq, aa_le; - int entry_count = 0; - struct berval *search_context_csn = NULL; - DB_LOCK ctxcsn_lock; - LDAPControl *ctrls[SLAP_SEARCH_MAX_CTRLS]; - int num_ctrls = 0; - AttributeName uuid_attr[2]; - int rc_sync = 0; - int entry_sync_state = -1; - AttributeName null_attr; - int no_sync_state_change = 0; - struct slap_limits_set *limit = NULL; - int isroot = 0; - u_int32_t locker = 0; DB_LOCK lock; + struct bdb_op_info *opinfo = NULL; + DB_TXN *ltid = NULL; -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, ENTRY, "bdb_back_search\n", 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, "=> bdb_back_search\n", - 0, 0, 0); -#endif - attrs = sop->oq_search.rs_attrs; - - /* psearch needs to be registered before refresh begins */ - /* psearch and refresh transmission is serialized in send_ldap_ber() */ - if ( !IS_PSEARCH && sop->o_sync_mode & SLAP_SYNC_PERSIST ) { - LDAP_LIST_INSERT_HEAD( &bdb->bi_psearch_list, sop, o_ps_link ); - } - null_attr.an_desc = NULL; - null_attr.an_oc = NULL; - null_attr.an_name.bv_len = 0; - null_attr.an_name.bv_val = NULL; - - for ( num_ctrls = 0; num_ctrls < SLAP_SEARCH_MAX_CTRLS; num_ctrls++ ) { - ctrls[num_ctrls] = NULL; - } - num_ctrls = 0; - - if ( IS_PSEARCH && IS_BDB_REPLACE(ps_type)) { - attrs = uuid_attr; - attrs[0].an_desc = NULL; - attrs[0].an_oc = NULL; - attrs[0].an_name.bv_len = 0; - attrs[0].an_name.bv_val = NULL; - } - - manageDSAit = get_manageDSAit( sop ); + Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_search) "\n", 0, 0, 0); + attrs = op->oq_search.rs_attrs; - /* Sync control overrides manageDSAit */ + opinfo = (struct bdb_op_info *) op->o_private; - if ( !IS_PSEARCH && sop->o_sync_mode & SLAP_SYNC_REFRESH ) { - if ( manageDSAit == SLAP_NO_CONTROL ) - manageDSAit = SLAP_CRITICAL_CONTROL; - } else if ( IS_PSEARCH ) { - if ( manageDSAit == SLAP_NO_CONTROL ) - manageDSAit = SLAP_CRITICAL_CONTROL; - } + manageDSAit = get_manageDSAit( op ); - rs->sr_err = LOCK_ID (bdb->bi_dbenv, &locker ); + if ( opinfo && opinfo->boi_txn ) { + ltid = opinfo->boi_txn; + locker = TXN_ID( ltid ); + } else { + rs->sr_err = LOCK_ID( bdb->bi_dbenv, &locker ); - switch(rs->sr_err) { - case 0: - break; - default: - send_ldap_error( sop, rs, LDAP_OTHER, "internal error" ); - return rs->sr_err; + switch(rs->sr_err) { + case 0: + break; + default: + send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); + return rs->sr_err; + } } - if ( sop->o_req_ndn.bv_len == 0 ) { + if ( op->o_req_ndn.bv_len == 0 ) { /* DIT root special case */ - e = (Entry *) &slap_entry_root; + ei_root.bei_e = &e_root; + ei_root.bei_parent = &ei_root; + e_root.e_private = &ei_root; + e_root.e_id = 0; + BER_BVSTR( &e_root.e_nname, "" ); + BER_BVSTR( &e_root.e_name, "" ); + ei = &ei_root; rs->sr_err = LDAP_SUCCESS; } else { + if ( op->ors_deref & LDAP_DEREF_FINDING ) { + BDB_IDL_ZERO(candidates); + } dn2entry_retry: /* get entry with reader lock */ - rs->sr_err = bdb_dn2entry( op, NULL, &sop->o_req_ndn, &ei, + rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1, locker, &lock ); } switch(rs->sr_err) { case DB_NOTFOUND: - matched = ei->bei_e; break; + matched = ei->bei_e; + break; case 0: - e = ei->bei_e; break; + e = ei->bei_e; + break; case LDAP_BUSY: - send_ldap_error( sop, rs, LDAP_BUSY, "ldap server busy" ); - LOCK_ID_FREE (bdb->bi_dbenv, locker ); + send_ldap_error( op, rs, LDAP_BUSY, "ldap server busy" ); + if ( !opinfo ) + LOCK_ID_FREE (bdb->bi_dbenv, locker ); return LDAP_BUSY; case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto dn2entry_retry; default: - send_ldap_error( sop, rs, LDAP_OTHER, "internal error" ); - LOCK_ID_FREE (bdb->bi_dbenv, locker ); + send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); + if ( !opinfo ) + LOCK_ID_FREE (bdb->bi_dbenv, locker ); return rs->sr_err; } - if ( e && (op->ors_deref & LDAP_DEREF_FINDING) && is_entry_alias(e) ) { - BDB_IDL_ZERO(candidates); - e = deref_base( op, rs, e, &matched, locker, &lock, - candidates, NULL ); + if ( op->ors_deref & LDAP_DEREF_FINDING ) { + if ( matched && is_entry_alias( matched )) { + struct berval stub; + + stub.bv_val = op->o_req_ndn.bv_val; + stub.bv_len = op->o_req_ndn.bv_len - matched->e_nname.bv_len - 1; + e = deref_base( op, rs, matched, &matched, locker, &lock, + candidates, NULL ); + if ( e ) { + build_new_dn( &op->o_req_ndn, &e->e_nname, &stub, + op->o_tmpmemctx ); + bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, + e, &lock); + matched = NULL; + goto dn2entry_retry; + } + } else if ( e && is_entry_alias( e )) { + e = deref_base( op, rs, e, &matched, locker, &lock, + candidates, NULL ); + } } if ( e == NULL ) { - struct berval matched_dn = { 0, NULL }; + struct berval matched_dn = BER_BVNULL; if ( matched != NULL ) { - BerVarray erefs; - ber_dupbv( &matched_dn, &matched->e_name ); + BerVarray erefs = NULL; + +#ifdef SLAP_ACL_HONOR_DISCLOSE + /* return referral only if "disclose" + * is granted on the object */ + if ( ! access_allowed( op, matched, + slap_schema.si_ad_entry, + NULL, ACL_DISCLOSE, NULL ) ) + { + rs->sr_err = LDAP_NO_SUCH_OBJECT; - erefs = is_entry_referral( matched ) - ? get_entry_referrals( op, matched ) - : NULL; + } else +#endif /* SLAP_ACL_HONOR_DISCLOSE */ + { + ber_dupbv( &matched_dn, &matched->e_name ); + + erefs = is_entry_referral( matched ) + ? get_entry_referrals( op, matched ) + : NULL; + if ( rs->sr_err == DB_NOTFOUND ) + rs->sr_err = LDAP_REFERRAL; + rs->sr_matched = matched_dn.bv_val; + } +#ifdef SLAP_ZONE_ALLOC + slap_zn_runlock(bdb->bi_cache.c_zctx, matched); +#endif bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, matched, &lock); matched = NULL; - if( erefs ) { + if ( erefs ) { rs->sr_ref = referral_rewrite( erefs, &matched_dn, - &sop->o_req_dn, sop->oq_search.rs_scope ); + &op->o_req_dn, op->oq_search.rs_scope ); ber_bvarray_free( erefs ); } } else { +#ifdef SLAP_ZONE_ALLOC + slap_zn_runlock(bdb->bi_cache.c_zctx, matched); +#endif rs->sr_ref = referral_rewrite( default_referral, - NULL, &sop->o_req_dn, sop->oq_search.rs_scope ); + NULL, &op->o_req_dn, op->oq_search.rs_scope ); + rs->sr_err = rs->sr_ref != NULL ? LDAP_REFERRAL : LDAP_NO_SUCH_OBJECT; } - rs->sr_err = LDAP_REFERRAL; - rs->sr_matched = matched_dn.bv_val; - send_ldap_result( sop, rs ); + send_ldap_result( op, rs ); - LOCK_ID_FREE (bdb->bi_dbenv, locker ); + if ( !opinfo ) + LOCK_ID_FREE (bdb->bi_dbenv, locker ); if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } - if ( matched_dn.bv_val ) { + if ( !BER_BVISNULL( &matched_dn ) ) { ber_memfree( matched_dn.bv_val ); rs->sr_matched = NULL; } return rs->sr_err; } - if (!manageDSAit && e != &slap_entry_root && is_entry_referral( e ) ) { +#ifdef SLAP_ACL_HONOR_DISCLOSE + /* NOTE: __NEW__ "search" access is required + * on searchBase object */ + if ( ! access_allowed_mask( op, e, slap_schema.si_ad_entry, + NULL, ACL_SEARCH, NULL, &mask ) ) + { + if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) { + rs->sr_err = LDAP_NO_SUCH_OBJECT; + } else { + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + } + +#ifdef SLAP_ZONE_ALLOC + slap_zn_runlock(bdb->bi_cache.c_zctx, e); +#endif + if ( e != &e_root ) { + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); + } + send_ldap_result( op, rs ); + return rs->sr_err; + } +#endif /* SLAP_ACL_HONOR_DISCLOSE */ + + if ( !manageDSAit && e != &e_root && is_entry_referral( e ) ) { /* entry is a referral, don't allow add */ - struct berval matched_dn; - BerVarray erefs; + struct berval matched_dn = BER_BVNULL; + BerVarray erefs = NULL; ber_dupbv( &matched_dn, &e->e_name ); erefs = get_entry_referrals( op, e ); + rs->sr_err = LDAP_REFERRAL; + +#ifdef SLAP_ZONE_ALLOC + slap_zn_runlock(bdb->bi_cache.c_zctx, e); +#endif bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock ); e = NULL; - if( erefs ) { + if ( erefs ) { rs->sr_ref = referral_rewrite( erefs, &matched_dn, - &sop->o_req_dn, sop->oq_search.rs_scope ); + &op->o_req_dn, op->oq_search.rs_scope ); ber_bvarray_free( erefs ); + + if ( !rs->sr_ref ) { + rs->sr_text = "bad_referral object"; + } } -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_search: entry is referral\n", 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, "bdb_search: entry is referral\n", + Debug( LDAP_DEBUG_TRACE, + LDAP_XSTRING(bdb_search) ": entry is referral\n", 0, 0, 0 ); -#endif - if (!rs->sr_ref) rs->sr_text = "bad_referral object"; - rs->sr_err = LDAP_REFERRAL; rs->sr_matched = matched_dn.bv_val; - send_ldap_result( sop, rs ); + send_ldap_result( op, rs ); - LOCK_ID_FREE (bdb->bi_dbenv, locker ); + if ( !opinfo ) { + LOCK_ID_FREE (bdb->bi_dbenv, locker ); + } ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; ber_memfree( matched_dn.bv_val ); @@ -552,85 +553,18 @@ dn2entry_retry: ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE )) { rs->sr_err = LDAP_ASSERTION_FAILED; - send_ldap_result( sop, rs ); - return 1; - } - - /* if not root, get appropriate limits */ - if ( be_isroot( op->o_bd, &sop->o_ndn ) ) { - isroot = 1; - } else { - ( void ) get_limits( op->o_bd, &sop->o_ndn, &limit ); - } - - /* The time/size limits come first because they require very little - * effort, so there's no chance the candidates are selected and then - * the request is not honored only because of time/size constraints */ - - /* if no time limit requested, use soft limit (unless root!) */ - if ( isroot ) { - if ( sop->oq_search.rs_tlimit == 0 ) { - sop->oq_search.rs_tlimit = -1; /* allow root to set no limit */ - } - - if ( sop->oq_search.rs_slimit == 0 ) { - sop->oq_search.rs_slimit = -1; - } - - } else { - /* if no limit is required, use soft limit */ - if ( sop->oq_search.rs_tlimit <= 0 ) { - sop->oq_search.rs_tlimit = limit->lms_t_soft; - - /* if requested limit higher than hard limit, abort */ - } else if ( sop->oq_search.rs_tlimit > limit->lms_t_hard ) { - /* no hard limit means use soft instead */ - if ( limit->lms_t_hard == 0 - && limit->lms_t_soft > -1 - && sop->oq_search.rs_tlimit > limit->lms_t_soft ) { - sop->oq_search.rs_tlimit = limit->lms_t_soft; - - /* positive hard limit means abort */ - } else if ( limit->lms_t_hard > 0 ) { - rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; - send_ldap_result( sop, rs ); - rs->sr_err = LDAP_SUCCESS; - goto done; - } - - /* negative hard limit means no limit */ - } - - /* if no limit is required, use soft limit */ - if ( sop->oq_search.rs_slimit <= 0 ) { - if ( get_pagedresults(sop) && limit->lms_s_pr != 0 ) { - sop->oq_search.rs_slimit = limit->lms_s_pr; - } else { - sop->oq_search.rs_slimit = limit->lms_s_soft; - } - - /* if requested limit higher than hard limit, abort */ - } else if ( sop->oq_search.rs_slimit > limit->lms_s_hard ) { - /* no hard limit means use soft instead */ - if ( limit->lms_s_hard == 0 - && limit->lms_s_soft > -1 - && sop->oq_search.rs_slimit > limit->lms_s_soft ) { - sop->oq_search.rs_slimit = limit->lms_s_soft; - - /* positive hard limit means abort */ - } else if ( limit->lms_s_hard > 0 ) { - rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; - send_ldap_result( sop, rs ); - rs->sr_err = LDAP_SUCCESS; - goto done; - } - - /* negative hard limit means no limit */ +#ifdef SLAP_ZONE_ALLOC + slap_zn_runlock(bdb->bi_cache.c_zctx, e); +#endif + if ( e != &e_root ) { + bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); } + send_ldap_result( op, rs ); + return 1; } /* compute it anyway; root does not use it */ - stoptime = op->o_time + sop->oq_search.rs_tlimit; + stoptime = op->o_time + op->ors_tlimit; /* need normalized dn below */ ber_dupbv( &realbase, &e->e_nname ); @@ -642,221 +576,134 @@ dn2entry_retry: base.e_nname = realbase; base.e_id = e->e_id; - if ( e != &slap_entry_root ) { +#ifdef SLAP_ZONE_ALLOC + slap_zn_runlock(bdb->bi_cache.c_zctx, e); +#endif + if ( e != &e_root ) { bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); } e = NULL; - rs->sr_err = bdb_get_commit_csn( sop, rs, &search_context_csn, locker, &ctxcsn_lock ); - - if ( rs->sr_err != LDAP_SUCCESS ) { - send_ldap_error( sop, rs, rs->sr_err, "error in csn management in search" ); - goto done; - } - /* select candidates */ - if ( sop->oq_search.rs_scope == LDAP_SCOPE_BASE ) { + if ( op->oq_search.rs_scope == LDAP_SCOPE_BASE ) { rs->sr_err = base_candidate( op->o_bd, &base, candidates ); } else { BDB_IDL_ZERO( candidates ); BDB_IDL_ZERO( scopes ); - rs->sr_err = search_candidates( op, sop, rs, &base, locker, candidates, scopes ); - } - - if ( sop->o_sync_mode != SLAP_SYNC_NONE ) { - bdb_cache_entry_db_unlock( bdb->bi_dbenv, &ctxcsn_lock ); + rs->sr_err = search_candidates( op, rs, &base, + locker, candidates, scopes ); } /* start cursor at beginning of candidates. */ cursor = 0; - if (IS_PSEARCH) { - if ( !BDB_IDL_IS_RANGE( candidates ) ) { - cursor = bdb_idl_search( candidates, ps_e->e_id ); - if ( candidates[cursor] != ps_e->e_id ) { - rs->sr_err = LDAP_SUCCESS; - goto done; - } - } else { - if ( ps_e->e_id < BDB_IDL_RANGE_FIRST(candidates) - || ps_e->e_id > BDB_IDL_RANGE_LAST(candidates)){ - rs->sr_err = LDAP_SUCCESS; - goto done; - } - } - candidates[0] = 1; - candidates[1] = ps_e->e_id; - } if ( candidates[0] == 0 ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_search: no candidates\n", 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, "bdb_search: no candidates\n", + Debug( LDAP_DEBUG_TRACE, + LDAP_XSTRING(bdb_search) ": no candidates\n", 0, 0, 0 ); -#endif - rs->sr_err = LDAP_SUCCESS; - rs->sr_entry = NULL; - send_ldap_result( sop, rs ); - goto done; + goto nochange; } /* if not root and candidates exceed to-be-checked entries, abort */ - if ( !isroot && limit->lms_s_unchecked != -1 ) { - if ( BDB_IDL_N(candidates) > (unsigned) limit->lms_s_unchecked ) { - rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; - send_ldap_result( sop, rs ); - rs->sr_err = LDAP_SUCCESS; - goto done; - } + if ( op->ors_limit /* isroot == FALSE */ && + op->ors_limit->lms_s_unchecked != -1 && + BDB_IDL_N(candidates) > (unsigned) op->ors_limit->lms_s_unchecked ) + { + rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; + send_ldap_result( op, rs ); + rs->sr_err = LDAP_SUCCESS; + goto done; } - if ( isroot || !limit->lms_s_pr_hide ) { + if ( op->ors_limit == NULL /* isroot == TRUE */ || + !op->ors_limit->lms_s_pr_hide ) + { tentries = BDB_IDL_N(candidates); } -#ifdef LDAP_CONTROL_PAGEDRESULTS - if ( get_pagedresults(sop) ) { - if ( sop->o_pagedresults_state.ps_cookie == 0 ) { - id = 0; + if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { + PagedResultsState *ps = op->o_pagedresults_state; + /* deferred cookie parsing */ + rs->sr_err = parse_paged_cookie( op, rs ); + if ( rs->sr_err != LDAP_SUCCESS ) { + send_ldap_result( op, rs ); + goto done; + } + + if ( (ID)( ps->ps_cookie ) == 0 ) { + id = bdb_idl_first( candidates, &cursor ); + } else { - if ( sop->o_pagedresults_size == 0 ) { + if ( ps->ps_size == 0 ) { rs->sr_err = LDAP_SUCCESS; rs->sr_text = "search abandoned by pagedResult size=0"; - send_ldap_result( sop, rs ); + send_ldap_result( op, rs ); goto done; } for ( id = bdb_idl_first( candidates, &cursor ); - id != NOID && id <= (ID)( sop->o_pagedresults_state.ps_cookie ); - id = bdb_idl_next( candidates, &cursor ) ); + id != NOID && + id <= (ID)( ps->ps_cookie ); + id = bdb_idl_next( candidates, &cursor ) ) + { + /* empty */; + } } + if ( cursor == NOID ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_search: no paged results candidates\n", - 0, 0, 0 ); -#else Debug( LDAP_DEBUG_TRACE, - "bdb_search: no paged results candidates\n", + LDAP_XSTRING(bdb_search) + ": no paged results candidates\n", 0, 0, 0 ); -#endif - send_pagerequest_response( sop, rs, lastid, 0 ); + send_paged_response( op, rs, &lastid, 0 ); rs->sr_err = LDAP_OTHER; goto done; } goto loop_begin; } -#endif - - if ( (sop->o_sync_mode & SLAP_SYNC_REFRESH) || IS_PSEARCH ) - { - MatchingRule *mr; - const char *text; - int match; - - cookief.f_choice = LDAP_FILTER_AND; - cookief.f_and = &csnfnot; - cookief.f_next = NULL; - - csnfnot.f_choice = LDAP_FILTER_NOT; - csnfnot.f_not = &csnfeq; - csnfnot.f_next = &csnfand; - - csnfeq.f_choice = LDAP_FILTER_EQUALITY; - csnfeq.f_ava = &aa_eq; - csnfeq.f_av_desc = slap_schema.si_ad_entryCSN; - csnfeq.f_av_value = sop->o_sync_state; - - csnfand.f_choice = LDAP_FILTER_AND; - csnfand.f_and = &csnfge; - csnfand.f_next = NULL; - - csnfge.f_choice = LDAP_FILTER_GE; - csnfge.f_ava = &aa_ge; - csnfge.f_av_desc = slap_schema.si_ad_entryCSN; - csnfge.f_av_value = sop->o_sync_state; - - if ( search_context_csn && !IS_PSEARCH ) { - csnfge.f_next = &contextcsnand; - - contextcsnand.f_choice = LDAP_FILTER_AND; - contextcsnand.f_and = &contextcsnle; - contextcsnand.f_next = NULL; - - contextcsnle.f_choice = LDAP_FILTER_LE; - contextcsnle.f_ava = &aa_le; - contextcsnle.f_av_desc = slap_schema.si_ad_entryCSN; - contextcsnle.f_av_value = *search_context_csn; - contextcsnle.f_next = sop->oq_search.rs_filter; - - mr = slap_schema.si_ad_entryCSN->ad_type->sat_ordering; - if ( sop->o_sync_state.bv_len != 0 ) { - value_match( &match, slap_schema.si_ad_entryCSN, mr, - SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, - &sop->o_sync_state, search_context_csn, &text ); - } else { - match = -1; - } - no_sync_state_change = !match; - } else { - csnfge.f_next = sop->oq_search.rs_filter; - } - } for ( id = bdb_idl_first( candidates, &cursor ); - id != NOID; - id = bdb_idl_next( candidates, &cursor ) ) + id != NOID ; id = bdb_idl_next( candidates, &cursor ) ) { - int scopeok = 0; + int scopeok; loop_begin: + /* check for abandon */ - if ( sop->o_abandon ) { - rs->sr_err = LDAP_SUCCESS; + if ( op->o_abandon ) { + rs->sr_err = SLAPD_ABANDON; goto done; } -#ifdef LDAP_EXOP_X_CANCEL - if ( sop->o_cancel ) { - assert( sop->o_cancel == SLAP_CANCEL_REQ ); - rs->sr_err = LDAP_CANCELLED; - send_ldap_result( sop, rs ); - sop->o_cancel = SLAP_CANCEL_ACK; - rs->sr_err = LDAP_SUCCESS; - goto done; - } -#endif - /* check time limit */ - if ( sop->oq_search.rs_tlimit != -1 && slap_get_time() > stoptime ) { + if ( op->ors_tlimit != SLAP_NO_LIMIT + && slap_get_time() > stoptime ) + { rs->sr_err = LDAP_TIMELIMIT_EXCEEDED; rs->sr_ref = rs->sr_v2ref; - send_ldap_result( sop, rs ); + send_ldap_result( op, rs ); rs->sr_err = LDAP_SUCCESS; goto done; } - - if (!IS_PSEARCH) { -id2entry_retry: +fetch_entry_retry: /* get the entry with reader lock */ ei = NULL; - rs->sr_err = bdb_cache_find_id( op, NULL, + rs->sr_err = bdb_cache_find_id( op, ltid, id, &ei, 0, locker, &lock ); if (rs->sr_err == LDAP_BUSY) { rs->sr_text = "ldap server busy"; - send_ldap_result( sop, rs ); + send_ldap_result( op, rs ); goto done; } else if ( rs->sr_err == DB_LOCK_DEADLOCK || rs->sr_err == DB_LOCK_NOTGRANTED ) { - goto id2entry_retry; + goto fetch_entry_retry; } if ( ei && rs->sr_err == LDAP_SUCCESS ) { @@ -868,50 +715,35 @@ id2entry_retry: if ( e == NULL ) { if( !BDB_IDL_IS_RANGE(candidates) ) { /* only complain for non-range IDLs */ -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_search: candidate %ld not found\n", - (long) id, 0, 0); -#else Debug( LDAP_DEBUG_TRACE, - "bdb_search: candidate %ld not found\n", + LDAP_XSTRING(bdb_search) + ": candidate %ld not found\n", (long) id, 0, 0 ); -#endif } goto loop_continue; } - } else { - e = ps_e; - } rs->sr_entry = e; -#ifdef BDB_SUBENTRIES - /* FIXME: send all but syncrepl - if ( !is_sync_protocol( sop ) ) { - */ - if ( is_entry_subentry( e ) ) { - if( sop->oq_search.rs_scope != LDAP_SCOPE_BASE ) { - if(!get_subentries_visibility( sop )) { - /* only subentries are visible */ - goto loop_continue; - } - } else if ( get_subentries( sop ) && - !get_subentries_visibility( sop )) - { + if ( is_entry_subentry( e ) ) { + if( op->oq_search.rs_scope != LDAP_SCOPE_BASE ) { + if(!get_subentries_visibility( op )) { /* only subentries are visible */ goto loop_continue; } - } else if ( get_subentries_visibility( sop )) { + } else if ( get_subentries( op ) && + !get_subentries_visibility( op )) + { /* only subentries are visible */ goto loop_continue; } - /* + + } else if ( get_subentries_visibility( op )) { + /* only subentries are visible */ + goto loop_continue; } - */ -#endif /* Does this candidate actually satisfy the search scope? * @@ -922,37 +754,41 @@ id2entry_retry: * scope while we are looking at it, and unless we're using * BDB_HIER, its parents cannot be moved either. */ - switch( sop->ors_scope ) { + scopeok = 0; + switch( op->ors_scope ) { case LDAP_SCOPE_BASE: /* This is always true, yes? */ - if ( id == base.e_id ) - scopeok = 1; + if ( id == base.e_id ) scopeok = 1; break; + case LDAP_SCOPE_ONELEVEL: - if ( ei->bei_parent->bei_id == base.e_id ) - scopeok = 1; + if ( ei->bei_parent->bei_id == base.e_id ) scopeok = 1; break; - case LDAP_SCOPE_SUBTREE: - { EntryInfo *tmp; - for ( tmp = BEI(e); tmp->bei_parent; - tmp = tmp->bei_parent ) { + +#ifdef LDAP_SCOPE_CHILDREN + case LDAP_SCOPE_CHILDREN: + if ( id == base.e_id ) break; + /* Fall-thru */ +#endif + case LDAP_SCOPE_SUBTREE: { + EntryInfo *tmp; + for ( tmp = BEI(e); tmp; tmp = tmp->bei_parent ) { if ( tmp->bei_id == base.e_id ) { scopeok = 1; break; } - } } - break; + } + } break; } -#ifdef BDB_ALIASES /* aliases were already dereferenced in candidate list */ - if ( sop->ors_deref & LDAP_DEREF_SEARCHING ) { + if ( op->ors_deref & LDAP_DEREF_SEARCHING ) { /* but if the search base is an alias, and we didn't * deref it when finding, return it. */ if ( is_entry_alias(e) && - ((sop->ors_deref & LDAP_DEREF_FINDING) - || !bvmatch(&e->e_nname, &op->o_req_ndn))) + ((op->ors_deref & LDAP_DEREF_FINDING) || + !bvmatch(&e->e_nname, &op->o_req_ndn))) { goto loop_continue; } @@ -960,18 +796,14 @@ id2entry_retry: /* scopes is only non-empty for onelevel or subtree */ if ( !scopeok && BDB_IDL_N(scopes) ) { unsigned x; - if ( sop->ors_scope == LDAP_SCOPE_ONELEVEL ) { - x = bdb_idl_search( scopes, - e->e_id ); - if ( scopes[x] == e->e_id ) - scopeok = 1; + if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) { + x = bdb_idl_search( scopes, e->e_id ); + if ( scopes[x] == e->e_id ) scopeok = 1; } else { - /* subtree, walk up the tree */ + /* subtree, walk up the tree */ EntryInfo *tmp = BEI(e); - for (;tmp->bei_parent; - tmp=tmp->bei_parent) { - x = bdb_idl_search( - scopes, tmp->bei_id ); + for (;tmp->bei_parent; tmp=tmp->bei_parent) { + x = bdb_idl_search( scopes, tmp->bei_id ); if ( scopes[x] == tmp->bei_id ) { scopeok = 1; break; @@ -980,19 +812,14 @@ id2entry_retry: } } } -#endif /* Not in scope, ignore it */ - if ( !scopeok ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_search: %ld scope not okay\n", - (long) id, 0, 0); -#else + if ( !scopeok ) + { Debug( LDAP_DEBUG_TRACE, - "bdb_search: %ld scope not okay\n", + LDAP_XSTRING(bdb_search) + ": %ld scope not okay\n", (long) id, 0, 0 ); -#endif goto loop_continue; } @@ -1001,17 +828,15 @@ id2entry_retry: * this for non-base searches, and don't check the filter * explicitly here since it's only a candidate anyway. */ - if ( !manageDSAit && sop->oq_search.rs_scope != LDAP_SCOPE_BASE + if ( !manageDSAit && op->oq_search.rs_scope != LDAP_SCOPE_BASE && is_entry_referral( e ) ) { - BerVarray erefs = get_entry_referrals( sop, e ); - rs->sr_ref = referral_rewrite( erefs, - &e->e_name, NULL, - sop->oq_search.rs_scope == LDAP_SCOPE_SUBTREE - ? LDAP_SCOPE_SUBTREE - : LDAP_SCOPE_BASE ); + BerVarray erefs = get_entry_referrals( op, e ); + rs->sr_ref = referral_rewrite( erefs, &e->e_name, NULL, + op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL + ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE ); - send_search_reference( sop, rs ); + send_search_reference( op, rs ); ber_bvarray_free( rs->sr_ref ); ber_bvarray_free( erefs ); @@ -1025,253 +850,95 @@ id2entry_retry: } /* if it matches the filter and scope, send it */ - if (IS_PSEARCH) { - if (ps_type != LDAP_PSEARCH_BY_SCOPEOUT) { - rs->sr_err = test_filter( sop, rs->sr_entry, &cookief ); - } else { - rs->sr_err = LDAP_COMPARE_TRUE; - } - } else { - if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) { - rc_sync = test_filter( sop, rs->sr_entry, &cookief ); - rs->sr_err = test_filter( sop, - rs->sr_entry, &contextcsnand ); - if ( rs->sr_err == LDAP_COMPARE_TRUE ) { - if ( rc_sync == LDAP_COMPARE_TRUE ) { - if ( no_sync_state_change ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_search: error in context csn management\n", - 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_search: error in context csn management\n", - 0, 0, 0 ); -#endif - } - entry_sync_state = LDAP_SYNC_ADD; - } else { - if ( no_sync_state_change ) { - goto loop_continue; - } - entry_sync_state = LDAP_SYNC_PRESENT; - } - } - } else { - rs->sr_err = test_filter( sop, - rs->sr_entry, sop->oq_search.rs_filter ); - } - } + rs->sr_err = test_filter( op, rs->sr_entry, op->oq_search.rs_filter ); if ( rs->sr_err == LDAP_COMPARE_TRUE ) { /* check size limit */ - if ( --sop->oq_search.rs_slimit == -1 ) { - if (!IS_PSEARCH) { + if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { + if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size ) { +#ifdef SLAP_ZONE_ALLOC + slap_zn_runlock(bdb->bi_cache.c_zctx, e); +#endif bdb_cache_return_entry_r( bdb->bi_dbenv, - &bdb->bi_cache, e, &lock ); - } - e = NULL; - rs->sr_entry = NULL; - rs->sr_err = LDAP_SIZELIMIT_EXCEEDED; - rs->sr_ref = rs->sr_v2ref; - send_ldap_result( sop, rs ); - rs->sr_err = LDAP_SUCCESS; - goto done; - } - -#ifdef LDAP_CONTROL_PAGEDRESULTS - if ( get_pagedresults(sop) ) { - if ( rs->sr_nentries >= sop->o_pagedresults_size ) { - send_pagerequest_response( sop, rs, - lastid, tentries ); + &bdb->bi_cache, e, &lock ); + e = NULL; + send_paged_response( op, rs, &lastid, tentries ); goto done; } lastid = id; } -#endif if (e) { /* safe default */ - int result = -1; - -#if 0 /* noop is masked SLAP_CTRL_UPDATE */ - if( op->o_noop ) { - result = 0; - } else -#endif - if (IS_PSEARCH) { - int premodify_found = 0; - int entry_sync_state; - - if ( ps_type == LDAP_PSEARCH_BY_ADD || - ps_type == LDAP_PSEARCH_BY_DELETE || - ps_type == LDAP_PSEARCH_BY_MODIFY || - ps_type == LDAP_PSEARCH_BY_SCOPEOUT ) - { - if ( ps_type == LDAP_PSEARCH_BY_MODIFY ) { - struct psid_entry* psid_e; - LDAP_LIST_FOREACH( psid_e, - &op->o_pm_list, ps_link) - { - if( psid_e->ps_op == sop ) { - premodify_found = 1; - LDAP_LIST_REMOVE(psid_e, ps_link); - break; - } - } - if (psid_e != NULL) free (psid_e); - } - if ( ps_type == LDAP_PSEARCH_BY_ADD ) { - entry_sync_state = LDAP_SYNC_ADD; - } else if ( ps_type == LDAP_PSEARCH_BY_DELETE ) { - entry_sync_state = LDAP_SYNC_DELETE; - } else if ( ps_type == LDAP_PSEARCH_BY_MODIFY ) { - if ( premodify_found ) { - entry_sync_state = LDAP_SYNC_MODIFY; - } else { - entry_sync_state = LDAP_SYNC_ADD; - } - } else if ( ps_type == LDAP_PSEARCH_BY_SCOPEOUT ) - entry_sync_state = LDAP_SYNC_DELETE; - else { - rs->sr_err = LDAP_OTHER; - goto done; - } - rs->sr_err = bdb_build_sync_state_ctrl( sop, - rs, e, entry_sync_state, ctrls, - num_ctrls++, 1, search_context_csn ); - if ( rs->sr_err != LDAP_SUCCESS ) goto done; - rs->sr_attrs = attrs; - rs->sr_ctrls = ctrls; - result = send_search_entry( sop, rs ); - ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); - ch_free( ctrls[--num_ctrls] ); - ctrls[num_ctrls] = NULL; - rs->sr_ctrls = NULL; - - } else if ( ps_type == LDAP_PSEARCH_BY_PREMODIFY ) { - struct psid_entry* psid_e; - psid_e = (struct psid_entry *) calloc (1, - sizeof(struct psid_entry)); - psid_e->ps_op = sop; - LDAP_LIST_INSERT_HEAD( &op->o_pm_list, - psid_e, ps_link ); - - } else { - printf("Error !\n"); - } - } else { - if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) { - rs->sr_err = bdb_build_sync_state_ctrl( sop, - rs, e, entry_sync_state, ctrls, - num_ctrls++, 0, search_context_csn ); - if ( rs->sr_err != LDAP_SUCCESS ) goto done; - - rs->sr_ctrls = ctrls; - if ( rc_sync == LDAP_COMPARE_TRUE ) { /* ADD */ - rs->sr_attrs = sop->oq_search.rs_attrs; - } else { /* PRESENT */ - rs->sr_attrs = &null_attr; - } - result = send_search_entry( sop, rs ); - ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); - ch_free( ctrls[--num_ctrls] ); - ctrls[num_ctrls] = NULL; - rs->sr_ctrls = NULL; - } else { - rs->sr_attrs = sop->oq_search.rs_attrs; - rs->sr_ctrls = NULL; - result = send_search_entry( sop, rs ); - } - } + rs->sr_attrs = op->oq_search.rs_attrs; + rs->sr_operational_attrs = NULL; + rs->sr_ctrls = NULL; + rs->sr_flags = 0; + rs->sr_err = LDAP_SUCCESS; + rs->sr_err = send_search_entry( op, rs ); - switch (result) { - case 0: /* entry sent ok */ + switch ( rs->sr_err ) { + case LDAP_SUCCESS: /* entry sent ok */ break; - case 1: /* entry not sent */ + default: /* entry not sent */ break; - case -1: /* connection closed */ - if (!IS_PSEARCH) + case LDAP_UNAVAILABLE: + case LDAP_SIZELIMIT_EXCEEDED: +#ifdef SLAP_ZONE_ALLOC + slap_zn_runlock(bdb->bi_cache.c_zctx, e); +#endif bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock); e = NULL; rs->sr_entry = NULL; - rs->sr_err = LDAP_OTHER; + if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) { + rs->sr_ref = rs->sr_v2ref; + send_ldap_result( op, rs ); + rs->sr_err = LDAP_SUCCESS; + + } else { + rs->sr_err = LDAP_OTHER; + } goto done; } } + } else { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_search: %ld does not match filter\n", (long) id, 0, 0); -#else Debug( LDAP_DEBUG_TRACE, - "bdb_search: %ld does not match filter\n", + LDAP_XSTRING(bdb_search) + ": %ld does not match filter\n", (long) id, 0, 0 ); -#endif } loop_continue: if( e != NULL ) { /* free reader lock */ - if (!IS_PSEARCH) { - bdb_cache_return_entry_r( bdb->bi_dbenv, - &bdb->bi_cache, e , &lock); - } +#ifdef SLAP_ZONE_ALLOC + slap_zn_runlock(bdb->bi_cache.c_zctx, e); +#endif + bdb_cache_return_entry_r( bdb->bi_dbenv, + &bdb->bi_cache, e , &lock ); e = NULL; rs->sr_entry = NULL; } - - ldap_pvt_thread_yield(); } - if (!IS_PSEARCH) { - if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) { - rs->sr_err = LDAP_SUCCESS; - rs->sr_rspoid = LDAP_SYNC_INFO; - rs->sr_ctrls = NULL; - bdb_send_ldap_intermediate( sop, rs, - LDAP_SYNC_STATE_MODE_DONE, search_context_csn ); - - /* If changelog is supported, this is where to process it */ - - if ( sop->o_sync_mode & SLAP_SYNC_PERSIST ) { - /* refreshAndPersist mode */ - bdb_send_ldap_intermediate( sop, rs, - LDAP_SYNC_LOG_MODE_DONE, search_context_csn ); - } else { - /* refreshOnly mode */ - bdb_build_sync_done_ctrl( sop, rs, ctrls, - num_ctrls++, 1, search_context_csn ); - rs->sr_ctrls = ctrls; - rs->sr_ref = rs->sr_v2ref; - rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS : LDAP_REFERRAL; - send_ldap_result( sop, rs ); - if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL ) { - ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); - } - ch_free( ctrls[--num_ctrls] ); - ctrls[num_ctrls] = NULL; - } - } else { - rs->sr_ctrls = NULL; - rs->sr_ref = rs->sr_v2ref; - rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS : LDAP_REFERRAL; - send_ldap_result( sop, rs ); - } +nochange: + rs->sr_ctrls = NULL; + rs->sr_ref = rs->sr_v2ref; + rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS : LDAP_REFERRAL; + rs->sr_rspoid = NULL; + if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { + send_paged_response( op, rs, NULL, 0 ); + } else { + send_ldap_result( op, rs ); } rs->sr_err = LDAP_SUCCESS; done: - if( !IS_PSEARCH && e != NULL ) { - /* free reader lock */ - bdb_cache_return_entry_r ( bdb->bi_dbenv, &bdb->bi_cache, e, &lock ); - } - - LOCK_ID_FREE (bdb->bi_dbenv, locker ); - - ber_bvfree( search_context_csn ); + if ( !opinfo ) + LOCK_ID_FREE( bdb->bi_dbenv, locker ); if( rs->sr_v2ref ) { ber_bvarray_free( rs->sr_v2ref ); @@ -1288,14 +955,8 @@ static int base_candidate( Entry *e, ID *ids ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ENTRY, - "base_candidate: base: \"%s\" (0x%08lx)\n", - e->e_nname.bv_val, (long) e->e_id, 0); -#else Debug(LDAP_DEBUG_ARGS, "base_candidates: base: \"%s\" (0x%08lx)\n", e->e_nname.bv_val, (long) e->e_id, 0); -#endif ids[0] = 1; ids[1] = e->e_id; @@ -1308,14 +969,15 @@ static int base_candidate( static int oc_filter( Filter *f, int cur, - int *max -) + int *max ) { int rc = 0; + assert( f != NULL ); + if( cur > *max ) *max = cur; - switch(f->f_choice) { + switch( f->f_choice ) { case LDAP_FILTER_PRESENT: if (f->f_desc == slap_schema.si_ad_objectClass) { rc = 1; @@ -1325,7 +987,7 @@ static int oc_filter( case LDAP_FILTER_AND: case LDAP_FILTER_OR: cur++; - for (f=f->f_and; f; f=f->f_next) { + for ( f=f->f_and; f; f=f->f_next ) { (void) oc_filter(f, cur, max); } break; @@ -1341,9 +1003,7 @@ static void search_stack_free( void *key, void *data ) ber_memfree_x(data, NULL); } -static void *search_stack( - Operation *op -) +static void *search_stack( Operation *op ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; void *ret = NULL; @@ -1369,7 +1029,6 @@ static void *search_stack( } static int search_candidates( - Operation *stackop, Operation *op, SlapReply *rs, Entry *e, @@ -1381,10 +1040,16 @@ static int search_candidates( int rc, depth = 1; Filter f, rf, xf, nf; ID *stack; - AttributeAssertion aa_ref; -#ifdef BDB_SUBENTRIES +#ifdef LDAP_COMP_MATCH + AttributeAssertion aa_ref = { NULL, BER_BVNULL, NULL }; +#else + AttributeAssertion aa_ref = { NULL, BER_BVNULL }; +#endif Filter sf; - AttributeAssertion aa_subentry; +#ifdef LDAP_COMP_MATCH + AttributeAssertion aa_subentry = { NULL, BER_BVNULL, NULL }; +#else + AttributeAssertion aa_subentry = { NULL, BER_BVNULL }; #endif /* @@ -1394,15 +1059,9 @@ static int search_candidates( * (|[(objectClass=referral)(objectClass=alias)](user-filter)) */ -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ENTRY, - "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n", - e->e_nname.bv_val, (long) e->e_id, op->oq_search.rs_scope); -#else Debug(LDAP_DEBUG_TRACE, "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n", e->e_nname.bv_val, (long) e->e_id, op->oq_search.rs_scope ); -#endif xf.f_or = op->oq_search.rs_filter; xf.f_choice = LDAP_FILTER_OR; @@ -1412,12 +1071,10 @@ static int search_candidates( * these clauses are redundant. */ if (!oc_filter(op->oq_search.rs_filter, 1, &depth) - && !get_subentries_visibility(op) - && !is_sync_protocol(op) ) - { + && !get_subentries_visibility(op)) { if( !get_manageDSAit(op) && !get_domainScope(op) ) { /* match referral objects */ - struct berval bv_ref = { sizeof("referral")-1, "referral" }; + struct berval bv_ref = BER_BVC( "referral" ); rf.f_choice = LDAP_FILTER_EQUALITY; rf.f_ava = &aa_ref; rf.f_av_desc = slap_schema.si_ad_objectClass; @@ -1434,14 +1091,13 @@ static int search_candidates( /* Dummy; we compute scope separately now */ nf.f_choice = SLAPD_FILTER_COMPUTED; nf.f_result = LDAP_SUCCESS; - nf.f_next = xf.f_or == op->oq_search.rs_filter + nf.f_next = ( xf.f_or == op->oq_search.rs_filter ) ? op->oq_search.rs_filter : &xf ; /* Filter depth increased again, adding dummy clause */ depth++; -#ifdef BDB_SUBENTRIES if( get_subentries_visibility( op ) ) { - struct berval bv_subentry = { sizeof("SUBENTRY")-1, "SUBENTRY" }; + struct berval bv_subentry = BER_BVC( "subentry" ); sf.f_choice = LDAP_FILTER_EQUALITY; sf.f_ava = &aa_subentry; sf.f_av_desc = slap_schema.si_ad_objectClass; @@ -1449,13 +1105,12 @@ static int search_candidates( sf.f_next = nf.f_next; nf.f_next = &sf; } -#endif /* Allocate IDL stack, plus 1 more for former tmp */ if ( depth+1 > bdb->bi_search_stack_depth ) { stack = ch_malloc( (depth + 1) * BDB_IDL_UM_SIZE * sizeof( ID ) ); } else { - stack = search_stack( stackop ); + stack = search_stack( op ); } if( op->ors_deref & LDAP_DEREF_SEARCHING ) { @@ -1474,243 +1129,173 @@ static int search_candidates( } if( rc ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, DETAIL1, - "bdb_search_candidates: failed (rc=%d)\n", rc, 0, 0 ); -#else Debug(LDAP_DEBUG_TRACE, "bdb_search_candidates: failed (rc=%d)\n", rc, NULL, NULL ); -#endif } else { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, DETAIL1, - "bdb_search_candidates: id=%ld first=%ld last=%ld\n", - (long) ids[0], (long) BDB_IDL_FIRST(ids), - (long) BDB_IDL_LAST(ids)); -#else Debug(LDAP_DEBUG_TRACE, "bdb_search_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST(ids), (long) BDB_IDL_LAST(ids) ); -#endif } return rc; } -#ifdef LDAP_CONTROL_PAGEDRESULTS -static void -send_pagerequest_response( - Operation *op, - SlapReply *rs, - ID lastid, - int tentries ) +static int +parse_paged_cookie( Operation *op, SlapReply *rs ) { - LDAPControl ctrl, *ctrls[2]; - char berbuf[LBER_ELEMENT_SIZEOF]; - BerElement *ber = (BerElement *)berbuf; - struct berval cookie = { 0, NULL }; - PagedResultsCookie respcookie; - -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ENTRY, - "send_pagerequest_response: lastid: (0x%08lx) " - "nentries: (0x%081x)\n", - lastid, rs->sr_nentries, NULL ); -#else - Debug(LDAP_DEBUG_ARGS, "send_pagerequest_response: lastid: (0x%08lx) " - "nentries: (0x%081x)\n", lastid, rs->sr_nentries, NULL ); -#endif - - ctrl.ldctl_value.bv_val = NULL; - ctrls[0] = &ctrl; - ctrls[1] = NULL; + LDAPControl **c; + int rc = LDAP_SUCCESS; + ber_tag_t tag; + ber_int_t size; + BerElement *ber; + struct berval cookie = BER_BVNULL; + PagedResultsState *ps = op->o_pagedresults_state; + + /* this function must be invoked only if the pagedResults + * control has been detected, parsed and partially checked + * by the frontend */ + assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ); + + /* look for the appropriate ctrl structure */ + for ( c = op->o_ctrls; c[0] != NULL; c++ ) { + if ( strcmp( c[0]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS ) == 0 ) + { + break; + } + } - ber_init2( ber, NULL, LBER_USE_DER ); + if ( c[0] == NULL ) { + rs->sr_text = "missing pagedResults control"; + return LDAP_PROTOCOL_ERROR; + } - respcookie = ( PagedResultsCookie )lastid; - op->o_conn->c_pagedresults_state.ps_cookie = respcookie; - cookie.bv_len = sizeof( respcookie ); - cookie.bv_val = (char *)&respcookie; + /* Tested by frontend */ + assert( c[0]->ldctl_value.bv_len > 0 ); - /* - * FIXME: we should consider sending an estimate of the entries - * left, after appropriate security check is done + /* Parse the control value + * realSearchControlValue ::= SEQUENCE { + * size INTEGER (0..maxInt), + * -- requested page size from client + * -- result set size estimate from server + * cookie OCTET STRING + * } */ - ber_printf( ber, "{iO}", tentries, &cookie ); - - if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) { - goto done; + ber = ber_init( &c[0]->ldctl_value ); + if ( ber == NULL ) { + rs->sr_text = "internal error"; + return LDAP_OTHER; } - ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS; - ctrls[0]->ldctl_iscritical = 0; - - rs->sr_ctrls = ctrls; - rs->sr_err = LDAP_SUCCESS; - send_ldap_result( op, rs ); - -done: - (void) ber_free_buf( ber ); -} -#endif - -int -bdb_build_sync_state_ctrl( - Operation *op, - SlapReply *rs, - Entry *e, - int entry_sync_state, - LDAPControl **ctrls, - int num_ctrls, - int send_cookie, - struct berval *csn) -{ - Attribute* a; - int ret; - int res; - const char *text = NULL; + tag = ber_scanf( ber, "{im}", &size, &cookie ); - char berbuf[LBER_ELEMENT_SIZEOF]; - BerElement *ber = (BerElement *)berbuf; + /* Tested by frontend */ + assert( tag != LBER_ERROR ); + assert( size >= 0 ); - struct berval entryuuid_bv = { 0, NULL }; + /* cookie decoding/checks deferred to backend... */ + if ( cookie.bv_len ) { + PagedResultsCookie reqcookie; + if( cookie.bv_len != sizeof( reqcookie ) ) { + /* bad cookie */ + rs->sr_text = "paged results cookie is invalid"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } - ber_init2( ber, 0, LBER_USE_DER ); + AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie )); - ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) ); + if ( reqcookie > ps->ps_cookie ) { + /* bad cookie */ + rs->sr_text = "paged results cookie is invalid"; + rc = LDAP_PROTOCOL_ERROR; + goto done; - for ( a = e->e_attrs; a != NULL; a = a->a_next ) { - AttributeDescription *desc = a->a_desc; - if ( desc == slap_schema.si_ad_entryUUID ) { - ber_dupbv( &entryuuid_bv, &a->a_vals[0] ); + } else if ( reqcookie < ps->ps_cookie ) { + rs->sr_text = "paged results cookie is invalid or old"; + rc = LDAP_UNWILLING_TO_PERFORM; + goto done; } - } - if ( send_cookie && csn ) { - ber_printf( ber, "{eOON}", - entry_sync_state, &entryuuid_bv, csn ); } else { - ber_printf( ber, "{eON}", - entry_sync_state, &entryuuid_bv ); - } - - ch_free( entryuuid_bv.bv_val ); - entryuuid_bv.bv_val = NULL; - - ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_STATE; - ctrls[num_ctrls]->ldctl_iscritical = op->o_sync; - ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); - - ber_free_buf( ber ); - - if ( ret < 0 ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_build_sync_ctrl: ber_flatten2 failed\n", - 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_build_sync_ctrl: ber_flatten2 failed\n", - 0, 0, 0 ); + /* Initial request. Initialize state. */ +#if 0 + if ( op->o_conn->c_pagedresults_state.ps_cookie != 0 ) { + /* There's another pagedResults control on the + * same connection; reject new pagedResults controls + * (allowed by RFC2696) */ + rs->sr_text = "paged results cookie unavailable; try later"; + rc = LDAP_UNWILLING_TO_PERFORM; + goto done; + } #endif - send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); - return ret; + ps->ps_cookie = 0; + ps->ps_count = 0; } - return LDAP_SUCCESS; +done:; + (void)ber_free( ber, 1 ); + + return rc; } -int -bdb_build_sync_done_ctrl( +static void +send_paged_response( Operation *op, SlapReply *rs, - LDAPControl **ctrls, - int num_ctrls, - int send_cookie, - struct berval *csn ) + ID *lastid, + int tentries ) { - int ret; - char berbuf[LBER_ELEMENT_SIZEOF]; - BerElement *ber = (BerElement *)berbuf; - - ber_init2( ber, NULL, LBER_USE_DER ); + LDAPControl ctrl, *ctrls[2]; + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + PagedResultsCookie respcookie; + struct berval cookie; - ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) ); + Debug(LDAP_DEBUG_ARGS, + "send_paged_response: lastid=0x%08lx nentries=%d\n", + lastid ? *lastid : 0, rs->sr_nentries, NULL ); - if ( send_cookie && csn ) { - ber_printf( ber, "{ON}", csn ); - } else { - ber_printf( ber, "{N}" ); - } + BER_BVZERO( &ctrl.ldctl_value ); + ctrls[0] = &ctrl; + ctrls[1] = NULL; - ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_DONE; - ctrls[num_ctrls]->ldctl_iscritical = op->o_sync; - ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); + ber_init2( ber, NULL, LBER_USE_DER ); - ber_free_buf( ber ); + if ( lastid ) { + respcookie = ( PagedResultsCookie )(*lastid); + cookie.bv_len = sizeof( respcookie ); + cookie.bv_val = (char *)&respcookie; - if ( ret < 0 ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_build_sync_done_ctrl: ber_flatten2 failed\n", - 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_build_sync_done_ctrl: ber_flatten2 failed\n", - 0, 0, 0 ); -#endif - send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); - return ret; + } else { + respcookie = ( PagedResultsCookie )0; + BER_BVSTR( &cookie, "" ); } - return LDAP_SUCCESS; -} - -int -bdb_send_ldap_intermediate( - Operation *op, - SlapReply *rs, - int state, - struct berval *cookie ) -{ - char berbuf[LBER_ELEMENT_SIZEOF]; - BerElement *ber = (BerElement *)berbuf; - struct berval rspdata; - - int ret; + op->o_conn->c_pagedresults_state.ps_cookie = respcookie; + op->o_conn->c_pagedresults_state.ps_count = + ((PagedResultsState *)op->o_pagedresults_state)->ps_count + + rs->sr_nentries; - ber_init2( ber, NULL, LBER_USE_DER ); + /* return size of 0 -- no estimate */ + ber_printf( ber, "{iO}", 0, &cookie ); - if ( cookie == NULL ) { - ber_printf( ber, "{eN}", state ); - } else { - ber_printf( ber, "{eON}", state, cookie ); + if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) { + goto done; } - ret = ber_flatten2( ber, &rspdata, 0 ); - - if ( ret < 0 ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_send_ldap_intermediate: ber_flatten2 failed\n", - 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_send_ldap_intermediate: ber_flatten2 failed\n", - 0, 0, 0 ); -#endif - send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); - return ret; - } + ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS; + ctrls[0]->ldctl_iscritical = 0; - rs->sr_rspdata = &rspdata; - send_ldap_intermediate( op, rs ); - rs->sr_rspdata = NULL; - ber_free_buf( ber ); + rs->sr_ctrls = ctrls; + rs->sr_err = LDAP_SUCCESS; + send_ldap_result( op, rs ); + rs->sr_ctrls = NULL; - return LDAP_SUCCESS; +done: + (void) ber_free_buf( ber ); } +