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