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